Files
Gabriel Brown fa8b14e05e Fix: Adopt a Terra the machine already trusts
The repository audit made any Terra that is not Panama's own pinned form a
trust-root failure, and status 78 then stopped every stage before it ran. A
machine that installed Terra the way Terra documents it -- terra-release's own
repo file, a metalink, the key at its stock path -- was classified hostile and
had no way back, because install_terra_repository refused to touch a machine
terra-release had already reached. A gate with no door.

The trust root is the signing key, and that key is byte-for-byte the
fingerprint this repository reviewed and pinned, with every signature check
already on. So verify the fingerprint and adopt the configuration into the
pinned form instead of refusing it. Adoption needs no network and no DNF, it
runs before any other transaction in the stage, and it is repeatable, which it
has to be: terra-release owns that file and restores it on update.

Adoption stays narrow. The pinned fingerprint must match both the reviewed key
and the key the machine actually verifies against, the gpgkey must be a local
file under the system trust directory, and the endpoint must be one Terra
itself serves -- so the reviewed baseurl or the reviewed metalink host, now
pinned as TERRA_METALINK_BASEURL. An unknown key, a redirected baseurl, a
second enabled Terra, or a disabled signature check is still a hard refusal.

A refusal also stops less than it did. It suppresses the stages that open DNF
and the migrations, which may run a transaction of their own, and the run still
exits 78. It no longer stops link-dotfiles, link-skills or link-user, which
read no repository and install no package. Exiting before them is what left
this laptop with a stale ~/.claude/skills and no shipped skill reachable.

Also stub ensure_flathub_remote in the extras contract, which has been failing
since that call was added to install_extra_category without one.

Claude-Session: https://claude.ai/code/session_01PeTrG9dGY89UWuhGm4Pr1s
2026-08-28 14:53:48 -04:00
..

Installer provenance

Reviewed on 2026-08-27. installers.conf is data, not a shell fragment: the installer reads it only with load_installer_provenance. Its versions, URLs, SHA-256 values, byte limits, and complete primary fingerprints are reviewed inputs. No installer path may substitute a latest URL or execute fetched content before the applicable verification succeeds.

Key retrieval and verification

Each command below was run in a private temporary directory on 2026-08-27. The resulting armored public key is vendored under keys/; each output was checked with the listed complete primary fingerprint before it was committed.

Key Source URL Expected primary fingerprint Verification command
Terra 44 https://repos.fyralabs.com/terra44/key.asc AE09157A4DE88B497EA1D5D300CDAB43DE226D6F gpg --batch --with-colons --import-options show-only --import terra44.asc | awk -F: '$1 == "fpr" { print $10; exit }'
Anthropic Claude Code https://downloads.claude.ai/keys/claude-code.asc 31DDDE24DDFAB679F42D7BD2BAA929FF1A7ECACE gpg --batch --with-colons --import-options show-only --import claude-code.asc | awk -F: '$1 == "fpr" { print $10; exit }'
Bun releases https://keys.openpgp.org/vks/v1/by-fingerprint/F3DCC08A8572C0749B3E18888EAB4D40A7B22B59 F3DCC08A8572C0749B3E18888EAB4D40A7B22B59 gpg --batch --with-colons --import-options show-only --import bun.asc | awk -F: '$1 == "fpr" { print $10; exit }'
RPM Fusion free https://download1.rpmfusion.org/free/fedora/RPM-GPG-KEY-rpmfusion-free-fedora-2020 E9A491A3DE247814E7E067EAE06F8ECDD651FF2E gpg --batch --with-colons --import-options show-only --import rpmfusion-free.asc | awk -F: '$1 == "fpr" { print $10; exit }'
RPM Fusion nonfree https://download1.rpmfusion.org/nonfree/fedora/RPM-GPG-KEY-rpmfusion-nonfree-fedora-2020 79BDB88F9BBF73910FD4095B6A2AF96194843C65 gpg --batch --with-colons --import-options show-only --import rpmfusion-nonfree.asc | awk -F: '$1 == "fpr" { print $10; exit }'
lionheartp/Hyprland COPR https://download.copr.fedorainfracloud.org/results/lionheartp/Hyprland/pubkey.gpg 97E23476C89635135407C7D5E9BA41342C4B2995 gpg --batch --with-colons --import-options show-only --import hyprland-copr.asc | awk -F: '$1 == "fpr" { print $10; exit }'
Flathub https://flathub.org/repo/flathub.flatpakrepo 6E5C05D979C76DAF93C081354184DD4D907A7CAE awk -F= '/^GPGKey=/{print $2}' flathub.flatpakrepo | base64 --decode | gpg --batch --with-colons --import-options show-only --import | awk -F: '$1 == "fpr" { print $10; exit }'
Claude Desktop Extra https://patrickjaja.github.io/claude-desktop-extra/gpg-key.asc 825A7D15D78BABE45646D5DF382409F597908867 gpg --batch --with-colons --import-options show-only --import claude-desktop.asc | awk -F: '$1 == "fpr" { print $10; exit }'

The retrieval command for every direct key was:

curl --fail --location --connect-timeout 10 --max-time 60 --output KEY.asc SOURCE_URL

Reviewed publisher records and artifact locations

The key sources above are supported by these publisher-controlled records:

  • https://github.com/terrapkg/packages/blob/frawhide/README.md
  • https://github.com/terrapkg/packages/discussions/7736
  • https://code.claude.com/docs/en/setup
  • https://github.com/oven-sh/bun/releases/tag/bun-v1.4.0
  • https://github.com/oven-sh/bun/blob/main/dockerhub/distroless/Dockerfile
  • https://github.com/nodejs/node/releases/tag/v24.20.0
  • https://github.com/nodejs/node/blob/main/README.md
  • https://github.com/openai/codex/releases/tag/rust-v0.150.1
  • https://github.com/openai/codex/blob/main/.github/workflows/rust-release.yml
  • https://github.com/rustdesk/rustdesk/releases/tag/1.4.9

The reviewed immutable artifact and repository URLs are:

  • https://github.com/oven-sh/bun/releases/download/bun-v1.4.0/bun-linux-x64.zip
  • https://github.com/oven-sh/bun/releases/download/bun-v1.4.0/bun-linux-aarch64.zip
  • https://nodejs.org/dist/v24.20.0/node-v24.20.0-linux-x64.tar.xz
  • https://nodejs.org/dist/v24.20.0/node-v24.20.0-linux-arm64.tar.xz
  • https://github.com/openai/codex/releases/download/rust-v0.150.1/codex-package-x86_64-unknown-linux-musl.tar.gz
  • https://github.com/openai/codex/releases/download/rust-v0.150.1/codex-package-aarch64-unknown-linux-musl.tar.gz
  • https://github.com/rustdesk/rustdesk/releases/download/1.4.9/rustdesk-1.4.9-0.x86_64.rpm
  • https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-44.noarch.rpm
  • https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-44.noarch.rpm
  • https://repos.fyralabs.com/terra44
  • https://download.copr.fedorainfracloud.org/results/lionheartp/Hyprland/fedora-$releasever-$basearch/
  • https://downloads.claude.ai/claude-code/rpm/stable
  • https://patrickjaja.github.io/claude-desktop-extra/rpm/

Artifact digests were checked with sha256sum ARTIFACT against the lowercase 64-hex values in installers.conf; all runtime downloads also enforce the recorded byte limit before atomic replacement.

The *_BINARY_SHA256 values are the SHA-256 digests of the exact executable bytes selected from each verified runtime archive. They were derived without executing the artifacts: tar -xO selected Node's bin/node and Codex's bin/codex, while unzip -p selected Bun's bun. Runtime version directories record both the reviewed archive digest and this reviewed installed-byte digest in .panama-provenance; later runs require the receipt and re-hash the installed binary before treating an existing directory as trusted.

Panama bootstrap

The public desktop and server commands use the same committed boot blob:

commit  0d1841cf86975d52485c94c0caa5d1b67e5c54a1
SHA-256 fd8dcd70d1266da109972df346e3d85d1037f6f6e1942b0157064412ab892372
URL     https://git.gbrown.org/gib/Panama/raw/commit/0d1841cf86975d52485c94c0caa5d1b67e5c54a1/boot

The digest was derived from the committed blob with:

git show 0d1841cf86975d52485c94c0caa5d1b67e5c54a1:boot | sha256sum

That implementation commit contains only boot and its boot/root-server contracts. The following documentation commit records the pin and does not contribute bytes to it. Rotate the bootstrap pin only through the same two-step sequence: commit the boot implementation first, derive its committed blob digest, then update the command and this ledger in a second commit.

Rotation policy

Do not replace a key on an automated update. A key rotation is a reviewed repository change: obtain the new key from the publisher record, independently confirm its complete primary fingerprint, update the vendored key and installers.conf together, refresh this retrieval record, and add a focused contract case if the verification behavior changes. Until that review lands, verification fails closed and preserves any known-good destination.

Container-only Terra 44 signed-bootstrap proof

On 2026-08-27, a single disposable rootless Podman container proved the Terra bootstrap path without changing the host package database, host keyring, or host repository files. Podman reported rootless=true, runtime=crun, and a user graph root. The fresh image was registry.fedoraproject.org/fedora@sha256:62f199d1eb34170a7bb2277485676d89c0e91aae4086151c4043062cce51c77c (sha256:87d8a4a90c0457689db68624cac1026fb2201cbdc1e99cc5455a8f8876118498). The container (5fc8fa42bb85afb3b57b336ca29b58a32fad50d460583329a4e910cc29fb4d2d) had no mounts and was removed automatically after podman stop.

Before copying the only host file admitted to the container, keys/terra44.asc, this exact host check reported the complete primary fingerprint AE09157A4DE88B497EA1D5D300CDAB43DE226D6F:

gpg --batch --with-colons --import-options show-only --import setup/provenance/keys/terra44.asc \
  | awk -F: '$1 == "fpr" { print $10; exit }'

Its SHA-256 was 3febbaadfa43509c22edc440d58c970705e502cdd0f347a75d5005562fd6b3d8. The container commands were:

podman create --name panama-terra-proof-20260827 --rm --pull=always \
  registry.fedoraproject.org/fedora:44 sleep infinity
podman cp setup/provenance/keys/terra44.asc \
  panama-terra-proof-20260827:/tmp/terra44.asc
podman start panama-terra-proof-20260827
podman exec panama-terra-proof-20260827 /bin/bash -lc '
  sha256sum /tmp/terra44.asc
  install -Dm0644 /tmp/terra44.asc /etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama
  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
'

Inside the container the copied and installed key both had the recorded SHA-256 before and after installation. terra-release-44-9.noarch was installed. Its effective terra configuration reported gpgcheck = 1, pkg_gpgcheck = 1, and repo_gpgcheck = 1; no GPG-bypass option was used. The package's own /etc/yum.repos.d/terra.repo uses its Terra metalink and RPM-GPG-KEY-terra44. That differs from Panama's deliberately staged local key/base-URL file in install-packages, which replaces the release-generated file only after this verified bootstrap step.

Although the command runner returned after 30 seconds while DNF was still loading metadata, Podman's retained event log records the exact command's completion. This read-only recovery command was run after container removal:

podman events --since '2026-08-27T10:55:00-04:00' --until '2026-08-27T11:02:00-04:00' \
  --filter container=5fc8fa42bb85afb3b57b336ca29b58a32fad50d460583329a4e910cc29fb4d2d \
  --format json

The first exec event, at timeNano=1787842633591543881, is the documented key-install and DNF command. Its matching first exec_died event, at timeNano=1787842671276003275, records ContainerExitCode:0. The same-container post-check independently confirmed the installed package and effective signature settings above; no retry or second container was used.