Docs: Pin the verified Panama bootstrap
This commit is contained in:
@@ -94,6 +94,22 @@ it against the real system.
|
||||
|
||||
Never bare `sudo`. Load the `panama-sudo` skill first. Migrations already follow the rule.
|
||||
|
||||
## Initial bootstrap trust
|
||||
|
||||
Use the complete command in `README.md` for a new machine. It downloads `boot`
|
||||
from the documented commit URL into a private temporary directory, enforces the
|
||||
documented curl time and byte limits, verifies the committed blob with
|
||||
`sha256sum -c`, and passes both pins to the verified script. Desktop and server
|
||||
bootstrap use the same commit and digest. Never substitute a branch URL, pipe a
|
||||
response into Bash, or invent a newer pin from an uncommitted file.
|
||||
|
||||
`boot` validates the full lowercase commit and SHA-256 before Git or install. A
|
||||
fresh destination fetches only that revision and creates a tracked local `main`
|
||||
after HEAD matches. An existing checkout must be clean and an ancestor of the
|
||||
requested revision; it advances with fast-forward only. Dirty, divergent,
|
||||
fetch-failed, or mismatched checkouts stop without reset or install. Once Panama
|
||||
exists, use `panama update` for normal updates.
|
||||
|
||||
`boot --server` is the one exception where a new Fedora VPS may begin as root.
|
||||
Before it offers SSH hardening, it copies a safe root key when possible or
|
||||
verifies the target key. The target user's `.ssh` must be owned by that user at
|
||||
|
||||
@@ -1,25 +1,37 @@
|
||||
# Panama
|
||||
|
||||
Formerly Sunhat. A personal config for Fedora, with the intention of helping a
|
||||
user set up their Fedora system with one command.
|
||||
user set up their Fedora system with one checked command.
|
||||
|
||||
```sh
|
||||
bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot)
|
||||
(
|
||||
set -euo pipefail
|
||||
bootstrap_commit=0d1841cf86975d52485c94c0caa5d1b67e5c54a1
|
||||
bootstrap_sha=fd8dcd70d1266da109972df346e3d85d1037f6f6e1942b0157064412ab892372
|
||||
bootstrap_dir="$(umask 077; mktemp -d)"
|
||||
trap 'rm -rf -- "$bootstrap_dir"' EXIT
|
||||
bootstrap="$bootstrap_dir/boot"
|
||||
curl --fail --location --connect-timeout 10 --max-time 30 --max-filesize 262144 \
|
||||
--output "$bootstrap" \
|
||||
"https://git.gbrown.org/gib/Panama/raw/commit/$bootstrap_commit/boot"
|
||||
printf '%s %s\n' "$bootstrap_sha" "$bootstrap" >"$bootstrap_dir/boot.sha256"
|
||||
sha256sum -c "$bootstrap_dir/boot.sha256"
|
||||
PANAMA_BOOT_REVISION="$bootstrap_commit" PANAMA_BOOT_SHA256="$bootstrap_sha" \
|
||||
bash "$bootstrap"
|
||||
)
|
||||
```
|
||||
|
||||
`boot` installs git if the machine lacks it, clones this repository to
|
||||
`boot` installs git if the machine lacks it, creates a verified checkout at
|
||||
`~/.local/share/Panama` (or `$PANAMA_PATH`), and hands off to `install`. It is
|
||||
deliberately small enough to read first, and the same two steps by hand work
|
||||
identically:
|
||||
deliberately small enough to read first. The command downloads one immutable
|
||||
`boot` blob into a private temporary directory, checks its SHA-256, then asks
|
||||
that verified script to fetch the same commit. A clean existing checkout may
|
||||
fast-forward to that exact revision. A dirty or divergent checkout, a failed
|
||||
fetch, or a revision mismatch stops before `install`; Panama never resets local
|
||||
work or falls back to whatever checkout happens to be present.
|
||||
|
||||
```sh
|
||||
git clone https://git.gbrown.org/gib/Panama.git ~/.local/share/Panama
|
||||
~/.local/share/Panama/install
|
||||
```
|
||||
|
||||
Both are safe to run again: an existing clone is fast-forwarded rather than
|
||||
replaced. Once a machine exists, though, the command that keeps it current is
|
||||
`panama update` — one command, and it never asks you anything:
|
||||
Once a machine exists, the command that keeps it current is `panama update` —
|
||||
one command, and it never asks you anything:
|
||||
|
||||
```sh
|
||||
panama update
|
||||
@@ -35,10 +47,25 @@ shell environment minus everything that needs a screen, plus rootless podman
|
||||
and the compose services in [`server/`](server/README.md). The answer is the
|
||||
one thing Panama records durably (`~/.local/state/panama/role`), because
|
||||
`panama update` asks nothing and still has to know. A fresh server skips the
|
||||
question entirely:
|
||||
question entirely. It uses the same immutable boot blob and pins as the desktop
|
||||
command; only the final `--server` argument differs:
|
||||
|
||||
```sh
|
||||
bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot) --server
|
||||
(
|
||||
set -euo pipefail
|
||||
bootstrap_commit=0d1841cf86975d52485c94c0caa5d1b67e5c54a1
|
||||
bootstrap_sha=fd8dcd70d1266da109972df346e3d85d1037f6f6e1942b0157064412ab892372
|
||||
bootstrap_dir="$(umask 077; mktemp -d)"
|
||||
trap 'rm -rf -- "$bootstrap_dir"' EXIT
|
||||
bootstrap="$bootstrap_dir/boot"
|
||||
curl --fail --location --connect-timeout 10 --max-time 30 --max-filesize 262144 \
|
||||
--output "$bootstrap" \
|
||||
"https://git.gbrown.org/gib/Panama/raw/commit/$bootstrap_commit/boot"
|
||||
printf '%s %s\n' "$bootstrap_sha" "$bootstrap" >"$bootstrap_dir/boot.sha256"
|
||||
sha256sum -c "$bootstrap_dir/boot.sha256"
|
||||
PANAMA_BOOT_REVISION="$bootstrap_commit" PANAMA_BOOT_SHA256="$bootstrap_sha" \
|
||||
bash "$bootstrap" --server
|
||||
)
|
||||
```
|
||||
|
||||
That command also works from a brand-new VPS's **root** login. It creates or
|
||||
@@ -220,7 +247,7 @@ docs/ Settings reference, and the design specs behind the work
|
||||
|
||||
## Tests
|
||||
|
||||
187 of them, under `tests/`. `tests/contracts.manifest` classifies every
|
||||
188 of them, under `tests/`. `tests/contracts.manifest` classifies every
|
||||
contract by the capabilities it needs. Run the hermetic set, or grant a
|
||||
specific external capability when automation needs it:
|
||||
|
||||
|
||||
@@ -72,6 +72,28 @@ 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:
|
||||
|
||||
```text
|
||||
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:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
@@ -43,6 +43,13 @@ Other tools that beat raw commands:
|
||||
- `panama test --safe` — run only contracts classified as hermetic in
|
||||
`tests/contracts.manifest`
|
||||
|
||||
For a new machine, use the complete verified bootstrap command in `README.md`.
|
||||
Desktop and server installs use the same commit-addressed `boot` file and
|
||||
SHA-256; server adds only `--server`. Do not replace that URL with a branch or
|
||||
pipe its response into Bash. `boot` refuses missing or malformed pins, a boot
|
||||
digest mismatch, and any dirty, divergent, fetch-failed, or mismatched existing
|
||||
checkout. Use `panama update` after installation.
|
||||
|
||||
A plain `panama test` prompts in a terminal before it starts non-hermetic contracts. Automation
|
||||
must grant each required capability with a repeatable `--allow`, such as
|
||||
`panama test --allow live-host updates`. Each contract has a 180-second outer timeout by default,
|
||||
|
||||
@@ -20,6 +20,74 @@ panama="$repo_dir/bin/panama"
|
||||
findings=()
|
||||
note() { findings+=("$1"); }
|
||||
|
||||
# ── Verified bootstrap command ───────────────────────────────────────────────
|
||||
|
||||
if grep -qE 'bash[[:space:]]+<\(curl[^)]*/raw/branch/main/boot' "$readme"; then
|
||||
note 'the README still executes the mutable main-branch bootstrap'
|
||||
fi
|
||||
if grep -q '/raw/branch/main/boot' "$readme"; then
|
||||
note 'the README still names the mutable main-branch boot URL'
|
||||
fi
|
||||
|
||||
require_bootstrap_occurrences() {
|
||||
local pattern="$1" expected="$2" explanation="$3" actual
|
||||
actual="$(grep -cE -- "$pattern" "$readme")"
|
||||
(( actual == expected )) || note "$explanation"
|
||||
}
|
||||
|
||||
mapfile -t documented_commits < <(
|
||||
sed -nE "s/^bootstrap_commit=['\"]?([0-9a-f]{40})['\"]?$/\1/p" "$readme" | sort -u
|
||||
)
|
||||
mapfile -t documented_shas < <(
|
||||
sed -nE "s/^bootstrap_sha=['\"]?([0-9a-f]{64})['\"]?$/\1/p" "$readme" | sort -u
|
||||
)
|
||||
|
||||
if (( ${#documented_commits[@]} != 1 )); then
|
||||
note 'the README does not declare one full lowercase 40-hex bootstrap commit'
|
||||
else
|
||||
documented_commit="${documented_commits[0]}"
|
||||
if ! git -C "$repo_dir" cat-file -e "$documented_commit^{commit}" 2>/dev/null; then
|
||||
note 'the documented bootstrap commit does not resolve to a repository commit'
|
||||
fi
|
||||
fi
|
||||
|
||||
if (( ${#documented_shas[@]} != 1 )); then
|
||||
note 'the README does not declare one lowercase 64-hex bootstrap SHA-256'
|
||||
else
|
||||
documented_sha="${documented_shas[0]}"
|
||||
fi
|
||||
|
||||
if [[ -n "${documented_commit:-}" && -n "${documented_sha:-}" ]] \
|
||||
&& [[ "$(git -C "$repo_dir" show "$documented_commit:boot" 2>/dev/null | sha256sum | cut -d' ' -f1)" != "$documented_sha" ]]; then
|
||||
note 'the documented SHA-256 does not match boot in the documented commit'
|
||||
fi
|
||||
|
||||
require_bootstrap_occurrences '^bootstrap_commit=[0-9a-f]{40}$' 2 \
|
||||
'the desktop and server commands do not declare the same full bootstrap commit'
|
||||
require_bootstrap_occurrences '^bootstrap_sha=[0-9a-f]{64}$' 2 \
|
||||
'the desktop and server commands do not declare the same full bootstrap SHA-256'
|
||||
require_bootstrap_occurrences 'https://git\.gbrown\.org/gib/Panama/raw/commit/\$bootstrap_commit/boot' 2 \
|
||||
'the desktop and server commands do not both use the commit-addressed boot URL'
|
||||
require_bootstrap_occurrences '--connect-timeout 10' 2 \
|
||||
'the desktop and server commands do not both use the 10-second connect timeout'
|
||||
require_bootstrap_occurrences '--max-time 30' 2 \
|
||||
'the desktop and server commands do not both use the 30-second total timeout'
|
||||
require_bootstrap_occurrences '--max-filesize 262144' 2 \
|
||||
'the desktop and server commands do not both use the 256 KiB response limit'
|
||||
require_bootstrap_occurrences 'mktemp[[:space:]]+-d' 2 \
|
||||
'the desktop and server commands do not both use a private temporary directory'
|
||||
require_bootstrap_occurrences 'sha256sum[[:space:]]+-c' 2 \
|
||||
'the desktop and server commands do not both verify with sha256sum -c'
|
||||
require_bootstrap_occurrences 'PANAMA_BOOT_REVISION="?\$bootstrap_commit"?[[:space:]]+PANAMA_BOOT_SHA256="?\$bootstrap_sha"?' 2 \
|
||||
'the desktop and server commands do not both pass the verified pins to boot'
|
||||
grep -qE 'bash[[:space:]]+"?\$bootstrap"?([[:space:]]|$)' "$readme" \
|
||||
|| note 'the README bootstrap does not execute the verified temporary file'
|
||||
grep -qE 'bash[[:space:]]+"?\$bootstrap"?[[:space:]]+--server' "$readme" \
|
||||
|| note 'the server bootstrap does not reuse the verified temporary file'
|
||||
if grep -qE 'curl[^|]*\|[[:space:]]*(bash|sh)|bash[[:space:]]+<\(curl' "$readme"; then
|
||||
note 'the README pipes a network response into a shell'
|
||||
fi
|
||||
|
||||
# ── The contract count ───────────────────────────────────────────────────────
|
||||
#
|
||||
# Counted the way `panama test` collects the suite, so the README agrees with
|
||||
|
||||
Reference in New Issue
Block a user