NK-WP-0058-T06: CCR-2026-0064 drafted in railiance-platform (b142131); watcher-CCR contract test; pins moved
All checks were successful
Bounded-execution contracts / contracts (push) Successful in 1m10s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 943911@bnt-lap001
Assistant-Session: fc322940-1c8e-4bed-ab39-86cec99f23a0
This commit is contained in:
tegwick 2026-11-06 08:56:23 +01:00
parent 06291a97da
commit c53de12f21
4 changed files with 54 additions and 6 deletions

View file

@ -20,7 +20,7 @@
},
{
"repo": "railiance-platform",
"commit": "2e1ca67a0ea2a4d69353a0f2a943fdd69f2a844d"
"commit": "b1421317e7ca25f8611e8ce27edf6fe6111ab3a6"
},
{
"repo": "key-cape",

View file

@ -369,7 +369,7 @@ evidence `docs/evidence/2026-11-04-nk56-t06-go-live/`, `2026-11-04-nk56-t06-pilo
| O2 | warden lanes ↔ child scripts | ops-warden: `warden access <lane> --exec` (silent, one command, fails on output, revokes on every path). Children: railiance-platform and audit-core silent scripts | the founder; seven lane invocations in the go-live runbook | none across repos | Seed r1 refused `token_env_must_be_unset`: warden strips `BAO_TOKEN` and `VAULT_TOKEN`, not `OPENBAO_TOKEN` | **keep**; **owner request** to ops-warden |
| O3 | Platform-admin session: lane vs shell | Two patterns: ops-warden lanes (railiance-platform, audit-core) and an interactive `bao login -method=oidc -path=netkingdom role=platform-admin` in the shell (net-kingdom `executor-lanes.py`, `pilot-run.sh`, T06 runbook 6c) | `executor-lanes.py attended_platform_admin()` | none | 2026-11-05: `window-close` failed `phase: identity, LaneError` in a shell without a login | **merge** into one pattern |
| O4 | Cluster access routes | Three in one runbook: `kubectl --kubeconfig ~/.kube/config-railiance01` (admin); `keycape-client.py` via `portal-client-rollout.py` hard-coding `/home/worsch/.kube/config-hosteurope` with `--server https://127.0.0.1:16444` (cluster UID pinned); the agent's default context (NetworkPolicy reads only) | founder, agents | none | none directly; costs founder setup | **merge** (T07: no hard-coded kubeconfigs) |
| O5 | Window watch: the write role outside a run | net-kingdom `bounded-executor/window_watch.py` (rule, modes); rapp CronJob `bounded-executor-window-watch` (schedule, identity); railiance-platform CCR for its OpenBao role (read, or read and delete, on the write role only) | the founder; the agent status identity (CronJob status) | `bounded-executor/tests/test_window_watch.py` (stubs); rapp packaging tests | 2026-11-04/05: the write role stayed open overnight (T11) | **keep** (new, NK-WP-0058-T06) |
| O5 | Window watch: the write role outside a run | net-kingdom `bounded-executor/window_watch.py` (rule, modes); rapp CronJob `bounded-executor-window-watch` (schedule, identity); railiance-platform CCR-2026-0064 (request type `auth-role-presence-watch`, `scripts/auth_role_watch_lane.py`) for its OpenBao role (read, or read and delete, on the write role only) | the founder; the agent status identity (CronJob status) | `bounded-executor/tests/test_window_watch.py` (stubs); rapp packaging tests | 2026-11-04/05: the write role stayed open overnight (T11) | **keep** (new, NK-WP-0058-T06) |
| F1 | Founder ↔ runbook steps | net-kingdom T06 runbook, railiance-platform go-live, audit-core founder runbook | the founder | live only | about 50 copy-paste rounds; values carried by hand between steps (table below) | **merge** into T04's commands |
| F2 | Founder identity in the browser | informed-decision UI at aal2; the identity model (`admin` for production, `platform-root` kept out) | the founder; executor `_check_approval` | none | The first approval came as `uid=platform-root`, the identity signed in at that moment, and was refused | **keep** the refusal; add identity hygiene to T04 |
@ -556,7 +556,7 @@ The agent's default context can read NetworkPolicies in `sso`, `approval-engine`
| C1 | `tests/test_executor_lanes.py` runs railiance-platform's real helper modules | net-kingdom contract CI |
| C2, C3 | the readiness check: `case_type_bytes_match_broker`, `case_materialized` | net-kingdom contract CI |
| C4, C5 | `tools/contract-tests/tests/test_custody_names.py` | net-kingdom contract CI |
| O5 | `bounded-executor/tests/test_window_watch.py` (rule and modes on stubs); rapp `tests/test_packaging.py` (CronJob shape) | net-kingdom contract CI; rapp CI |
| O5 | `bounded-executor/tests/test_window_watch.py` (rule and modes on stubs); `tools/contract-tests/tests/test_window_watch_contract.py` (watcher and CCR-2026-0064 agree); rapp `tests/test_packaging.py` (CronJob shape); railiance-platform `tests/test_auth_role_watch_lane.py` | net-kingdom contract CI; rapp CI |
| O2–O4, F1, F2 | `tools/bounded-execution-run/tests/test_bx.py` (lane child silent, window always closed); `tools/conventions/lint.py` (`one-cluster-route` for O4) | net-kingdom contract CI |
Not covered from source: OpenBao's ingress (rapp-openbao is private) and live drift from source, such as the

View file

@ -0,0 +1,36 @@
"""Row O5: the window watcher and its CCR name the same roles and identity (NK-WP-0058-T06)."""
import importlib.util
import sys
from pathlib import Path
import pytest
import yaml
REPO = Path(__file__).resolve().parents[3]
CCRS = REPO.parent / 'railiance-platform' / 'credential-change-requests'
sys.path.insert(0, str(REPO / 'bounded-executor'))
spec = importlib.util.spec_from_file_location('window_watch_contract', REPO / 'bounded-executor/window_watch.py')
watch = importlib.util.module_from_spec(spec)
spec.loader.exec_module(watch)
def ccr(prefix):
files = sorted(CCRS.glob(prefix + '-*.yaml'))
if not files:
pytest.skip(f'railiance-platform {prefix} required')
return yaml.safe_load(files[0].read_text())
def test_watcher_logs_in_with_the_ccr_role_and_watches_the_write_role():
watch_ccr, write_ccr = ccr('CCR-2026-0064'), ccr('CCR-2026-0058')
auth = watch_ccr['openbao']['auth']
assert watch.WATCH_ROLE == auth['role']
assert watch.WRITE_ROLE == watch_ccr['openbao']['watch']['role'] == write_ccr['openbao']['auth']['role']
assert watch.ROLE_PATH == '/v1/auth/kubernetes/role/' + watch.WRITE_ROLE
assert auth['bound_claims'] == {'service_account_names': ['nk-window-watch'], 'service_account_namespaces': ['sso']}
assert auth['audience'] == 'openbao'
def test_flag_mode_matches_what_the_watcher_needs():
mode = ccr('CCR-2026-0064')['openbao']['watch']['mode']
assert mode in ('flag', 'close') # the CronJob's --mode must not need more than the CCR grants

View file

@ -511,7 +511,7 @@ status: wait
priority: medium
assignee: claude-code
blocked_on: message-from:railiance-platform
blocking_reason: "OpenBao role net-kingdom-bounded-executor-window-watch (CCR) requested in 50c86169; then the founder runs make deploy-window-watch."
blocking_reason: "CCR-2026-0064 drafted (railiance-platform b142131, proposed): founder approval, deploy-window-watch, binding confirmation and the delegated apply."
depends_on: [NK-WP-0058-T09]
state_hub_task_id: "6a4c7413-0675-5a06-b471-5f849ce0c721"
```
@ -535,8 +535,20 @@ The open check from 2026-11-05 on the overnight window is T11.
- **Image:** `sha256:6e364fd9…` (tag `main-c1df8ec`). Its executor files were verified byte-identical to
`c1df8ec`, and it is pinned in the rapp (`1db015a`). It also carries T03's preflight and named causes, so the next
admission uses it.
- **Open:** railiance-platform's CCR for the OpenBao role (read-only first, `50c86169`), then the founder's
`make deploy-window-watch`.
- **CCR drafted on the founder's instruction:** railiance-platform CCR-2026-0064 (`b142131`, `proposed`, mode
`flag`).
- It adds a new request type, `auth-role-presence-watch`, with lane `scripts/auth_role_watch_lane.py`. The
policy is generated from the CCR: `read` on the watched role path only, plus token self-lifecycle.
- Its validator refuses any widening. Apply writes the policy and role and reads both back.
- Tests: 7 lane tests in railiance-platform, and `tools/contract-tests/tests/test_window_watch_contract.py`,
which keeps the watcher and the CCR in agreement.
- **Open, founder:**
- approve CCR-2026-0064 as platform-owner and as net-kingdom-owner;
- `make deploy-window-watch`, which creates the ServiceAccount;
- `confirm-binding` with its uid;
- `applier-apply` in the warden lane.
Then the agent verifies the watch Jobs.
### Runbook and tooling conventions