Fix rotation review evidence and reconcile blocked S1 workplans
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e3b9-b19e-7ba1-9eb4-4faea76af3ea
This commit is contained in:
parent
41f25fe42d
commit
9886567b40
10 changed files with 255 additions and 18 deletions
54
docs/evidence/2026-09-27-loose-ends.md
Normal file
54
docs/evidence/2026-09-27-loose-ends.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Existing workplan closeout review — 2026-09-27
|
||||
|
||||
Reviewed all root and archived workplans. The only unfinished plans are
|
||||
RAIL-HO-WP-0011, 0012 and 0013; all now have state `blocked`, with eight
|
||||
remaining tasks in `wait`. No new task or workplan was opened. No residual task
|
||||
has been marked done without its required live acceptance evidence.
|
||||
|
||||
## Implemented under WP-0011 T06/T08
|
||||
|
||||
- Rotation dry-run output exposes the exact metadata-only review plan.
|
||||
- Approval binds each changed ciphertext's SHA-256 as well as recipients/path.
|
||||
- Applied receipts retain the original and resulting recipient/hash evidence.
|
||||
- Unrelated Make targets no longer eagerly decrypt the Hetzner token or read
|
||||
and export the local age private key.
|
||||
|
||||
Validation: 54 Python unit tests pass, including three new rotation regression
|
||||
tests. Inventory, baseline parity, read-only handoff contract, protected secret
|
||||
paths, SOPS recipient metadata and whitespace checks pass. Ansible-core 2.17.13
|
||||
host-time playbook syntax check passes in a disposable controller environment.
|
||||
No production decryption, recipient rotation or credential retrieval occurred.
|
||||
|
||||
## Read-only host verification
|
||||
|
||||
`ansible-playbook playbooks/verify.yaml`, Ansible-core 2.17.13, reached both hosts:
|
||||
|
||||
| Host | Checks completed | Blocking assertion | Changes |
|
||||
| --- | --- | --- | --- |
|
||||
| CoulombCore | Executable and baseline stat | `/usr/local/bin/goss` absent | 0 |
|
||||
| Railiance01 | Executable and baseline stat | Installed baseline digest differs from source render | 0 |
|
||||
|
||||
The initial sandboxed attempt failed writing Ansible's connection cache; the
|
||||
rerun with that access produced the host findings above. Neither attempt is a
|
||||
passing handoff. Host refresh includes installation/configuration and an hourly
|
||||
timer, so the concrete rendered diff must be reviewed before that separate
|
||||
mutation; subsequent baseline failures must also be resolved before T05 closes.
|
||||
|
||||
## Backup dependency correction
|
||||
|
||||
The exact S1 offsite contract remains pending:
|
||||
`d150eb3e6a19d658aa76c930b32fc20ef75ffa399558fc193fbde0738551ee62`.
|
||||
Warden's route reports unknown execution workload identity. Platform WP-0029's
|
||||
September 15 closure resolves the old upload-share incident, but does not accept
|
||||
this contract or prove S1 transfer/restore. Keep WP-0012 T05/T06 waiting for those
|
||||
specific owner and recovery receipts.
|
||||
|
||||
## Clock dependency check
|
||||
|
||||
The existing railiance-clock collector produced
|
||||
`2026-09-27-railiance01-clock-inventory.json`. Read-only `dpkg-query -W systemd
|
||||
systemd-timesyncd` returned `255.4-1ubuntu8.17` for both. Effective source/poll
|
||||
observations and configuration hashes are recorded in the receipt and WP-0013.
|
||||
RCLK-WP-0002 still lacks completed policy review; no disposable Ubuntu VM is
|
||||
declared here for reboot/outage/rollback testing. The already deployed authority
|
||||
does not close those gates. No clocks or services were changed.
|
||||
48
docs/evidence/2026-09-27-railiance01-clock-inventory.json
Normal file
48
docs/evidence/2026-09-27-railiance01-clock-inventory.json
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"host_alias": "railiance01",
|
||||
"collector_reported_at": "2026-09-27T16:46:14.477816+00:00",
|
||||
"read_only": true,
|
||||
"authority_usable": null,
|
||||
"synchronized_reported": true,
|
||||
"limitations": [
|
||||
"OS synchronization flag is not an independent UTC error bound",
|
||||
"host and collector timestamps are observations, not authenticated time samples",
|
||||
"SSH uses existing caller identity/trust; no sudo, installation or time mutation"
|
||||
],
|
||||
"collector_sha256": "3aadb6fb888d87cefb63e94ac87c9c640ef63ef6f404b09a01e8e8642b26784e",
|
||||
"remote_script_sha256": "597e08b95855c4bd1fee40ad8e7c1a8359312c1583ac8363e5bd922b493f074a",
|
||||
"inventory": {
|
||||
"remote_reported_at": "2026-09-27T16:46:16.708853+00:00",
|
||||
"commands": {
|
||||
"clock": {
|
||||
"returncode": 0,
|
||||
"stdout": "Timezone=Etc/UTC\nLocalRTC=no\nNTP=yes\nNTPSynchronized=yes\n"
|
||||
},
|
||||
"upstream": {
|
||||
"returncode": 0,
|
||||
"stdout": "LinkNTPServers=\nSystemNTPServers=ntp.ubuntu.com\nRuntimeNTPServers=\nFallbackNTPServers=ntp.ubuntu.com\nServerName=ntp.ubuntu.com\nServerAddress=2620:2d:4000:1::41\nRootDistanceMaxUSec=500ms\nPollIntervalMinUSec=32s\nPollIntervalMaxUSec=1min 4s\nPollIntervalUSec=1min 4s\nNTPMessage={ Leap=0, Version=4, Mode=4, Stratum=2, Precision=-25, RootDelay=6.454ms, RootDispersion=183us, Reference=1D586304, OriginateTimestamp=Sun 2026-09-27 16:45:18 UTC, ReceiveTimestamp=Sun 2026-09-27 16:45:18 UTC, TransmitTimestamp=Sun 2026-09-27 16:45:18 UTC, DestinationTimestamp=Sun 2026-09-27 16:45:18 UTC, Ignored=no, PacketCount=15904, Jitter=3.125ms }\nFrequency=1174453\n"
|
||||
},
|
||||
"timesyncd": {
|
||||
"returncode": 0,
|
||||
"stdout": "User=systemd-timesync\nActiveState=active\nFragmentPath=/usr/lib/systemd/system/systemd-timesyncd.service\nDropInPaths=\nUnitFileState=enabled\n"
|
||||
},
|
||||
"other_daemons": {
|
||||
"returncode": 4,
|
||||
"stdout": "inactive\ninactive\ninactive\n"
|
||||
},
|
||||
"virtualization": {
|
||||
"returncode": 0,
|
||||
"stdout": "kvm\n"
|
||||
},
|
||||
"ntp_listeners": {
|
||||
"returncode": 0,
|
||||
"stdout": ""
|
||||
}
|
||||
},
|
||||
"config_sha256": {
|
||||
"/etc/systemd/timesyncd.conf": "e6734751f8aaf19fddfff891ad246387f5f59bd9ff1a5f0cac2c34bc81941c62",
|
||||
"/etc/systemd/timesyncd.conf.d/60-railiance-clock.conf": "c787da5279c983dc6284ed16258fa2ff069cc62b53f360f4f3fed5bb94f79d5f"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
# Metadata-only example. Copy outside Git for an attended approved rotation.
|
||||
approved: false
|
||||
approved_by: "operator-name"
|
||||
approved_by: "reviewer-name"
|
||||
approved_at: "2026-08-23T00:00:00Z"
|
||||
changes:
|
||||
- path: secrets/hetzner-token.yaml
|
||||
sha256: "replace-with-exact-ciphertext-sha256-from-plan"
|
||||
before_recipients:
|
||||
- age1old-example-not-valid
|
||||
after_recipients:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ python3 scripts/sops_rotation.py --check
|
|||
|
||||
It compares each protected file's public age-recipient metadata with the first
|
||||
matching rule in `.sops.yaml`. CI runs this check to detect recipient drift.
|
||||
The JSON output includes the exact file paths, ciphertext SHA-256 hashes, and
|
||||
before/after recipient sets. Run without `--check` to inspect proposed drift.
|
||||
|
||||
An attended non-printing decryption check may emit a receipt:
|
||||
|
||||
|
|
@ -21,7 +23,10 @@ receipt or command output.
|
|||
|
||||
Actual key updates require `--apply` and an approval YAML containing
|
||||
`approved: true`, `approved_by`, `approved_at`, and an exact `changes` list from
|
||||
the current plan. The command fails if that list differs from current metadata.
|
||||
the current plan (including each changed file's `sha256`). The command fails if
|
||||
that list differs from current metadata or the reviewed ciphertext has changed.
|
||||
Applied receipts retain the reviewed before/after recipient sets and original
|
||||
ciphertext hash, plus `after_sha256` for the resulting ciphertext.
|
||||
Review and preserve recovery-key custody before approving recipient removal.
|
||||
Start from `docs/sops-rotation-approval.example.yaml`; the committed example is
|
||||
deliberately unapproved and contains no usable recipient.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue