Make S1 handoff read-only by default
All checks were successful
CI Smoke / source-contract (push) Successful in 8s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02994-7685-7940-bf34-3555b8256018
This commit is contained in:
codex 2026-08-23 12:41:23 +02:00
parent 24b799ec59
commit 40e295e3bd
16 changed files with 637 additions and 46 deletions

View file

@ -37,12 +37,19 @@ make verify
This runs `ansible/playbooks/verify.yaml` against all hosts. The playbook:
1. Downloads the Goss binary (pinned version) to `/usr/local/bin/goss`
2. Copies `goss/baseline.yaml` to `/etc/goss/baseline.yaml` on each host
3. Runs `goss validate --format tap`
4. Fails the play (non-zero exit) if any assertion fails
5. Fetches the TAP report to `reports/goss-<host>-<timestamp>.tap`
6. Auto-commits the report to git
1. Reads the installed Goss binary and `/etc/goss/baseline.yaml` metadata.
2. Renders the selected profile on the controller and requires its SHA-256
digest to match the installed baseline exactly.
3. Runs the fixed `goss validate --format tap` argument vector.
4. Fails the play if the surface is missing/stale or any assertion fails.
5. Writes TAP evidence only on the controller under `reports/`.
`scripts/handoff_contract.py` statically rejects remote modules other than
`stat`, `assert`, and the exact Goss `command`. Controller writes must be
delegated to `localhost` and remain under `reports/`. It also pins every Goss
command assertion and both profile firewall probes to their reviewed read-only
set. `make verify` therefore does not install packages, rewrite files, reload
systemd, or change services on a managed host.
**All assertions passed** → exit 0
**One or more assertions FAILED** → exit non-zero, TAP report in `reports/`
@ -59,6 +66,20 @@ make verify # assert it got there
Run `make status` for a quick human-readable summary; run `make verify` when
you need a structured, automatable check.
If verification fails because the installed surface is stale, review the
rendered changes and use the explicit mutating interface for only the intended
host:
```bash
make verify-refresh-host \
HOST=Railiance01 \
APPROVE_VERIFY_REFRESH=REFRESH-GOSS-Railiance01
```
Refreshing every host requires the distinct approval value
`APPROVE_VERIFY_REFRESH=REFRESH-GOSS-ALL`. Both refresh targets install or
update Goss, its baseline, wrapper, service, and timer before running checks.
## Goss test file
`goss/baseline.yaml.j2` is rendered per host from the same inventory lists
@ -80,14 +101,15 @@ that converge UFW. The mapping is:
1. Add the desired state to `spec/server-baseline.yaml`.
2. If it introduces a new control kind, teach both consumers that kind.
3. Run `make validate-baseline` and the unit tests.
4. Run `make converge-firewall` and `make verify-host HOST=…` only in the
appropriate reviewed live-change sequence.
4. Run the applicable reviewed convergence/refresh command, then use
`make verify-host HOST=…` as the read-only acceptance check.
An hourly on-host timer (`railiance-goss-baseline.timer`) reruns the last
rendered baseline. See `docs/conformance-loop.md`.
## Reports
TAP reports are committed to `reports/` after each `make verify` run.
They are machine-readable and suitable for CI pipelines. A cleanup policy
for old reports is tracked as extension point EP `78ef4879`.
TAP reports are transient under ignored `reports/`. They are machine-readable
and suitable for CI pipelines. Promote deliberately retained evidence under
`docs/evidence/` after reviewing it for safe metadata. A cleanup policy for old
reports is tracked as extension point EP `78ef4879`.