diff --git a/docs/contracts/root-grant-read-contract_v0.1.md b/docs/contracts/root-grant-read-contract_v0.1.md index 7e441e5..5862dd9 100644 --- a/docs/contracts/root-grant-read-contract_v0.1.md +++ b/docs/contracts/root-grant-read-contract_v0.1.md @@ -25,10 +25,24 @@ transport concurrency state, not the custody revision. user-engine reads through an authenticated exact-path read-only identity; separate attended human custody writes publish whole-document CAS updates. -The actual user-engine runtime identity/auth binding, writer custody binding, -bootstrap provenance and live acceptance are still owner delivery requirements. +The runtime owner declarations now confirm namespace and ServiceAccount +`user-engine` (`rapp-user-engine/manifests/runtime.yaml`). The reader admission +uses role `user-engine-root-custody-reader` on existing `auth/kubernetes`, +with a separate projected JWT audience `openbao`. Its short-lived OpenBao token +has no default policy and only the exact document read. The flex-auth JWT and +ESO credentials are separate and cannot substitute for this admission. + +The founder subsequently approved going forward with implementation and the +approved delivery design. Actual admission, attended custody publication, +bootstrap provenance and live acceptance remain owner execution requirements. The producer packet is `railiance-platform/openbao/root-grant/README.md`. +user-engine retains its source/revision baseline atomically in its existing +PostgreSQL store. Runtime starts with initial-baseline bootstrap disabled; +controlled initialization must bind the authenticated owner read to retained +publisher provenance. A database or OpenBao restore requires reconciliation +against independently retained latest publication evidence before activation. + ## Producer requirements (T05) The selected owner must implement these requirements in its own repository, diff --git a/tools/custody-record/README.md b/tools/custody-record/README.md index 716c787..e399a35 100644 --- a/tools/custody-record/README.md +++ b/tools/custody-record/README.md @@ -16,6 +16,8 @@ a removed entry is not a revocation), and secret-looking values. `observe_root_grant` is the consumer rule from ADR-0017 section 3: a grant only for tenant `platform`, from a valid record read at most 15 minutes ago, otherwise no grant (fail closed). +Observations include `expires_at`, derived from the actual read time and the +record's cache bound, so downstream consumers can honor bounds below 900 seconds. Pass the last trusted document as `previous_record` to `observe_root_grant` to reject rollback or same-revision mutation. New custody actions cannot be diff --git a/tools/custody-record/tests/test_custody_record.py b/tools/custody-record/tests/test_custody_record.py index 917148a..5755dec 100644 --- a/tools/custody-record/tests/test_custody_record.py +++ b/tools/custody-record/tests/test_custody_record.py @@ -152,7 +152,8 @@ class ObservationTests(unittest.TestCase): self.assertEqual(observation["grant"]["scope_id"], "platform") self.assertEqual(observation["grant"]["relation"], "platform-root-custodian") self.assertEqual(observation["source"], {"record_id": "nk-custody:platform-root", "revision": 1}) - self.assertEqual(set(observation), {"subject", "grant", "source", "observed_at"}) + self.assertEqual(set(observation), {"subject", "grant", "source", "observed_at", "expires_at"}) + self.assertEqual(observation["expires_at"], "2026-10-03T09:15:00Z") def test_fail_closed_cases(self) -> None: grant = load("valid/grant.json") @@ -175,7 +176,11 @@ class ObservationTests(unittest.TestCase): self.assertIsNotNone(self.observe(load("valid/supersession.json"), subject=KING_2)) tighter = copy.deepcopy(load("valid/grant.json")) tighter["freshness"]["max_cache_seconds"] = 60 + self.assertEqual(self.observe(tighter)["expires_at"], "2026-10-03T09:01:00Z") self.assertIsNone(self.observe(tighter, age=61)) + tighter["freshness"]["max_cache_seconds"] = 0 + self.assertEqual(self.observe(tighter)["expires_at"], "2026-10-03T09:00:00Z") + self.assertIsNone(self.observe(tighter, age=1)) class CommandLineTests(unittest.TestCase): diff --git a/tools/custody-record/validate.py b/tools/custody-record/validate.py index ad12fb2..b1a2c79 100644 --- a/tools/custody-record/validate.py +++ b/tools/custody-record/validate.py @@ -202,6 +202,7 @@ def observe_root_grant( "grant": dict(entry["grant"]), "source": {"record_id": record["record_id"], "revision": record["revision"]}, "observed_at": read_at.isoformat().replace("+00:00", "Z"), + "expires_at": (read_at + dt.timedelta(seconds=bound)).isoformat().replace("+00:00", "Z"), } return None diff --git a/workplans/NK-WP-0045-root-grant-custody-record.md b/workplans/NK-WP-0045-root-grant-custody-record.md index 77811ac..bd4ccb1 100644 --- a/workplans/NK-WP-0045-root-grant-custody-record.md +++ b/workplans/NK-WP-0045-root-grant-custody-record.md @@ -4,7 +4,7 @@ type: workplan title: "Make the platform-root custody record readable as a non-secret root-grant fact" domain: infotech repo: net-kingdom -status: blocked +status: active flavor: implementation owner: claude-code topic_slug: netkingdom @@ -14,11 +14,12 @@ related: [NK-ADR-0017, NK-WP-0042] state_hub_workstream_id: "43fbb1aa-b711-5792-b72b-07cd93ca8f45" --- -NK-ADR-0017 makes the platform-root custody record the authority for the root -grant, but the record has no machine-readable, non-secret form a workload can -read. Until it does, user-engine returns "no root grant" and USER-WP-0037-T02 -stays blocked. This workplan defines that form and its read surface. It does -not change custody itself, and no secret material enters the record. +Accepted NK-ADR-0017 makes the platform-root custody record the authority for +the root grant. The non-secret schema/validator and OpenBao delivery design are +complete and approved; owner implementation is progressing. Live delivery and +user-engine acceptance remain T05/T06. Until those receipts exist, consumers +return no root grant. This work does not assign a custodian from directory or +claim projections, and no secret material enters the record. ## Accept ADR-0017 @@ -114,7 +115,7 @@ answer fixes T05. ```task id: NK-WP-0045-T05 -status: wait +status: progress depends_on: [NK-WP-0045-T04, RPF-WP-0049-T05] wait_kind: dependency blocked_on: message-from:railiance-platform @@ -150,7 +151,7 @@ Tell user-engine the read path is live so USER-WP-0037-T02 can derive - user-engine derives the root grant without inferring it from claims. -## Implementation and dependency review — 2026-10-03 +## Initial implementation review, before founder approval — 2026-10-03 Local implementation is complete for the current draft. Workplan moved to `blocked`: T01/T04 require the founder's open decision; T05 needs the selected @@ -215,3 +216,27 @@ Knowledge reload: package 0.2.3 digest start/decisions cards withheld due to changed informed-decision source. Reviewed current informed-decision README and owner guidance directly. This approval is recorded from the human instruction, not inferred from situational knowledge. + + +## Go-forward implementation — 2026-10-03 + +Bernd subsequently approved: “Good, i approve go forward please.” Continuing +implementation and the bounded approved delivery design is authorized; do not +request ADR, surface or generic go-forward approval again. Plan temporarily +active while owner implementation progresses; T05 in progress. Missing facts +and an attended OIDC/MFA handoff remain execution conditions, not a request to +repeat the approval. + +Delegated source ownership: railiance-platform producer/executor and admission; +user-engine authenticated transport, durable baseline and runtime mapping; +rapp-user-engine deployment packaging and dedicated projected JWT. Confirmed +consumer owner declarations in `rapp-user-engine/manifests/runtime.yaml` name +namespace/Deployment/ServiceAccount `user-engine`, automount disabled and an +existing flex-auth-only projection. OpenBao requires its separate audience. + +Custody evidence review: local bootstrap metadata records a temporary-single- +king approval in May 2026 and a directory reference. The signed local escrow +roster is `planned`, with planned identity references. Neither binds a current +exact OIDC issuer/subject as a real root-grant ceremony record. Asked the founder +for only the non-secret ceremony reference and exact issuer/subject; no grant +will be inferred from directory/JWT projections or these historical records.