From add152fcdb8806a9fadb08b92406a1863678814d Mon Sep 17 00:00:00 2001 From: tegwick Date: Thu, 5 Nov 2026 23:05:08 +0100 Subject: [PATCH] NK-WP-0058-T09 done: contract table part 2 (CCRs, case broker, custody, routing and visibility) 7 rows: seeders and Secret names were settled 2026-11-04 (one stale platform doc left); case-type hash pins lack a net-kingdom guard; lane tooling imports platform internals; routing plus access-engine's list rule decide who can approve (NK-WP-0057). Co-Authored-By: Claude Opus 5.5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 943911@bnt-lap001 Assistant-Session: fc322940-1c8e-4bed-ab39-86cec99f23a0 --- WORK-RECORDS.md | 2 +- docs/bounded-execution-contract-table.md | 125 +++++++++++++++++- ...K-WP-0058-bounded-execution-operability.md | 21 ++- 3 files changed, 144 insertions(+), 4 deletions(-) diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index 4c71137..d9acb66 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -378,7 +378,7 @@ | task | NK-WP-0058-T06 | todo | — | workplans/NK-WP-0058-bounded-execution-operability.md | | task | NK-WP-0058-T07 | todo | — | workplans/NK-WP-0058-bounded-execution-operability.md | | task | NK-WP-0058-T08 | todo | — | workplans/NK-WP-0058-bounded-execution-operability.md | -| task | NK-WP-0058-T09 | todo | — | workplans/NK-WP-0058-bounded-execution-operability.md | +| task | NK-WP-0058-T09 | done | — | workplans/NK-WP-0058-bounded-execution-operability.md | | task | NK-WP-0058-T10 | todo | — | workplans/NK-WP-0058-bounded-execution-operability.md | | task | NK-WP-0058-T11 | done | — | workplans/NK-WP-0058-bounded-execution-operability.md | | intake | NK-IN-0001 | closed | blue | docs/intakes/activity-core-ops-sso-operators.md | diff --git a/docs/bounded-execution-contract-table.md b/docs/bounded-execution-contract-table.md index beec6bf..73f948d 100644 --- a/docs/bounded-execution-contract-table.md +++ b/docs/bounded-execution-contract-table.md @@ -1,7 +1,7 @@ # Bounded execution: cross-repo contract table -NK-WP-0058-T01 (part 1), as of 2026-11-05. Parts 2 (T09: approval, case and custody chain) and 3 (T10: operations -and the founder) add rows to this file. NK-WP-0057-T01 takes the rows marked **owner decision** as inputs and does +NK-WP-0058-T01 (part 1) and T09 (part 2), as of 2026-11-05. Part 3 (T10: operations and the founder) adds rows to +this file. NK-WP-0057-T01 takes the rows marked **owner decision** as inputs and does not inventory them again. Each row is one interface on the bounded-execution path. Every claim cites the file that defines it, at these @@ -226,3 +226,124 @@ resolve through the rapp config and must equal the routing recipient for the mem - `executor-lanes.py` lane errors without a cause; - `approval_entry` without the failed field. - **Hard-coded path for T07:** `test_approval_request.py:216`. + +## Part 2: the approval, case and custody chain + +NK-WP-0058-T09, as of 2026-11-05. It uses the same revisions as part 1, plus access-engine `535bab7`. + +| ID | Interface | Owner and source of truth | Consumer | Tested today | 2026-11-04/05 failure | Mark | +| --- | --- | --- | --- | --- | --- | --- | +| C1 | CCR lifecycle ↔ net-kingdom lane tooling | railiance-platform: `credential-change-requests/CCR-2026-0058`, `-0059`, `scripts/credential-change.py` | `tools/service-binds/executor-lanes.py`, which imports three platform helper modules; `pilot-run.sh` | Local: `tests/test_executor_lanes.py` copies `railiance-platform/scripts` | `window-close` failed as bare `LaneError` (identity phase) | **merge**; **owner decision** on a supported interface | +| C2 | Case-type bytes ↔ broker admission | net-kingdom `security-case-types/*/type.yaml` (canon). Pin: railiance-platform `scripts/keycape_client_secret_generate.py ACKNOWLEDGED_TYPES` (sha256) | railiance-platform credential broker | none in net-kingdom. The README errata warns against edits | none (both hashes match today) | **keep**; add a net-kingdom guard test | +| C3 | Case status ↔ broker gate | net-kingdom `security-cases/*.yaml` (`status`, `acceptance`); canon `canon/standards/security-case-types_v0.1.md` | broker (`case_not_materialized`), founder runbooks | Local: the broker case check on a synthetic copy | net-kingdom commits `materialized` **before** the mint, because the broker refuses anything else | **owner decision** | +| C4 | KeyCape client secret delivery | railiance-platform: CCR-2026-0060 and -0061, `manifests/nk-bind-executor-eso.yaml`, template `keycape-issuer-eso.yaml` | net-kingdom `sso-mfa/k8s/keycape/deployment.yaml` env `KEYCAPE_NK_BIND_EXECUTOR_APPROVAL_CLIENT_SECRET`; `keycape-client.py env_secret_name()`; executor E1 lane | railiance-platform `tests/test_nk_bind_executor_custody.py`, `test_keycape_client_secret_generate.py`; net-kingdom `sso-mfa/k8s/keycape/test_keycape_client.py`; no cross test | none (custody verify passed 2026-11-04) | **merge** | +| C5 | audit-core sender bearer custody | railiance-platform: CCR-2026-0063 (path `platform/workloads/net-kingdom/bounded-executor/audit-sender`, field `AUDIT_TOKEN`), ESO to `sso/bounded-executor-tokens` key `audit-core`. Seed: audit-core `scripts/seed-nk-bounded-executor-sender.py` (single seeder) | rapp `templates/job.yaml` mount; executor `audit_core.token_file`; railiance-platform `nk_bind_executor_custody.py verify` | audit-core `tests/test_seed_nk_bounded_executor_sender.py`; railiance-platform custody tests; no cross test | While being prepared: competing seeders in two repos and two Secret names. Settled in RPF-WP-0069 and AUDIT-WP-0018-T04; one stale copy remains | **merge**; **delete** the stale design text | +| C6 | Executor's submitter profile | **Two owners, one fact.** informed-decision `deploy/lifecycle/intake-submitters.json` and access-engine `examples/informed-decision-present-existing-review/policy.md present_existing_profiles` (v14) | informed-decision intake; access-engine decisions; executor `executor_identity` (rapp config) | none across the three | none | **merge**; **owner decision** on which is the source | +| C7 | Memo routing ↔ who can see it | informed-decision `deploy/lifecycle/review-groups.json` (the recipient). access-engine policy v14 `recipient_ok`: `list` only when `review_recipient == subject.id` | the founder in informed-decision; executor `_check_approval` (E5) | none | The memo was visible only to `platform-root`, so one window was wasted | **owner decision** (NK-WP-0057; this is E5's routing half) | + +### C1: CCR lifecycle and the lane tooling + +- **Contract:** + - `executor-lanes.py` acts only under both CCRs, approved by `platform-owner` and `net-kingdom-owner` with + `bound_claims_confirmed: true`; + - each CCR is passed as the sha256 of its file (`--write-ccr-sha256`, `--journey-ccr-sha256`), computed by + `sha256sum` in `pilot-run.sh`; + - the identity phase requires an attended `platform-admin` token from `auth/netkingdom/`, never root. +- **Gap:** `executor-lanes.py` puts `railiance-platform/scripts` on `sys.path` and imports helpers from three + scripts, `state_hub_preflight_lane`, `repair_eso_kubernetes_auth` and `telemetry_smtp_delivery`. None of them was + written as an interface for another repo, so a refactor there breaks the window commands without a failing test + in either CI. +- **Owner decision (railiance-platform):** offer a supported entry point for role create, delete and read, under a + CCR digest, or accept these helpers as a versioned interface. Either way T02 adds a test that fails in the + consumer. + +### C2: case-type hash pins + +- **Contract:** the broker admits `oidc-browser-relying-party@1.1` (`f705c64e…`) and `oidc-service-client@0.2` + (`cd238693…`) only when the net-kingdom `type.yaml` bytes hash to these values. A wording fix in net-kingdom + silently breaks the mint. +- **Proposal:** a net-kingdom CI test that compares each acknowledged `type.yaml` with a pin list kept in + net-kingdom. That list is checked against the broker's `ACKNOWLEDGED_TYPES` once owner source can reach CI (T02). + +### C3: case status and the broker + +- **Contract:** the broker refuses unless the case is `status: materialized` with + `acceptance: {at, record, by: [{role: owner}, {role: founder}]}`. +- **Gap:** the go-live runbook (`docs/credential-lane-designs/nk-bind-executor-go-live.md`, gate G1) has + net-kingdom commit `materialized` before the mint that materializes the case. The status claims a fact before it + is true. +- **Owner decision:** net-kingdom owns the case canon. Either the broker gates on `accepted` and the status moves to + `materialized` after verify, or the canon defines `materialized` as "admitted for materialization". This needs + railiance-platform's agreement, because the broker check changes. + +### C4: KeyCape client secret delivery + +- **Chain:** + 1. the broker mints into `platform/workloads/keycape/nk-bind-executor-approval` (`CLIENT_SECRET`); + 2. ESO (CCR-2026-0060) delivers it to `sso/keycape-nk-bind-executor-approval-client` key `client-secret`; + 3. KeyCape reads it from env `KEYCAPE_NK_BIND_EXECUTOR_APPROVAL_CLIENT_SECRET`; + 4. the executor reads the same KV through CCR-2026-0061. +- **Duplicates:** the Secret name follows a naming convention written twice: net-kingdom + `keycape-client.py env_secret_name()` and railiance-platform's ESO template. The KV path appears in the CCRs, the + rapp config and the custody tool. +- **Proposal:** one test computes the convention from both sides for every registered client. The executor's KV + path is checked against CCR-2026-0061 (T02). + +### C5: audit sender custody + +- **Contract:** + - audit-core's seeder mints the bearer CAS 0 into the CCR-2026-0063 path, merges the registry row + `nk-bounded-executor` with compare-and-set, force-syncs and probes; + - railiance-platform adds only the coding-agent fence and `verify`; + - ESO delivers to `sso/bounded-executor-tokens` key `audit-core`; + - the rapp Job mounts it at `/var/run/secrets/bounded-executor/audit-core`. +- **Settled 2026-11-04:** one seeder (RPF-WP-0069 "One seeder"; AUDIT-WP-0018-T04, audit-core `3157454`). The + Secret moved from `sso/nk-bind-executor-audit` key `audit-token` to `sso/bounded-executor-tokens` key + `audit-core`. +- **Still duplicated or stale:** + - railiance-platform `docs/credential-lane-designs/bounded-executor.md:85-90` still names + `sso/nk-bind-executor-audit` key `audit-token`. That is a removal or correction request to railiance-platform. + - audit-core's seeder hard-codes `/home/worsch/railiance-platform/...CCR-2026-0063...yaml` and the cluster UID + (`seed-nk-bounded-executor-sender.py:58-69`), for T07. + - the names appear in four repos (CCR, seeder, ESO manifest, rapp Job) and no test compares them. + +### C6: the executor's submitter profile + +The executor is described as one requester profile in three places: + +| Where | Fields | +| --- | --- | +| informed-decision `intake-submitters.json` | `system:serviceaccount:sso:nk-bind-executor` → `nk-bind-executor`, class `bounded-execution`, group `net-kingdom-admins`, `present_existing.approval_actor` `service:nk-bind-executor`, limit 10 | +| access-engine policy v14 `present_existing_profiles` | `service:nk-bind-executor` → `intake_submitter` `nk-bind-executor`, `memo_class` `bounded-execution`, `approval_action` `bounded-execution` | +| rapp `config.pilot.json` | `executor_identity` `service:nk-bind-executor`, `runtime_principal` `system:serviceaccount:sso:nk-bind-executor` | + +The policy says its profiles are "owner-authored here, not generated". That was a deliberate access-engine choice +(GH-DEC-2026-026), so it isn't changed locally. **Owner decision:** whether informed-decision's registry or +access-engine's policy is the source, with the other checked against it. Until then, T02 compares the three. + +### C7: routing and visibility + +- informed-decision maps the review group to exactly one recipient (`intake_service.py:189`). +- access-engine's `list` allows a viewer only if they are that recipient (`policy.md recipient_ok`). +- The two rules together mean the routing table decides who can approve, without the admission seeing it. On + 2026-11-04 the admission named `admin`, routing named `platform-root`, and the policy then hid the memo from + `admin`. +- This is NK-WP-0057's core question. The T03 readiness check compares the admission's approver with the routing + recipient before a window opens. + +## Summary for part 2 + +- **keep:** C2, with a net-kingdom guard test for the acknowledged `type.yaml` bytes. +- **merge:** + - C1: lane tooling on platform internals; + - C4: the KeyCape secret naming convention and the KV path; + - C5: audit custody names in four repos; + - C6: the submitter profile in three places. +- **delete:** the stale Secret name in railiance-platform `docs/credential-lane-designs/bounded-executor.md` + (an owner request). +- **owner decision:** + - C1: a supported platform interface for window roles (railiance-platform); + - C3: what `materialized` means and when the broker admits (net-kingdom canon with railiance-platform); + - C6: the source of the submitter profile (informed-decision and access-engine); + - C7: routing and visibility (NK-WP-0057, together with E5). +- **For T07:** the hard-coded path and cluster UID in audit-core's seeder. diff --git a/workplans/NK-WP-0058-bounded-execution-operability.md b/workplans/NK-WP-0058-bounded-execution-operability.md index 8ebb4e2..3e9ab02 100644 --- a/workplans/NK-WP-0058-bounded-execution-operability.md +++ b/workplans/NK-WP-0058-bounded-execution-operability.md @@ -167,7 +167,7 @@ details per row. ```task id: NK-WP-0058-T09 -status: todo +status: done priority: high assignee: claude-code depends_on: [NK-WP-0058-T01] @@ -184,6 +184,25 @@ Mark the duplicated pieces, for example the two seeders and the two Secret names **Done when:** every part 2 row has sources and a keep, merge, delete or owner-decision mark. +**Result, 2026-11-05.** Part 2 of `docs/bounded-execution-contract-table.md` has seven rows (C1–C7). + +- **The two seeders and the two Secret names** were already settled on 2026-11-04: audit-core's script is the + single seeder, and the Secret is `sso/bounded-executor-tokens:audit-core`. One stale copy remains in + railiance-platform `docs/credential-lane-designs/bounded-executor.md`, which is a **delete** request. +- **keep:** C2. Acknowledged `type.yaml` bytes are hash-pinned by the broker, and net-kingdom has no guard test. +- **merge:** + - C1: `executor-lanes.py` imports three railiance-platform internal helpers; + - C4: the KeyCape secret naming convention is written twice; + - C5: the audit custody names appear in four repos; + - C6: the executor's submitter profile is in informed-decision, access-engine and the rapp. +- **owner decisions:** + - C1: a supported platform interface; + - C3: `materialized` is committed before the mint; + - C6: which repo is the source of the profile; + - C7: routing and visibility. access-engine's `list` admits only the routing recipient, so the routing table + decides who can approve. This goes to NK-WP-0057 with E5. +- **For T07:** audit-core's seeder hard-codes a home path and the cluster UID. + ### Interface and responsibility inventory, part 3: operations and the founder ```task