#!/usr/bin/env bash set -euo pipefail # Verifies repro-bundle fail-closed policy controls: # - build-attestation-bundle.sh enforces digest-pinned images # - deterministic env defaults are present # - release Dockerfiles fail without @sha256 pinning SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" BUNDLE_SCRIPT="${REPO_ROOT}/devops/tools/build-attestation-bundle.sh" DOTNET_DOCKERFILE="${REPO_ROOT}/devops/release/docker/Dockerfile.dotnet-service" ANGULAR_DOCKERFILE="${REPO_ROOT}/devops/release/docker/Dockerfile.angular-ui" fail() { echo "[repro-policy] $*" >&2 exit 1 } require_line() { local file=$1 local pattern=$2 if ! grep -Fq "$pattern" "$file"; then fail "Missing required pattern in ${file}: ${pattern}" fi } [[ -f "${BUNDLE_SCRIPT}" ]] || fail "Missing script: ${BUNDLE_SCRIPT}" [[ -f "${DOTNET_DOCKERFILE}" ]] || fail "Missing Dockerfile: ${DOTNET_DOCKERFILE}" [[ -f "${ANGULAR_DOCKERFILE}" ]] || fail "Missing Dockerfile: ${ANGULAR_DOCKERFILE}" bash -n "${BUNDLE_SCRIPT}" require_line "${BUNDLE_SCRIPT}" "export LC_ALL=C" require_line "${BUNDLE_SCRIPT}" "export TZ=UTC" require_line "${BUNDLE_SCRIPT}" "SOURCE_DATE_EPOCH=\${SOURCE_DATE_EPOCH:-0}" require_line "${BUNDLE_SCRIPT}" "must be digest-pinned (@sha256:...)" require_line "${DOTNET_DOCKERFILE}" 'RUN case "${SDK_IMAGE}" in *@sha256:*)' require_line "${DOTNET_DOCKERFILE}" 'RUN case "${RUNTIME_IMAGE}" in *@sha256:*)' require_line "${ANGULAR_DOCKERFILE}" 'RUN case "${NODE_IMAGE}" in *@sha256:*)' require_line "${ANGULAR_DOCKERFILE}" 'RUN case "${NGINX_IMAGE}" in *@sha256:*)' tmp_dir="$(mktemp -d)" trap 'rm -rf "${tmp_dir}"' EXIT attest_dir="${tmp_dir}/attest" bundle_out="${tmp_dir}/out" mkdir -p "${attest_dir}" printf '{"fixture":"ok"}\n' > "${attest_dir}/fixture.json" # Positive path (pinned image) BUILDER_IMG='registry.example.org/build/my-builder@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' \ SOURCE_DATE_EPOCH=0 \ bash "${BUNDLE_SCRIPT}" "${attest_dir}" "${bundle_out}" > /dev/null [[ -f "${bundle_out}/attestation-bundle-0.tgz" ]] || fail "Expected deterministic bundle archive was not created" # Negative path (unpinned image must fail closed with exit 65) set +e BUILDER_IMG='registry.example.org/build/my-builder:latest' \ SOURCE_DATE_EPOCH=0 \ bash "${BUNDLE_SCRIPT}" "${attest_dir}" "${bundle_out}" > "${tmp_dir}/negative.out" 2> "${tmp_dir}/negative.err" status=$? set -e if [[ ${status} -ne 65 ]]; then fail "Expected unpinned image run to fail with exit 65, got ${status}" fi if ! grep -Fq "must be digest-pinned" "${tmp_dir}/negative.err"; then fail "Expected digest pinning failure message was not emitted" fi echo "[repro-policy] PASS"