#!/usr/bin/env bash
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
OUTPUT="$ROOT/target/replacement-certification.json"
PROOF_DIR="$ROOT/target/replacement-proofs"
CONTRACT="$ROOT/scripts/replacement-certificate-contract.json"
REPRODUCIBLE_DIR="$ROOT/target/reproducible-release"
BINARY="$ROOT/target/reproducible-release/systemd-resolved"
CLIENT="$ROOT/target/reproducible-release/resolvectl"
NSS_MODULE="$ROOT/target/reproducible-release/libnss_resolve.so.2"
REFERENCE="127.0.0.53:53"
CANDIDATE="127.0.0.1:10553"
RUN_HOST_TESTS=true
RUN_NETWORK_NAMESPACE_TESTS=true

usage() {
    cat <<'EOF'
Usage: scripts/certify-replacement-v2.sh [OPTIONS]

Creates a fail-closed schema-3 replacement certificate. Certification requires a clean
Git tree, the immutable upstream baseline, every local build/live gate, and
external proofs for a Rust 1.74 reproducible release, the pinned upstream resolver
suites, the full security suite, and a rebooted replacement VM.

Options:
  --output PATH             Certificate .json leaf under target or /tmp
  --proof-directory PATH    External proof directory
  --reproducible-directory PATH
                             Local two-build release directory
  --binary PATH             Release daemon binary
  --client PATH             Release resolvectl binary
  --nss-module PATH         Release libnss_resolve.so.2
  --reference HOST:PORT     Existing resolver for shadow comparison
  --candidate HOST:PORT     Candidate shadow endpoint
  --no-host-tests           Record host differential testing as failed
  --no-netns-tests          Record live mDNS/DNS-SD testing as failed
  -h, --help                Show this help
EOF
}

while (($#)); do
    case "$1" in
        --output)
            OUTPUT=${2:?missing output path}
            shift 2
            ;;
        --proof-directory)
            PROOF_DIR=${2:?missing proof directory}
            shift 2
            ;;
        --reproducible-directory)
            REPRODUCIBLE_DIR=${2:?missing reproducible directory}
            shift 2
            ;;
        --binary)
            BINARY=${2:?missing binary path}
            shift 2
            ;;
        --client)
            CLIENT=${2:?missing client path}
            shift 2
            ;;
        --nss-module)
            NSS_MODULE=${2:?missing NSS module path}
            shift 2
            ;;
        --reference)
            REFERENCE=${2:?missing reference endpoint}
            shift 2
            ;;
        --candidate)
            CANDIDATE=${2:?missing candidate endpoint}
            shift 2
            ;;
        --no-host-tests)
            RUN_HOST_TESTS=false
            shift
            ;;
        --no-netns-tests)
            RUN_NETWORK_NAMESPACE_TESTS=false
            shift
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            printf 'Unknown option: %s\n' "$1" >&2
            usage >&2
            exit 2
            ;;
    esac
done

for command in basename dirname mkdir mktemp mv readlink rm; do
    command -v "$command" >/dev/null || {
        printf 'Required command is missing: %s\n' "$command" >&2
        exit 2
    }
done

[[ ! -L $ROOT/target ]] || {
    printf 'Repository target directory must not be a symbolic link: %s\n' \
        "$ROOT/target" >&2
    exit 2
}
mkdir -p "$ROOT/target"
TARGET_ROOT="$(readlink -f -- "$ROOT/target")"
TMP_ROOT="$(readlink -f -- /tmp)"
OUTPUT_NAME="$(basename -- "$OUTPUT")"
OUTPUT_PARENT_INPUT="$(dirname -- "$OUTPUT")"
if [[ $OUTPUT_NAME != *.json || $OUTPUT_NAME == .json ]]; then
    printf 'Certificate output must be a nonempty .json leaf: %s\n' "$OUTPUT" >&2
    exit 2
fi
if [[ ! -d $OUTPUT_PARENT_INPUT ]]; then
    printf 'Certificate output parent must already exist: %s\n' \
        "$OUTPUT_PARENT_INPUT" >&2
    exit 2
fi
OUTPUT_PARENT="$(readlink -f -- "$OUTPUT_PARENT_INPUT")" || {
    printf 'Cannot resolve certificate output parent: %s\n' \
        "$OUTPUT_PARENT_INPUT" >&2
    exit 2
}
case "$OUTPUT_PARENT" in
    "$TARGET_ROOT"|"$TMP_ROOT") ;;
    *)
        printf 'Certificate output parent must resolve exactly to %s or %s: %s\n' \
            "$TARGET_ROOT" "$TMP_ROOT" "$OUTPUT_PARENT" >&2
        exit 2
        ;;
esac
OUTPUT="$OUTPUT_PARENT/$OUTPUT_NAME"
REPORT_DIR="$OUTPUT_PARENT/${OUTPUT_NAME%.json}.d"
if [[ $REPORT_DIR == "$OUTPUT" || -L $OUTPUT || -L $REPORT_DIR ]]; then
    printf 'Certificate output or report path is unsafe: %s\n' "$OUTPUT" >&2
    exit 2
fi
if [[ -e $OUTPUT || -L $OUTPUT ]]; then
    printf 'Certificate output must not already exist: %s\n' "$OUTPUT" >&2
    exit 2
fi
if [[ -e $REPORT_DIR || -L $REPORT_DIR ]]; then
    printf 'Certificate report path must not already exist: %s\n' \
        "$REPORT_DIR" >&2
    exit 2
fi

for command in cargo git make python3 rustc sha256sum; do
    command -v "$command" >/dev/null || {
        printf 'Required command is missing: %s\n' "$command" >&2
        exit 2
    }
done
[[ -x /usr/bin/python3 ]] || {
    printf '%s\n' 'Required isolated Python interpreter is missing: /usr/bin/python3' >&2
    exit 2
}

PROOF_DIR="$(readlink -m "$PROOF_DIR")"
REPRODUCIBLE_DIR="$(readlink -m "$REPRODUCIBLE_DIR")"
FINAL_OUTPUT=$OUTPUT
FINAL_REPORT_DIR=$REPORT_DIR
STAGED_REPORT_DIR="$(mktemp -d \
    "$OUTPUT_PARENT/.${OUTPUT_NAME%.json}.d.new.XXXXXX")"
STAGED_OUTPUT="$(mktemp \
    "$OUTPUT_PARENT/.${OUTPUT_NAME}.new.XXXXXX")"
: >"$STAGED_REPORT_DIR/.rustd-resolved-certification-stage"
cleanup_staging() {
    if [[ -n ${STAGED_REPORT_DIR:-} \
        && -f $STAGED_REPORT_DIR/.rustd-resolved-certification-stage ]]; then
        rm -rf -- "$STAGED_REPORT_DIR"
    fi
    if [[ -n ${STAGED_OUTPUT:-} ]]; then
        rm -f -- "$STAGED_OUTPUT"
    fi
}
trap cleanup_staging EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
REPORT_DIR=$STAGED_REPORT_DIR
OUTPUT=$STAGED_OUTPUT
LOG_DIR="$REPORT_DIR/logs"
ARTIFACT_DIR="$REPORT_DIR/artifacts"
RESULTS="$REPORT_DIR/gates.tsv"
mkdir -p "$LOG_DIR" "$ARTIFACT_DIR"
: >"$RESULTS"

record() {
    local gate=$1
    local status=$2
    local detail=$3
    detail=${detail//$'\t'/ }
    detail=${detail//$'\n'/ }
    printf '%s\t%s\t%s\n' "$gate" "$status" "$detail" >>"$RESULTS"
}

run_gate() {
    local gate=$1
    shift
    local log="$LOG_DIR/${gate//[^A-Za-z0-9_.-]/_}.log"
    {
        printf '$'
        printf ' %q' "$@"
        printf '\n'
        "$@"
    } >"$log" 2>&1
    local status=$?
    if ((status == 0)); then
        record "$gate" pass "$log"
    else
        record "$gate" fail "$log (exit $status)"
    fi
    return 0
}

SOURCE_COMMIT="$(git -C "$ROOT" rev-parse HEAD)"
SOURCE_TREE="$(git -C "$ROOT" rev-parse 'HEAD^{tree}')"
BASELINE_COMMIT="$(cat "$ROOT/compat/upstream-systemd/commit" 2>/dev/null || true)"
BASELINE_RELEASE="$(cat "$ROOT/compat/upstream-systemd/release" 2>/dev/null || true)"

if [[ -z $(git -C "$ROOT" status --porcelain=v1 --untracked-files=all) ]]; then
    record source-clean pass clean
else
    git -C "$ROOT" status --porcelain=v1 --untracked-files=all >"$LOG_DIR/source-clean.log"
    record source-clean fail "$LOG_DIR/source-clean.log"
fi

if [[ $SOURCE_COMMIT =~ ^[0-9a-f]{40}$ && $SOURCE_TREE =~ ^[0-9a-f]{40}$ ]]; then
    record source-identity pass "$SOURCE_COMMIT:$SOURCE_TREE"
else
    record source-identity fail invalid
fi

run_gate upstream-baseline \
    bash "$ROOT/scripts/verify-upstream-resolved-baseline.sh"

RUST_TOOLCHAIN_LOG="$LOG_DIR/rust-1.74.log"
{
    rustc --version --verbose
    cargo --version --verbose
} >"$RUST_TOOLCHAIN_LOG" 2>&1
RUSTC_RELEASE="$(rustc --version | awk '{print $2}')"
CARGO_RELEASE="$(cargo --version | awk '{print $2}')"
if [[ $RUSTC_RELEASE == 1.74.0 && $CARGO_RELEASE == 1.74.0 ]]; then
    record rust-1.74 pass "$RUST_TOOLCHAIN_LOG"
else
    record rust-1.74 fail "$RUST_TOOLCHAIN_LOG"
fi

run_gate rust-format \
    cargo fmt --manifest-path "$ROOT/Cargo.toml" --all -- --check
run_gate native \
    make -C "$ROOT" check-native
run_gate packaging \
    make -C "$ROOT" check-packaging
run_gate nss \
    make -C "$ROOT" check-nss
run_gate rust-clippy \
    cargo clippy --manifest-path "$ROOT/Cargo.toml" \
    --all-targets --locked -- -D warnings
run_gate rust-tests \
    cargo test --manifest-path "$ROOT/Cargo.toml" \
    --all-targets --locked
run_gate release-build \
    cargo build --manifest-path "$ROOT/Cargo.toml" \
    --release --locked

BINARY_SHA256=""
CLIENT_SHA256=""
NSS_SHA256=""
if [[ -x $BINARY && -x $CLIENT && -f $NSS_MODULE ]]; then
    BINARY="$(readlink -f "$BINARY")"
    CLIENT="$(readlink -f "$CLIENT")"
    NSS_MODULE="$(readlink -f "$NSS_MODULE")"
    BINARY_SHA256="$(sha256sum "$BINARY" | awk '{print $1}')"
    CLIENT_SHA256="$(sha256sum "$CLIENT" | awk '{print $1}')"
    NSS_SHA256="$(sha256sum "$NSS_MODULE" | awk '{print $1}')"
    cp -a "$BINARY" "$ARTIFACT_DIR/systemd-resolved"
    cp -a "$CLIENT" "$ARTIFACT_DIR/resolvectl"
    cp -a "$NSS_MODULE" "$ARTIFACT_DIR/libnss_resolve.so.2"
    record release-binaries pass "$BINARY_SHA256:$CLIENT_SHA256:$NSS_SHA256"
else
    record release-binaries fail missing
fi

run_gate live-dns \
    /usr/bin/python3 -I "$ROOT/tests/live-dns.py" "$BINARY" "$CLIENT"
run_gate live-dbus \
    bash "$ROOT/tests/dbus-introspection.sh" "$BINARY"

if [[ $RUN_NETWORK_NAMESPACE_TESTS == true ]] \
    && command -v sudo >/dev/null \
    && sudo -n true >/dev/null 2>&1; then
    run_gate live-mdns \
        /usr/bin/python3 -I "$ROOT/tests/live-mdns.py" "$BINARY"
    run_gate live-mdns-responder \
        /usr/bin/python3 -I "$ROOT/tests/live-mdns-responder.py" "$BINARY"
    run_gate live-dnssd \
        /usr/bin/python3 -I "$ROOT/tests/live-dnssd.py" "$BINARY"
else
    record live-mdns fail disabled-or-passwordless-sudo-unavailable
    record live-mdns-responder fail disabled-or-passwordless-sudo-unavailable
    record live-dnssd fail disabled-or-passwordless-sudo-unavailable
fi

PREFLIGHT_ARCHIVE="$ARTIFACT_DIR/preflight.tar.gz"
if [[ $RUN_HOST_TESTS == true && -x $BINARY && -x $CLIENT ]]; then
    run_gate host-differential \
        bash "$ROOT/scripts/preflight-replacement.sh" \
        --reference "$REFERENCE" \
        --candidate "$CANDIDATE" \
        --binary "$BINARY" \
        --client "$CLIENT" \
        --output "$PREFLIGHT_ARCHIVE" \
        --no-build
else
    record host-differential fail disabled-or-binary-missing
fi

verify_proof() {
    local gate=$1
    local proof="$PROOF_DIR/$gate.json"
    local log="$LOG_DIR/proof-$gate.log"
    if [[ ! -s $proof ]]; then
        printf 'Missing proof: %s\n' "$proof" >"$log"
        record "$gate" fail "$log"
        return
    fi
    if {
        if [[ $gate == reproducible-release ]]; then
            /usr/bin/python3 -I "$ROOT/scripts/validate-reproducible-release.py" \
                --directory "$REPRODUCIBLE_DIR" \
                --source-commit "$SOURCE_COMMIT" \
                --source-tree "$SOURCE_TREE" \
                --upstream-commit "$BASELINE_COMMIT" \
                --expected-daemon-sha256 "$BINARY_SHA256" \
                --expected-client-sha256 "$CLIENT_SHA256" \
                --expected-nss-sha256 "$NSS_SHA256"
        fi
        /usr/bin/python3 -I "$ROOT/scripts/validate-replacement-proof.py" \
            --proof "$proof" \
            --gate "$gate" \
            --source-commit "$SOURCE_COMMIT" \
            --source-tree "$SOURCE_TREE" \
            --upstream-commit "$BASELINE_COMMIT" \
            --expected-daemon-sha256 "$BINARY_SHA256" \
            --expected-client-sha256 "$CLIENT_SHA256" \
            --expected-nss-sha256 "$NSS_SHA256" \
            --local-reproducible-directory "$REPRODUCIBLE_DIR" \
            --proof-directory "$PROOF_DIR"
        /usr/bin/python3 -I - "$proof" "$PROOF_DIR/artifacts/$gate" \
            "$ARTIFACT_DIR/external-proofs" "$gate" <<'PY'
from __future__ import annotations

import hashlib
import json
from pathlib import Path
import sys


def sha256(path: Path) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as stream:
        for chunk in iter(lambda: stream.read(1024 * 1024), b""):
            digest.update(chunk)
    return digest.hexdigest()


proof_path = Path(sys.argv[1])
source_directory = Path(sys.argv[2]).resolve()
bundle_directory = Path(sys.argv[3])
gate = sys.argv[4]
if proof_path.is_symlink() or not proof_path.is_file():
    raise SystemExit(f"proof is missing or is a symbolic link: {proof_path}")
try:
    payload = json.loads(proof_path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as error:
    raise SystemExit(f"cannot read proof {proof_path}: {error}") from error
raw_artifacts = payload.get("artifacts") if isinstance(payload, dict) else None
if not isinstance(raw_artifacts, list) or not raw_artifacts:
    raise SystemExit("proof contains no artifacts to bundle")

entries: dict[str, tuple[int, str]] = {}
for raw in raw_artifacts:
    if not isinstance(raw, dict):
        raise SystemExit("proof artifact entry is malformed")
    name = raw.get("name")
    size = raw.get("size")
    expected = raw.get("sha256")
    if (
        not isinstance(name, str)
        or not name
        or name in {".", ".."}
        or Path(name).name != name
        or name in entries
    ):
        raise SystemExit("proof artifact name is unsafe or duplicated")
    if not isinstance(size, int) or size < 0:
        raise SystemExit(f"proof artifact size is invalid: {name}")
    if (
        not isinstance(expected, str)
        or len(expected) != 64
        or any(character not in "0123456789abcdef" for character in expected)
    ):
        raise SystemExit(f"proof artifact hash is invalid: {name}")
    entries[name] = (size, expected)

destination_directory = bundle_directory / "artifacts" / gate
destination_directory.mkdir(parents=True, exist_ok=False)
for name, (size, expected) in entries.items():
    source = source_directory / name
    if (
        source.is_symlink()
        or not source.is_file()
        or source.resolve().parent != source_directory
        or source.stat().st_size != size
        or sha256(source) != expected
    ):
        raise SystemExit(f"proof artifact source binding differs: {name}")
    destination = destination_directory / name
    destination.write_bytes(source.read_bytes())
    if destination.stat().st_size != size or sha256(destination) != expected:
        raise SystemExit(f"bundled proof artifact binding differs: {name}")

bundle_directory.mkdir(parents=True, exist_ok=True)
bundled_proof = bundle_directory / f"{gate}.json"
bundled_proof.write_bytes(proof_path.read_bytes())
if sha256(bundled_proof) != sha256(proof_path):
    raise SystemExit(f"bundled proof hash differs: {gate}")
PY
    } >"$log" 2>&1
    then
        if [[ $gate == reproducible-release ]]; then
            mkdir -p "$ARTIFACT_DIR/reproducible-release"
            for artifact in \
                manifest.json systemd-resolved resolvectl libnss_resolve.so.2 \
                rustd-resolved.tar.gz files.sha256 rust-toolchain.txt; do
                cp -a "$REPRODUCIBLE_DIR/$artifact" \
                    "$ARTIFACT_DIR/reproducible-release/$artifact"
            done
        fi
        record "$gate" pass "$proof"
    else
        record "$gate" fail "$log"
    fi
}

verify_proof reproducible-release
verify_proof upstream-test-75
verify_proof upstream-test-89-mdns
verify_proof security-suite
verify_proof boot-replacement

if [[ -z $(git -C "$ROOT" status --porcelain=v1 --untracked-files=all) ]]; then
    record source-clean-after-tests pass clean
else
    git -C "$ROOT" status --porcelain=v1 --untracked-files=all \
        >"$LOG_DIR/source-clean-after-tests.log"
    record source-clean-after-tests fail "$LOG_DIR/source-clean-after-tests.log"
fi

CERTIFICATION_STATUS=0
/usr/bin/python3 -I - \
    "$RESULTS" "$OUTPUT" "$REPORT_DIR" "$FINAL_OUTPUT" "$FINAL_REPORT_DIR" \
    "$CONTRACT" "$SOURCE_COMMIT" "$SOURCE_TREE" \
    "$BASELINE_RELEASE" "$BASELINE_COMMIT" "$BINARY" "$BINARY_SHA256" \
    "$CLIENT" "$CLIENT_SHA256" "$NSS_MODULE" "$NSS_SHA256" \
    "$PREFLIGHT_ARCHIVE" "$RUSTC_RELEASE" "$CARGO_RELEASE" <<'PY' \
    || CERTIFICATION_STATUS=$?
from __future__ import annotations

from datetime import datetime, timezone
import hashlib
import json
from pathlib import Path
import sys

(
    results_path,
    output_path,
    report_directory,
    final_output_path,
    final_report_directory,
    contract_path,
    source_commit,
    source_tree,
    upstream_release,
    upstream_commit,
    binary_path,
    binary_sha256,
    client_path,
    client_sha256,
    nss_path,
    nss_sha256,
    preflight_archive,
    rustc_release,
    cargo_release,
) = sys.argv[1:]

contract = json.loads(Path(contract_path).read_text(encoding="utf-8"))
if not isinstance(contract, dict) or set(contract) != {"schema", "required_gates"}:
    raise SystemExit("replacement certificate contract is invalid")
schema = contract.get("schema")
expected_order = contract.get("required_gates")
if (
    schema != 3
    or not isinstance(expected_order, list)
    or not all(isinstance(name, str) and name for name in expected_order)
):
    raise SystemExit("replacement certificate contract is invalid")
expected = set(expected_order)
if len(expected) != len(expected_order):
    raise SystemExit("replacement certificate contract contains duplicate gates")

gates = []
for raw in Path(results_path).read_text(encoding="utf-8").splitlines():
    name, status, detail = raw.split("\t", 2)
    gates.append({"name": name, "status": status, "detail": detail})
gate_names = [gate["name"] for gate in gates]
missing = sorted(expected - set(gate_names))
extra = sorted(set(gate_names) - expected)
duplicates = sorted({name for name in gate_names if gate_names.count(name) > 1})
contract_errors = []
if missing:
    contract_errors.append("missing gates: " + ", ".join(missing))
if extra:
    contract_errors.append("extra gates: " + ", ".join(extra))
if duplicates:
    contract_errors.append("duplicate gates: " + ", ".join(duplicates))
certified = bool(gates) and not contract_errors and all(
    gate["status"] == "pass" for gate in gates
)
actual_report_directory = Path(report_directory).resolve()
final_output = Path(final_output_path).resolve()
final_report = Path(final_report_directory).resolve()
artifact_prefix = final_report.relative_to(final_output.parent) / "artifacts"
def portable_artifact(path: Path) -> dict[str, object]:
    report_relative = path.resolve().relative_to(actual_report_directory)
    final_path = final_report / report_relative
    relative = final_path.relative_to(final_output.parent)
    if not path.is_file():
        return {"path": str(final_path), "artifact_path": str(relative), "sha256": ""}
    return {
        "path": str(final_path),
        "artifact_path": str(relative),
        "sha256": hashlib.sha256(path.read_bytes()).hexdigest(),
    }

reproducible_directory = Path(report_directory) / "artifacts" / "reproducible-release"
try:
    reproducible_manifest = json.loads(
        (reproducible_directory / "manifest.json").read_text(encoding="utf-8")
    )
except (OSError, json.JSONDecodeError):
    reproducible_manifest = {}
external_proof_directory = (
    Path(report_directory) / "artifacts" / "external-proofs"
)

def bundled_external_proof(gate: str) -> dict[str, object]:
    proof_path = external_proof_directory / f"{gate}.json"
    try:
        payload = json.loads(proof_path.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError):
        return {"proof": portable_artifact(proof_path), "artifacts": []}
    raw_artifacts = payload.get("artifacts") if isinstance(payload, dict) else None
    entries = []
    if isinstance(raw_artifacts, list):
        for raw in raw_artifacts:
            if not isinstance(raw, dict) or not isinstance(raw.get("name"), str):
                continue
            name = raw["name"]
            path = external_proof_directory / "artifacts" / gate / name
            portable = portable_artifact(path)
            entries.append(
                {
                    "name": name,
                    "size": path.stat().st_size if path.is_file() else -1,
                    "artifact_path": portable["artifact_path"],
                    "sha256": portable["sha256"],
                }
            )
    return {"proof": portable_artifact(proof_path), "artifacts": entries}

report = {
    "schema": schema,
    "certified": certified,
    "contract_errors": contract_errors,
    "generated_at": datetime.now(timezone.utc).isoformat(),
    "source_commit": source_commit,
    "source_tree": source_tree,
    "upstream_release": upstream_release,
    "upstream_commit": upstream_commit,
    "toolchain": {
        "rustc_release": rustc_release,
        "cargo_release": cargo_release,
        "rustc_sha256": reproducible_manifest.get("rustc_sha256"),
        "cargo_sha256": reproducible_manifest.get("cargo_sha256"),
    },
    "binary": {
        "path": binary_path,
        "artifact_path": str(artifact_prefix / "systemd-resolved"),
        "sha256": binary_sha256,
    },
    "client": {
        "path": client_path,
        "artifact_path": str(artifact_prefix / "resolvectl"),
        "sha256": client_sha256,
    },
    "nss": {
        "path": nss_path,
        "artifact_path": str(artifact_prefix / "libnss_resolve.so.2"),
        "sha256": nss_sha256,
    },
    "reproducible_release": {
        "manifest": portable_artifact(reproducible_directory / "manifest.json"),
        "package": portable_artifact(reproducible_directory / "rustd-resolved.tar.gz"),
        "files": portable_artifact(reproducible_directory / "files.sha256"),
        "toolchain": portable_artifact(reproducible_directory / "rust-toolchain.txt"),
    },
    "external_proofs": {
        gate: bundled_external_proof(gate)
        for gate in (
            "reproducible-release",
            "upstream-test-75",
            "upstream-test-89-mdns",
            "security-suite",
            "boot-replacement",
        )
    },
    "report_directory": str(final_report),
    "preflight_archive": (
        str(final_report / Path(preflight_archive).resolve().relative_to(actual_report_directory))
        if Path(preflight_archive).is_file()
        else None
    ),
    "gates": gates,
}
encoded = json.dumps(report, indent=2, sort_keys=True) + "\n"
Path(output_path).write_text(encoded, encoding="utf-8")
print(encoded, end="")
raise SystemExit(0 if certified else 1)
PY

if [[ ! -s $OUTPUT ]]; then
    printf '%s\n' 'Certification did not produce a certificate; no output was published.' >&2
    exit "${CERTIFICATION_STATUS:-1}"
fi
if [[ -e $FINAL_OUTPUT || -L $FINAL_OUTPUT \
    || -e $FINAL_REPORT_DIR || -L $FINAL_REPORT_DIR ]]; then
    printf '%s\n' 'Certificate destination appeared during certification; refusing publication.' >&2
    exit 2
fi
mv --no-clobber --no-target-directory "$REPORT_DIR" "$FINAL_REPORT_DIR"
if [[ -e $REPORT_DIR || -L $REPORT_DIR || ! -d $FINAL_REPORT_DIR ]]; then
    printf '%s\n' 'Certificate report publication was not atomic.' >&2
    exit 2
fi
STAGED_REPORT_DIR=
mv --no-clobber --no-target-directory "$OUTPUT" "$FINAL_OUTPUT"
if [[ -e $OUTPUT || -L $OUTPUT || ! -f $FINAL_OUTPUT ]]; then
    printf '%s\n' 'Certificate publication was not atomic.' >&2
    exit 2
fi
STAGED_OUTPUT=
trap - EXIT HUP INT TERM
exit "$CERTIFICATION_STATUS"
