fix: harden embedded Pi lifecycle recovery

This commit is contained in:
2026-08-04 23:14:47 +02:00
parent a368889838
commit 935bb1db0e
15 changed files with 572 additions and 101 deletions
+31 -12
View File
@@ -75,7 +75,10 @@ Before inventory, update activates the durable maintenance gate. Activation writ
all leases. A recreated candidate reads that marker at startup and therefore starts gated. The
loopback-only control endpoints cannot be reached through the frontend proxy and do not depend on
the configured authentication principal mode. Lost activation/deactivation responses are resolved
by querying gate status.
by querying gate status only when the original result is unknown. An explicit file or directory
durability failure is never converted to success by matching readback: the control API reports
`maintenance_durability_failed`, keeps or restores the safest durable marker state, and requires
recovery.
Open, unarchived sessions stop an update. After an operator has completed or otherwise drained
their work, `--drain` makes the command poll the authenticated bare-array
@@ -91,9 +94,10 @@ Rollback atomically promotes the previous selector. Terminal cleanup removes onl
files and never deletes the durable selector.
Only `core` is recreated, with `--no-deps --force-recreate`; `frontend` is not recreated and no
volume-replacement flags are used. Verification checks health, exact requested Pi version, the
provider/model/settings smoke, unchanged non-secret rendered configuration, and the complete
persistence-mount fingerprint.
volume-replacement flags are used. Verification checks health; exact requested Pi version at all
three declared boundaries (the candidate executable, `PI_VERSION` environment, and
`org.opencontainers.image.version` image label); the provider/model/settings smoke; unchanged
non-secret rendered configuration; and the complete persistence-mount fingerprint.
## Recovery, rollback, and maintenance cleanup
@@ -114,6 +118,11 @@ Any post-candidate failure explicitly confirms or reactivates maintenance and re
before compensation. Automatic rollback selects the transaction's previous image through the
lifecycle override and clears maintenance only after the previous image, configuration, mounts,
health, Pi smoke, and terminal recovery write are verified. Ambiguous compensation remains gated.
If the candidate core is stopped and cannot serve the maintenance endpoint, rollback proves that
state with Compose and writes the marker through a one-off previous-image `core` container sharing
the settings volume. It does not require the failed candidate, a host Node runtime, or the Docker
socket inside a container. The restored core is then recreated, verified, and rescanned before the
gate can open.
For an interrupted transaction, first run:
@@ -140,12 +149,22 @@ Missing confirmation, invalid arguments, active sessions, and an interrupted tra
`2`. Docker and verification failures exit nonzero with concise, redacted guidance. Direct
read-only/log commands preserve the original Docker child exit code.
## Go 1.24 dependency security boundary
## Go dependency security boundary
`golang.org/x/sys` is a direct dependency for the Windows durable-replace implementation. The
newest release compatible with the required Go 1.24 toolchain is pinned (`v0.41.0`). Releases
`v0.42.0` through `v0.44.0` require Go 1.25, so `v0.44.0` cannot be selected without changing the
product toolchain contract. Govulncheck reports GO-2026-5024 at module level for `v0.41.0`, but no
thothctl call trace reaches the vulnerable `windows.NewNTUnicodeString`; thothctl calls only
`UTF16PtrFromString` and `MoveFileEx` in that package. Upgrade to at least `v0.44.0` together with
the planned Go 1.25-or-newer toolchain migration.
The supported toolchain is Go `1.26.5`, released 2026-07-07, with module language version
`1.26.0`. The Docker builder is pinned by both patch tag and the multi-platform manifest-list
digest:
```text
golang:1.26.5-bookworm@sha256:1ecb7edf62a0408027bd5729dfd6b1b8766e578e8df93995b225dfd0944eb651
```
That manifest provides both `linux/amd64` and `linux/arm64/v8` builders. Go's official release
history is the authority for the patch level (`https://go.dev/doc/devel/release`); the Docker
Official Image is the authority for the builder (`https://hub.docker.com/_/golang`).
`golang.org/x/sys`, used by the Windows durable-replace implementation, is pinned to `v0.47.0`.
The directly used `github.com/sirupsen/logrus` is pinned to `v1.9.1`, which removes
GO-2025-4188 from the imported package set. The build contract verifies the exact toolchain,
dependencies, digest, and all five supported target builds (Windows amd64, Darwin amd64/arm64, and
Linux amd64/arm64). `go mod verify`, tests including the race detector, `go vet`, and
`govulncheck` are release gates.