RAIL-HO-WP-0015-T01: owner answer for the S1 execution-attribution receipt (NK-WP-0040-T02)
No S1 runner exists: operator runs ansible-playbook through make converge. Records the future converge-wrapper emitter, the proposed audit-core sender name, per-field fillability, and open items. Emission not implemented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 308701@bnt-lap001 Assistant-Session: 5548e447-444c-4dcc-bed1-05c16eebfe56
This commit is contained in:
parent
969d42088d
commit
babae80c82
2 changed files with 135 additions and 0 deletions
|
|
@ -18,6 +18,7 @@
|
|||
| workplan | RAIL-HO-WP-0012 | blocked | — | workplans/RAIL-HO-WP-0012-s1-backup-recovery-loop.md |
|
||||
| workplan | RAIL-HO-WP-0013 | blocked | — | workplans/RAIL-HO-WP-0013-host-time-baseline.md |
|
||||
| workplan | RAIL-HO-WP-0014 | active | — | workplans/RAIL-HO-WP-0014-custodian-agt-restricted-host-account.md |
|
||||
| workplan | RAIL-HO-WP-0015 | active | — | workplans/RAIL-HO-WP-0015-s1-execution-attribution-receipt-owner-answer.md |
|
||||
| task | RAIL-HO-WP-ADHOC-2026-08-22-T01 | done | — | workplans/ADHOC-2026-08-22.md |
|
||||
| task | RAIL-HO-WP-ADHOC-2026-08-22-T02 | done | — | workplans/ADHOC-2026-08-22.md |
|
||||
| task | RAIL-HO-WP-ADHOC-2026-08-22-T03 | done | — | workplans/ADHOC-2026-08-22.md |
|
||||
|
|
@ -66,3 +67,5 @@
|
|||
| task | RAIL-HO-WP-0014-T01 | done | — | workplans/RAIL-HO-WP-0014-custodian-agt-restricted-host-account.md |
|
||||
| task | RAIL-HO-WP-0014-T02 | done | — | workplans/RAIL-HO-WP-0014-custodian-agt-restricted-host-account.md |
|
||||
| task | RAIL-HO-WP-0014-T03 | wait | — | workplans/RAIL-HO-WP-0014-custodian-agt-restricted-host-account.md |
|
||||
| task | RAIL-HO-WP-0015-T01 | done | — | workplans/RAIL-HO-WP-0015-s1-execution-attribution-receipt-owner-answer.md |
|
||||
| task | RAIL-HO-WP-0015-T02 | wait | — | workplans/RAIL-HO-WP-0015-s1-execution-attribution-receipt-owner-answer.md |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
---
|
||||
id: RAIL-HO-WP-0015
|
||||
type: workplan
|
||||
title: "S1 playbook runner: owner answer for the execution-attribution receipt"
|
||||
domain: financials
|
||||
repo: railiance-infra
|
||||
status: active
|
||||
flavor: decision
|
||||
owner: railiance-infra
|
||||
topic_slug: railiance
|
||||
created: "2026-10-28"
|
||||
updated: "2026-10-28"
|
||||
related_workplans:
|
||||
- NK-WP-0040
|
||||
- RPF-WP-0067
|
||||
- AUDIT-WP-0014
|
||||
- RAIL-HO-WP-0013
|
||||
---
|
||||
|
||||
Owner record for the net-kingdom request (State Hub message
|
||||
`848ef70a-992e-4834-8d8a-a5ba3c67f96f`, NK-WP-0040-T02) to name the component
|
||||
that emits the "Execution Attribution Receipt (proposed)" of
|
||||
`net-kingdom/canon/standards/playbook-capability-contract_v0.2.md` (lines
|
||||
292-337) for the reference declaration
|
||||
`capabilities/playbooks/railiance-infra.bootstrap-host.yaml`. Answered from
|
||||
source only. Emission is **not** implemented here.
|
||||
|
||||
## T01 — Answer the four owner questions from source
|
||||
|
||||
```task
|
||||
id: RAIL-HO-WP-0015-T01
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
**(1) What runs S1 playbooks today.** There is no runner component. S1
|
||||
playbooks are run by a human operator calling `ansible-playbook` directly
|
||||
through Make targets:
|
||||
|
||||
- The declaration names `invocation: make converge` for
|
||||
`ansible/playbooks/bootstrap.yaml`
|
||||
(`capabilities/playbooks/railiance-infra.bootstrap-host.yaml:16-19`).
|
||||
- `make converge` is `cd ansible && ansible-playbook $(PLAY) $(ANSIBLE_USER_FLAG)`
|
||||
with `PLAY := ansible/playbooks/bootstrap.yaml` (`Makefile:284`, `Makefile:361-362`);
|
||||
`converge-host` / `converge-tags` / `ansible-bootstrap` are variants
|
||||
(`Makefile:193-194`, `Makefile:364-370`). `SSH_USER` is optional; the
|
||||
remote user otherwise comes from inventory (`Makefile:285-288`).
|
||||
- The documented live path is the operator on the host:
|
||||
`ssh tegwick@92.205.62.239 '... ansible-playbook playbooks/bootstrap.yaml -c local --become -l Railiance01'`
|
||||
(`Makefile:234`, printed by `make deploy-stack`).
|
||||
- `ansible/ansible.cfg:7` uses `stdout_callback = default`; there is no
|
||||
callback plugin, wrapper or service that records a run.
|
||||
|
||||
Started by: the founder/operator (`tegwick`) from a shell, on the
|
||||
workstation or on Railiance01. Not a cluster workload, CI job or agent
|
||||
service. The only existing receipt-producing wrapper is
|
||||
`scripts/s1_handoff.py` (`make s1-handoff`, `Makefile:84-85`), and it wraps
|
||||
the **read-only** `verify.yaml`, not the converge playbook
|
||||
(`scripts/s1_handoff.py:133-139`). It writes a local JSON file under
|
||||
`reports/` (`scripts/s1_handoff.py:153-159`) and sends nothing to audit-core.
|
||||
|
||||
Owner decision: the emitter will be a railiance-infra **converge wrapper**
|
||||
modelled on `scripts/s1_handoff.py` (Python, invoked by `make converge`
|
||||
in place of the bare `ansible-playbook` call). It does not exist yet.
|
||||
|
||||
**(2) Emission at every terminal outcome keyed by run_id.** Not today.
|
||||
`make converge` emits nothing. `s1_handoff.py` emits only on its normal
|
||||
path: it returns 2 without a receipt on a dirty checkout
|
||||
(`scripts/s1_handoff.py:119-123`) or a missing `ansible-playbook`
|
||||
(`:129-131`), and an inventory/spec validation exception exits without a
|
||||
receipt (`:111-117`). Owner commitment for the future wrapper: one
|
||||
`run_id` (UUID4, as `s1_handoff.py:63`) generated before anything else, and
|
||||
a receipt emitted from a `finally` path for every terminal outcome:
|
||||
`succeeded`, `failed` (non-zero ansible exit), `refused` (pre-flight
|
||||
refusal, e.g. dirty tree) and `interrupted` (signal/exception). A receipt
|
||||
that cannot be delivered is kept locally under `reports/` and retried with
|
||||
the same `run_id` as Idempotency-Key. This is a commitment, gated on the
|
||||
receipt schema (NK-WP-0040-T02) and the sender credential below.
|
||||
|
||||
**(3) audit-core sender identity.** Proposed sender name:
|
||||
`railiance-infra-s1-runner` (envelope `source` = that name, per the pattern
|
||||
in `railiance-platform/workplans/RPF-WP-0067-*.md:49-67`). No sender exists
|
||||
(RPF-WP-0067:66-67); the credential is a CCR to railiance-platform, not done
|
||||
here. **Open, needs founder/railiance-platform:** the documented delivery is
|
||||
a per-sender bearer projected by ESO into a Kubernetes Secret. The S1 runner
|
||||
runs in an operator shell, not a pod, so that projection does not reach it.
|
||||
How an operator-run process gets that bearer (for example a short-lived
|
||||
fetch from OpenBao by the operator, or sending through an in-cluster relay)
|
||||
is not decided in source.
|
||||
|
||||
**(4) Per-field fillability today** (for a wrapper built from current
|
||||
source; "no" fields must be recorded as `unknown`, or omitted where the
|
||||
contract says so, never inferred):
|
||||
|
||||
| Field | Truthful today? | Basis / gap |
|
||||
| --- | --- | --- |
|
||||
| `initiator.iss` / `initiator.sub` | No | Operator starts the run from a shell; no IAM Profile token is presented or checked anywhere on the path (`Makefile:361-362`, `:234`). |
|
||||
| `delegation` | No | The runner cannot tell whether an agent invoked `make` for the operator. The contract allows "absent" only when there was no delegation (`playbook-capability-contract_v0.2.md:315`), which the runner cannot assert. Needs an `unknown` value in the schema (NK). |
|
||||
| `executing_workload` | No | No workload binding: the run is a shell process, not a Tenancy Posture workload. |
|
||||
| `runtime_principal` | Partly | The local OS user and the remote SSH user / `become` root can be read at run time. These are OS accounts, not IAM principals. A warden SSH cert principal, if used, is not visible to the wrapper. |
|
||||
| `tenant` | No | `inventory/servers.yaml` has no tenant field. S1 acts for the platform; the value to record needs an NK convention. |
|
||||
| `environment` | No | `inventory/servers.yaml` has no environment field (hosts carry `baseline_profile` only, `:9`, `:15`). |
|
||||
| `run_id` | Yes | UUID4 per run (pattern `scripts/s1_handoff.py:63`). |
|
||||
| `source_commit` | Yes | `git rev-parse HEAD` (`Makefile:9`, `s1_handoff.py:119`), but only truthful with the clean-tree refusal (`s1_handoff.py:120-123`); `make converge` has no such check today. |
|
||||
| `artifact_digest` | No | No built artifact. A digest of the playbook + roles tree and `inventory_sha256` (`s1_handoff.py:68`) is possible, but the Galaxy collections are unpinned (`ansible/requirements.yaml:2-4`), so the executed code is not fully pinned. What the digest covers for an Ansible tree needs an NK definition. |
|
||||
| `target` | Yes | Inventory host names from `--limit` / inventory plus inventory SHA-256 (`s1_handoff.py:38-46`, `:68-70`). |
|
||||
| `action` | Yes | Playbook path + tags/limit, e.g. `ansible/playbooks/bootstrap.yaml` / `converge`. |
|
||||
| `decision_refs` | No | `make converge` has no approval gate. The gated targets use approval tokens (`APPROVE_VERIFY_REFRESH`, `Makefile:352-356`; tf-apply "exact approval", `:101`), not decision record ids. |
|
||||
| `time_interval.start` / `.end` | Yes | Controller UTC wall clock around the `ansible-playbook` call (`s1_handoff.py:34-35`, `:125`). |
|
||||
| `time_interval.clock_source` | Partly | Can name "controller system clock"; its sync state is not verified by the runner. |
|
||||
| `time_interval.bound` | No (omit) | No bound established: `railiance_clock_enabled: false` by default (`ansible/roles/railiance_clock/defaults/main.yaml:3`) and RAIL-HO-WP-0013 is `blocked`. The `max_error_ns` default (`:16`) is a policy target, not a measured bound. |
|
||||
|
||||
Side observation (not investigated further): `bootstrap.yaml:14` names a
|
||||
`swapfile` role that is neither under `ansible/roles/` nor in
|
||||
`ansible/requirements.yaml`, so `make converge` as declared may not run
|
||||
cleanly. Should be checked before any wrapper work.
|
||||
|
||||
## T02 — Build the converge wrapper and emit receipts
|
||||
|
||||
```task
|
||||
id: RAIL-HO-WP-0015-T02
|
||||
status: wait
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Waits on: the receipt schema and validator in net-kingdom `canon/schemas/`
|
||||
(NK-WP-0040-T02), including an `unknown` value for `delegation` and
|
||||
definitions for `tenant`, `environment` and `artifact_digest` for S1; the
|
||||
`railiance-infra-s1-runner` sender in the audit-core registry plus a decided
|
||||
bearer delivery path for an operator-run process (railiance-platform CCR,
|
||||
founder decision). Wrapper scope: replace the bare `ansible-playbook` call in
|
||||
`make converge*` with the wrapper. Do not start before these are settled.
|
||||
Loading…
Add table
Add a link
Reference in a new issue