Files
SilverMetal/linux/build/scripts/verify-reproducibility.sh
SysAdmin 4444dc11f3 feat(linux/build): scaffold reproducible ISO build pipeline (M1.1)
Vendors Kicksecure derivative-maker as a pinned submodule (18.1.7.4),
adds the wrapper + verify + diagnose scripts, the pinned builder image,
and the reproducibility-gated Gitea Actions workflow. Base flavour only —
no hardening overlay (that's M1.2).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 04:25:48 +01:00

87 lines
2.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# SilverMetal Linux — reproducibility gate.
#
# Builds the ISO twice from clean clones of HEAD and compares SHA256.
# This is the M1.1 exit-criterion check; CI runs it on every push.
#
# Usage:
# linux/build/scripts/verify-reproducibility.sh
# COMMIT=abc1234 linux/build/scripts/verify-reproducibility.sh # specific SHA
#
# Exit codes:
# 0 Both builds produced byte-identical ISOs
# 1 Mismatch — diagnose-divergence.sh has been invoked
# 2 Setup / clone error
# 3 One of the builds failed before producing an ISO
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../../.." && pwd)"
COMMIT="${COMMIT:-$(git -C "${REPO_ROOT}" rev-parse HEAD)}"
WORKROOT="${WORKROOT:-/tmp/silvermetal-repro-$$}"
DIR_A="${WORKROOT}/build-a"
DIR_B="${WORKROOT}/build-b"
cleanup() {
if [[ "${KEEP_BUILD_DIRS:-0}" != "1" ]]; then
rm -rf "${WORKROOT}"
else
echo "verify: kept ${WORKROOT} for inspection"
fi
}
trap cleanup EXIT
mkdir -p "${DIR_A}" "${DIR_B}"
clone_one() {
local dest="$1"
git clone --recurse-submodules "${REPO_ROOT}" "${dest}/repo" >/dev/null 2>&1 \
|| { echo "verify: clone -> ${dest} failed" >&2; exit 2; }
git -C "${dest}/repo" checkout --quiet "${COMMIT}"
git -C "${dest}/repo" submodule update --init --recursive --quiet
}
build_one() {
local dest="$1"
BUILD_DIR="${dest}/out" "${dest}/repo/linux/build/scripts/build.sh" \
|| { echo "verify: build in ${dest} failed" >&2; exit 3; }
}
echo "verify: cloning two copies at ${COMMIT}"
clone_one "${DIR_A}"
clone_one "${DIR_B}"
echo "verify: building copy A"
build_one "${DIR_A}"
echo "verify: building copy B"
build_one "${DIR_B}"
ISO_A="$(ls "${DIR_A}/out"/*.iso 2>/dev/null | head -n1 || true)"
ISO_B="$(ls "${DIR_B}/out"/*.iso 2>/dev/null | head -n1 || true)"
if [[ -z "${ISO_A}" || -z "${ISO_B}" ]]; then
echo "verify: missing ISO (A=${ISO_A:-<none>} B=${ISO_B:-<none>})" >&2
exit 3
fi
HASH_A="$(sha256sum "${ISO_A}" | cut -d' ' -f1)"
HASH_B="$(sha256sum "${ISO_B}" | cut -d' ' -f1)"
echo "verify: A = ${HASH_A} ${ISO_A}"
echo "verify: B = ${HASH_B} ${ISO_B}"
if [[ "${HASH_A}" == "${HASH_B}" ]]; then
echo "verify: PASS — reproducible at ${COMMIT}"
exit 0
fi
echo "verify: FAIL — running diffoscope"
KEEP_BUILD_DIRS=1
ISO_A="${ISO_A}" ISO_B="${ISO_B}" \
"${REPO_ROOT}/linux/build/scripts/diagnose-divergence.sh" \
|| true
exit 1