update: docs + publish script for the self-update feature
README gets a top-level Updating section; docs/privileges.md gains a step-by-step trust-model writeup of `banger update`. The new scripts/publish-banger-release.sh drives the manual release cut: build, tar, sha256sum, cosign sign-blob, verify against the embedded public key, jq-merge into manifest.json, rclone upload to the R2 bucket. Refuses outright if the embedded key is still the placeholder so we can't accidentally publish an unverifiable release. Also folds in gofmt drift accumulated across the updater package and a few sibling files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8ed351ea47
commit
fae28e3d8b
10 changed files with 310 additions and 33 deletions
|
|
@ -198,6 +198,84 @@ What `uninstall` does NOT do automatically:
|
|||
- It does not remove the owner user, the owner's home, or anything
|
||||
the user wrote into a guest from inside the guest.
|
||||
|
||||
## Updating banger
|
||||
|
||||
`banger update` is a user-triggered, manually-invoked operation. It
|
||||
never runs in the background and never auto-checks for new releases.
|
||||
|
||||
The flow:
|
||||
|
||||
1. **Discover.** GET `https://releases.thaloco.com/banger/manifest.json`
|
||||
over HTTPS. The URL is hardcoded in the binary at compile time —
|
||||
a compromised daemon config can't redirect the updater. Manifest
|
||||
schema_version gates forward compat: a CLI that doesn't recognise
|
||||
the server's schema_version refuses to update.
|
||||
2. **In-flight gate.** `daemon.operations.list` RPC. If any operation
|
||||
is not Done, refuse with the operation list. `--force` overrides.
|
||||
3. **Download.** Capped GET on the tarball + `SHA256SUMS` (≤ 256 MiB
|
||||
and ≤ 16 KiB respectively). Tarball is sha256-verified on the fly
|
||||
against the digest published in `SHA256SUMS`; partial files are
|
||||
removed on any verification failure.
|
||||
4. **Cosign signature.** `SHA256SUMS.sig` is fetched (≤ 1 KiB) and
|
||||
verified against the `BangerReleasePublicKey` embedded in the
|
||||
running banger binary. The signature is an ECDSA P-256 / SHA-256
|
||||
blob signature produced by `cosign sign-blob` — verified by Go's
|
||||
stdlib `crypto/ecdsa.VerifyASN1`, no third-party crypto deps. A
|
||||
missing signature URL or a verification failure aborts the update
|
||||
before any binary is touched.
|
||||
5. **Sanity-run.** Staged `banger --version` must mention the
|
||||
expected version; staged `bangerd --check-migrations --system`
|
||||
must exit 0 (compatible) or 1 (will auto-migrate). Exit 2
|
||||
(incompatible — DB has migrations the new binary doesn't know)
|
||||
aborts the swap; the running install is untouched.
|
||||
6. **Swap.** Atomic `os.Rename` for each of the three binaries
|
||||
(banger-vsock-agent → bangerd → banger), with `.previous` backups.
|
||||
7. **Restart.** `systemctl restart bangerd-root.service` then
|
||||
`bangerd.service`. Wait for the new daemon socket to answer
|
||||
`ping`. Running VMs survive the daemon restart — they're each
|
||||
their own firecracker process and live in `bangerd-root.service`'s
|
||||
cgroup; restart's `KillMode=control-group` doesn't reach them.
|
||||
The new daemon's `reconcile` step re-attaches by reading the
|
||||
per-VM `handles.json` scratch file and verifying the firecracker
|
||||
process is still alive.
|
||||
8. **Verify.** Run `banger doctor` against the just-installed CLI.
|
||||
FAIL triggers auto-rollback: restore `.previous` backups, restart
|
||||
services again so the OLD binaries take over. The original error
|
||||
bubbles to the operator; `--force` skips this step.
|
||||
9. **Finalise.** Update `/etc/banger/install.toml`'s Version /
|
||||
Commit / BuiltAt. Remove `.previous` backups. Wipe the staging
|
||||
directory under `/var/cache/banger/updates/`.
|
||||
|
||||
What you're trusting in this flow:
|
||||
|
||||
- The cosign **public key** baked into the binary you're updating
|
||||
FROM. The maintainer rotates it by cutting a new release with a
|
||||
new key embedded; from then on, only signatures made with the
|
||||
new private key are accepted. v0.1.x predates a clean rotation
|
||||
story.
|
||||
- TLS to `releases.thaloco.com` for transport. The cosign signature
|
||||
is the actual integrity check; TLS just gets us the bytes faster.
|
||||
- The systemd unit owners (root for the helper, owner for the
|
||||
daemon). `banger update` requires root because it writes
|
||||
`/usr/local/bin` and talks to systemctl; it does NOT run via the
|
||||
helper RPC interface.
|
||||
|
||||
What `banger update` deliberately does NOT do:
|
||||
|
||||
- No background check timers. Operators run `banger update --check`
|
||||
on a schedule themselves if they want.
|
||||
- No update across MINOR boundaries without an explicit `--to`
|
||||
flag. v0.x is pre-stable; we don't promise that v0.1.5 → v0.2.0
|
||||
is automatic.
|
||||
- No state-DB downgrade. Schema migrations are forward-only;
|
||||
`--check-migrations` refuses to swap a binary that's older than
|
||||
the running schema.
|
||||
- No agent re-injection into existing VMs. The vsock agent inside
|
||||
each VM is the version banger had at image-pull time, not the
|
||||
current install. v0.1.x doesn't enforce or detect skew here; the
|
||||
agent's HTTP API is small enough that compat across MINORs is
|
||||
expected.
|
||||
|
||||
## Running outside the system install
|
||||
|
||||
Everything above describes the supported deployment: `banger system
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue