#!/bin/bash

## Copyright (C) 2012 - 2026 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## AI-Assisted

## Verify a built image reproduces, by comparing it against a reference build
## with diffoscope (via developer-meta-files'
## 'dm-reproducible-compare-artifacts'). Set
## 'dist_build_reproducible_reference_folder' to a reference build's
## output folder to enable this.

set -x
set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
shopt -s inherit_errexit
shopt -s shift_verbose
export LC_ALL=C

true "INFO: Currently running script: ${BASH_SOURCE[0]} $*"

MYDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

cd "${MYDIR}"
cd ..
cd help-steps

source pre
source variables

compare_target() {
   local target artifact reference_artifact report_out compare_exit_code
   target="$1"
   artifact="$2"

   if [ ! -f "${artifact}" ]; then
      true "${cyan}INFO: no ${target} artifact at '${artifact}', skipping.${reset}"
      return 0
   fi

   reference_artifact="${dist_build_reproducible_reference_folder}/$(basename -- "${artifact}")"
   if [ ! -f "${reference_artifact}" ]; then
      true "${cyan}INFO: no reference ${target} artifact at '${reference_artifact}', skipping.${reset}"
      return 0
   fi

   report_out="${binary_build_folder_dist}/$(basename -- "${artifact}").compare-report.txt"
   true "${cyan}INFO: comparing ${target} build vs reference with diffoscope...${reset}"

   compare_exit_code="0"
   ## The comparator locates ONE artifact of '$target' under each directory rather than
   ## taking two file paths, so pass the containing directories. Both paths were resolved
   ## to existing files above, so their dirnames are the right search roots.
   "${dist_developer_meta_files_folder}/usr/bin/dm-reproducible-compare-artifacts" \
      --target "${target}" \
      --dir-a "$(dirname -- "${reference_artifact}")" \
      --dir-b "$(dirname -- "${artifact}")" \
      --output "${report_out}" \
      || compare_exit_code="$?"

   if [ "${compare_exit_code}" = "0" ]; then
      true "${bold}${green}INFO: ${target} reproducible: identical to the reference build.${reset}"
   elif [ "${compare_exit_code}" = "1" ]; then
      true "${bold}${red}WARNING: ${target} differs from the reference build; see '${report_out}'.${reset}"
   else
      error "dm-reproducible-compare-artifacts failed for ${target} (exit ${compare_exit_code})."
   fi
}

main() {
   if [ "${build_dry_run:-}" = "true" ]; then
      true "${bold}${cyan}INFO: dry-run, skipping ${BASH_SOURCE[0]}. ${reset}"
      return 0
   fi

   if [ "${dist_build_fast2:-}" = "1" ]; then
      printf '%s\n' "${bold}${cyan}INFO: run with '--fast 2' switch, skipping ${BASH_SOURCE[0]}. ${reset}"
      return 0
   fi

   if [ ! "${dist_build_script_create_report:-}" = "true" ]; then
      true "${bold}${cyan}INFO: run without --report true, skipping, ok. ${reset}"
      return 0
   fi

   ## TODO: (not applicable to AI agents) We should document in the wiki how to
   ## do a reproducible build and compare it to a reference artifact. This
   ## script is not the right place to document that info.
   if [ "${dist_build_reproducible_reference_folder:-}" = "" ]; then
      true "${bold}${cyan}INFO: dist_build_reproducible_reference_folder is unset, no reference to compare with. Skipping, OK.${reset}"
      return 0
   fi

   if [ "${dist_build_raw:-}" = "true" ]; then
      true "${cyan}INFO: raw is a build intermediate with no released artifact, dm-reproducible-compare-artifacts has no 'raw' target. Skipping, OK.${reset}"
   fi

   if [ "${dist_build_virtualbox:-}" = "true" ]; then
      compare_target "virtualbox" "${binary_image_ova_file}"
   fi

   if [ "${dist_build_qcow2:-}" = "true" ]; then
      compare_target "qcow2" "${libvirt_target_qcow2_xz_archive_file}"
   fi

   if [ "${dist_build_iso:-}" = "true" ]; then
      compare_target "iso" "${binary_image_iso_file}"
   fi
}

main "$@"
