#!/usr/bin/env bash # The production change that breaks these cases is accepting an unverified # download, a wrong signer, or executable/malformed provenance data. set -euo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" fixtures="$repo_dir/tests/setup/fixtures/provenance" config="$repo_dir/setup/provenance/installers.conf" test_tmp="$(mktemp -d)" host_gnupg="${GNUPGHOME:-$HOME/.gnupg}" host_rpmdb="/usr/lib/sysimage/rpm/rpmdb.sqlite" ambient_gnupg="$test_tmp/fresh-ambient-gnupg" cleanup() { rm -rf -- "$test_tmp" } trap cleanup EXIT trap 'exit 130' INT trap 'exit 143' TERM fail() { printf 'package provenance contract: %s\n' "$*" >&2 exit 1 } expect_success() { "$@" || fail "expected success: $*" } expect_failure() { if "$@"; then fail "expected failure: $*" fi } assert_file_bytes() { local path="$1" expected="$2" [[ "$(<"$path")" == "$expected" ]] || fail "unexpected bytes in $path" } snapshot() { local path="$1" if [[ -e "$path" ]]; then stat -c '%i:%s:%Y:%Z' "$path" else printf 'absent' fi } snapshot_gpg_state() { local path="$1" file relative [[ -d "$path" ]] || { printf 'absent\n' return 0 } { printf 'directory\0' find "$path" -mindepth 1 -print0 | LC_ALL=C sort -z \ | while IFS= read -r -d '' file; do relative="${file#"$path"/}" printf '%s\0' "$relative" if [[ -L "$file" ]]; then printf 'symlink\0%s\0' "$(readlink -- "$file")" elif [[ -f "$file" ]]; then printf 'file\0%s\0' "$(sha256sum -- "$file" | awk '{ print $1 }')" elif [[ -d "$file" ]]; then printf 'directory\0' else printf 'other\0%s\0' "$(stat -c '%F:%a:%s:%Y:%Z' "$file")" fi done } | sha256sum | awk '{ print $1 }' } snapshot_file_state() { local path="$1" if [[ -f "$path" ]]; then printf 'file:%s:%s\n' "$(stat -c '%a:%s:%Y:%Z' "$path")" \ "$(sha256sum "$path" | awk '{ print $1 }')" elif [[ -L "$path" ]]; then printf 'symlink:%s\n' "$(readlink -- "$path")" else printf 'absent\n' fi } export GNUPGHOME="$ambient_gnupg" mkdir -m 700 "$ambient_gnupg" printf 'baseline-value\n' > "$ambient_gnupg/unexpected-entry" ambient_before="$(snapshot "$ambient_gnupg")" ambient_gpg_files_before="$(snapshot_gpg_state "$ambient_gnupg")" printf 'tampered-value\n' > "$ambient_gnupg/unexpected-entry" [[ "$ambient_gpg_files_before" != "$(snapshot_gpg_state "$ambient_gnupg")" ]] \ || fail 'ambient GPG snapshot ignored unexpected file content' printf 'baseline-value\n' > "$ambient_gnupg/unexpected-entry" ambient_gpg_files_before="$(snapshot_gpg_state "$ambient_gnupg")" before_gnupg="$(snapshot "$host_gnupg")" before_gpg_files="$(snapshot_gpg_state "$host_gnupg")" before_rpmdb="$(snapshot "$host_rpmdb")" before_repo_files="$(snapshot_gpg_state /etc/yum.repos.d)" before_rpm_key_files="$(snapshot_gpg_state /etc/pki/rpm-gpg)" before_system_flatpak="$(snapshot_file_state /var/lib/flatpak/repo/config)" before_system_flathub_key="$(snapshot_file_state /var/lib/flatpak/repo/flathub.trustedkeys.gpg)" before_user_flatpak="$(snapshot_file_state "$HOME/.local/share/flatpak/repo/config")" before_bashrc="$(snapshot_file_state "$HOME/.bashrc")" # This must be the only production file sourced by the contract. # shellcheck source=../../setup/lib/artifact-provenance source "$repo_dir/setup/lib/artifact-provenance" fixture_fingerprint='6016FF18CAE298CE3648EE2325E01F765E1EF9FA' tiny_sha256='291bd319ae85488101e908e37fc0fa1b0da1429ba27e10d2b391cb3f60dd44ea' base64 --decode "$fixtures/signed-fixture.rpm.base64" > "$test_tmp/signed-fixture.rpm" base64 --decode "$fixtures/unsigned-fixture.rpm.base64" > "$test_tmp/unsigned-fixture.rpm" base64 --decode "$fixtures/wrong-signer-fixture.rpm.base64" > "$test_tmp/wrong-signer-fixture.rpm" [[ "$(wc -l < "$fixtures/SHASUMS256.txt")" -eq 4 ]] || fail 'signed checksum fixture is not four lines' [[ "$(cmp -l "$fixtures/tiny-artifact" "$fixtures/tiny-artifact-tampered" | wc -l)" -eq 1 ]] \ || fail 'tampered artifact does not differ by exactly one byte' expect_success key_fingerprint_matches "$fixtures/fixture-key.asc" "$fixture_fingerprint" [[ "$ambient_before" == "$(snapshot "$ambient_gnupg")" ]] \ || fail 'fingerprint inspection created ambient GPG state' [[ "$ambient_gpg_files_before" == "$(snapshot_gpg_state "$ambient_gnupg")" ]] \ || fail 'fingerprint inspection created an ambient GPG keybox or trust database' expect_failure key_fingerprint_matches "$fixtures/fixture-key.asc" '0000000000000000000000000000000000000000' cat "$fixtures/fixture-key.asc" "$fixtures/wrong-signer-key.asc" > "$test_tmp/combined-key.asc" expect_failure key_fingerprint_matches "$test_tmp/combined-key.asc" "$fixture_fingerprint" expect_success verify_detached_signature \ "$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/SHASUMS256.txt" expect_failure verify_detached_signature \ "$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/tiny-artifact" expect_failure verify_detached_signature \ "$fixtures/fixture-key.asc" "$fixtures/SHASUMS256.txt.asc" "$fixtures/tiny-artifact-tampered" cp "$fixtures/SHASUMS256.txt.asc" "$test_tmp/bad-signature.asc" sed -i 's/^=MJqv$/=MJqa/' "$test_tmp/bad-signature.asc" expect_failure verify_detached_signature \ "$fixtures/fixture-key.asc" "$test_tmp/bad-signature.asc" "$fixtures/SHASUMS256.txt" expect_failure verify_detached_signature \ "$test_tmp/combined-key.asc" "$fixtures/wrong-signer-SHASUMS256.txt.asc" "$fixtures/SHASUMS256.txt" mkdir "$test_tmp/bin" cat > "$test_tmp/bin/curl" <<'STUB' #!/usr/bin/env bash set -euo pipefail output='' connect_timeout='' max_time='' max_filesize='' while (($#)); do case "$1" in --output) output="$2"; shift 2 ;; --connect-timeout) connect_timeout="$2"; shift 2 ;; --max-time) max_time="$2"; shift 2 ;; --max-filesize) max_filesize="$2"; shift 2 ;; *) shift ;; esac done [[ "$connect_timeout" == 10 && "$max_time" == 600 && "$max_filesize" == "${CURL_EXPECTED_MAX_BYTES:?}" ]] || exit 65 case "${CURL_FIXTURE:?}" in good) cp "$CURL_FIXTURE_ROOT/tiny-artifact" "$output" ;; oversized) head -c 1025 /dev/zero > "$output" ;; interrupted) printf 'partial' > "$output"; exit 42 ;; *) exit 64 ;; esac STUB chmod +x "$test_tmp/bin/curl" PATH="$test_tmp/bin:$PATH" export PATH CURL_FIXTURE_ROOT="$fixtures" CURL_EXPECTED_MAX_BYTES=1024 destination="$test_tmp/destination" export CURL_FIXTURE=good expect_success download_sha256 'https://fixture.invalid/good' "$tiny_sha256" 1024 "$destination" cmp -s "$fixtures/tiny-artifact" "$destination" || fail 'verified download changed artifact bytes' [[ ! -e "$destination.part" ]] || fail 'successful download left a part file' export CURL_FIXTURE=good expect_failure download_sha256 'https://fixture.invalid/uppercase-digest' \ '291BD319AE85488101E908E37FC0FA1B0DA1429BA27E10D2B391CB3F60DD44EA' 1024 \ "$test_tmp/uppercase-destination" printf 'known-good\n' > "$destination" export CURL_FIXTURE=good expect_failure download_sha256 'https://fixture.invalid/bad-digest' \ '0000000000000000000000000000000000000000000000000000000000000000' 1024 "$destination" assert_file_bytes "$destination" 'known-good' [[ ! -e "$destination.part" ]] || fail 'bad digest left a part file' protected="$test_tmp/protected-known-good" printf 'known-good\n' > "$protected" ln -s "$protected" "$destination.part" expect_failure download_sha256 'https://fixture.invalid/symlink-part' \ '0000000000000000000000000000000000000000000000000000000000000000' 1024 "$destination" assert_file_bytes "$protected" 'known-good' [[ -L "$destination.part" ]] || fail 'symlinked destination part was not preserved' rm -f -- "$destination.part" ln "$protected" "$destination.part" expect_failure download_sha256 'https://fixture.invalid/hard-link-part' \ '0000000000000000000000000000000000000000000000000000000000000000' 1024 "$destination" assert_file_bytes "$protected" 'known-good' [[ "$(stat -c %i "$protected")" == "$(stat -c %i "$destination.part")" ]] \ || fail 'hard-linked destination part was not preserved' rm -f -- "$destination.part" export CURL_FIXTURE=oversized expect_failure download_sha256 'https://fixture.invalid/oversized' "$tiny_sha256" 1024 "$destination" assert_file_bytes "$destination" 'known-good' [[ ! -e "$destination.part" ]] || fail 'oversized download left a part file' export CURL_FIXTURE=interrupted expect_failure download_sha256 'https://fixture.invalid/interrupted' "$tiny_sha256" 1024 "$destination" assert_file_bytes "$destination" 'known-good' [[ ! -e "$destination.part" ]] || fail 'interrupted download left a part file' expect_success rpm_signature_matches \ "$test_tmp/signed-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint" expect_failure rpm_signature_matches \ "$test_tmp/unsigned-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint" expect_failure rpm_signature_matches \ "$test_tmp/signed-fixture.rpm" "$fixtures/fixture-key.asc" '0000000000000000000000000000000000000000' expect_failure rpm_signature_matches \ "$test_tmp/wrong-signer-fixture.rpm" "$fixtures/fixture-key.asc" "$fixture_fingerprint" expect_failure rpm_signature_matches \ "$test_tmp/wrong-signer-fixture.rpm" "$test_tmp/combined-key.asc" "$fixture_fingerprint" expect_success load_installer_provenance "$config" [[ "${INSTALLER_PROVENANCE[BUN_VERSION]:-}" == '1.4.0' ]] || fail 'valid provenance was not loaded' for key_spec in \ 'terra44 TERRA_FINGERPRINT' \ 'claude-code CLAUDE_CODE_FINGERPRINT' \ 'bun BUN_FINGERPRINT' \ 'rpmfusion-free RPMFUSION_FREE_FINGERPRINT' \ 'rpmfusion-nonfree RPMFUSION_NONFREE_FINGERPRINT' \ 'hyprland-copr HYPRLAND_COPR_FINGERPRINT' \ 'flathub FLATHUB_FINGERPRINT' \ 'claude-desktop CLAUDE_DESKTOP_FINGERPRINT'; do read -r key_file fingerprint_name <<<"$key_spec" expect_success key_fingerprint_matches "$repo_dir/setup/provenance/keys/$key_file.asc" \ "${INSTALLER_PROVENANCE[$fingerprint_name]}" done [[ "$before_gnupg" == "$(snapshot "$host_gnupg")" ]] || fail 'host GPG state changed' [[ "$before_gpg_files" == "$(snapshot_gpg_state "$host_gnupg")" ]] || fail 'host GPG state changed' [[ "$before_rpmdb" == "$(snapshot "$host_rpmdb")" ]] || fail 'host RPM database changed' [[ "$ambient_before" == "$(snapshot "$ambient_gnupg")" ]] || fail 'production helper created ambient GPG state' [[ "$ambient_gpg_files_before" == "$(snapshot_gpg_state "$ambient_gnupg")" ]] \ || fail 'production helper created or changed an ambient GPG entry' parser_fixture="$test_tmp/installers.conf" cp "$config" "$parser_fixture" printf 'UNKNOWN_KEY=value\n' >> "$parser_fixture" expect_failure load_installer_provenance "$parser_fixture" cp "$config" "$parser_fixture" printf 'BUN_VERSION=1.4.0\n' >> "$parser_fixture" expect_failure load_installer_provenance "$parser_fixture" grep -v '^NODE_VERSION=' "$config" > "$parser_fixture" expect_failure load_installer_provenance "$parser_fixture" cp "$config" "$parser_fixture" sed -i 's/^BUN_VERSION=/ BUN_VERSION=/' "$parser_fixture" expect_failure load_installer_provenance "$parser_fixture" cp "$config" "$parser_fixture" sed -i 's/^BUN_VERSION=.*/BUN_VERSION=$(id -u)/' "$parser_fixture" expect_failure load_installer_provenance "$parser_fixture" cp "$config" "$parser_fixture" printf 'BUN_ARMV7_URL=https://fixture.invalid/bun\n' >> "$parser_fixture" expect_failure load_installer_provenance "$parser_fixture" # Repository setup runs from a fixture copy of the installer with every # external command replaced. A contract failure can therefore inspect exact # ordering and staged bytes without consulting or changing the host. installer_fixture="$test_tmp/installer-fixture" mkdir -p "$installer_fixture/setup/lib" "$installer_fixture/setup/provenance/keys" \ "$installer_fixture/setup/scripts" cp "$repo_dir/setup/lib/artifact-provenance" "$repo_dir/setup/lib/extras-catalog" \ "$repo_dir/setup/lib/machine-role" "$installer_fixture/setup/lib/" cp "$config" "$installer_fixture/setup/provenance/installers.conf" cp "$repo_dir"/setup/provenance/keys/*.asc "$installer_fixture/setup/provenance/keys/" sed '/^# --- The server path/,$d' "$repo_dir/setup/scripts/install-packages" \ > "$installer_fixture/setup/scripts/install-packages" make_stub_commands() { local case_root="$1" mkdir -p "$case_root/bin" "$case_root/home" "$case_root/tmp" "$case_root/etc/yum.repos.d" \ "$case_root/etc/pki/rpm-gpg" "$case_root/flatpak-repo" cat > "$case_root/bin/rpm" <<'STUB' #!/usr/bin/env bash set -euo pipefail if [[ "$*" == '-E %fedora' ]]; then printf 'rpm:release\n' >> "$COMMAND_LOG" printf '%s\n' "${STUB_FEDORA_RELEASE:-44}" elif [[ "${1:-}" == -q ]]; then printf 'rpm:query:%s\n' "${2:-}" >> "$COMMAND_LOG" case "${2:-}" in terra-release) [[ "${STUB_TERRA_INSTALLED:-0}" == 1 ]] ;; claude-desktop-extra) [[ "${STUB_CLAUDE_DESKTOP_INSTALLED:-0}" == 1 ]] ;; *) exit 1 ;; esac else exit 64 fi STUB cat > "$case_root/bin/curl" <<'STUB' #!/usr/bin/env bash set -euo pipefail output='' max_filesize='' connect_timeout='' max_time='' url='' while (($#)); do case "$1" in --output) output="$2"; shift 2 ;; --max-filesize) max_filesize="$2"; shift 2 ;; --connect-timeout) connect_timeout="$2"; shift 2 ;; --max-time) max_time="$2"; shift 2 ;; --fail|--location) shift ;; *) url="$1"; shift ;; esac done [[ -n "$output" && "$connect_timeout" == 10 && "$max_time" == 600 ]] || exit 65 output_name="$(basename "$output")" output_name="${output_name#.}" output_name="${output_name%.part.*}" printf 'curl:%s:max=%s:output=%s\n' "$url" "$max_filesize" "$output_name" >> "$COMMAND_LOG" case "$url" in *rpmfusion-free*) cp "$SIGNED_RPM" "$output" ;; *rpmfusion-nonfree*) cp "$SIGNED_RPM" "$output" ;; *flathub.flatpakrepo) cp "$FLATHUB_DESCRIPTOR" "$output" ;; *) exit 66 ;; esac STUB cat > "$case_root/bin/gpg" <<'STUB' #!/usr/bin/env bash set -euo pipefail key="${!#}" fingerprint='' for candidate in "$REVIEWED_KEYS"/*.asc; do if cmp -s "$key" "$candidate"; then case "$(basename "$candidate")" in terra44.asc) fingerprint='AE09157A4DE88B497EA1D5D300CDAB43DE226D6F' ;; claude-code.asc) fingerprint='31DDDE24DDFAB679F42D7BD2BAA929FF1A7ECACE' ;; rpmfusion-free.asc) fingerprint='E9A491A3DE247814E7E067EAE06F8ECDD651FF2E' ;; rpmfusion-nonfree.asc) fingerprint='79BDB88F9BBF73910FD4095B6A2AF96194843C65' ;; hyprland-copr.asc) fingerprint='97E23476C89635135407C7D5E9BA41342C4B2995' ;; flathub.asc) fingerprint='6E5C05D979C76DAF93C081354184DD4D907A7CAE' ;; claude-desktop.asc) fingerprint='825A7D15D78BABE45646D5DF382409F597908867' ;; esac break fi done [[ -n "$fingerprint" ]] || exit 1 printf 'gpg:fingerprint:%s\n' "$fingerprint" >> "$COMMAND_LOG" printf 'pub:-:4096:1:0000000000000000:0:0::-:::scESC::::::23::0:\n' printf 'fpr:::::::::%s:\n' "$fingerprint" STUB cat > "$case_root/bin/rpmkeys" <<'STUB' #!/usr/bin/env bash set -euo pipefail action='' package='' while (($#)); do case "$1" in --dbpath) shift 2 ;; --import) action=import; package="$2"; shift 2 ;; --checksig) action=checksig; shift; [[ "${1:-}" == --verbose ]] && shift; package="$1"; shift ;; *) shift ;; esac done printf 'rpmkeys:%s:%s\n' "$action" "$(basename "$package")" >> "$COMMAND_LOG" if [[ "$action" == checksig ]]; then [[ "${STUB_RPM_SIGNATURE_FAIL:-}" != "$(basename "$package")" ]] || exit 1 printf 'Header OpenPGP signature: OK\n' fi STUB cat > "$case_root/bin/sudo" <<'STUB' #!/usr/bin/env bash set -euo pipefail if [[ "${1:-}" == install ]]; then shift [[ "${1:-}" == -m && ( "${2:-}" == 0644 || "${2:-}" == 644 ) ]] || exit 67 source_file="$3" destination="$4" printf 'sudo:install:%s:%s\n' "$(basename "$source_file")" "$destination" >> "$COMMAND_LOG" mapped="$STUB_ETC${destination#/etc}" mkdir -p "$(dirname "$mapped")" /usr/bin/install -m 0644 "$source_file" "$mapped" count=0 [[ ! -f "$STUB_INSTALL_COUNTER" ]] || read -r count < "$STUB_INSTALL_COUNTER" count=$((count + 1)) printf '%s\n' "$count" > "$STUB_INSTALL_COUNTER" if [[ -n "${STUB_INSTALL_FAIL_AT:-}" && "$count" == "$STUB_INSTALL_FAIL_AT" ]]; then exit 67 fi exit 0 fi if [[ "${1:-}" == rm && "${2:-}" == -f && "${3:-}" == -- ]]; then destination="$4" printf 'sudo:rm:%s\n' "$destination" >> "$COMMAND_LOG" rm -f -- "$STUB_ETC${destination#/etc}" exit 0 fi original="$*" logged=() for argument in "$@"; do if [[ "$argument" == --gpg-import=*/flathub-key.asc ]]; then logged+=(--gpg-import=FLATHUB_KEY) continue fi case "$(basename "$argument")" in rpmfusion-free-release.rpm) logged+=(RPMFUSION_FREE) ;; rpmfusion-nonfree-release.rpm) logged+=(RPMFUSION_NONFREE) ;; flathub-key.asc) logged+=(FLATHUB_KEY) ;; *) logged+=("$argument") ;; esac done printf 'sudo:%s\n' "${logged[*]}" >> "$COMMAND_LOG" if [[ -n "${STUB_DNF_FAIL_MATCH:-}" && "$original" == *"$STUB_DNF_FAIL_MATCH"* ]]; then exit 68 fi if [[ "${1:-}" == flatpak && "${2:-}" == remote-add ]]; then if [[ ! -f "$STUB_FLATPAK_REPO/config" ]] \ || ! grep -q '^\[remote "flathub"\]$' "$STUB_FLATPAK_REPO/config"; then key='' url="${!#}" for argument in "$@"; do [[ "$argument" != --gpg-import=* ]] || key="${argument#--gpg-import=}" done [[ -n "$key" ]] || exit 69 printf '[core]\nrepo_version=1\n\n[remote "flathub"]\nurl=%s\ngpg-verify=true\ngpg-verify-summary=true\n' \ "$url" > "$STUB_FLATPAK_REPO/config" cp "$key" "$STUB_FLATPAK_REPO/flathub.trustedkeys.gpg" printf 'mutated\n' > "$STUB_FLATPAK_STATE" fi fi STUB cat > "$case_root/bin/dnf" <<'STUB' #!/usr/bin/env bash set -euo pipefail if [[ "$*" == '--quiet --no-plugins --dump-repo-config=terra*' ]]; then printf 'dnf:dump-terra\n' >> "$COMMAND_LOG" mode="${STUB_TERRA_EFFECTIVE_MODE:-auto}" if [[ "$mode" == auto ]]; then case "${STUB_TERRA_REPO_MODE:-absent}" in trusted|wrong-key) mode=trusted ;; nogpg) mode=legacy ;; wrong-url) mode=override-url ;; esac if [[ "$mode" == auto && -f "$STUB_ETC/yum.repos.d/terra.repo" ]] \ && grep -q '^baseurl=https://repos.fyralabs.com/terra44$' "$STUB_ETC/yum.repos.d/terra.repo"; then mode=trusted elif [[ "$mode" == auto ]]; then mode=absent fi fi case "$mode" in absent) exit 0 ;; trusted) printf '======== "terra" repository configuration: ========\n' printf 'baseurl = https://repos.fyralabs.com/terra44\n' printf 'enabled = 1\n' printf 'gpgcheck = 1\n' printf 'gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama\n' printf 'metalink = \nmirrorlist = \npkg_gpgcheck = 1\nrepo_gpgcheck = 1\n' ;; legacy) printf '======== "terra" repository configuration: ========\n' printf 'baseurl = \nenabled = 1\ngpgcheck = 0\n' printf 'gpgkey = https://repos.fyralabs.com/terra44.key\n' printf 'metalink = https://tetsudou.fyralabs.com/terra44\nmirrorlist = \n' printf 'pkg_gpgcheck = 0\nrepo_gpgcheck = 0\n' ;; override-url) printf '======== "terra" repository configuration: ========\n' printf 'baseurl = https://evil.invalid/terra44\nenabled = 1\ngpgcheck = 1\n' printf 'gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama\n' printf 'metalink = \nmirrorlist = \npkg_gpgcheck = 1\nrepo_gpgcheck = 1\n' ;; override-gpg) printf '======== "terra" repository configuration: ========\n' printf 'baseurl = https://repos.fyralabs.com/terra44\nenabled = 1\ngpgcheck = 0\n' printf 'gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama\n' printf 'metalink = \nmirrorlist = \npkg_gpgcheck = 0\nrepo_gpgcheck = 0\n' ;; duplicate) for id in terra terra; do printf '======== "%s" repository configuration: ========\n' "$id" printf 'baseurl = https://repos.fyralabs.com/terra44\nenabled = 1\ngpgcheck = 1\n' printf 'gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama\n' printf 'metalink = \nmirrorlist = \npkg_gpgcheck = 1\nrepo_gpgcheck = 1\n' done ;; alternate) for id in terra terra-legacy; do printf '======== "%s" repository configuration: ========\n' "$id" printf 'baseurl = https://repos.fyralabs.com/terra44\nenabled = 1\ngpgcheck = 1\n' printf 'gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama\n' printf 'metalink = \nmirrorlist = \npkg_gpgcheck = 1\nrepo_gpgcheck = 1\n' done ;; esac exit 0 fi exit 69 STUB cat > "$case_root/bin/flatpak" <<'STUB' #!/usr/bin/env bash exit 69 STUB chmod +x "$case_root/bin"/* } reset_installer_fixture() { cp "$config" "$installer_fixture/setup/provenance/installers.conf" cp "$repo_dir"/setup/provenance/keys/*.asc "$installer_fixture/setup/provenance/keys/" } write_flathub_descriptor() { local destination="$1" key="$2" verify_line="${3:-}" url="${4:-https://dl.flathub.org/repo/}" local encoded encoded="$(base64 -w 0 "$key")" printf '[Flatpak Repo]\nTitle=Flathub\nUrl=%s\nGPGKey=%s\n%s\n' \ "$url" "$encoded" "$verify_line" > "$destination" } run_installer_function() { local name="$1" function_name="$2" case_root case_root="$test_tmp/cases/$name" rm -rf -- "$case_root" make_stub_commands "$case_root" : > "$case_root/commands.log" printf '0\n' > "$case_root/install-counter" printf 'preserved\n' > "$case_root/flatpak-state" write_flathub_descriptor "$case_root/flathub.flatpakrepo" \ "${STUB_FLATHUB_KEY_FILE:-$installer_fixture/setup/provenance/keys/flathub.asc}" \ "${STUB_FLATHUB_VERIFY_LINE:-}" "${STUB_FLATHUB_URL:-https://dl.flathub.org/repo/}" if [[ "${STUB_EXISTING_REPOSITORY:-}" == hyprland \ || "${STUB_PAIR_PRIOR:-}" == present && "${STUB_PAIR_NAME:-}" == hyprland ]]; then printf 'known key\n' > "$case_root/etc/pki/rpm-gpg/RPM-GPG-KEY-panama-hyprland" printf 'known repo\n' > "$case_root/etc/yum.repos.d/panama-hyprland.repo" fi if [[ "${STUB_PAIR_PRIOR:-}" == present && "${STUB_PAIR_NAME:-}" == claude-code ]]; then printf 'known key\n' > "$case_root/etc/pki/rpm-gpg/RPM-GPG-KEY-claude-code-panama" printf 'known repo\n' > "$case_root/etc/yum.repos.d/claude-code.repo" fi case "${STUB_TERRA_REPO_MODE:-absent}" in trusted) cp "$installer_fixture/setup/provenance/keys/terra44.asc" \ "$case_root/etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama" printf '[terra]\nbaseurl=https://repos.fyralabs.com/terra44\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama\n' \ > "$case_root/etc/yum.repos.d/terra.repo" ;; nogpg) printf '[terra]\nbaseurl=https://repos.fyralabs.com/terra44\nenabled=1\ngpgcheck=0\nrepo_gpgcheck=0\ngpgkey=https://repos.fyralabs.com/terra44.key\n' \ > "$case_root/etc/yum.repos.d/terra.repo" ;; wrong-url) cp "$installer_fixture/setup/provenance/keys/terra44.asc" \ "$case_root/etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama" printf '[terra]\nbaseurl=https://evil.invalid/terra44\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama\n' \ > "$case_root/etc/yum.repos.d/terra.repo" ;; wrong-key) cp "$installer_fixture/setup/provenance/keys/flathub.asc" \ "$case_root/etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama" printf '[terra]\nbaseurl=https://repos.fyralabs.com/terra44\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama\n' \ > "$case_root/etc/yum.repos.d/terra.repo" ;; esac case "${STUB_FLATPAK_REMOTE_MODE:-absent}" in trusted) printf '[core]\nrepo_version=1\n\n[remote "flathub"]\nurl=https://dl.flathub.org/repo/\ngpg-verify=true\ngpg-verify-summary=true\n' \ > "$case_root/flatpak-repo/config" cp "$installer_fixture/setup/provenance/keys/flathub.asc" \ "$case_root/flatpak-repo/flathub.trustedkeys.gpg" ;; wrong-url) printf '[core]\nrepo_version=1\n\n[remote "flathub"]\nurl=https://evil.invalid/repo/\ngpg-verify=true\ngpg-verify-summary=true\n' \ > "$case_root/flatpak-repo/config" cp "$installer_fixture/setup/provenance/keys/flathub.asc" \ "$case_root/flatpak-repo/flathub.trustedkeys.gpg" ;; wrong-key) printf '[core]\nrepo_version=1\n\n[remote "flathub"]\nurl=https://dl.flathub.org/repo/\ngpg-verify=true\ngpg-verify-summary=true\n' \ > "$case_root/flatpak-repo/config" cp "$installer_fixture/setup/provenance/keys/terra44.asc" \ "$case_root/flatpak-repo/flathub.trustedkeys.gpg" ;; no-gpg) printf '[core]\nrepo_version=1\n\n[remote "flathub"]\nurl=https://dl.flathub.org/repo/\ngpg-verify=false\ngpg-verify-summary=false\n' \ > "$case_root/flatpak-repo/config" cp "$installer_fixture/setup/provenance/keys/flathub.asc" \ "$case_root/flatpak-repo/flathub.trustedkeys.gpg" ;; alternate-key) printf '[core]\nrepo_version=1\n\n[remote "flathub"]\nurl=https://dl.flathub.org/repo/\ngpg-verify=true\ngpg-verify-summary=true\ngpgkeypath=/unreviewed/keyring.gpg\n' \ > "$case_root/flatpak-repo/config" cp "$installer_fixture/setup/provenance/keys/flathub.asc" \ "$case_root/flatpak-repo/flathub.trustedkeys.gpg" ;; empty-alternate-key|duplicate-alternate-key|malformed-alternate-key) printf '[core]\nrepo_version=1\n\n[remote "flathub"]\nurl=https://dl.flathub.org/repo/\ngpg-verify=true\ngpg-verify-summary=true\n' \ > "$case_root/flatpak-repo/config" case "$STUB_FLATPAK_REMOTE_MODE" in empty-alternate-key) printf 'gpgkeypath=\n' ;; duplicate-alternate-key) printf 'gpgkeypath=\ngpgkeypath=/unreviewed/keyring.gpg\n' ;; malformed-alternate-key) printf 'gpgkeypath /unreviewed/keyring.gpg\n' ;; esac >> "$case_root/flatpak-repo/config" cp "$installer_fixture/setup/provenance/keys/flathub.asc" \ "$case_root/flatpak-repo/flathub.trustedkeys.gpg" ;; esac case "${STUB_CLAUDE_DESKTOP_REPO_MODE:-absent}" in trusted) cp "$installer_fixture/setup/provenance/keys/claude-desktop.asc" \ "$case_root/etc/pki/rpm-gpg/claude-desktop-local.asc" printf '[claude-desktop]\nbaseurl=https://patrickjaja.github.io/claude-desktop-extra/rpm/\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=file://%s\n' \ "$case_root/etc/pki/rpm-gpg/claude-desktop-local.asc" \ > "$case_root/etc/yum.repos.d/claude-desktop.repo" ;; untrusted) cp "$installer_fixture/setup/provenance/keys/claude-desktop.asc" \ "$case_root/etc/pki/rpm-gpg/claude-desktop-local.asc" printf '[claude-desktop]\nbaseurl=https://evil.invalid/rpm/\nenabled=1\ngpgcheck=0\nrepo_gpgcheck=0\ngpgkey=file://%s\n' \ "$case_root/etc/pki/rpm-gpg/claude-desktop-local.asc" \ > "$case_root/etc/yum.repos.d/claude-desktop.repo" ;; esac COMMAND_LOG="$case_root/commands.log" \ FIXTURE_ROOT="$installer_fixture" \ REVIEWED_KEYS="$repo_dir/setup/provenance/keys" \ SIGNED_RPM="$test_tmp/signed-fixture.rpm" \ FLATHUB_DESCRIPTOR="$case_root/flathub.flatpakrepo" \ STUB_ETC="$case_root/etc" \ STUB_FLATPAK_STATE="$case_root/flatpak-state" \ STUB_FLATPAK_REPO="$case_root/flatpak-repo" \ STUB_INSTALL_COUNTER="$case_root/install-counter" \ HOME="$case_root/home" \ TMPDIR="$case_root/tmp" \ PANAMA_PATH="$installer_fixture" \ PATH="$case_root/bin:/usr/bin:/bin" \ bash -c 'source "$PANAMA_PATH/setup/scripts/install-packages"; PANAMA_SYSTEM_ETC="$STUB_ETC"; PANAMA_SYSTEM_FLATPAK_REPO="$STUB_FLATPAK_REPO"; declare -F "$1" >/dev/null; "$1"' \ bash "$function_name" > "$case_root/output" 2>&1 } assert_log() { local name="$1" expected="$2" path path="$test_tmp/cases/$name/commands.log" [[ "$(<"$path")" == "$expected" ]] || { printf 'package provenance contract: unexpected %s command log\n' "$name" >&2 diff -u <(printf '%s\n' "$expected") "$path" >&2 || true exit 1 } } reset_installer_fixture expect_success run_installer_function rpmfusion install_rpmfusion_repositories assert_log rpmfusion "$(cat <<'EXPECTED' rpm:release curl:https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-44.noarch.rpm:max=4194304:output=rpmfusion-free-release.rpm gpg:fingerprint:E9A491A3DE247814E7E067EAE06F8ECDD651FF2E rpmkeys:import:rpmfusion-free.asc rpmkeys:checksig:rpmfusion-free-release.rpm curl:https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-44.noarch.rpm:max=4194304:output=rpmfusion-nonfree-release.rpm gpg:fingerprint:79BDB88F9BBF73910FD4095B6A2AF96194843C65 rpmkeys:import:rpmfusion-nonfree.asc rpmkeys:checksig:rpmfusion-nonfree-release.rpm sudo:dnf install -y --setopt=localpkg_gpgcheck=1 RPMFUSION_FREE RPMFUSION_NONFREE EXPECTED )" reset_installer_fixture expect_success run_installer_function terra install_terra_repository assert_log terra "$(cat <<'EXPECTED' rpm:release dnf:dump-terra rpm:query:terra-release gpg:fingerprint:AE09157A4DE88B497EA1D5D300CDAB43DE226D6F sudo:install:terra44.asc:/etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama sudo:dnf install -y --repofrompath terra,https://repos.fyralabs.com/terra44 --setopt=terra.pkg_gpgcheck=1 --setopt=terra.repo_gpgcheck=1 --setopt=terra.gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama terra-release sudo:install:terra.repo:/etc/yum.repos.d/terra.repo dnf:dump-terra gpg:fingerprint:AE09157A4DE88B497EA1D5D300CDAB43DE226D6F gpg:fingerprint:AE09157A4DE88B497EA1D5D300CDAB43DE226D6F EXPECTED )" cmp -s "$installer_fixture/setup/provenance/keys/terra44.asc" \ "$test_tmp/cases/terra/etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama" \ || fail 'Terra privileged install did not preserve the fully staged reviewed key' assert_file_bytes "$test_tmp/cases/terra/etc/yum.repos.d/terra.repo" "$(cat <<'EXPECTED' [terra] name=Panama reviewed Terra 44 baseurl=https://repos.fyralabs.com/terra44 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama EXPECTED )" reset_installer_fixture expect_success run_installer_function hyprland configure_hyprland_repository assert_log hyprland "$(cat <<'EXPECTED' rpm:release gpg:fingerprint:97E23476C89635135407C7D5E9BA41342C4B2995 sudo:install:hyprland-copr.asc:/etc/pki/rpm-gpg/RPM-GPG-KEY-panama-hyprland sudo:install:panama-hyprland.repo:/etc/yum.repos.d/panama-hyprland.repo EXPECTED )" cmp -s "$installer_fixture/setup/provenance/keys/hyprland-copr.asc" \ "$test_tmp/cases/hyprland/etc/pki/rpm-gpg/RPM-GPG-KEY-panama-hyprland" \ || fail 'Hyprland privileged install did not preserve the fully staged reviewed key' assert_file_bytes "$test_tmp/cases/hyprland/etc/yum.repos.d/panama-hyprland.repo" "$(cat <<'EXPECTED' [panama-hyprland] name=Panama reviewed Hyprland COPR baseurl=https://download.copr.fedorainfracloud.org/results/lionheartp/Hyprland/fedora-$releasever-$basearch/ enabled=1 gpgcheck=1 repo_gpgcheck=0 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-panama-hyprland EXPECTED )" reset_installer_fixture expect_success run_installer_function flathub ensure_flathub_remote assert_log flathub "$(cat <<'EXPECTED' rpm:release curl:https://flathub.org/repo/flathub.flatpakrepo:max=1048576:output=flathub.flatpakrepo gpg:fingerprint:6E5C05D979C76DAF93C081354184DD4D907A7CAE sudo:flatpak remote-add --if-not-exists --gpg-import=FLATHUB_KEY flathub https://dl.flathub.org/repo/ gpg:fingerprint:6E5C05D979C76DAF93C081354184DD4D907A7CAE EXPECTED )" reset_installer_fixture expect_success run_installer_function claude-code install_claude_code assert_log claude-code "$(cat <<'EXPECTED' rpm:release gpg:fingerprint:31DDDE24DDFAB679F42D7BD2BAA929FF1A7ECACE sudo:install:claude-code.asc:/etc/pki/rpm-gpg/RPM-GPG-KEY-claude-code-panama sudo:install:claude-code.repo:/etc/yum.repos.d/claude-code.repo sudo:dnf install -y claude-code EXPECTED )" cmp -s "$installer_fixture/setup/provenance/keys/claude-code.asc" \ "$test_tmp/cases/claude-code/etc/pki/rpm-gpg/RPM-GPG-KEY-claude-code-panama" \ || fail 'Claude Code privileged install did not preserve the fully staged reviewed key' assert_file_bytes "$test_tmp/cases/claude-code/etc/yum.repos.d/claude-code.repo" "$(cat <<'EXPECTED' [claude-code] name=Claude Code baseurl=https://downloads.claude.ai/claude-code/rpm/stable enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-claude-code-panama EXPECTED )" reset_installer_fixture expect_success run_installer_function claude-desktop-absent install_claude_desktop_if_trusted assert_log claude-desktop-absent 'rpm:release' [[ "$(grep -c 'Claude Desktop is optional; configure its reviewed local-key repository manually' \ "$test_tmp/cases/claude-desktop-absent/output")" -eq 1 ]] \ || fail 'absent Claude Desktop repository did not produce exactly one manual message' reset_installer_fixture STUB_CLAUDE_DESKTOP_REPO_MODE=trusted \ expect_success run_installer_function claude-desktop-trusted install_claude_desktop_if_trusted assert_log claude-desktop-trusted "$(cat <<'EXPECTED' rpm:release gpg:fingerprint:825A7D15D78BABE45646D5DF382409F597908867 gpg:fingerprint:825A7D15D78BABE45646D5DF382409F597908867 sudo:dnf install -y claude-desktop-extra EXPECTED )" # Existing repository state is part of the trust boundary. Idempotency is only # success when the already-active repository matches the reviewed policy. reset_installer_fixture STUB_FLATPAK_REMOTE_MODE=trusted \ expect_success run_installer_function flathub-existing-trusted ensure_flathub_remote assert_log flathub-existing-trusted "$(cat <<'EXPECTED' rpm:release gpg:fingerprint:6E5C05D979C76DAF93C081354184DD4D907A7CAE EXPECTED )" assert_file_bytes "$test_tmp/cases/flathub-existing-trusted/flatpak-state" 'preserved' for mode in wrong-url wrong-key no-gpg alternate-key empty-alternate-key \ duplicate-alternate-key malformed-alternate-key; do reset_installer_fixture name="flathub-existing-$mode" STUB_FLATPAK_REMOTE_MODE="$mode" \ expect_failure run_installer_function "$name" ensure_flathub_remote assert_file_bytes "$test_tmp/cases/$name/flatpak-state" 'preserved' [[ "$(<"$test_tmp/cases/$name/commands.log")" != *'curl:'* \ && "$(<"$test_tmp/cases/$name/commands.log")" != *'sudo:'* ]] \ || fail "untrusted existing Flathub $mode state was changed" done reset_installer_fixture STUB_TERRA_INSTALLED=1 STUB_TERRA_REPO_MODE=trusted \ expect_success run_installer_function terra-existing-trusted install_terra_repository assert_log terra-existing-trusted "$(cat <<'EXPECTED' rpm:release dnf:dump-terra gpg:fingerprint:AE09157A4DE88B497EA1D5D300CDAB43DE226D6F gpg:fingerprint:AE09157A4DE88B497EA1D5D300CDAB43DE226D6F EXPECTED )" for mode in nogpg wrong-url wrong-key absent; do reset_installer_fixture name="terra-existing-$mode" STUB_TERRA_INSTALLED=1 STUB_TERRA_REPO_MODE="$mode" \ expect_failure run_installer_function "$name" install_terra_repository [[ "$(<"$test_tmp/cases/$name/commands.log")" != *'sudo:'* ]] \ || fail "untrusted existing Terra $mode state reached a mutation" done # An optional security field may be absent, but duplicates are malformed even # when one copy looks safe. These cases catch the absent/duplicate conflation. for duplicate_case in \ $'duplicate-no-gpg NoGPGVerify=false\nNoGPGVerify=true' \ $'duplicate-gpg-verify GPGVerify=true\nGPGVerify=false' \ 'alternate-gpg-key-path GPGKeyPath=/unreviewed/keyring.gpg' \ 'empty-gpg-key-path GPGKeyPath=' \ $'duplicate-gpg-key-path GPGKeyPath=\nGPGKeyPath=/unreviewed/keyring.gpg' \ 'malformed-gpg-key-path GPGKeyPath /unreviewed/keyring.gpg'; do name="${duplicate_case%% *}" lines="${duplicate_case#* }" reset_installer_fixture STUB_FLATHUB_VERIFY_LINE="$lines" \ expect_failure run_installer_function "$name" ensure_flathub_remote assert_file_bytes "$test_tmp/cases/$name/flatpak-state" 'preserved' [[ "$(<"$test_tmp/cases/$name/commands.log")" != *'sudo:'* ]] \ || fail "$name descriptor reached remote activation" done # DNF's non-networking effective configuration dump, rather than any one repo # file, decides whether Terra is absent, trusted, overridden, or duplicated. reset_installer_fixture STUB_TERRA_EFFECTIVE_MODE=absent \ expect_success run_installer_function terra-effective-absent preflight_terra_trust assert_log terra-effective-absent 'dnf:dump-terra' reset_installer_fixture STUB_TERRA_EFFECTIVE_MODE=trusted STUB_TERRA_REPO_MODE=trusted \ expect_success run_installer_function terra-effective-trusted preflight_terra_trust assert_log terra-effective-trusted "$(cat <<'EXPECTED' dnf:dump-terra gpg:fingerprint:AE09157A4DE88B497EA1D5D300CDAB43DE226D6F gpg:fingerprint:AE09157A4DE88B497EA1D5D300CDAB43DE226D6F EXPECTED )" for mode in legacy override-url override-gpg duplicate alternate; do reset_installer_fixture name="terra-effective-$mode" status=0 STUB_TERRA_EFFECTIVE_MODE="$mode" STUB_TERRA_REPO_MODE=trusted \ run_installer_function "$name" preflight_terra_trust || status=$? [[ "$status" -eq 78 ]] \ || fail "effective Terra $mode returned $status instead of hard trust status 78" [[ "$(<"$test_tmp/cases/$name/commands.log")" != *'sudo:'* ]] \ || fail "effective Terra $mode reached a transaction" done assert_pair_rollback() { local name="$1" pair="$2" prior="$3" key repo case "$pair" in hyprland) key="$test_tmp/cases/$name/etc/pki/rpm-gpg/RPM-GPG-KEY-panama-hyprland" repo="$test_tmp/cases/$name/etc/yum.repos.d/panama-hyprland.repo" ;; claude-code) key="$test_tmp/cases/$name/etc/pki/rpm-gpg/RPM-GPG-KEY-claude-code-panama" repo="$test_tmp/cases/$name/etc/yum.repos.d/claude-code.repo" ;; esac if [[ "$prior" == present ]]; then assert_file_bytes "$key" 'known key' assert_file_bytes "$repo" 'known repo' else [[ ! -e "$key" && ! -e "$repo" ]] \ || fail "$pair activation failure left part of an absent pair" fi [[ "$(<"$test_tmp/cases/$name/commands.log")" != *'sudo:dnf'* ]] \ || fail "$pair activation failure reached DNF" } # Both activation writes can fail after changing their target. Each repository # must restore known-good pairs and return prior-absent pairs to full absence. for pair_spec in \ 'hyprland configure_hyprland_repository' \ 'claude-code install_claude_code'; do read -r pair function_name <<<"$pair_spec" for prior in absent present; do for fail_at in 1 2; do reset_installer_fixture name="$pair-$prior-activation-$fail_at" STUB_PAIR_NAME="$pair" STUB_PAIR_PRIOR="$prior" STUB_INSTALL_FAIL_AT="$fail_at" \ expect_failure run_installer_function "$name" "$function_name" assert_pair_rollback "$name" "$pair" "$prior" done done done # A Fedora version outside the reviewed policy stops every public transaction # before curl, sudo, Flatpak, or repository inspection can act. for function_name in install_rpmfusion_repositories install_terra_repository \ configure_hyprland_repository ensure_flathub_remote install_claude_code \ install_claude_desktop_if_trusted; do reset_installer_fixture name="wrong-fedora-${function_name}" STUB_FEDORA_RELEASE=45 expect_failure run_installer_function "$name" "$function_name" assert_log "$name" 'rpm:release' done reset_installer_fixture sed -i 's#^RPMFUSION_FREE_RELEASE_URL=.*#RPMFUSION_FREE_RELEASE_URL=https://evil.invalid/free.rpm#' \ "$installer_fixture/setup/provenance/installers.conf" expect_failure run_installer_function rpmfusion-wrong-url install_rpmfusion_repositories assert_log rpmfusion-wrong-url 'rpm:release' for policy_case in \ 'terra-wrong-url TERRA_BASEURL install_terra_repository' \ 'hyprland-wrong-url HYPRLAND_COPR_BASEURL configure_hyprland_repository' \ 'flathub-wrong-url FLATHUB_DESCRIPTOR_URL ensure_flathub_remote' \ 'claude-code-wrong-url CLAUDE_CODE_BASEURL install_claude_code' \ 'claude-desktop-wrong-url CLAUDE_DESKTOP_BASEURL install_claude_desktop_if_trusted'; do read -r name config_name function_name <<<"$policy_case" reset_installer_fixture sed -i "s#^${config_name}=.*#${config_name}=https://evil.invalid/#" \ "$installer_fixture/setup/provenance/installers.conf" expect_failure run_installer_function "$name" "$function_name" [[ "$(<"$test_tmp/cases/$name/commands.log")" != *'curl:'* \ && "$(<"$test_tmp/cases/$name/commands.log")" != *'sudo:'* ]] \ || fail "$config_name mismatch reached a download or mutation" done reset_installer_fixture cp "$installer_fixture/setup/provenance/keys/terra44.asc" \ "$installer_fixture/setup/provenance/keys/rpmfusion-free.asc" expect_failure run_installer_function rpmfusion-wrong-key install_rpmfusion_repositories assert_log rpmfusion-wrong-key "$(cat <<'EXPECTED' rpm:release curl:https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-44.noarch.rpm:max=4194304:output=rpmfusion-free-release.rpm gpg:fingerprint:AE09157A4DE88B497EA1D5D300CDAB43DE226D6F EXPECTED )" reset_installer_fixture STUB_RPM_SIGNATURE_FAIL=rpmfusion-free-release.rpm \ expect_failure run_installer_function rpmfusion-bad-signature install_rpmfusion_repositories [[ "$(<"$test_tmp/cases/rpmfusion-bad-signature/commands.log")" != *'rpmfusion-nonfree'* ]] \ || fail 'RPM Fusion signature failure did not stop the dependent download' [[ "$(<"$test_tmp/cases/rpmfusion-bad-signature/commands.log")" != *'sudo:'* ]] \ || fail 'RPM Fusion signature failure reached a privileged mutation' reset_installer_fixture cp "$installer_fixture/setup/provenance/keys/terra44.asc" \ "$installer_fixture/setup/provenance/keys/hyprland-copr.asc" STUB_EXISTING_REPOSITORY=hyprland \ expect_failure run_installer_function hyprland-wrong-key configure_hyprland_repository assert_file_bytes "$test_tmp/cases/hyprland-wrong-key/etc/pki/rpm-gpg/RPM-GPG-KEY-panama-hyprland" \ 'known key' assert_file_bytes "$test_tmp/cases/hyprland-wrong-key/etc/yum.repos.d/panama-hyprland.repo" \ 'known repo' [[ "$(<"$test_tmp/cases/hyprland-wrong-key/commands.log")" != *'sudo:'* ]] \ || fail 'Hyprland key mismatch replaced known-good repository files' reset_installer_fixture STUB_FLATHUB_VERIFY_LINE='NoGPGVerify=true' \ expect_failure run_installer_function flathub-no-gpg ensure_flathub_remote assert_file_bytes "$test_tmp/cases/flathub-no-gpg/flatpak-state" 'preserved' [[ "$(<"$test_tmp/cases/flathub-no-gpg/commands.log")" != *'sudo:'* ]] \ || fail 'Flathub disabled-GPG descriptor mutated a remote' reset_installer_fixture STUB_FLATHUB_KEY_FILE="$installer_fixture/setup/provenance/keys/terra44.asc" \ expect_failure run_installer_function flathub-wrong-key ensure_flathub_remote assert_file_bytes "$test_tmp/cases/flathub-wrong-key/flatpak-state" 'preserved' [[ "$(<"$test_tmp/cases/flathub-wrong-key/commands.log")" != *'sudo:'* ]] \ || fail 'Flathub key mismatch mutated an existing remote' reset_installer_fixture STUB_FLATHUB_URL='https://evil.invalid/repo/' \ expect_failure run_installer_function flathub-wrong-repo-url ensure_flathub_remote assert_file_bytes "$test_tmp/cases/flathub-wrong-repo-url/flatpak-state" 'preserved' [[ "$(<"$test_tmp/cases/flathub-wrong-repo-url/commands.log")" != *'sudo:'* ]] \ || fail 'Flathub repository URL mismatch mutated an existing remote' reset_installer_fixture STUB_CLAUDE_DESKTOP_REPO_MODE=untrusted \ expect_success run_installer_function claude-desktop-untrusted install_claude_desktop_if_trusted assert_log claude-desktop-untrusted 'rpm:release' [[ "$(grep -c 'Claude Desktop is optional; configure its reviewed local-key repository manually' \ "$test_tmp/cases/claude-desktop-untrusted/output")" -eq 1 ]] \ || fail 'untrusted Claude Desktop repository did not produce one manual message' reset_installer_fixture STUB_DNF_FAIL_MATCH=terra-release expect_failure run_installer_function terra-dnf-failure install_terra_repository [[ "$(tail -n 1 "$test_tmp/cases/terra-dnf-failure/commands.log")" == *'terra-release' ]] \ || fail 'Terra DNF failure ran a later transaction command' [[ -z "$(find "$test_tmp/cases/terra-dnf-failure/tmp" -mindepth 1 -print -quit)" ]] \ || fail 'Terra DNF failure left private staging files behind' [[ "$before_gnupg" == "$(snapshot "$host_gnupg")" ]] || fail 'repository cases changed host GPG state' [[ "$before_gpg_files" == "$(snapshot_gpg_state "$host_gnupg")" ]] \ || fail 'repository cases changed host GPG files' [[ "$before_rpmdb" == "$(snapshot "$host_rpmdb")" ]] || fail 'repository cases changed host RPM database' [[ "$before_repo_files" == "$(snapshot_gpg_state /etc/yum.repos.d)" ]] \ || fail 'repository cases changed host repository files' [[ "$before_rpm_key_files" == "$(snapshot_gpg_state /etc/pki/rpm-gpg)" ]] \ || fail 'repository cases changed host RPM key files' [[ "$before_system_flatpak" == "$(snapshot_file_state /var/lib/flatpak/repo/config)" ]] \ || fail 'repository cases changed the system Flatpak remote' [[ "$before_system_flathub_key" == "$(snapshot_file_state /var/lib/flatpak/repo/flathub.trustedkeys.gpg)" ]] \ || fail 'repository cases changed the system Flathub trusted key' [[ "$before_user_flatpak" == "$(snapshot_file_state "$HOME/.local/share/flatpak/repo/config")" ]] \ || fail 'repository cases changed the user Flatpak remote' [[ "$before_bashrc" == "$(snapshot_file_state "$HOME/.bashrc")" ]] \ || fail 'repository cases changed the protected bashrc' printf 'package provenance contract: PASS\n'