Make S1 handoff read-only by default
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a02994-7685-7940-bf34-3555b8256018
This commit is contained in:
parent
24b799ec59
commit
40e295e3bd
16 changed files with 637 additions and 46 deletions
|
|
@ -10,11 +10,11 @@ conformance (that is 10c, blocked on the family declaration validator).
|
|||
|
||||
| Piece | Where | Cadence |
|
||||
| --- | --- | --- |
|
||||
| Rendered Goss baseline | `/etc/goss/baseline.yaml` from `goss/baseline.yaml.j2` | every `make verify` |
|
||||
| Rendered Goss baseline | `/etc/goss/baseline.yaml` from `goss/baseline.yaml.j2` | reviewed converge or `make verify-refresh*` |
|
||||
| On-host timer | `railiance-goss-baseline.timer` | hourly, plus 5 minutes after boot |
|
||||
| Wrapper | `/usr/local/sbin/goss-baseline-check` | writes `/var/lib/railiance/goss/` |
|
||||
| Operator collect | `make goss-status` | on demand |
|
||||
| Operator run | `make verify` / `make verify-host HOST=…` | on demand; commits TAP to `reports/` |
|
||||
| Operator run | `make verify` / `make verify-host HOST=…` | on demand; read-only remotely, writes transient TAP locally |
|
||||
|
||||
The firewall assertions are generated from the same inventory lists that
|
||||
converge UFW (`k3s_api_allowed_sources`, `k3s_api_revoked_sources`,
|
||||
|
|
@ -37,7 +37,9 @@ Railiance01 after T01.
|
|||
to a State Hub `/progress/` endpoint. The wrapper notifies only on a
|
||||
pass↔fail transition, so a known-fail host (CoulombCore, UFW inactive)
|
||||
does not spam.
|
||||
4. **git TAP** — `make verify` still commits `reports/goss-<host>-<ts>.tap`
|
||||
4. **controller TAP** — `make verify` writes ignored
|
||||
`reports/goss-<host>-<ts>.tap`; reviewed durable evidence is promoted
|
||||
deliberately under `docs/evidence/`
|
||||
|
||||
`make goss-status` fails the play if any host still has the `FAILED` flag.
|
||||
|
||||
|
|
|
|||
|
|
@ -23,11 +23,19 @@ The current profiles are:
|
|||
- `CoulombCore`: `external-firewall`, which verifies the declared iptables
|
||||
INPUT default-drop replacement control
|
||||
|
||||
The verification play installs or refreshes the Goss check surface before it
|
||||
runs. Treat the first run after source changes as an attended host change:
|
||||
review the rendered contract and access path first. The command does not run
|
||||
Terraform, change provider resources, rotate credentials, or converge the base
|
||||
role.
|
||||
The gate is read-only on managed hosts. Before connecting,
|
||||
`scripts/handoff_contract.py` proves that its playbook contains only remote
|
||||
`stat`, `assert`, and the fixed Goss validation command, and pins the Goss
|
||||
assertion commands themselves to a reviewed read-only set. It renders each
|
||||
selected profile locally and fails if the installed
|
||||
`/etc/goss/baseline.yaml` digest differs, instead of refreshing it implicitly.
|
||||
TAP and the aggregate receipt are written only beneath the controller's
|
||||
ignored `reports/` path.
|
||||
|
||||
If a surface is stale, the operator must review it and separately approve
|
||||
`make verify-refresh-host`; that change cannot be smuggled through a handoff
|
||||
run. The handoff command does not run Terraform, change provider resources,
|
||||
rotate credentials, converge a role, write remote files, or change services.
|
||||
|
||||
Receipts validate with:
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue