28 KiB
Trusted installation inputs implementation plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Ensure every automatic executable input is publisher-signed or pinned by a reviewed SHA-256 before Panama executes or installs it.
Architecture: Add four small provenance helpers plus declarative reviewed pins. Keep vendor-specific decisions in install-packages, drive them through one hermetic public contract, and preserve existing installations when verification fails. Finish with a commit-pinned, digest-checked Panama bootstrap.
Tech Stack: Bash 5, GnuPG, rpmkeys with a temporary database, SHA-256, DNF5/Flatpak/Git command adapters, Panama contract runner.
Spec: docs/superpowers/specs/2026-08-27-secure-bootstrap-privileged-installation-design.md
Global constraints
- Never execute fetched shell, install an unverified RPM, or accept a moving
latestresponse during automatic setup. - Download without sudo into a private checked temporary directory. Verify before any sudo, extraction, execution, or target replacement.
- Preserve a known-good installed version on every verification/download failure.
- Use exact complete fingerprints and reviewed per-architecture SHA-256 values from the approved spec.
- Use
curl --connect-timeout 10 --max-time 600; enforce each configured maximum byte count before verification. - Parse
setup/provenance/installers.confas data. Do notsource,eval, or shell-expand it. - Claude Desktop repository setup is optional and never automatic.
- No task may mutate the host package database, repository configuration, Flatpak remotes, or live installed tools.
- The Terra command gets at most one disposable Fedora 44 container smoke test with no host mounts, credentials, services, or production state.
- Package 3 owns authenticated
panama update; Package 5 owns mutable source-app and Neovim inputs. - Preserve
/home/gib/.local/share/Panama/config/bash/.bashrcoutside this worktree.
File map
setup/lib/artifact-provenance: fingerprint, digest-download, detached-signature, and temporary-RPM-keyring helpers.setup/provenance/installers.conf: strict reviewed versions, URLs, SHA-256 values, fingerprints, and maximum sizes.setup/provenance/keys/*: reviewed ASCII-armored public keys.setup/provenance/README.md: source, retrieval date, verification command, and rotation notes.tests/setup/package-provenance-contract: real cryptographic fixture plus stateful curl/sudo/DNF/Flatpak/rpm command adapters.tests/setup/fixtures/provenance/*: test-only GPG key, tiny signed manifest, good/tampered artifacts, and trusted/untrusted repo data.setup/scripts/install-packages: vendor-specific verified repository/artifact flows.install: include provenance and installer behavior in the package-stage hash.setup/scripts/link-vicinae-scripts: usenpm ciagainst the tracked lock.boot,README.md,tests/setup/boot-contract,tests/setup/readme-contract: verified initial Panama revision and boot digest.tests/contracts.manifest: one new hermetic contract.
Task 1: Build and prove the provenance helpers
Files:
- Create:
setup/lib/artifact-provenance - Create:
setup/provenance/installers.conf - Create:
setup/provenance/keys/terra44.asc - Create:
setup/provenance/keys/claude-code.asc - Create:
setup/provenance/keys/bun.asc - Create:
setup/provenance/keys/rpmfusion-free.asc - Create:
setup/provenance/keys/rpmfusion-nonfree.asc - Create:
setup/provenance/keys/hyprland-copr.asc - Create:
setup/provenance/keys/flathub.asc - Create:
setup/provenance/keys/claude-desktop.asc - Create:
setup/provenance/README.md - Create:
tests/setup/package-provenance-contract - Create:
tests/setup/fixtures/provenance/ - Modify:
tests/contracts.manifest
Interfaces:
-
Consumes:
curl,gpg,sha256sum,rpmkeys,stat, and strictNAME=valueprovenance data. -
Produces:
load_installer_provenance FILE,key_fingerprint_matches FILE EXPECTED,download_sha256 URL EXPECTED MAX_BYTES DEST,verify_detached_signature KEY SIGNATURE CONTENT, andrpm_signature_matches PACKAGE KEY EXPECTED. -
Step 1: Create cryptographic fixtures and write failing helper cases
Generate a test-only key in a temporary GNUPGHOME, export its public key, sign a four-line SHASUMS256.txt, and commit only the public key, content, detached signature, a good tiny artifact, and a one-byte-tampered artifact. The private key must never enter the repository; the contract does not need it after fixture creation.
Write contract cases that source only setup/lib/artifact-provenance and assert:
known fingerprint -> 0
wrong fingerprint -> nonzero
valid detached signature -> 0
wrong content or signature -> nonzero
matching digest/size -> atomic destination created
wrong digest, oversized body, interrupted curl -> destination absent or original bytes preserved
valid RPM signed by fixture key -> 0 through a temporary rpmdb
unsigned/wrong-key RPM -> nonzero and host rpmdb untouched
Add provenance-parser cases for unknown key, duplicate key, missing required key, whitespace around the name, shell expansion text, and unsupported architecture.
- Step 2: Run the new contract and confirm the missing-helper failure
bash -n tests/setup/package-provenance-contract
tests/setup/package-provenance-contract
Expected: nonzero because the helper/config do not exist.
- Step 3: Implement exact helpers
Use these signatures and behaviors:
key_fingerprint_matches() {
local file="$1" expected="$2" actual
actual="$(gpg --batch --with-colons --import-options show-only --import "$file" 2>/dev/null \
| awk -F: '$1 == "fpr" { print $10; exit }')"
[[ "$actual" == "$expected" ]]
}
verify_detached_signature() {
local key="$1" signature="$2" content="$3" home
home="$(mktemp -d)" || return 1
chmod 700 "$home"
GNUPGHOME="$home" gpg --batch --quiet --import "$key" >/dev/null 2>&1 \
&& GNUPGHOME="$home" gpg --batch --verify "$signature" "$content" >/dev/null 2>&1
local status=$?
rm -rf -- "$home"
return "$status"
}
download_sha256 downloads to DEST.part, passes --max-filesize MAX_BYTES, verifies stat -c %s <= MAX_BYTES, compares a lowercase 64-hex digest, then mv -f atomically. Its EXIT/INT/TERM cleanup removes only the checked .part path.
The installer may define one private download_bounded URL MAX_BYTES DEST wrapper for publisher-signed RPMs whose trust assertion is the later RPM signature rather than a reviewed digest. It uses the same curl timeouts, .part cleanup, post-download size check, and atomic rename as download_sha256; it does not execute or install the result before rpm_signature_matches succeeds.
rpm_signature_matches creates a private temporary rpmdb, imports only KEY, verifies the complete expected primary fingerprint before import, and requires rpmkeys --dbpath DB --checksig PACKAGE success with an OpenPGP signature line. It never imports into the host keyring.
load_installer_provenance reads with IFS='=' read -r name value, accepts only an explicit name allowlist, rejects duplicate/empty values and any line without exactly one =, and exports nothing. Store values in one associative array named INSTALLER_PROVENANCE.
- Step 4: Add reviewed keys and config
Fetch each key from the exact source URL in the spec to a temporary directory, verify its full fingerprint, and add its exact ASCII-armored content with apply_patch. Fill installers.conf with these reviewed values and conservative byte caps:
BUN_VERSION=1.4.0
BUN_X86_64_URL=https://github.com/oven-sh/bun/releases/download/bun-v1.4.0/bun-linux-x64.zip
BUN_X86_64_SHA256=2d03fb5fb83ac8b567aca0a281b2ce1a1a19d488f56c2968d88c3f25e92fe452
BUN_X86_64_MAX_BYTES=67108864
BUN_AARCH64_URL=https://github.com/oven-sh/bun/releases/download/bun-v1.4.0/bun-linux-aarch64.zip
BUN_AARCH64_SHA256=4b1a332ee861983eb93bcfe6f770fff94e3e31b2c388bdaea3c8ed35e58eed0e
BUN_AARCH64_MAX_BYTES=67108864
NODE_VERSION=24.20.0
NODE_X86_64_URL=https://nodejs.org/dist/v24.20.0/node-v24.20.0-linux-x64.tar.xz
NODE_X86_64_SHA256=2f2c0da162318f0de47665410c7c8c2ed3d36c8f3105de4bbc61176c70a7cbf2
NODE_X86_64_MAX_BYTES=67108864
NODE_AARCH64_URL=https://nodejs.org/dist/v24.20.0/node-v24.20.0-linux-arm64.tar.xz
NODE_AARCH64_SHA256=5f4ddab610c1ab2016b3c227cebdbf6d9495161487e4739c7b90090595f465f7
NODE_AARCH64_MAX_BYTES=67108864
CODEX_VERSION=0.150.1
CODEX_X86_64_URL=https://github.com/openai/codex/releases/download/rust-v0.150.1/codex-package-x86_64-unknown-linux-musl.tar.gz
CODEX_X86_64_SHA256=00aba704f029f6dc0d948be407a756e0c97cc840132fd691353b2c6b0a505b17
CODEX_X86_64_MAX_BYTES=134217728
CODEX_AARCH64_URL=https://github.com/openai/codex/releases/download/rust-v0.150.1/codex-package-aarch64-unknown-linux-musl.tar.gz
CODEX_AARCH64_SHA256=1ecac3f87823efb98153233b076ea3d6e34a7a8cebe43c5285dc5f79e1514639
CODEX_AARCH64_MAX_BYTES=134217728
RUSTDESK_VERSION=1.4.9
RUSTDESK_X86_64_URL=https://github.com/rustdesk/rustdesk/releases/download/1.4.9/rustdesk-1.4.9-0.x86_64.rpm
RUSTDESK_X86_64_SHA256=eb1b053ac5b2f774f2271f7fbbfd2ea475899f7a55135c5e172bc54b9388f108
RUSTDESK_X86_64_MAX_BYTES=134217728
FEDORA_RELEASE=44
RPMFUSION_FREE_RELEASE_URL=https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-44.noarch.rpm
RPMFUSION_FREE_RELEASE_MAX_BYTES=4194304
RPMFUSION_NONFREE_RELEASE_URL=https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-44.noarch.rpm
RPMFUSION_NONFREE_RELEASE_MAX_BYTES=4194304
TERRA_BASEURL=https://repos.fyralabs.com/terra44
HYPRLAND_COPR_BASEURL=https://download.copr.fedorainfracloud.org/results/lionheartp/Hyprland/fedora-$releasever-$basearch/
FLATHUB_DESCRIPTOR_URL=https://flathub.org/repo/flathub.flatpakrepo
FLATHUB_DESCRIPTOR_MAX_BYTES=1048576
CLAUDE_CODE_BASEURL=https://downloads.claude.ai/claude-code/rpm/stable
CLAUDE_DESKTOP_BASEURL=https://patrickjaja.github.io/claude-desktop-extra/rpm/
TERRA_FINGERPRINT=AE09157A4DE88B497EA1D5D300CDAB43DE226D6F
CLAUDE_CODE_FINGERPRINT=31DDDE24DDFAB679F42D7BD2BAA929FF1A7ECACE
BUN_FINGERPRINT=F3DCC08A8572C0749B3E18888EAB4D40A7B22B59
RPMFUSION_FREE_FINGERPRINT=E9A491A3DE247814E7E067EAE06F8ECDD651FF2E
RPMFUSION_NONFREE_FINGERPRINT=79BDB88F9BBF73910FD4095B6A2AF96194843C65
HYPRLAND_COPR_FINGERPRINT=97E23476C89635135407C7D5E9BA41342C4B2995
FLATHUB_FINGERPRINT=6E5C05D979C76DAF93C081354184DD4D907A7CAE
CLAUDE_DESKTOP_FINGERPRINT=825A7D15D78BABE45646D5DF382409F597908867
Use the exact hashes and fingerprints from the spec; no value may be resolved through latest. The provenance README must list every source URL and the command used to verify it on 2026-08-27.
- Step 5: Add the manifest entry and run the focused gate
# Provenance uses local signed fixtures and stubs every network/package operation.
hermetic tests/setup/package-provenance-contract
Run:
bash -n setup/lib/artifact-provenance tests/setup/package-provenance-contract
tests/setup/package-provenance-contract
tests/setup/contract-manifest-contract
./bin/panama test --safe package-provenance
git diff --check
Expected: all pass and no host GPG/RPM state changes.
- Step 6: Commit the provenance foundation
git add setup/lib/artifact-provenance setup/provenance tests/setup/fixtures/provenance \
tests/setup/package-provenance-contract tests/contracts.manifest
git commit -m "Test: Add installer provenance boundary"
Task 2: Verify third-party repository roots
Files:
- Modify:
setup/scripts/install-packages:218-276,339-370,396-456 - Modify:
tests/setup/package-provenance-contract - Test:
tests/setup/desktop-first-contract - Test:
tests/setup/package-lists-contract
Interfaces:
-
Consumes:
INSTALLER_PROVENANCE, the four helper functions, vendored keys, and command adapters. -
Produces:
install_rpmfusion_repositories,install_terra_repository,configure_hyprland_repository,ensure_flathub_remote,install_claude_code, andinstall_claude_desktop_if_trusted. -
Step 1: Add public installer cases for every repository
Run a fixture copy of install-packages with temporary HOME/state and stubbed sudo, dnf, rpm, rpmkeys, curl, flatpak, and gpg. Assert exact command-log order and policy:
RPM Fusion: exact Fedora 44 URL -> size cap -> RPM signature -> localpkg_gpgcheck=1 install
Terra: exact F44 key -> pkg_gpgcheck=1 -> repo_gpgcheck=1 -> local gpgkey -> terra-release
COPR: exact baseurl/local key, package gpgcheck=1, explicit metadata-signature exception; no `dnf copr enable`
Flathub: decoded embedded key fingerprint and GPG-enabled remote; mismatch preserves existing remote
Claude Code: exact Anthropic key/repo checks before DNF
Claude Desktop absent/untrusted: one manual message, no download, no DNF, overall success
Claude Desktop trusted existing repo: DNF install only
Inject wrong keys, wrong base URLs, GPG flags off, signature failure, and DNF failure. Assert nothing downstream in the dependent transaction runs after a trust-root failure. Require rpm -E %fedora to equal the reviewed FEDORA_RELEASE; any other release fails before a third-party download or repository mutation.
- Step 2: Run the contract and confirm current unsafe paths fail
tests/setup/package-provenance-contract
Expected: nonzero findings for --nogpgcheck, TOFU COPR, unvalidated Flathub, remote-script Claude Desktop, and unverified RPM Fusion URLs.
- Step 3: Implement signed repository setup
Source the helper and load the config from PANAMA_PATH at installer start. Download RPM Fusion release RPMs, verify signatures with the matching vendored key, then call:
sudo dnf install -y --setopt=localpkg_gpgcheck=1 "$free_rpm" "$nonfree_rpm"
Replace Terra with --repofrompath terra,https://repos.fyralabs.com/terra44 plus:
--setopt=terra.pkg_gpgcheck=1
--setopt=terra.repo_gpgcheck=1
--setopt=terra.gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-terra44-panama
Stage repo/key files completely before atomic sudo install. Write the COPR repo from reviewed local values rather than dnf copr enable, with:
[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
The repo_gpgcheck=0 line is the single audited exception: the publisher returns no repodata/repomd.xml.asc, while its RPMs are signed by the pinned project key. The contract rejects this exception for every other repository and still requires package signatures.
Parse the Flathub descriptor as INI data, base64-decode GPGKey, verify its fingerprint, and reject NoGPGVerify=true or equivalent disabled state. Write Claude Code's stable repository with the vendored local key, gpgcheck=1, and repo_gpgcheck=1; its publisher provides signed metadata.
For Claude Desktop, inspect only an already configured repo. Trust it only when its base URL equals https://patrickjaja.github.io/claude-desktop-extra/rpm/, both GPG checks are 1, and its gpgkey is an existing local file whose complete fingerprint matches the vendored claude-desktop.asc. Never curl or run the community setup script. The host's current remote-key configuration is therefore treated as untrusted until an operator configures a local reviewed key. Untrusted/absent configuration logs an optional manual instruction and returns success.
- Step 4: Verify ordering and regression contracts
bash -n setup/scripts/install-packages tests/setup/package-provenance-contract
tests/setup/package-provenance-contract
tests/setup/desktop-first-contract
tests/setup/package-lists-contract
./bin/panama test --safe package-provenance
git diff --check
- Step 5: Commit repository trust roots
git add setup/scripts/install-packages tests/setup/package-provenance-contract
git commit -m "Fix: Verify third-party package repositories"
Task 3: Pin language runtimes and agent tools
Files:
- Modify:
setup/scripts/install-packages:100-177,334-394 - Modify:
tests/setup/package-provenance-contract - Modify:
tests/quickshell/declared-dependencies-contract
Interfaces:
-
Consumes:
download_sha256, loaded reviewed pins, supporteduname -mvaluesx86_64andaarch64. -
Produces:
install_node,install_bun,install_claude_code,install_codex, andinstall_rustdeskwith verified staging and known-good preservation. -
Step 1: Add failing per-architecture and preservation cases
For each artifact, assert exact URL/digest selection for x86_64 and aarch64, unsupported-architecture refusal before curl, digest mismatch preserving a seeded old version, interrupted download cleanup, atomic replacement, and already-installed exact-version no-op.
Require source scans and public command logs to reject:
curl ... | bash
nvm install --lts
npm install -g pnpm
npm install -g @openai/codex
releases/latest
api.github.com/.../releases/latest
RustDesk supports only the reviewed x86_64 RPM. aarch64 records a deliberate soft failure without downloading. pnpm must come from signed Fedora DNF; no network-script/npm fallback is allowed.
- Step 2: Run the focused contract and confirm it fails on moving inputs
tests/setup/package-provenance-contract
Expected: nonzero findings naming each current moving or piped installer.
- Step 3: Implement verified atomic installs
Map architecture once:
case "$(uname -m)" in
x86_64) artifact_arch=X86_64 ;;
aarch64) artifact_arch=AARCH64 ;;
*) log "Unsupported architecture: $(uname -m)"; return 1 ;;
esac
Install Node 24.20.0 into $NVM_DIR/versions/node/v24.20.0 from a sibling staging directory, reject archive entries outside the expected single top-level directory, require staged bin/node --version to print v24.20.0, then rename and set nvm's default alias to 24.20.0 without nvm install.
For Bun, reject unexpected archive paths, stage the binary at $HOME/.bun/versions/1.4.0/bin/bun, require --version to print 1.4.0, then atomically replace a temporary symlink at $HOME/.bun/bin/bun. For Codex, reject absolute/parent-traversal tar members, stage the release's codex binary at $HOME/.local/lib/panama/codex/0.150.1/codex, require --version to identify 0.150.1, then atomically replace $HOME/.local/bin/codex through a temporary symlink. Existing version directories must match the reviewed binary/version or cause a soft failure; never delete and recreate an unverified collision.
Install Claude Code through the signed stable repository from Task 2. Download RustDesk's versioned RPM, verify SHA-256, then pass only that local path to DNF. Install pnpm through the signed Fedora package transaction and record a soft failure if unavailable. Every archive extracts into a checked private directory first; no archive writes directly into its final prefix.
Every helper failure appends the same component name to softly_failed; report_soft_failures keeps the package hash unstamped.
- Step 4: Run focused and dependency checks
bash -n setup/scripts/install-packages tests/setup/package-provenance-contract
tests/setup/package-provenance-contract
tests/quickshell/declared-dependencies-contract
tests/setup/desktop-first-contract
./bin/panama test --safe package-provenance
git diff --check
- Step 5: Commit pinned user tools
git add setup/scripts/install-packages tests/setup/package-provenance-contract \
tests/quickshell/declared-dependencies-contract
git commit -m "Fix: Pin runtime and agent artifacts"
Task 4: Invalidate stale installer state and lock npm installs
Files:
- Modify:
install:67-106 - Modify:
setup/scripts/link-vicinae-scripts:79-97 - Modify:
tests/setup/launcher-search-contract - Modify:
tests/setup/update-command-contract - Modify:
tests/setup/package-provenance-contract
Interfaces:
-
Consumes: tracked package lists, installer, provenance helper/config/keys, and extension lockfile.
-
Produces:
hash_packagescovering every installer trust input and Vicinaenpm cibehavior. -
Step 1: Write failing hash and lockfile assertions
Run hash_packages from a disposable installer copy and assert the digest changes independently when each of these changes:
setup/packages/core-packages
setup/scripts/install-packages
setup/lib/artifact-provenance
setup/provenance/installers.conf
one setup/provenance/keys file
In the Vicinae fixture, stub npm and require argv ci, not install. Seed a lock mismatch and assert nonzero extension-build status with the lockfile byte-for-byte unchanged.
- Step 2: Confirm current hash and npm behavior fail
tests/setup/package-provenance-contract
tests/setup/launcher-search-contract
Expected: current hash ignores installer/provenance changes and extension setup invokes npm install.
- Step 3: Hash exact inputs and switch to
npm ci
Replace the current find ... -maxdepth 1 stream with a sorted NUL-safe list containing top-level package files, setup/scripts/install-packages, setup/lib/artifact-provenance, and every regular file under setup/provenance. Hash file paths plus contents so renames change the digest.
Change only the extension dependency command to npm ci; do not add lockfile repair or update behavior.
- Step 4: Verify upgrade and extension behavior
bash -n install setup/scripts/link-vicinae-scripts
tests/setup/package-provenance-contract
tests/setup/launcher-search-contract
tests/setup/update-command-contract
./bin/panama test --safe package-provenance
git diff --check
- Step 5: Commit state invalidation and npm locking
git add install setup/scripts/link-vicinae-scripts tests/setup/launcher-search-contract \
tests/setup/update-command-contract tests/setup/package-provenance-contract
git commit -m "Fix: Re-run verified installer inputs"
Task 5: Verify the initial Panama revision before handoff
Files:
- Modify:
boot:20-166 - Modify:
tests/setup/boot-contract - Modify:
README.md:1-48 - Modify:
tests/setup/readme-contract - Modify:
.claude/skills/panama/SKILL.md - Modify:
skills/panama-desktop/SKILL.md
Interfaces:
-
Consumes:
PANAMA_BOOT_REVISIONas a full lowercase 40-hex commit andPANAMA_BOOT_SHA256as a lowercase 64-hex digest. -
Produces: verified fresh clone at that revision, fast-forward-only clean existing checkout, and documentation pinned to the implementation commit immediately preceding its documentation commit.
-
Step 1: Replace old permissive boot-contract expectations with red trust cases
The public fixture must assert:
missing/malformed revision -> no git clone/fetch and no install
fresh clone -> fetch exact revision, resolve HEAD^{commit}, equality, handoff
HEAD mismatch -> nonzero, no install
existing clean ancestor -> fast-forward to exact revision, then install
existing dirty or divergent checkout -> nonzero, no reset, no install
fetch failure -> nonzero, no install
Delete the old assertion that a failed pull proceeds with the checkout as-is. Add README assertions rejecting bash <(curl .../main/boot) and requiring a commit URL, 40-hex revision, 64-hex SHA-256, sha256sum -c, 10-second connect timeout, 30-second total timeout, and 256 KiB maximum.
- Step 2: Run boot and README contracts to prove they fail
tests/setup/boot-contract
tests/setup/readme-contract
Expected: both fail on the mutable branch bootstrap and permissive pull fallback.
- Step 3: Implement exact-revision clone/handoff and commit it
Validate inputs before Git:
[[ "${PANAMA_BOOT_REVISION:-}" =~ ^[0-9a-f]{40}$ ]] || exit 1
[[ "${PANAMA_BOOT_SHA256:-}" =~ ^[0-9a-f]{64}$ ]] || exit 1
actual_boot_sha="$(sha256sum "${BASH_SOURCE[0]}" | cut -d' ' -f1)"
[[ "$actual_boot_sha" == "$PANAMA_BOOT_SHA256" ]] || exit 1
For a fresh destination, initialize/fetch the exact commit, verify git rev-parse HEAD^{commit} equality, create local main at that commit, and set branch.main.remote=origin plus branch.main.merge=refs/heads/main. For an existing checkout, require empty git status --porcelain, fetch the exact commit, require git merge-base --is-ancestor HEAD REVISION, and fast-forward only. Never use reset or execute after mismatch/failure.
Run focused tests, then commit only implementation and contract changes:
bash -n boot tests/setup/boot-contract
tests/setup/boot-contract
tests/setup/root-server-bootstrap-contract
git add boot tests/setup/boot-contract tests/setup/root-server-bootstrap-contract
git commit -m "Fix: Verify the initial Panama revision"
- Step 4: Compute the committed boot pin and write the documented command
Use the implementation commit just created:
bootstrap_commit="$(git rev-parse HEAD)"
bootstrap_sha="$(git show "$bootstrap_commit:boot" | sha256sum | cut -d' ' -f1)"
Write README commands that download
https://git.gbrown.org/gib/Panama/raw/commit/$bootstrap_commit/boot to a checked temporary file with curl --connect-timeout 10 --max-time 30 --max-filesize 262144, compare $bootstrap_sha through sha256sum -c, then invoke with both environment values. Use the same verified command for desktop and --server; never pipe the response to Bash.
The README contract must parse those literal values, run git cat-file -e COMMIT^{commit}, and require:
test "$(git show "$commit:boot" | sha256sum | cut -d' ' -f1)" = "$documented_sha"
- Step 5: Update operator skills and run the complete installer plan gate
bash -n boot install setup/scripts/install-packages setup/scripts/link-vicinae-scripts \
setup/lib/artifact-provenance tests/setup/package-provenance-contract \
tests/setup/boot-contract
tests/setup/package-provenance-contract
tests/setup/boot-contract
tests/setup/root-server-bootstrap-contract
tests/setup/readme-contract
tests/setup/package-lists-contract
tests/setup/desktop-first-contract
tests/setup/launcher-search-contract
tests/setup/update-command-contract
./bin/panama test --safe
git diff --check
Expected: 133 hermetic contracts pass after the SSH and provenance contracts exist; non-hermetic skip counts remain unchanged.
- Step 6: Commit the pinned documentation
git add README.md tests/setup/readme-contract .claude/skills/panama/SKILL.md \
skills/panama-desktop/SKILL.md setup/provenance/README.md
git commit -m "Docs: Pin the verified Panama bootstrap"
Task 6: Smoke-test signed Terra bootstrap in a disposable Fedora 44 container
Files:
- Modify:
setup/provenance/README.md - Modify:
tests/setup/package-provenance-contractonly if the smoke test exposes a fixture gap
Interfaces:
-
Consumes: exact Terra key/repo command landed in Task 2.
-
Produces: recorded disposable proof or a fail-closed Terra-unavailable implementation; never host installation.
-
Step 1: Preflight the disposable target
Require rootless Podman, no bind mounts, a fresh registry.fedoraproject.org/fedora:44 container, and no forwarded credentials or host sockets. The command may download repository metadata and the terra-release package only inside the disposable container.
- Step 2: Run the exact key and DNF verification path
Copy only the vendored Terra key into the container, verify its full fingerprint, then run the exact --repofrompath and three terra.* GPG settings from Task 2. Query the resulting repo file and package signature settings. Remove the container on exit.
Expected: DNF installs terra-release with both package and metadata verification enabled and without --nogpgcheck.
- Step 3: Apply the fail-closed result
If the exact command fails, do not weaken GPG settings. Change the installer to print Terra unavailable and exit before initial/desktop/Hyprland transactions; update the fixture expectation to that branch. If it succeeds, make no production change.
- Step 4: Record proof and rerun the hermetic gate
Document the container image, date, exact command, exit status, key fingerprint, and inspected repo settings in setup/provenance/README.md. Do not claim host installation.
tests/setup/package-provenance-contract
./bin/panama test --safe
git diff --check
- Step 5: Commit the provenance proof
git add setup/provenance/README.md setup/scripts/install-packages \
tests/setup/package-provenance-contract
git commit -m "Docs: Record signed Terra bootstrap proof"