From ad3b052f4da3a5a27a33074eb593906cf66bccce Mon Sep 17 00:00:00 2001 From: codex Date: Sun, 1 Nov 2026 23:10:55 +0100 Subject: [PATCH] docs: preserve reviewed NetKingdom session artifacts --- .../mason-browser/validation.json | 18 + .../pause-checkpoint-publication.json | 26 + .../collect_public_metadata.py | 38 + .../platform-owner-review.patch | 30 + .../platform-signer-custody/README.md | 19 + .../platform-signer-custody/manifest-r1.json | 43 + .../native-adapter-r1/README.md | 17 + .../native-adapter-r1/coordinator-review.json | 11 + .../native-adapter-r1/implementation.patch | 774 ++++++++++ .../native-adapter-r1/manifest.json | 32 + .../native-adapter-r1/owner-review.json | 29 + .../scripts/flex_auth_signer_custody.py | 149 ++ ...-WP-0035-credential-lane-implementation.md | 1356 +++++++++++++++++ .../native-adapter-r1/routing-blocker.json | 12 + .../native-adapter-r1/validation.json | 49 + .../native-adapter-r2/README.md | 20 + .../native-adapter-r2/implementation-r2.patch | 1002 ++++++++++++ .../native-adapter-r2/manifest.json | 67 + .../native-packet-p2/README.md | 38 + .../admission-scope.incomplete.json | 39 + .../native-packet-p2/evidence-pins.json | 139 ++ .../native-packet-p2/finalize.py | 34 + .../native-packet-p2/manifest.json | 20 + .../native-packet-p2/remaining-inputs.json | 15 + .../native-packet-p2/test_finalize.py | 56 + .../native-packet-p2/verification.json | 20 + .../native-packet-p3/README.md | 44 + .../admission-scope.incomplete.json | 39 + .../native-packet-p3/evidence-pins.json | 153 ++ .../native-packet-p3/finalize.py | 34 + .../native-packet-p3/manifest.json | 20 + .../native-packet-p3/remaining-inputs.json | 68 + .../native-packet-p3/test_finalize.py | 60 + .../native-packet-p3/verification.json | 27 + .../native-packet-preparation/README.md | 42 + .../admission-scope.incomplete.json | 39 + .../assembler-r2-revision.json | 31 + .../evidence-pins.json | 91 ++ .../native-packet-preparation/finalize.py | 32 + .../native-packet-preparation/manifest.json | 15 + .../p1-original-finalize.py | 27 + .../preparation-verification.json | 7 + .../native-packet-preparation/prepare.py | 16 + .../test_finalize.py | 44 + .../native-adapter-r2/owner-review.json | 27 + ...lex-auth-envelope-signing-native-plan.json | 150 ++ .../scripts/flex_auth_signer_custody.py | 149 ++ ...-WP-0035-credential-lane-implementation.md | 1356 +++++++++++++++++ ...ex-auth-envelope-signing-native-adapter.md | 119 ++ ...lex-auth-envelope-signing-native-plan.json | 150 ++ 50 files changed, 6793 insertions(+) create mode 100644 docs/changes/netkingdom-target-2026-10-16/mason-browser/validation.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/pause-checkpoint-publication.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-native-plan-review-next/collect_public_metadata.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-native-plan-review-next/platform-owner-review.patch create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/README.md create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/manifest-r1.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/README.md create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/coordinator-review.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/implementation.patch create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/manifest.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/owner-review.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/preimages/scripts/flex_auth_signer_custody.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/preimages/workplans/RPF-WP-0035-credential-lane-implementation.md create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/routing-blocker.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/validation.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/README.md create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/implementation-r2.patch create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/manifest.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/README.md create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/admission-scope.incomplete.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/evidence-pins.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/finalize.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/manifest.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/remaining-inputs.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/test_finalize.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/verification.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p3/README.md create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p3/admission-scope.incomplete.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p3/evidence-pins.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p3/finalize.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p3/manifest.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p3/remaining-inputs.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p3/test_finalize.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p3/verification.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/README.md create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/admission-scope.incomplete.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/assembler-r2-revision.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/evidence-pins.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/finalize.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/manifest.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/p1-original-finalize.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/preparation-verification.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/prepare.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-preparation/test_finalize.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/owner-review.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-base/docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-base/scripts/flex_auth_signer_custody.py create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-base/workplans/RPF-WP-0035-credential-lane-implementation.md create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-r1/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md create mode 100644 docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-r1/docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json diff --git a/docs/changes/netkingdom-target-2026-10-16/mason-browser/validation.json b/docs/changes/netkingdom-target-2026-10-16/mason-browser/validation.json new file mode 100644 index 00000000..19700692 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/mason-browser/validation.json @@ -0,0 +1,18 @@ +{ + "command": "python3 -m pytest tests/test_case_version_source.py tests/test_case_plan.py tests/test_case_build.py tests/test_case_structure.py -q", + "cwd": "/tmp/netkingdom-mason-browser-20261016", + "result": "50 passed in 16.14s", + "git_diff_check": "PASS", + "ruff": "unavailable: /usr/bin/python3: No module named ruff", + "actual_12_projection": { + "type_status": "acknowledged", + "case_status": "proposed", + "case_acceptance": null, + "plan_status": "draft", + "objects": 6, + "digest": "sha256:c0afd5576cdae0cbc807eccb2b9fa87ac668f15e32ec7cf79d295bdb23c75b35" + }, + "native_effects": false, + "statehub_consistency": "deferred to parent after canonical owner patch integration; isolated plan status unchanged", + "canonical_git_apply_check": "PASS: git apply --check implementation.patch in /home/worsch/ops-mason; no mutation" +} diff --git a/docs/changes/netkingdom-target-2026-10-16/pause-checkpoint-publication.json b/docs/changes/netkingdom-target-2026-10-16/pause-checkpoint-publication.json new file mode 100644 index 00000000..60e89af9 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/pause-checkpoint-publication.json @@ -0,0 +1,26 @@ +{ + "checkpoint": "3607d3e08ffdbc473d19e9baf7225843c4075ae0", + "published": true, + "sync_summary": { + "fail": 0, + "automation_error": 0, + "warn": 7, + "info": 4 + }, + "bindings": "89/89", + "original_brief_index_and_worktree_restored_and_verified": true, + "agents_terminal": true, + "runtime_trial_active": false, + "scope_receipt": "pause-publication-scope.json", + "requested_status": "paused", + "completion_estimate": { + "percent": 40, + "range_percent": [ + 30, + 50 + ], + "basis": "Rough judgment, not measured gate completion", + "acceptance_gates_fully_closed": 0, + "acceptance_gates_total": 16 + } +} diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-native-plan-review-next/collect_public_metadata.py b/docs/changes/netkingdom-target-2026-10-16/platform-native-plan-review-next/collect_public_metadata.py new file mode 100644 index 00000000..290ebf06 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-native-plan-review-next/collect_public_metadata.py @@ -0,0 +1,38 @@ +"""Root-reviewed remote public metadata collector; stdin Python, no mutations/Secrets/full specs. +Capture/discard raw kubectl stdout/stderr on any error. Output selected structured fields only. +""" +import datetime,json,subprocess,urllib.parse + +def val(path): + return '{{with '+path+'}}{{printf "%q" .}}{{else}}null{{end}}' +def arr(path,fields): + return '[{{range $i,$v := '+path+'}}{{if $i}},{{end}}{'+','.join(json.dumps(k)+':'+val('$v.'+v) for k,v in fields.items())+'}{{end}}]' +META='{'+','.join(json.dumps(k)+':'+val(v) for k,v in {'name':'.metadata.name','namespace':'.metadata.namespace','uid':'.metadata.uid','resource_version':'.metadata.resourceVersion'}.items())+','+'"owners":'+arr('.metadata.ownerReferences',{'kind':'kind','name':'name','uid':'uid'})+'}' +SOURCE='{'+','.join(json.dumps(x)+':'+val('.'+x) for x in ['repoURL','path','targetRevision','chart'])+'}' +APP='{"metadata":'+META+',"source":{{with .spec.source}}'+SOURCE+'{{else}}null{{end}},"sources":[{{range $i,$v := .spec.sources}}{{if $i}},{{end}}'+SOURCE+'{{end}}],"operation_present":{{if .operation}}true{{else}}false{{end}},"automated_present":{{if eq .spec.syncPolicy.automated nil}}false{{else}}true{{end}},"operation_phase":'+val('.status.operationState.phase')+',"resources":'+arr('.status.resources',{'kind':'kind','name':'name','namespace':'namespace'})+'}' +OBJECT='{"metadata":'+META+',"conditions":'+arr('.status.conditions',{'type':'type','status':'status','reason':'reason'})+',"field_managers":'+arr('.metadata.managedFields',{'manager':'manager','operation':'operation'})+'}' +def query(kind,name,namespace,template): + cmd=['kubectl','get',kind,name,'--ignore-not-found','-o','go-template='+template] + if namespace:cmd.extend(['-n',namespace]) + try: + r=subprocess.run(cmd,capture_output=True,text=True,timeout=12) + if r.returncode or len(r.stdout)>131072:return {'ok':False,'refused':'public-query-failed','stderr_present':bool(r.stderr)} + if not r.stdout.strip():return {'ok':True,'exists':False} + data=json.loads(r.stdout) + # repo source allowlist prevents accidental credential-bearing URL output. + for source in ([data.get('source')]+data.get('sources',[])): + if not source:continue + url=source.get('repoURL') + if url: + parsed=urllib.parse.urlsplit(url) + if parsed.username or parsed.password or parsed.query or parsed.fragment or url not in {'https://forgejo.coulomb.social/coulomb/railiance-platform.git','https://forgejo.coulomb.social/coulomb/informed-decision.git'}: + source['repoURL']=None;source['repoURL_redacted']=True + return {'ok':True,'exists':True,'selected':data,'stderr_present':bool(r.stderr)} + except Exception:return {'ok':False,'refused':'sanitized-public-query-failure'} +result={'schema':'platform-native-plan-public-supplement.v1','observed_at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'persistent_mutations':False,'held_fence':False} +cluster=query('namespace','kube-system',None,'{"uid":'+val('.metadata.uid')+'}') +if cluster.get('selected',{}).get('uid')!='a553c742-0115-43d4-99a4-a5ca56fe0786':result={'refused':'cluster-identity','persistent_mutations':False} +else: + result['applications']={name:query('applications.argoproj.io',name,'argocd',APP) for name in ['railiance-apps-root','informed-decision','openbao-secretstore','eso-token-renewer']} + result['objects']={kind+'/'+name:query(kind,name,'flex-auth',OBJECT) for kind,name in [('deployment','flex-auth-secrets-engine'),('serviceaccount','flex-auth-secrets-engine'),('persistentvolumeclaim','flex-auth-secrets-engine-outbox'),('serviceaccount','flex-auth-envelope-signing-eso'),('secretstore.external-secrets.io','openbao-flex-auth-envelope-signing'),('externalsecret.external-secrets.io','flex-auth-secrets-engine-envelope-signing')]} +print(json.dumps(result,sort_keys=True)) diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-native-plan-review-next/platform-owner-review.patch b/docs/changes/netkingdom-target-2026-10-16/platform-native-plan-review-next/platform-owner-review.patch new file mode 100644 index 00000000..9af4a3ce --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-native-plan-review-next/platform-owner-review.patch @@ -0,0 +1,30 @@ +--- a/credential-change-requests/CCR-2026-0050-flex-auth-envelope-signing.yaml ++++ b/credential-change-requests/CCR-2026-0050-flex-auth-envelope-signing.yaml +@@ -19,7 +19,10 @@ + - access-engine-owner + - secrets-engine-owner + - cluster-runtime-storage-owner +- comments: [] ++ comments: ++ - reviewer: railiance-platform-owner (agent railiance-platform, codex) ++ decision: approved ++ comment: "INTENT Secure Custody/Stable Interfaces/Operable and Observable; RPF-WP-0035-T12. Approved Platform source/plan review only for frozen P4 manifest sha256:9eec861838a8e9138f2c821cff3014998fbe74bb01447642bf50d44e8b3b7cb3 and R2 manifest sha256:5be7a7f438624dcb35b7dbc96e7c9e5a8e2d5d1b1966cb4338aa5aecbe3a8b59; own bounded review artifact docs/evidence/2026-10-16-flex-auth-native-plan-review.json; sanitized supplement sha256:f02a9b595d9246a358d19b37bdad8fde158b7f0c9657a6ff088874732511a32c. Exact read policy/role/ESO proposal and one-use CAS0 writer stay separate. Identified manual Applications and recovery gates are mandatory. No founder decision, native execution, confirmed bindings or completed admission assent; current proposed status unchanged." + target: + domain: infotech + tenant: platform +--- a/workplans/RPF-WP-0035-credential-lane-implementation.md ++++ b/workplans/RPF-WP-0035-credential-lane-implementation.md +@@ -1391,3 +1391,13 @@ + PV retention, native custody, independent post-key trust or founder/owner + approval is inferred. Exact successor source/CCR/plan pins and fresh scoped + reviews remain required; T12 native gates and historical T13 outcome unchanged. ++ ++2026-10-16 T12 bounded native plan review: Platform independently approves the ++exact P4/R2 custody/read-lane and existing manual Argo Application freeze/recovery ++proposal only, per docs/evidence/2026-10-16-flex-auth-native-plan-review.json. ++Current observed inventory has no signer Application; root and informed-decision ++manual sync are held during ceremony, while shared openbao-secretstore and legacy ++eso-token-renewer stay unchanged. Exact CCR read grant and one-use custody writer ++remain separate. Actual CCR/founder/entity/expiry/window/fence, native ESO/readback, ++independent Secrets public trust and Access/cluster runtime proofs remain gates. ++No authority/admission field changes; T12 remains progress. diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/README.md b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/README.md new file mode 100644 index 00000000..e97068c3 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/README.md @@ -0,0 +1,19 @@ +# Platform signer custody source proposal + +Prepared in `/tmp/netkingdom-platform-signer-custody-20261016`, based on +`5f30ddd90c33e7eb1b9efa1093c7324d83210cf2`; canonical Platform checkout untouched. +`source-proposal-r1.patch` contains five source files. Exact preimages, output +hashes and inputs are in `manifest-r1.json`; 11 offline checks passed in +`validation-r1.json`. `owner-source-review-r1.json` approves the source proposal +only. No key, CCR admission, rollout, publication or credentials were created/read. + +The proposal reuses namespace SecretStore/ESO and the existing Access read-only +seed mount and durable single-writer outbox. It separates public trust admission +from private seed projection and leaves exact scope approvals, protected writer, +image/consumer provenance, managed-package debt, durability/retention, costs/risk +and native acceptance explicit. Source templates end `.proposed` outside deployment +manifests. CCR-2026-0048/0049 and WORK-RECORDS are untouched. + +`protected-recovery-next-owner-task-r1.json` documents the separately outstanding +restart recovery gap and concrete owner acceptance criteria. No recovery was +implemented. Root owns integration, work-record synchronization and session log. diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/manifest-r1.json b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/manifest-r1.json new file mode 100644 index 00000000..b936c433 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/manifest-r1.json @@ -0,0 +1,43 @@ +{ + "schema": "railiance-platform.signer-custody-source-manifest.v1", + "base_revision": "5f30ddd90c33e7eb1b9efa1093c7324d83210cf2", + "isolated_owner_checkout": "/tmp/netkingdom-platform-signer-custody-20261016", + "patch_sha256": "0f31567718023cdf2e2c1b3a5d8c8916312fd44b039b9bc32a2e404011fe4a57", + "files": { + "docs/credential-lane-designs/flex-auth-envelope-signing.md": { + "before_sha256": null, + "after_sha256": "5b4f94341c603e684a5cdfe8c947564edf185bcf938bc9e051c786146eee6ae5" + }, + "docs/credential-lane-designs/flex-auth-envelope-signing.proposal.json": { + "before_sha256": null, + "after_sha256": "94907821addf525fb35b0eebfbbfaa55ecab4bada2858435acddd9dd9af83afd" + }, + "docs/credential-lane-designs/flex-auth-envelope-signing-policy.hcl.proposed": { + "before_sha256": null, + "after_sha256": "a8ae0ea97e5bde8a9e5d785fc87b8095e4cc24b5fcf358a4b7b1568ab1dd07ee" + }, + "docs/credential-lane-designs/flex-auth-envelope-signing-projection.yaml.proposed": { + "before_sha256": null, + "after_sha256": "4fde665568dedc5dd800e16f11e6dbfca83ea41d955efdb1fccef3976f35d6dc" + }, + "workplans/RPF-WP-0035-credential-lane-implementation.md": { + "before_sha256": "f70c0011cb5d2ef310d6e2bf392a0b6bb6f78b407b9182a1e38bed2f80472f23", + "after_sha256": "369b66a7d47307538ef6914af60856bd86d5bc0471660519690b2d3d2c492332" + } + }, + "preserved_canonical_dirty": [ + "WORK-RECORDS.md" + ], + "unrelated_CCR0048_CCR0049": "not edited or admitted", + "inputs": { + "/home/worsch/railiance-platform/AGENTS.md": "8d2f1a165e3f4eecf2e6e1d6a19c4bac9e8dcb64a76650e7185d55722f233c8b", + "/home/worsch/railiance-platform/INTENT.md": "12c6540735af591f7a4a9fe85ff10d3cd00eec55b5b6b1ddf148abf2d3ac9a9c", + "/home/worsch/the-custodian/canon/standards/delegated-owner-review_v0.1.md": "d372b2ad21849a18d90d40636fad3c31425b2bd61f0778f43e57c62402a06d6c", + "/home/worsch/the-custodian/docs/decisions/2026-10-11-security-unblock-decisions.md": "660b7a3d008cd6000bbefa55ef692bb5879e067aa086f01effd249f68a382209", + "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-16/access-native-source/source-preparation-r2.patch": "cee7af8e1e8ee8b63f9d5bc5927a6d89ae6c1169b3ec23f59e0958664fc91dca", + "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-16/access-native-preparation/native-admission-proposal-r1.json": "cfc43a0a9144ec4f4abc11ffaf52614691b335de33393fe290223732cec73cad", + "/home/worsch/access-engine/charts/flex-auth/values.yaml": "05a11ad50d64299e1dbc8b0950528e7e40885f98f9157691b40a53b92aba3643", + "/home/worsch/access-engine/charts/flex-auth/templates/deployment.yaml": "99991461acd090a0b80c31cd48af529a7dac40a707b4c527c3dd0beb9440ddcc", + "/home/worsch/access-engine/internal/emission/outbox.go": "7460e0c856f784b7a7b99110a66b562f889951a0892473bb763afdaa73800f1a" + } +} diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/README.md b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/README.md new file mode 100644 index 00000000..56c4ebc4 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/README.md @@ -0,0 +1,17 @@ +# Native signer adapter source R1 + +Apply after canonical7be8b6e and separate native-preparationR1. The five-file +patch adds fixed silent attended native adapter, tests, docs and workplan note, +and extracts shared receipt initialization without weakening fixture admission. +Exact preimages, hashes, checks and source-only review are retained here. + +Actual disposable tests cover metadata/CAS/readback and executor process death +followed by independent read-only reconciliation. All identity/review/Kubernetes +fence observations are synthetic; no production authority follows. Native +transport/tool bounds are separately tested. See validation history for retained +initial test defects and their corrections. + +Live action remains refused: current routing plan selects the wrong lane, CCR +is proposed/unconfirmed, exact independently approved image/caller/trust/source +inputs and distinct reviews are missing. No token/seed/key/grant/deployment was +retrieved or changed live. The source supplies no authority defaults. diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/coordinator-review.json b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/coordinator-review.json new file mode 100644 index 00000000..bf39a463 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/coordinator-review.json @@ -0,0 +1,11 @@ +{ + "checked_at": "2026-10-16T15:46:48.569249+00:00", + "patch_sha256": "sha256:f316a53b604f4333414b832691968ede8056d49a61635f0f25831084b1d75f19", + "independent_reconstruction": "/tmp/netkingdom-target-root-review/platform-native-adapter-r1", + "existing_tests": "44 passed in28.60s", + "counterexample": "Actual process death after metadata POST leaves original write-intent-unknown phase metadata-setup, public_key null, current_version0 and data404. Independently scoped read-only recovery refuses original receipt before any target read; phase is not reconcilable.", + "counterexample_result": "1 passed in0.77s (test asserts gap); first collection missed imported bao_dev fixture, then corrected; not an application defect", + "counterexample_file_sha256": "sha256:9da1cc8a2d5997962921da6e389aeb28b1d9c46112d33a04c24bd87a0eb81582", + "disposition": "changes_requested; phase-aware read-only recovery required, no replay/remint permission", + "native_accepted": false +} diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/implementation.patch b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/implementation.patch new file mode 100644 index 00000000..00d20ffb --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/implementation.patch @@ -0,0 +1,774 @@ +--- a/scripts/flex_auth_signer_custody.py ++++ b/scripts/flex_auth_signer_custody.py +@@ -58,6 +58,10 @@ + or '-dev' not in process.args or '-dev-no-store-token' not in process.args + or '-dev-listen-address=127.0.0.1:'+str(admission.port) not in process.args): + raise Refused('live owner-spawned disposable dev process required') ++ self.admission=admission ++ self._initialize_receipt(directory,operation_id,kid=kid,expected_version=expected_version,bindings=bindings) ++ ++ def _initialize_receipt(self,directory,operation_id,*,kid,expected_version,bindings): + if (type(operation_id) is not str or not re.fullmatch(r'[a-zA-Z0-9_-]{1,80}',operation_id) + or type(kid) is not str or not re.fullmatch(r'[a-zA-Z0-9_-]{1,80}',kid) + or type(expected_version) is not int or not 0<=expected_version<2**31 +@@ -66,7 +70,7 @@ + raise Refused('exact signer operation contract required') + if directory.absolute()!=directory.resolve() or directory.is_symlink():raise Refused('indirect receipt custody refused') + Journal._private(directory.stat(),directory=True) +- self.admission=admission;self.directory=directory;self.path=directory/(operation_id+'.json') ++ self.directory=directory;self.path=directory/(operation_id+'.json') + self.expected_version=expected_version;self.kid=kid;self.attempted=False + self.receipt={'schema':'railiance-platform.signer-cas-receipt.v1','operation_id':operation_id, + 'bindings':dict(bindings),'writer_sha256':'sha256:'+hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), +diff --git a/scripts/flex_auth_signer_native.py b/scripts/flex_auth_signer_native.py +new file mode 100644 +index 0000000..0cd7a34 +--- /dev/null ++++ b/scripts/flex_auth_signer_native.py +@@ -0,0 +1,384 @@ ++#!/usr/bin/env python3 ++"""Silent attended retained-lifecycle signer custody; never a credential front door. ++ ++Invoke only through the reviewed warden platform-admin envelope. The externally ++reviewed admission SHA is an exact-command input, not approval by JSON shape. ++No private value crosses stdout/stderr, argv, receipt or persistent local storage. ++""" ++from __future__ import annotations ++import argparse ++import base64 ++from datetime import datetime,timezone ++import fcntl ++import hashlib ++import hmac ++import http.client ++import importlib.util ++import json ++import os ++from pathlib import Path ++import re ++import selectors ++import shlex ++import subprocess ++import sys ++import time ++ ++from cryptography.hazmat.primitives import serialization ++from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey ++from flex_auth_signer_custody import SignerWriter,PATH,FIELDS,BINDINGS,encoded,b64 ++from task_execution_journal import Journal,Refused ++from task_execution_native_fixture import _absolute_budget ++from task_execution_recovery import _json_unique,_invalid_constant,_policy_absent,_same_policy ++ ++ROOT=Path(__file__).resolve().parents[1] ++META='platform/metadata/workloads/flex-auth/envelope-signing' ++CCR='credential-change-requests/CCR-2026-0050-flex-auth-envelope-signing.yaml' ++PLAN='docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json' ++CLUSTER='a553c742-0115-43d4-99a4-a5ca56fe0786' ++BAO_CLUSTER='fd28df5d-98ec-57dd-42ec-9b3e4f4e53bf' ++NAME='flex-auth-secrets-engine' ++SECRET='flex-auth-secrets-engine-envelope-signing' ++ROLE='external-secrets-flex-auth-envelope-signing' ++LIFECYCLE='sha256:bd11c5fe77ce6439c65fea225ad6b71d2110efc5e7b5bc9b499c59cd0a53b8b4' ++REVIEWS={'founder','railiance-platform-owner','access-engine-owner','secrets-engine-owner','cluster-gitops-owner'} ++SOURCE_FILES={'scripts/flex_auth_signer_native.py','scripts/flex_auth_signer_custody.py','scripts/task_execution_native_fixture.py','scripts/task_execution_journal.py','scripts/task_execution_recovery.py','scripts/credential-change.py'} ++ ++ ++def require(ok,reason): ++ if not ok:raise Refused(reason) ++ ++ ++def digest(raw):return 'sha256:'+hashlib.sha256(raw).hexdigest() ++def is_digest(value):return type(value) is str and re.fullmatch(r'sha256:[0-9a-f]{64}',value) is not None ++ ++def private_read(path,limit=65536): ++ path=Path(path) ++ require(path.is_absolute() and path.absolute()==path.resolve() and not path.is_symlink(),'indirect private input') ++ Journal._private(path.parent.stat(),directory=True) ++ fd=os.open(path,os.O_RDONLY|os.O_NOFOLLOW|os.O_NONBLOCK) ++ try: ++ before=os.fstat(fd);Journal._private(before) ++ raw=os.read(fd,limit+1);after=os.fstat(fd) ++ require((before.st_dev,before.st_ino,before.st_size,before.st_mtime_ns,before.st_ctime_ns)== ++ (after.st_dev,after.st_ino,after.st_size,after.st_mtime_ns,after.st_ctime_ns) ++ and len(raw)==before.st_size and len(raw)<=limit,'private input changed or oversized') ++ return raw ++ finally:os.close(fd) ++ ++ ++def parsed(raw): ++ try:return json.loads(raw,object_pairs_hook=_json_unique,parse_constant=_invalid_constant) ++ except Exception:raise Refused('invalid closed JSON input') from None ++ ++ ++def validate_admission(value): ++ fields={'schema','action','operation_id','kid','expires_at','founder_entity_id','ccr_sha256','source_bundle','bindings', ++ 'producer_image','caller_binding','deployment_projection_sha256','authority','routing','owner_reviews', ++ 'exclusive_window_sha256','consumer_trust_sha256','original_receipt_sha256'} ++ require(type(value) is dict and set(value)==fields,'exact admission schema required') ++ require(value['schema']=='railiance-platform.signer-native-admission.v1' and value['action'] in {'bootstrap','recover'},'native admission action refused') ++ require(type(value['operation_id']) is str and re.fullmatch(r'[A-Za-z0-9_-]{1,80}',value['operation_id']) and ++ type(value['kid']) is str and re.fullmatch(r'[A-Za-z0-9_-]{1,80}',value['kid']),'native operation identity required') ++ require(type(value['founder_entity_id']) is str and re.fullmatch(r'[a-f0-9-]{36}',value['founder_entity_id']),'explicit attended identity required') ++ require(all(is_digest(value[x]) for x in ['ccr_sha256','deployment_projection_sha256','exclusive_window_sha256','consumer_trust_sha256']),'explicit custody/image/trust selections required') ++ require(type(value['producer_image']) is str and re.fullmatch(r'forgejo\.coulomb\.social/coulomb/flex-auth@sha256:[a-f0-9]{64}',value['producer_image']),'immutable producer image required') ++ require(value['caller_binding']=='secrets-engine=system:serviceaccount:secrets-engine:secrets-engine','retained caller binding required') ++ require(value['authority']=='founder-attended-exact-source-scope; no standing grant','independent attended authority required') ++ route=value['routing'];require(type(route) is dict and set(route)=={'lane_id','verdict','founder_act','receipt_sha256'} and ++ route['lane_id']=='openbao-platform-admin-login' and route['verdict']=='founder_required' and route['founder_act']=='oidc_login' and is_digest(route['receipt_sha256']),'routing mismatch refused') ++ reviews=value['owner_reviews'];require(type(reviews) is dict and set(reviews)==REVIEWS,'distinct owner reviews required') ++ for role,review in reviews.items(): ++ require(type(review) is dict and set(review)=={'approved_admission_sha256','approval_ref'} and ++ is_digest(review['approved_admission_sha256']) and type(review['approval_ref']) is str and ++ 00,'absolute custody command timeout') ++ for item,_ in sel.select(remaining): ++ chunk=os.read(item.fileobj.fileno(),65536) ++ if not chunk:sel.unregister(item.fileobj) ++ else: ++ data[item.fileobj].extend(chunk) ++ require(sum(map(len,data.values()))<=1048576,'custody command output bound') ++ code=proc.wait(timeout=max(.001,deadline-time.monotonic())) ++ require(code in allowed,'custody command unconfirmed') ++ return code,bytes(data[proc.stdout]) ++ finally:sel.close() ++ except BaseException: ++ proc.kill();proc.wait(timeout=2);raise Refused('custody command unconfirmed') from None ++ finally: ++ proc.stdout.close();proc.stderr.close() ++ def bao(self,args,payload=None,allowed=(0,)): ++ with _absolute_budget(2): ++ code,raw=self.captured(['bao',*args],payload,allowed=allowed) ++ return code,parsed(raw) ++ def kube(self,resource,name=None): ++ args=['kubectl','--request-timeout=2s'] ++ if resource!='namespace':args+=['-n','flex-auth'] ++ args+=['get',resource] ++ if name:args.append(name) ++ args+=['-o','json'] ++ with _absolute_budget(2): ++ _,raw=self.captured(['ssh','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','ConnectTimeout=2','railiance01',shlex.join(args)]) ++ return parsed(raw) ++ def http(self,method,path,body=None): ++ require(method in {'GET','POST'} and path in {META,PATH,PATH+'?version=1'},'fixed custody path required') ++ require(type(getattr(self,'_token',None)) is str and self._token,'contained attended session required') ++ with _absolute_budget(2): ++ conn=http.client.HTTPConnection('127.0.0.1',18200,timeout=2) ++ try: ++ conn.request(method,'/v1/'+path,body=None if body is None else encoded(body), ++ headers={'X-Vault-Token':self._token,'Content-Type':'application/json'}) ++ response=conn.getresponse();raw=response.read(1048577) ++ require(len(raw)<=1048576,'custody response bound') ++ return response.status,parsed(raw) if raw else {} ++ finally:conn.close() ++ ++ ++def deployment_projection(deployment): ++ spec=deployment['spec']['template']['spec'];containers=spec.get('containers',[]) ++ require(type(containers) is list and len(containers)==1 and not spec.get('initContainers'),'single fixed signer container required') ++ item=containers[0] ++ # Never hash arbitrary env values or an entire Secret/spec response. ++ return {'service_account':spec.get('serviceAccountName'),'image':item.get('image'), ++ 'args':item.get('args'),'volume_mounts':item.get('volumeMounts',[]), ++ 'volumes':spec.get('volumes',[]),'security_context':spec.get('securityContext')} ++ ++ ++def fence(io,contract): ++ namespace=io.kube('namespace','kube-system') ++ require(namespace.get('metadata',{}).get('uid')==CLUSTER,'wrong target cluster') ++ deployment=io.kube('deployment',NAME);spec=deployment.get('spec',{});meta=deployment.get('metadata',{}) ++ require(type(spec.get('replicas')) is int and spec['replicas']==0 and ++ deployment.get('status',{}).get('observedGeneration',-1)==meta.get('generation') and ++ not deployment.get('status',{}).get('replicas',0),'all signer replicas must be stopped') ++ projection=deployment_projection(deployment) ++ require(digest(encoded(projection))==contract['deployment_projection_sha256'] and ++ projection['service_account']==NAME and projection['image']==contract['producer_image'],'fenced deployment source/image mismatch') ++ args=projection['args'];require(type(args) is list and all(type(x) is str for x in args),'exact signer args required') ++ def option(flag): ++ require(args.count(flag)==1 and args.index(flag)+1=3:self.pods=[{'spec':{'serviceAccountName':m.NAME}}] ++ return deepcopy(self.dep) ++ return {'items':deepcopy({'pods':self.pods,'hpa':self.hpas,'replicasets':self.rs}[resource])} ++ def http(self,method,path,body=None): ++ self.calls.append(('http',method,path)) ++ if self.denied and path in {m.PATH,m.PATH+'?version=1'} and method=='GET':return 403,{'errors':['secret backend detail']} ++ result=call(method,path,body) ++ if self.lost and method=='POST' and path==m.PATH:raise OSError('secret response lost') ++ return result ++ io=IO() ++ c={'schema':'railiance-platform.signer-native-admission.v1','action':'bootstrap','operation_id':'synthetic-native-operation','kid':'synthetic-native-kid', ++ 'expires_at':(datetime.now(timezone.utc)+timedelta(seconds=100)).isoformat(),'founder_entity_id':io.entity, ++ 'ccr_sha256':m.digest((source/m.CCR).read_bytes()),'source_bundle':{n:m.digest((source/n).read_bytes()) for n in m.SOURCE_FILES}, ++ 'bindings':{k:'sha256:'+'2'*64 for k in m.BINDINGS},'producer_image':image,'caller_binding':'secrets-engine=system:serviceaccount:secrets-engine:secrets-engine', ++ 'deployment_projection_sha256':m.digest(m.encoded(m.deployment_projection(dep))), ++ 'authority':'founder-attended-exact-source-scope; no standing grant', ++ 'routing':{'lane_id':'openbao-platform-admin-login','verdict':'founder_required','founder_act':'oidc_login','receipt_sha256':'sha256:'+'3'*64}, ++ 'owner_reviews':{},'exclusive_window_sha256':'sha256:'+'4'*64,'consumer_trust_sha256':'sha256:'+'5'*64,'original_receipt_sha256':None} ++ c['bindings'].update(proposal_sha256=m.digest((source/m.PLAN).read_bytes()),policy_sha256=m.LIFECYCLE,image_sha256='sha256:'+'1'*64,trust_sha256=c['consumer_trust_sha256'],deployment_sha256=c['deployment_projection_sha256'],executed_revision_sha256=m.digest(m.encoded(c['source_bundle']))) ++ def approve(value): ++ scope=m.digest(m.encoded({k:v for k,v in value.items() if k!='owner_reviews'})) ++ value['owner_reviews']={role:{'approved_admission_sha256':scope,'approval_ref':'synthetic-fixture-'+role} for role in m.REVIEWS} ++ return value ++ approve(c) ++ return c,io,directory,call,approve,source ++ ++ ++def test_actual_native_bootstrap_exact_readback_and_no_retry(native): ++ c,io,directory,call,approve,source=native ++ result=m.execute(c,directory,io=io) ++ assert result['status']=='custody-verified-pending-independent-public-admission' and result['exact_readback'] ++ assert call('GET',m.META)[1]['data']['current_version']==1 ++ assert [(x[1],x[2]) for x in io.calls if x[0]=='http' and x[1]=='POST']==[('POST',m.META),('POST',m.PATH)] ++ private=call('GET',m.PATH)[1]['data']['data']['ED25519_PRIVATE_KEY'] ++ raw=(directory/(c['operation_id']+'.json')).read_bytes();assert private.encode() not in raw ++ before=len(io.calls) ++ with pytest.raises(FileExistsError):m.execute(c,directory,io=io) ++ assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls[before:]) ++ ++ ++def test_actual_process_loss_unknown_fresh_recovery_read_only(native): ++ c,io,directory,call,approve,source=native ++ child=os.fork() ++ if child==0: ++ original_http=io.http ++ def die_after_native_write(method,path,body=None): ++ result=original_http(method,path,body) ++ if method=='POST' and path==m.PATH:os._exit(73) ++ return result ++ io.http=die_after_native_write ++ try:m.execute(c,directory,io=io) ++ except BaseException:os._exit(74) ++ os._exit(75) ++ _,status=os.waitpid(child,0) ++ assert os.waitstatus_to_exitcode(status)==73 ++ old=directory/(c['operation_id']+'.json');original=old.read_bytes();assert json.loads(original)['status']=='write-intent-unknown' ++ recovery=deepcopy(c);recovery.update(action='recover',operation_id='synthetic-independent-recovery',original_receipt_sha256=m.digest(original));approve(recovery) ++ io.lost=False;io.calls.clear() ++ result=m.execute(recovery,directory,io=io,original_receipt=old) ++ assert result['status']=='custody-reconciled-pending-independent-public-admission' ++ assert result['no_write_or_remint'] and old.read_bytes()==original ++ assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls) ++ assert call('GET',m.META)[1]['data']['current_version']==1 ++ assert (directory/(recovery['operation_id']+'.json')).stat().st_mode&0o777==0o600 ++ io.calls.clear() ++ with pytest.raises(FileExistsError):m.execute(recovery,directory,io=io,original_receipt=old) ++ assert not any(x[0]=='http' for x in io.calls) ++ ++ ++@pytest.mark.parametrize('case',['missing-image','missing-trust','mismatched-source','bad-review','bad-route','expired','wrong-entity','wrong-backend','wrong-cluster','root','pod','terminating-pod','hpa','replicas','image-drift','role-drift','pod-after-metadata']) ++def test_refusals_no_seed_effect(native,case): ++ c,io,directory,call,approve,source=native ++ if case=='missing-image':c['producer_image']='' ++ elif case=='missing-trust':c['consumer_trust_sha256']='' ++ elif case=='mismatched-source':(source/'scripts/flex_auth_signer_custody.py').write_text('changed source') ++ elif case=='bad-review':c['owner_reviews']['founder']['approved_admission_sha256']='sha256:'+'f'*64 ++ elif case=='bad-route':c['routing']['lane_id']='openbao-structure-survey';approve(c) ++ elif case=='expired':c['expires_at']=(datetime.now(timezone.utc)-timedelta(seconds=1)).isoformat();approve(c) ++ elif case=='wrong-entity':io.entity='other' ++ elif case=='wrong-backend':io.backend='other' ++ elif case=='wrong-cluster':io.cluster='other' ++ elif case=='root':io.root=True ++ elif case=='pod':io.pods=[{'spec':{'serviceAccountName':m.NAME}}] ++ elif case=='terminating-pod':io.pods=[{'metadata':{'deletionTimestamp':'now'},'spec':{'volumes':[{'secret':{'secretName':m.SECRET}}]}}] ++ elif case=='hpa':io.hpas=[{'spec':{'scaleTargetRef':{'name':m.NAME}}}] ++ elif case=='replicas':io.dep['spec']['replicas']=1 ++ elif case=='image-drift':io.dep['spec']['template']['spec']['containers'][0]['image']='unreviewed' ++ elif case=='role-drift':io.role_drift=True ++ elif case=='pod-after-metadata':io.pod_on_recheck=True ++ with pytest.raises(Refused):m.execute(c,directory,io=io) ++ assert not any(x[0]=='http' and x[1]=='POST' and x[2]==m.PATH for x in io.calls) ++ assert call('GET',m.PATH)[0]==404 ++ ++ ++@pytest.mark.parametrize('case',['damaged-receipt','typed-damaged-receipt','changed-version','read-denied','no-fresh-review']) ++def test_recovery_refuses_without_new_effect(native,case): ++ c,io,directory,call,approve,source=native;io.lost=True ++ with pytest.raises(Refused):m.execute(c,directory,io=io) ++ old=directory/(c['operation_id']+'.json');recovery=deepcopy(c);recovery.update(action='recover',operation_id='recovery',original_receipt_sha256=m.digest(old.read_bytes()));approve(recovery) ++ if case=='damaged-receipt':old.write_text('{}') ++ elif case=='typed-damaged-receipt': ++ damaged=json.loads(old.read_text());damaged['expected_version']=False;old.write_text(json.dumps(damaged));recovery['original_receipt_sha256']=m.digest(old.read_bytes());approve(recovery) ++ elif case=='changed-version': ++ doc=call('GET',m.PATH)[1]['data']['data'];assert call('POST',m.PATH,{'options':{'cas':1},'data':doc})[0]==200 ++ elif case=='read-denied':io.denied=True ++ elif case=='no-fresh-review':recovery['owner_reviews']['founder']['approved_admission_sha256']='sha256:'+'f'*64 ++ io.calls.clear();io.lost=False ++ with pytest.raises(Refused):m.execute(recovery,directory,io=io,original_receipt=old) ++ assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls) ++ ++ ++@pytest.mark.parametrize('bad_args',[False,True]) ++def test_main_missing_approval_silent_and_no_io(tmp_path,capsys,bad_args): ++ if bad_args: ++ assert m.main(['--unrecognized'])==1 ++ output=capsys.readouterr();assert output.out==output.err=='' ++ return ++ assert m.main(['--admission',str(tmp_path/'missing'),'--admission-sha256','sha256:'+'0'*64,'--receipt-directory',str(tmp_path)])==1 ++ output=capsys.readouterr();assert output.out==output.err=='' ++ ++ ++def test_native_command_byte_and_elapsed_bounds_no_output(capsys): ++ io=m.NativeIO() ++ with pytest.raises(Refused):io.captured([sys.executable,'-c',"import sys;sys.stdout.write('x'*1048577)"]) ++ import time ++ started=time.monotonic() ++ with pytest.raises(Refused):io.captured([sys.executable,'-c',"import time;time.sleep(10)"]) ++ assert time.monotonic()-started<3 ++ output=capsys.readouterr();assert output.out==output.err=='' ++ ++ ++def test_exclusive_native_window_refuses_second_writer(native): ++ import fcntl ++ c,io,directory,call,approve,source=native ++ fd=os.open(directory/'.signer-window.lock',os.O_RDWR|os.O_CREAT,0o600) ++ try: ++ fcntl.flock(fd,fcntl.LOCK_EX|fcntl.LOCK_NB) ++ with pytest.raises(BlockingIOError):m.execute(c,directory,io=io) ++ assert io.calls==[] ++ finally:os.close(fd) ++ ++ ++def test_native_fixed_http_transport_against_disposable_backend(bao_dev,monkeypatch,capsys): ++ origin,token,call,process=bao_dev ++ assert call('POST','sys/mounts/platform',{'type':'kv','options':{'version':'2'}})[0] in {200,204} ++ factory=m.http.client.HTTPConnection;port=int(origin.rsplit(':',1)[1]);destinations=[] ++ def fixture_socket(host,requested_port,*args,**kwargs): ++ destinations.append((host,requested_port)) ++ return factory(host,port if requested_port==18200 else requested_port,*args,**kwargs) ++ monkeypatch.setattr(m.http.client,'HTTPConnection',fixture_socket) ++ io=m.NativeIO();io._token=token ++ assert io.http('GET',m.META)==(404,{'errors':[]}) ++ assert io.http('POST',m.META,{'cas_required':True,'max_versions':2,'delete_version_after':'0s'})[0] in {200,204} ++ m.exact_metadata(*io.http('GET',m.META),created=False) ++ assert all(host=='127.0.0.1' and selected_port==18200 for host,selected_port in destinations) ++ with pytest.raises(Refused):io.http('GET','other/path') ++ output=capsys.readouterr();assert output.out==output.err=='' +diff --git a/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md b/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md +new file mode 100644 +index 0000000..2d88649 +--- /dev/null ++++ b/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md +@@ -0,0 +1,119 @@ ++# Attended native signer custody adapter source ++ ++RPF-WP-0035-T12 / CUST-WP-0080. This source implements the protected native ++adapter described by the separate frozen native-preparation R1. It does not ++admit an execution. Its CLI is silent and intended only as the exact reviewed ++child of `warden access openbao-platform-admin-login --exec` in the founder's ++attended OIDC envelope. The existing Warden owner contains the token helper, ++checks child output and revokes/removes the session on exit. No new service, ++credential broker, standing grant, API or key-returning interface is created. ++ ++## Current routing blocker ++ ++During preparation the required `warden plan` query for attended OpenBao ++platform administration of signer CAS0/metadata selected `openbao-structure-survey` ++with an approve ceremony, rather than `openbao-platform-admin-login` with ++`oidc_login`. The installed CLI reports wheel-bundled catalog0.1.2 fallback. ++This is preserved as a live refusal, not routed around. Exact `route show` names ++the existing active attended login, but that pointer does not cure dispatch. ++The adapter requires an independently retained routing receipt selecting the ++correct lane/verdict/identity act. No founder execution step is ready until the ++routing defect and all other native approvals are resolved by their owners. ++ ++## Independent input and authority boundary ++ ++The CLI requires an absolute owner-private admission file, its independently ++approved exact SHA256, the exact private receipt directory selected in the ++reviewed native proposal, and an original receipt only for recovery. No default ++image/package/caller trust, founder identity, approval, route or source pin is ++usable. The admission schema is closed in `validate_admission`; it includes the ++immutable published producer image, retained caller, deployment projection, ++selected consumer trust baseline, exact native plan/CCR/source bundle, fresh ++UTC authority expiry (5..120seconds), founder entity and five distinct externally ++reviewed owner dispositions. Each disposition binds the same approval-free ++scope digest. An admission shape, local digest or review string never approves ++itself: the founder and owners must independently review the exact supplied ++command/file hash through existing governance before attended invocation. ++ ++The trust hash selects the independently reviewed consumer verifier/policy/trust ++baseline for this custody action. It is not a claim that the newly generated ++public key is already online: generation happens later, and independent delivery ++and successor trust installation are required after the public receipt. The ++writer never reads consumer private credentials or discovers trust from KV. ++All successful custody states remain pending independent public admission. ++ ++`checked_sources` verifies the actual selected native action plan, exact proposed ++kid, read CCR hash/status/binding, generated policy source, and source bundle. ++The read CCR must independently be approved/binding-confirmed; the canonical ++proposed CCR remains unapproved, so ordinary source checkout refuses. Source ++bundle pins execution modules, not arbitrary request-selected code. The native ++image/caller/seed projection is compared to the actual stopped Deployment. ++The lifecycle policy digest/version stays unchanged; execute-ccr probes must ++prove no ALLOW/effect. Current generic runtime guard can return HTTP503 before ++the lifecycle evaluator, so signed unknown_action is not promised. ++ ++## Actual checks and effects ++ ++Before private work, the child checks OpenBao cluster ID, unsealed state, exact ++non-root platform-admin OIDC entity, enabled audit, actual exact read-policy HCL ++and role bindings/15m limits. The selected fixed loopback transport is the existing ++owner-admin bridge; Kubernetes reads use fixed strict-host SSH to railiance01. ++The OpenBao token lookup-self identifier stays only in the contained custody ++process to authenticate fixed HTTP calls; it never reaches the agent, a receipt, ++argv or another token file. This is a native protected-process implementation, ++not evidence that agent runtime isolation has been promoted or granted. ++ ++The fence checks the pinned kube-system UID, stopped Deployment generation and ++replica status, exact immutable image/caller/seed mount/kid projection, zero owned ++ReplicaSet replicas, no live or terminating signer-SA/owned/seed-mount pods, and ++no targeting HPA. It rechecks before metadata setup and immediately before CAS. ++A private filesystem lock excludes a second local custody window. The lock and ++observations do not provide atomic Kubernetes fencing: the independently reviewed ++exclusive window must keep GitOps/Helm/other creators stopped. No rollout or ++cluster mutation is performed by this adapter, and no concurrency guarantee is ++inferred from source alone. Access/cluster owners retain that admission. ++ ++Bootstrap requires the exact OpenBao empty-errors HTTP404 metadata absence. A ++durable private intent precedes exact CAS-required/max_versions2/no-auto-delete ++metadata setup, followed by exact native readback. Only then does the shared ++Ed25519 primitive generate one in-memory seed and CAS0 the fixed three-field ++KV document. Independent version1 private readback and final metadata verification ++precede the durable success receipt. The seed is never put in argv/env/local ++files or output. The receipt carries public key, ASCII-base64url fingerprint, ++version, bindings and closed phases only. The old fixture's live-dev-process gate ++is preserved; its shared receipt initialization was extracted without weakening ++that gate. Python cannot promise seed zeroization. ++ ++Every backend/body/close and tool call has a two-second absolute budget and ++1MiB combined output bound. The complete operation is bounded by the supplied ++fresh expiry. CLI validation and runtime failures remain silent. Existing0600/ ++0700 no-follow/ownership checks, exclusive creation, fsync/atomic replacement and ++directory fsync retain evidence. Same-UID hostile code is not isolated by modes; ++Warden's contained home, trusted runtime and independently reviewed custody ++location are required, not inferred from approval frequency or shell prefixes. ++ ++## Process loss and independent read-only recovery ++ ++Any failed/ambiguous metadata/write/readback/final receipt outcome remains ++unconfirmed. A success receipt is withheld until final metadata verification. ++A child death immediately after the real native CAS leaves the earlier public ++intent with its derived public key and no private value. A fresh `recover` ++admission must bind that exact original receipt SHA and the same immutable scope. ++It reserves a new durable recovery intent before private reads, verifies current ++version1 metadata and exact private seed/public/kid correspondence, and records ++separate public reconciliation. It never creates a writer, generates a seed, ++POSTs metadata/data, restores a seed, consumes approval or dispatches business ++operations. Original unknown evidence is never rewritten. Changed versions, ++damaged/typed-invalid receipts, missing fresh reviews and denied reads refuse; ++replaying a recovery ID cannot repeat even the private backend read. ++ ++This source implements bootstrap and read-only version1 reconciliation only. ++Rotation needs a separately reviewed exact-version native action; the disposable ++primitive's CAS1 test is not a native rotation grant. No automatic retry, remint, ++rollback or general recovery API exists. Metadata-only setup uncertainty without ++a public seed intent requires separate attended reconciliation, not this path. ++ ++Access observed zero PVCs in flex-auth. Its proposed new1Gi/local-path outbox, ++PV Retain/reclaim disposition and runtime process-lock/capacity/startup bounds ++remain separate reviews. This writer grants no PVC, audit egress, policy role, ++SecretStore/Secret or producer/consumer deployment admission. +--- a/workplans/RPF-WP-0035-credential-lane-implementation.md ++++ b/workplans/RPF-WP-0035-credential-lane-implementation.md +@@ -1354,3 +1354,14 @@ + founder plus distinct owner reviews remain necessary. Access observed zero PVCs; + new outbox storage/retention/runtime bounds remain separate Access/cluster scope. + No live credentials, grants, roles, key or deployment changed. T12 stays progress. ++ ++2026-10-16 T12 native signer adapter source: silent fixed-scope attended child ++checks exact independent admission/source/CCR/image/caller/trust/identity inputs, ++actual backend/reader role/policy, signer fence and private exclusive receipt ++custody before fixed metadata/CAS0 effects. Separate fresh read-only recovery ++reconciles real process loss after native write without remint/retry/new effects. ++Disposable tests exercise actual KV while owner reviews/identity/fence facts are ++explicitly synthetic. Current warden plan dispatch selects structure-survey, not ++OIDC admin login; mismatch remains a live refusal. Canonical proposed CCR, native ++owner/founder approval and Access/cluster/outbox/PVC gates stay open; no live ++key, credential read, grant, role, storage or deployment action performed. diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/manifest.json b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/manifest.json new file mode 100644 index 00000000..0ee0cec9 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/manifest.json @@ -0,0 +1,32 @@ +{ + "schema": "railiance-platform.signer-native-adapter-source.v1", + "proposal_id": "RPF35-PDP-SIGNER-NATIVE-ADAPTER-20261016-R1", + "canonical_base": "7be8b6e76d602a5306052f9e42881fbea250ede8", + "requires_native_preparation_patch_sha256": "a9d4631d3320ac3fa56f5a61965005c546eae241d2004cc1e6385e04668b7f7f", + "isolated_source": "/tmp/netkingdom-platform-signer-native-adapter-20261016", + "patch_sha256": "f316a53b604f4333414b832691968ede8056d49a61635f0f25831084b1d75f19", + "files": { + "scripts/flex_auth_signer_custody.py": { + "before_sha256": "8ed281a49c1f1cdb23772efe3593e75c62572a12b8d7a6a4c574f27b38722e75", + "after_sha256": "f169ad12f90d729b647085c3bed2c0d8d005db23a2341b6d3d5f1793bcfd110c" + }, + "scripts/flex_auth_signer_native.py": { + "before_sha256": null, + "after_sha256": "11418b56bf5b5b44d926d8ad7f40c478cfb8f85189ca2ca03826bd0c05fc28c1" + }, + "tests/test_flex_auth_signer_native.py": { + "before_sha256": null, + "after_sha256": "a368dfaebaa88621b5800236a96ec27efa4b8c568de39bb5108dc84457b7ef2f" + }, + "docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md": { + "before_sha256": null, + "after_sha256": "8a33a92c928d9e78d57d996dc0323045f608fe8ffdd247221d78e1973f44a724" + }, + "workplans/RPF-WP-0035-credential-lane-implementation.md": { + "before_sha256": "bab368699a4f80ac0f9092a467c7f4b50c9831c4543dc86a3f51eabb82fdf320", + "after_sha256": "19184125dfefdcb71b0be0263c3225a014e6c8cd93185f15b9e65a331ae1e5ed" + } + }, + "production_admission": false, + "authority_granted": false +} diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/owner-review.json b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/owner-review.json new file mode 100644 index 00000000..5aa8b257 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/owner-review.json @@ -0,0 +1,29 @@ +{ + "schema": "railiance-platform.owner-source-review.v1", + "reviewer_role": "railiance-platform-owner", + "agent": "railiance-platform (codex)", + "reviewed_revision_sha256": "f316a53b604f4333414b832691968ede8056d49a61635f0f25831084b1d75f19", + "disposition": "approve-source-only-pending-independent-coordinator-review", + "basis": "Existing RPF-WP-0035-T12 owner scope and explicit delegated native-adapter source authorization; no live scope inferred", + "assessment": "Fixed silent attended adapter reuses existing custody route and protected Ed25519 receipt primitive. Exact reviewed inputs and real identity/cluster/reader metadata/fence checks precede fixed metadata/CAS0 effects; bounded I/O and durable intent preserve ambiguity. Fresh recovery is read-only with exact original receipt/source/bindings and public/private correspondence, preserving old unknown. Fixture live-process gate remains intact.", + "limitations": [ + "Routing mismatch blocks live action until owner repair and exact receipt.", + "Canonical proposed CCR is not approved/binding-confirmed; no real owner/founder disposition or candidate image/caller trust selection supplied.", + "Admission JSON/digest/review references are independently reviewed exact-command inputs, not self-authorizing evidence.", + "Tests prove actual disposable KV effects and process loss; identity and Kubernetes fence facts are synthetic, not native acceptance.", + "Cluster fence checks are observations, not atomic locks. Independent Access/cluster exclusive-window control must pause all competing writers/controllers.", + "Contained Warden helper/private modes do not prove same-UID hostile-code isolation or autopilot promotion.", + "Native scope is bootstrapCAS0/version1 read-only reconciliation only; rotation remains separate reviewed action.", + "No ESO/Secret/PVC/outbox/audit egress/producer or consumer deployment activation.", + "Distinct Access, Secrets, cluster/GitOps and founder reviews remain unrecorded by Platform." + ], + "preserved": [ + "signer R1/R2/R3", + "native-preparation R1", + "budget/fullchain source proof", + "CCR0048/CCR0049", + "WORK-RECORDS.md" + ], + "incremental_source_spend_eur": 0, + "authority_granted": false +} diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/preimages/scripts/flex_auth_signer_custody.py b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/preimages/scripts/flex_auth_signer_custody.py new file mode 100644 index 00000000..1783a6fe --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/preimages/scripts/flex_auth_signer_custody.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +"""Protected signer CAS primitive. Disposable owner fixture only; no live entry. + +This module deliberately cannot admit production custody. A reviewed native CCR, +protected executor, fencing and founder scope are prerequisites for that adapter. +""" +from __future__ import annotations +from dataclasses import dataclass,field +from datetime import datetime,timezone +import base64 +import hashlib +import hmac +import http.client +import json +import os +from pathlib import Path +import re +import secrets +import subprocess + +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey +from task_execution_journal import Journal,Refused +from task_execution_native_fixture import _absolute_budget +from task_execution_recovery import _json_unique,_invalid_constant + +PATH='platform/data/workloads/flex-auth/envelope-signing' +FIELDS={'ED25519_PRIVATE_KEY','ED25519_PUBLIC_KEY','kid'} +BINDINGS={'proposal_sha256','executed_revision_sha256','deployment_sha256','image_sha256','policy_sha256','trust_sha256'} + + +def encoded(value):return json.dumps(value,sort_keys=True,separators=(',',':'),allow_nan=False).encode() +def b64(value):return base64.urlsafe_b64encode(value).decode().rstrip('=') + + +@dataclass(frozen=True) +class FixtureWriterAdmission: + port:int + owner_token:str=field(repr=False) + server_process:subprocess.Popen=field(repr=False) + fenced:bool=False + + +class SignerWriter: + """Single attempted operation; failed/unknown writes never retry or remint. + + File permissions are accidental-disclosure guards, not same-UID isolation. + The receipt directory must be independent owner custody in a native adapter. + Python cannot promise seed zeroization; process lifetime is the boundary. + """ + def __init__(self,admission:FixtureWriterAdmission,directory:Path,operation_id:str,*,kid:str,expected_version:int,bindings:dict): + if (type(admission) is not FixtureWriterAdmission or type(admission.port) is not int + or not 1<=admission.port<=65535 or type(admission.owner_token) is not str + or not admission.owner_token or type(admission.fenced) is not bool or not admission.fenced): + raise Refused('exact fenced fixture custody required') + process=admission.server_process + if (type(process) is not subprocess.Popen or process.poll() is not None or type(process.args) is not list + or '-dev' not in process.args or '-dev-no-store-token' not in process.args + or '-dev-listen-address=127.0.0.1:'+str(admission.port) not in process.args): + raise Refused('live owner-spawned disposable dev process required') + if (type(operation_id) is not str or not re.fullmatch(r'[a-zA-Z0-9_-]{1,80}',operation_id) + or type(kid) is not str or not re.fullmatch(r'[a-zA-Z0-9_-]{1,80}',kid) + or type(expected_version) is not int or not 0<=expected_version<2**31 + or type(bindings) is not dict or set(bindings)!=BINDINGS + or any(type(v) is not str or not re.fullmatch(r'sha256:[0-9a-f]{64}',v) for v in bindings.values())): + raise Refused('exact signer operation contract required') + if directory.absolute()!=directory.resolve() or directory.is_symlink():raise Refused('indirect receipt custody refused') + Journal._private(directory.stat(),directory=True) + self.admission=admission;self.directory=directory;self.path=directory/(operation_id+'.json') + self.expected_version=expected_version;self.kid=kid;self.attempted=False + self.receipt={'schema':'railiance-platform.signer-cas-receipt.v1','operation_id':operation_id, + 'bindings':dict(bindings),'writer_sha256':'sha256:'+hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + 'actor':'synthetic-owner-fixture','created_at':datetime.now(timezone.utc).isoformat(),'path':PATH,'expected_version':expected_version,'kid':kid, + 'status':'prepared','production_admission':False,'rollback':'forward-recovery-only', + 'public_key':None,'public_fingerprint':None,'kv_version':None,'exact_readback':False} + self._save(initial=True) + + def _save(self,*,initial=False): + raw=encoded(self.receipt) + if len(raw)>65536:raise Refused('receipt bound exceeded') + if initial: + target=self.path + else: + fd=os.open(self.path,os.O_RDONLY|os.O_NOFOLLOW|os.O_NONBLOCK) + try:Journal._private(os.fstat(fd)) + finally:os.close(fd) + target=self.directory/('.pending-'+secrets.token_hex(16)) + fd=os.open(target,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600) + try: + with os.fdopen(fd,'wb',closefd=False) as stream:stream.write(raw);stream.flush();os.fsync(fd) + finally:os.close(fd) + if not initial:os.replace(target,self.path) + fd=os.open(self.directory,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW) + try:os.fsync(fd) + finally:os.close(fd) + + def _http(self,method,path,body=None): + # Fixed loopback owner process and fixed data path; never arbitrary URL. + if self.admission.server_process.poll() is not None:raise Refused('fixture custody backend unavailable') + with _absolute_budget(2.0): + conn=http.client.HTTPConnection('127.0.0.1',self.admission.port,timeout=2) + try: + conn.request(method,'/v1/'+path,body=None if body is None else encoded(body),headers={ + 'X-Vault-Token':self.admission.owner_token,'Content-Type':'application/json'}) + response=conn.getresponse();raw=response.read(1048577) + if len(raw)>1048576:raise Refused('backend response bound exceeded') + value=json.loads(raw,object_pairs_hook=_json_unique,parse_constant=_invalid_constant) if raw else {} + return response.status,value + finally:conn.close() + + def write(self): + if self.attempted:raise Refused('signer operation already attempted') + self.attempted=True + # All source/receipt checks precede generation; no seed import, argv, + # environment, temporary file or public output interface exists. + private=Ed25519PrivateKey.generate() + seed=b64(private.private_bytes(serialization.Encoding.Raw,serialization.PrivateFormat.Raw,serialization.NoEncryption())) + public=b64(private.public_key().public_bytes(serialization.Encoding.Raw,serialization.PublicFormat.Raw)) + document={'ED25519_PRIVATE_KEY':seed,'ED25519_PUBLIC_KEY':public,'kid':self.kid} + self.receipt.update(status='write-intent-unknown',public_key=public, + public_fingerprint='sha256:'+hashlib.sha256(public.encode()).hexdigest()) + self._save() # A durable intent must exist before any possible effect. + try: + status,result=self._http('POST',PATH,{'options':{'cas':self.expected_version},'data':document}) + if status!=200 or type(result) is not dict:raise Refused('signer write unconfirmed') + version=result.get('data',{}).get('version') + if type(version) is not int or version!=self.expected_version+1:raise Refused('signer write version unconfirmed') + self.receipt['kv_version']=version + status,result=self._http('GET',PATH+'?version='+str(version)) + if status!=200 or type(result) is not dict:raise Refused('signer readback unconfirmed') + data=result.get('data',{});stored=data.get('data') if type(data) is dict else None + metadata=data.get('metadata') if type(data) is dict else None + if (type(stored) is not dict or set(stored)!=FIELDS or any(type(v) is not str for v in stored.values()) + or type(metadata) is not dict or type(metadata.get('version')) is not int or metadata['version']!=version + or any(not hmac.compare_digest(stored[name],document[name]) for name in FIELDS)): + raise Refused('signer readback mismatch') + self.receipt.update(status='custody-verified-pending-independent-public-admission',exact_readback=True) + self._save() + return dict(self.receipt) + except BaseException: + # Persist only closed metadata; unknown never implies absence or retry. + # If receipt storage fails, the durable earlier intent remains unknown. + self.receipt.update(status='write-intent-unknown',exact_readback=False) + self._save() + raise Refused('signer custody outcome unconfirmed') from None + + +if __name__=='__main__': + raise SystemExit('production signer custody unadmitted; no live entry point') diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/preimages/workplans/RPF-WP-0035-credential-lane-implementation.md b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/preimages/workplans/RPF-WP-0035-credential-lane-implementation.md new file mode 100644 index 00000000..da4e2ded --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/preimages/workplans/RPF-WP-0035-credential-lane-implementation.md @@ -0,0 +1,1356 @@ +--- +id: RPF-WP-0035 +type: workplan +title: "Implement reviewed credential lanes with separate owner gates" +domain: financials +repo: railiance-platform +status: blocked +flavor: implementation +owner: codex +created: "2026-09-05" +updated: "2026-10-13" +related: + - RPF-WP-0032 + - RPF-WP-0033 + - RPF-WP-0034 +state_hub_workstream_id: "975db491-5412-5e27-8e34-14a2417bb039" +--- + +# Credential lane implementation + +One S3 queue for three designed lanes; each task keeps its own approval, +execution and closure boundary. This replaces the implementation tasks in the +three completed design workplans, not the designs themselves. No approval is +inherited by consolidation. INTENT binding: secure custody, dependable delivery, +stable consumer interfaces. Incident custody remains in RPF-WP-0027/0029. + +## Consolidate completed designs and owner dependencies + +```task +id: RPF-WP-0035-T01 +status: done +priority: medium +state_hub_task_id: "0f3606bb-e95b-5484-8a57-bcdd6e3916fd" +``` + +Completed 2026-09-05. Preserved the three designs under +`docs/credential-lane-designs/`, identified native owner responsibilities and +linked each superseded task below. Owners have not been sent new requests and +no new external acceptance is claimed. STATE-WP-0085-T09 is already done; +the signing dependency belongs to the proposed FLEX-WP-0020-T05 cutover. + +## Accept and provision secrets-engine service JWT login + +```task +id: RPF-WP-0035-T02 +status: wait +decision_id: 62aa95e4-3ccc-4867-8806-5e3db005b483 +depends_on: [KEY-WP-0039-T02, MASON-WP-0009-T05] +blocking_reason: "Agent work, not a human gate: claim refusals (KEY-WP-0039-T02 probe) and capabilities-self deny, then ops-mason MASON-WP-0009-T05." +priority: high +state_hub_task_id: "e0c82ea9-05a5-537e-8fbf-67534263572e" +``` + +2026-10-11: requalified — the remaining waits are other owners' tasks, not a human gate. See the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +Supersedes RPF-WP-0032-T02. Design: +`docs/credential-lane-designs/secrets-engine-service-jwt.md`. + +Platform owns the exact JWT mount/role/policy, effective-policy negative tests +and a metadata-only custody receipt. KeyCape owns issuer/JWKS and service +registration (KEY-WP-0009); secrets-engine owns service authentication and +authority consumption (SECRETS-WP-0008-T06, SECRETS-WP-0007-T04). + +**Unblock:** live registration and protected client custody, reviewed exact source +and attended apply authority. Issuer/JWKS and consumer source claims now agree; +see the 2026-09-27 return below. A service login does +not grant lane mutation authority. Do not build another identity provider or +lifecycle engine here. + +**Done when:** approved exact role succeeds for the intended service, wrong +issuer/audience/subject/claims and unrelated secret access fail, bounded TTL +and revocation are proven, the consumer explicitly opts into the verified +contract, and rollback/cleanup receipts contain no secret material. + +2026-10-09 (T03 source): founder ruled the tenant segment stays `coulomb` +(ops-mason `b72ff77d`). New CCR request type `workload-kv-operator-matrix` +(`scripts/operator_matrix_lane.py`): exact per-entry capabilities, OIDC role on +the existing `netkingdom` mount only, and exact agent denies on all four data +and metadata paths appended to the live `agent-high-risk-boundary` (live content +preserved; partial presence refused). `scripts/fluid_telegram_custody_move.py` +copies the four undocumented `infotech` entries with CAS 0, verifies all, then +metadata-deletes the sources. `scripts/kv_duplicate_retire.py` retires +`activity-core/default/llm-connect-provider-secrets` only if no live non-admin +policy grants it. Founder session (each helper prints nothing; read the receipts): + +```bash +cd ~/railiance-platform +export BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200 +W='warden access openbao-platform-admin-login --exec --' +# 1. dry-runs (no value reads, no writes) +$W python3 scripts/fluid_telegram_custody_move.py --dry-run --confirm 'MOVE fluid-telegram hall-of-helix to coulomb' --receipt ~/ft-move-dry.json +$W python3 scripts/kv_duplicate_retire.py --dry-run --confirm 'RETIRE activity-core/default/llm-connect-provider-secrets' --receipt ~/kv-retire-dry.json +# 2. lane: approve, confirm binding, apply +python3 scripts/credential-change.py approve CCR-2026-0039 --reviewer "platform-owner, fluid-telegram-owner, key-cape-owner (founder Bernd Worsch)" --comment "Approve ops-mason plan fluid-telegram-operator-credential-lane (spec 41a0ca27): four-entry matrix at coulomb/fluid-telegram/hall-of-helix, OIDC role on netkingdom, agent denies." \ + && python3 scripts/credential-change.py confirm-binding CCR-2026-0039 --reviewer founder --comment "groups=[fluid-telegram-operators] (LLDAP, member tegwick) and /assurance/level=aal2 match key-cape b2ed890f." \ + && $W python3 scripts/credential-change.py applier-apply CCR-2026-0039 --confirm "DELEGATED APPLY CCR-2026-0039" --actor founder --record-state-hub --quiet +# 3. custody move, then duplicate retirement +$W python3 scripts/fluid_telegram_custody_move.py --confirm 'MOVE fluid-telegram hall-of-helix to coulomb' --receipt ~/ft-move.json +$W python3 scripts/kv_duplicate_retire.py --confirm 'RETIRE activity-core/default/llm-connect-provider-secrets' --receipt ~/kv-retire.json +``` + +2026-10-09 (T03 founder session): CCR-2026-0039 applied at 10:30Z; readback +matched for the 8 boundary denies, policy and role. Custody move `moved`: all +four entries copied at coulomb v1 (operator-session from infotech v4) and the +infotech entries metadata-deleted. Duplicate +`activity-core/default/llm-connect-provider-secrets` retired; its first dry-run +refused on mount-wide `platform/metadata/*` survey grants, after which the check +was narrowed to data-path grants (`64ae594`). Receipts: +`docs/evidence/2026-10-09-fluid-telegram-t03-founder-session.json`. + +2026-10-03: the historical D1 routing was withdrawn because provision/delivery already completed. Owner routing now uses decision `ab85ae8a-12a0-4945-ae64-1d3d86d5b26f`, specifically independent archive readback and coordinated interim audit bearer revocation acceptance. `needs_human` and the wait remain; resolving a decision requires owner receipt re-check, not automatic completion. + +2026-10-03 (CUST-WP-0075): gate check. SECRETS-WP-0007-T04 is done (2026-09-27), so the gate named in the design is open. It is not the last one: the design says to confirm the exact live client registration and protected client-side custody before writing, and positive-login proof needs a real KeyCape service JWT. KeyCape's contract (`openbao-service-auth-contract.md`) and KEY-WP-0009 claim source registration only; the live registration of `secrets-engine-openbao` and its client-credential custody are "a separate approved custody action" that no workplan task owns yet (SECRETS-WP-0008-T06 waits on this task). Re-qualified with `blocked_on: message-from:key-cape`; key-cape was asked for the owning task id, which will replace it as `depends_on`. The design stays proposed and no child command was written. Not approvable in D1 yet. + +2026-10-04: Founder authorized the prepared coordination request. Sent +`b4fc62ea-f92c-4410-919a-9f3cce2d406b` to key-cape on preparation thread +`f84637fa-2355-4971-a2dc-7f1fd01710a8`, referencing platform source +`6b91d510395215d178d60ee8884e7fc00930a0cf`. Requested actual registration and +protected-custody owning tasks/status/revisions and non-secret receipts. Source +registration is not live custody; no value fetch or live registration was +requested. T02 remains waiting on the owner return and separate execution gates. + +2026-10-04 blocked-task review: KeyCape returns 58826056/eb20a78c now identify +KEY-WP-0037-T02/T03/T04, replacing the unowned-registration wait with real +dependencies. Prepared proposed CCR-2026-0033 and exact-path issuer policy/auth, +sso-only ESO and evidence checklist from the returned candidate coordinates. +No issuer/consumer value, registration or native issuance is supplied by them. +secrets-engine must return independent source acceptance of consumer host/path, +protected delivery and rotation/revocation ownership; awaiting that source phase +does not depend on its full live service-login task. KeyCape's exact-primary sync +remains pending its scoped historical identity repair. Requirements and acceptance +boundaries: `docs/provisioning-windows/2026-10-04-1000/dependency-requirements.md`. +This workplan was already blocked and remains blocked on its open owner/live gates. + +2026-10-06: secrets-engine returned consumer custody source acceptance +(message 680136e2, SECRETS-WP-0012, commit a3897c2). CCR-2026-0033 finalized as +**proposed**: KV path corrected to `platform/workloads/keycape/secrets-engine-openbao` +(applier scope), consumer copy coordinates with D1-D4 pending founder choice, +rotation/revocation ownership, live order and rollback. Attended custody child +`scripts/keycape_secrets_engine_openbao_custody.py` with fake-only tests +(`tests/test_keycape_secrets_engine_openbao_custody.py`) refuses without an exact +founder decision id recorded in the approved CCR. Nothing executed, generated or +applied; nothing added to active GitOps. The founder approval it needs is T09. + +2026-10-09: KEY-WP-0037 finished 2026-10-07 (registration live, issuance +verified 10/10, key-cape e0b5fae); CCR-2026-0033/0034 applied. Source for this +lane is now complete as **CCR-2026-0038** (proposed, +`credential-change-requests/CCR-2026-0038-secrets-engine-service-jwt-login.yaml`). +The delegated applier gained a narrow `service-jwt-login` request type +(`scripts/service_jwt_lane.py`): auth mount fixed to `keycape-services`, policy +must equal the generated login-self policy, role/config keys allow-listed, +TTLs at most 15m, uses 1..16, `token_no_default_policy`, refusal if the mount +exists with another type, and a value-free readback compare after the writes. +Policy `secrets-engine-login-self` now also carries explicit `deny` on +`platform/{data,metadata}/workloads/keycape/secrets-engine-openbao` so +ops-mason invariant (ii) (no capability on the client-secret path) holds even +if identity groups were ever attached. Tests: `tests/test_service_jwt_lane.py` +(8) plus the updated contract test; full suite unchanged apart from 5 +pre-existing failures unrelated to this lane. + +Founder apply (one line; approval, binding confirmation and silent apply): + +```bash +cd /home/worsch/railiance-platform && python3 scripts/credential-change.py approve CCR-2026-0038 --reviewer "platform-owner, key-cape-owner, secrets-engine-owner (founder Bernd Worsch)" --comment "Approve service-JWT login lane: mount keycape-services, role secrets-engine-openbao, policy secrets-engine-login-self (self endpoints + deny on the client-secret path)." && python3 scripts/credential-change.py confirm-binding CCR-2026-0038 --reviewer founder --comment "Bound claims match KeyCape registration: aud secrets-engine-openbao, sub service:secrets-engine, principal_type service, tenant tenant:platform, roles secrets-engine, scope openbao:login; issuer https://kc.coulomb.social RS256." && warden access openbao-platform-admin-login --exec -- python3 /home/worsch/railiance-platform/scripts/credential-change.py applier-apply CCR-2026-0038 --confirm "DELEGATED APPLY CCR-2026-0038" --actor founder --record-state-hub --quiet +``` + +Done after that: login proof with a real KeyCape service JWT +(SECRETS-WP-0012-T03 probe-openbao; policies exactly +[secrets-engine-login-self], capabilities-self deny on the guarded paths, +revoke-self), negative claim checks, then publish the consumer contract file +and ops-mason MASON-WP-0009-T05 rechecks invariant (ii). + +## Implement the platform operator-write CCR contract and Fluid lane + +```task +id: RPF-WP-0035-T03 +status: wait +decision_id: 62aa95e4-3ccc-4867-8806-5e3db005b483 +blocking_reason: "Founder session done 2026-10-09; waits on ops-mason verification (MASON-WP-0005-T05) and the FT-WP-0002 owner salt CAS probe." +priority: high +depends_on: [MASON-WP-0005-T05, FT-WP-0002] +state_hub_task_id: "f47e5bc5-6f3c-54bb-aa35-260ad03892ba" +``` + +2026-10-11: requalified — founder part done; remaining waits are owner tasks. See the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +Supersedes RPF-WP-0033-T02. Design: +`docs/credential-lane-designs/fluid-telegram-operator-kv.md`. + +Platform owns the per-path capability schema/validator, exact OpenBao policy +and accepted custody coordinates. MASON-WP-0005 owns construction coordination +and engine integration; KeyCape/NetKingdom own OIDC/MFA and group membership; +FT-WP-0002 owns client CAS, prefix correction, output containment and Telegram +application acceptance. Retain the existing read-only CCR semantics. + +**Unblock:** accept tenant/path and per-entry field/capability matrix; confirm +actual group/assurance and callbacks, reviewed construction contract and writer +authority. Contract review can proceed without a live credential; the final +schema cannot be treated as accepted solely because a draft exists. + +**Done when:** validation rejects broad/unsupported grants, the consumer proves +CAS=0 first-write behavior and no value output, approved identities can perform +only the exact matrix, negative/expiry/revocation checks pass, custody is seeded +through the separate writer, and the verified route has a safe handoff receipt. +The unattended adapter remains a separate demand and gets no operator session. + +2026-10-03: the historical D1 routing was withdrawn because provision/delivery already completed. Owner routing now uses decision `ab85ae8a-12a0-4945-ae64-1d3d86d5b26f`, specifically independent archive readback and coordinated interim audit bearer revocation acceptance. `needs_human` and the wait remain; resolving a decision requires owner receipt re-check, not automatic completion. + +## Accept the needed signing lane and deliver it to the owning runtime + +```task +id: RPF-WP-0035-T04 +status: done +priority: medium +state_hub_task_id: "35a85846-61d5-54ce-8b18-ede45733d53c" +``` + +Supersedes RPF-WP-0034-T02. Design: +`docs/credential-lane-designs/state-hub-preflight-signing.md`. + +Platform owns signing-key custody, exact read policy/role and scoped delivery +acceptance. State Hub owns API chart/env wiring, all-replica rotation fencing +and health. FLEX-WP-0020-T05 owns the rename preflight/cutover dependency; +STATE-WP-0085-T09's adoption-plan delivery is already complete. + +**Unblock:** State Hub/repo-manager and the consuming migration owner confirm +that this transitional State Hub lane is still needed during retirement; +record the target runtime, namespace/SA/auth audience and an executable +rotation fence, plus approved writer and deployment window. Do not broaden the +lane into a general repository-rename authority or provision for a stale demand. + +**Done when:** protected one-time generation, API-only ESO delivery, negative +access checks and a non-mutating signed preflight pass; every API replica uses +the accepted version; rotation/invalidation and recovery are evidenced. No +repository rename is part of S3 lane acceptance. If demand is withdrawn, record +the owning decision and cancel this task explicitly rather than provision it. + +2026-09-05 continuation: verified the live primary cluster identity and healthy +single API replica; the signing ExternalSecret is still absent. Added a writer +guard against wrong-cluster kubeconfigs before any OpenBao access. The default +workstation kubeconfig's local port-forward listener was unavailable. Activation +still needs the contained attended OIDC/MFA login and the acceptance evidence +above; source preparation is not live completion. See +`history/2026-09-05-preflight-signing-activation-readiness.md`. + + +Completed 2026-09-05: user-led attended activation generated version 1 and +rotated to version 2 with every API replica stopped. Exact access and negative +identity checks passed; ESO delivery and API-only exposure passed; the recovered +single API replica accepts new signed preflight and rejects its predecessor by +signature, with healthy primary identity and no preflight blockers. State Hub +chart commit `49e3182`, Helm revision 59. No repository rename executed. +Evidence: `docs/evidence/RPF-WP-0035-T04-signing-activation-2026-09-05.json`; +closure: `history/2026-09-05-preflight-signing-activation-complete.md`. + +## Admit KeyCape approval-engine client custody and delivery + +```task +id: RPF-WP-0035-T05 +status: done +needs_human: false +intervention_note: "" +priority: high +state_hub_task_id: "e15d62c9-e5da-5721-a135-87c050f7851c" +``` + +Answers KEY-WP-0013-T02 (State Hub message +`278a3ebe-b529-49f6-bd1a-e3ebcf318260`). Admission: +`docs/credential-lane-designs/keycape-approval-clients.md`; requests +`CCR-2026-0017` (secrets-engine-approval) and `CCR-2026-0018` +(approval-engine-operator). + +Platform owns the two custody paths, exact-path read policies, Kubernetes auth +roles and the KeyCape-side ESO delivery. KeyCape owns the client registrations, +issuance, claim set and disablement; approval-engine owns approval semantics and +audit of emitted actions. + +2026-09-08 admission response: both proposed KV paths confirmed unchanged; field +`client_secret` corrected to `CLIENT_SECRET` for the uppercase KV convention and +CCR validator. Kubernetes delivery references confirmed against the live `sso` +namespace, which already resolves `KEYCAPE_RAPP_QONTO_CLIENT_SECRET` through the +same `secretKeyRef{key: client-secret}` shape on image `main-153258b`. Attended +authority named as the governed `openbao-platform-admin-login` lane +(`founder_required`); KeyCape's refusal to treat its generic `warden plan` +database match as authorization was correct. Rollout agreed as one attended +session with the KeyCape reading build pinned but undeployed, ordered after the +Authelia issuer precondition in message `c8b1ad10-dae8-48fb-a0ea-7e2a101c54bf`. +Policies, ClusterSecretStores and ExternalSecrets are written and validated, +none applied. + +**Unblock:** owner approval of both CCRs, a KeyCape image that reads both +environment names, the settled Authelia `iss` pin, and a founder-attended window +date. Verifier-side custody only — no client-side read lane is admitted, and no +scope beyond the two declared sets. + +**Done when:** both CCRs are approved, the attended window seeds both KV paths +with CAS=0, policies/roles/stores/ExternalSecrets apply and sync, the KeyCape +build resolves both environment names, KeyCape evidences live JWKS signature and +exact claim bindings with excess scopes denied (operator `consume`, human +`consume`), platform evidences cross-path/wrong-identity/out-of-namespace denial, +and every receipt is metadata-only. If either registration is abandoned, KeyCape +disables it before the KV version is destroyed. + +### 2026-09-08 actual upstream issuer returned + +The admitted KeyCape one-shot probe verified the actual signed upstream issuer +as **`https://auth.coulomb.social`** at 21:44:44 UTC. Signature, audience, +validity window and nonce checks passed and the pinned Job exited 0. All +five temporary resources and the Pod were removed; normal KeyCape Deployment +and config Secret metadata are unchanged. See +`docs/evidence/2026-09-08-keycape-upstream-issuer-proof.json`. + +T05's unknown-issuer input is resolved. The configuration owner still ensures +`authelia.issuer` equals that exact HTTPS value before the custody window. +Both CCRs remain proposed and await the named reviews; this probe grants no +custody mutation or client-side read. Keep the current authority preflight and +this signed-token proof as separate receipts. Live ESO/client/approval and +separate audit/client-side custody acceptance remain open. + + +2026-09-09 configuration and review-queue return: NetKingdom pinned the verified +HTTPS issuer, using an atomic UID/resourceVersion test and independent readback. +Secret revision `58713343`; unrelated configuration and signing key unchanged; +no Deployment rollout. Receipt: `docs/evidence/2026-09-09-keycape-upstream-issuer-pin.json`. + +The two existing CCRs remain proposed. They now link to concrete pending review +decisions, with platform-operator and key-cape-owner named explicitly. See +`docs/credential-lane-designs/keycape-approval-clients-review.md`. T05 owns this +human dependency; HFACT consumes it without a duplicate approval request. +Custody/ESO activation, client verification and the separate client-side/audit +lanes remain open. Current CLI apply plans refuse the proposed requests. + + +2026-09-09 admission: the user explicitly approved both CCRs in the named +platform-operator and key-cape-owner roles. Both source requests are approved +and both linked Hub decisions are resolved. Receipt: +`docs/evidence/2026-09-09-keycape-approval-admission.json`. The completed review +intervention is cleared; T05 is progress while the contained first-provision +procedure is exercised and the admitted attended rollout is carried through. +Verifier-side scope, separate client-side/audit lanes and live acceptance remain +as defined in the reviewed requests. + +2026-09-09 verifier-side return: both CCRs are verified after recorded user approval, +CAS=0 version-1 custody, native read/auth denials and revocation, Valid stores, +SecretSynced delivery, compatible KeyCape rollout and live positive/negative +service checks. Existing human OpenBao login passed again on the new image. +Receipt: `docs/evidence/2026-09-09-keycape-verifier-admission.json`. Failed attempts restored the compatible +configuration/image and detached delivery; final resume reused version 1. + +T05 is done against its verifier-only acceptance criteria. Its former +"remains progress for client-side reads" statement expanded the task past its +reviewed scope; that residual now has the live owner task RPF-WP-0035-T06 below. +Neither Warden fetch selector is resolvable through these verifier-only CCRs. +Do not re-request the completed two named reviews or reseed these paths. +Rotation is a distinct, version-guarded operation. + +## Dispose of the ungoverned whynot-design npm duplicate + +```task +id: RPF-WP-0035-T07 +status: wait +decision_id: 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa +blocking_reason: "Hold kept by D3 until SECRETS-WP-0006-T06 moves publishing off the legacy whynot-design npm path; then rotate and prove a fresh publish." +priority: high +depends_on: [SECRETS-WP-0006-T06] +state_hub_task_id: "0dd7c9a5-65a0-53fc-b6c3-5ad96ee56f7b" +``` + +2026-10-11: requalified after founder decision D3 (trust root, build-mode default) resolved — see the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +Found by the attended session on 2026-09-10 while settling the npm field +question. `secret/coulomb/whynot-design/npm/publish` exists at version 1, +created 2026-07-03T15:00:44Z and never updated — five days after the governed +lane at `platform/workloads/coulomb/whynot-design/npm-publish` was verified +(CCR-2026-0001, 2026-06-28). It sits outside that lane's exact-path policy and +outside any CCR here. Receipt: +`docs/evidence/2026-09-10-npm-lane-field-resolution.json`. + +Only metadata was read. Its field names were not enumerated, its value was not +read, and nothing was deleted — a location holding real credential material is +disposed of deliberately, not tidied away in the session that found it. + +The likely explanation, unconfirmed: secrets-engine reports the lane's field +under a lowercase name that is absent from the governed path, and their catalog +declares this legacy location. If their proven pilot publish read from here, +then a working production lane has been running off an ungoverned duplicate, +and the governed lane's acceptance evidence describes a path the consumer does +not use. That is worth establishing before anything is removed. + +**Operator decision, 2026-09-15:** destroy the legacy path after confirming the +governed lane is the live consumer. Do not wrap `secret/coulomb/whynot-design/npm/publish` +in a CCR. Value remains unread. Platform will ask secrets-engine which path +publish actually reads before any attended destroy. + +**Unblock:** admit the governed exact-path AppRole policy and coordinated catalog +path/field migration under SECRETS-WP-0006-T06; prove native delivery from the +governed lane before the attended legacy destroy. secrets-engine confirmed the +legacy source path on 2026-09-21 (message `355424d4-17ab-435e-9e1d-6921775cb4a2`). +No comparison of values, fingerprints, lengths or shapes is needed or authorized. + +**Done when:** the legacy path's provenance and consumer are established, the +governed lane is confirmed as the one in use or the consumer is moved to it as a +reviewed lane change, the duplicate is destroyed under the September 15 operator decision and the +disposition is recorded. Do not bring the legacy duplicate under a CCR. If the value proves to be live and +ungoverned, treat it as an exposure with the same custody rules as RPF-WP-0027: +never record the value, fingerprint, length or shape. + +2026-10-03: human gate routed to hub decision 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa (D3: Trust root and secret custody: unseal/recovery holders, break-glass, and the deferred rotation of exposed material) by CUST-WP-0075; resolving that decision raises C-40 here. + +## Admit the separate approval client-side readers + +```task +id: RPF-WP-0035-T06 +status: done +decision_id: 62aa95e4-3ccc-4867-8806-5e3db005b483 +priority: high +intervention_note: "" +state_hub_task_id: "68bff751-e48b-548b-8fb4-dfb3b16210c2" +``` + +2026-10-11: requalified after founder decision D1 (attended window standing rule) resolved — see the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +**Current return, 2026-09-10:** CCR-2026-0020 is cancelled on the requesting +Approval Engine owner's explicit withdrawal, source +`849c75bb094613ff6ac1a1d4cda56a745520c5a1:docs/keycape-service-registrations.md`. +No presenter exists and no reader is wanted. The validator now accepts terminal +cancellation of an incomplete request only with owner/source/reason evidence, +retained declared omissions and a disabled, non-resolvable front door. Apply +remains refused. No live identity, policy, role, custody or verifier was changed. +Human approval follows existing INFD-WP-0001-T07/T08; future service requesters +need a separate narrow registration, not this withdrawn bundle. + +**Operator binding confirmed, 2026-09-14:** The user explicitly selected +`net-kingdom-admins` and authorized applying CCR-2026-0019. Its OIDC role is +`secrets-engine-approval-client-workload-kv-read`, aligned with the platform +applier naming rule; policy and exact KV scope are unchanged. The metadata dry +run passes with no warnings. Attended apply and exact role/policy readback passed; the enclosing Warden +command exited successfully after its self-revocation/cleanup. Receipt: +`docs/evidence/2026-09-14-ccr0019-operator-binding.json`. Scoped delivery proof +remains pending; the front door stays non-resolvable. Completed CCR-2026-0017/0018 +remain closed and T06 stays `wait`. + +Consumer procedure returned in source, 2026-09-10: +`secrets-engine@98d72ceb1dbcff2d2a80fb8c3058d76777a0ac93:docs/approval-service-auth.md` +specifies the requested private 0700 runtime directory, 0600 file outside Git, +path-only use, claim/consume lifetime and attended cleanup including hard-stop +residual inspection. CCR-2026-0019 retains this source-review comment without +changing admission status. Exact group, required-owner review, attended apply and +native positive/negative/cleanup evidence remain. No role or credential changed. + +Separate retained owner decision: KeyCape's 2026-09-10 return +`21427688-725f-4dea-aab4-7c78fd4328d2` identifies the already-live, unpresented +CCR-2026-0018 registration. Approval Engine, KeyCape and Platform must explicitly +decide retention/expiry or coordinated disablement. Reader cancellation neither +disables that live registration nor accepts indefinite retention. Keep this +disposition in T06; it is separate from the wanted CCR-2026-0019 factory reader. +No unilateral issuer/config/Secret change is authorized by this closeout. + +**Operator decision, 2026-09-15:** coordinated disablement with KeyCape and +Approval Engine. Platform will not disable the live registration or verifier +delivery unilaterally. T06 stays `wait` until both owners confirm the joint +disablement sequence. + +Residual handoff from RPF-WP-0035-T05; consumes the completed verifier custody +without extending CCR-2026-0017/0018. Owner: railiance-platform with the named +secrets-engine and approval-engine operator consumers. + +Prepare separate exact-reader admissions for existing version-1 paths: +`platform/workloads/secrets-engine/approval-client` and +`platform/workloads/approval-engine/operator-client`, field `CLIENT_SECRET`. +Name each actual actor/placement, bounded authentication/reader policy, protected +consumer delivery, cleanup/revocation and rollback, then obtain the required +owner reviews for those concrete requests. No reseeding, rotation, shared reader, +reuse of the sso verifier Secret, or implicit operator consume grant. + +2026-09-09 preparation return: both exact-reader admissions are prepared as +`CCR-2026-0019` (secrets-engine) and `CCR-2026-0020` (approval-engine-operator), +with their exact-path read policies written and committed. Design: +`docs/credential-lane-designs/keycape-approval-client-side-readers.md`. Both +reuse existing version-1 custody; no reseed, rotation, shared reader or verifier +Secret reuse. Both are `in_flight` and unapproved; nothing is applied. + +Read-only survey findings that decided the two shapes. Namespace +`secrets-engine` holds only ServiceAccount `secrets-engine` with no workload, +and `flex-auth/flex-auth-secrets-engine` is that consumer's PDP, not the +service; secrets-engine consumes the client secret through an operator-run CLI +reading `SECRETS_ENGINE_APPROVAL_CLIENT_SECRET_FILE` (SECRETS-WP-0009-T03, +revision `9eb07fd`). So reader 1 is an attended operator-workstation OIDC lane, +not an ESO lane. approval-engine has no namespace, workload or Service; its +manifest is unapplied, and no owner source names who presents the operator +client — approval-engine verifies these tokens and never holds them. + +**Unblock:** reader 1 needs the exact NetKingdom/KeyCape group claim for the +authorized operator, plus secrets-engine confirming the file mode and removal +step; `openbao.auth` is declared missing rather than filled with a placeholder +that would later read as a confirmed binding. Reader 2 needs its owner to name +the presenting actor and placement, or to record that no client-side reader is +wanted so the request is cancelled. Naming a reader for the widest approval +scope without that decision is the failure this task exists to avoid. + +**Done when:** each reader has a named actor and placement, a completed and +reviewed auth binding, admitted delivery, and its owner approvals; positive and +negative checks pass, including cross-path, wrong-identity and parent-list +denial and operator `consume` denial; or the request is explicitly cancelled by +its owner. Rotation stays a distinct version-guarded operation shared with +CCR-2026-0017/0018. + + +Consumer input supplied 2026-09-09: secrets-engine now implements per-request +`secrets-engine-approval` exchange from a protected temporary client-secret file, +with exact approval-engine / tenant:platform / read-or-consume scope, no token +file and no fallback. The pinned KeyCape image and actual Approval Engine source +passed its disposable component exercise; only the PDP was a sequencing double. +See `secrets-engine/docs/approval-service-auth.md` and the metadata receipt +`secrets-engine/docs/evidence/2026-09-09-approval-identity-exercise.json`. + +Routing check: `warden route show keycape-secrets-engine-approval-client` is +unknown; generic `openbao-api-key` routes ownership only and is not a delegable +lane. Do not advertise a working fetch command before this task supplies its +own accepted native delivery return. Client-side admission is not ready for a +new human decision until exact requests and contained execution/rollback checks +are reviewable; the completed verifier reviews must not recur in that queue. + +**Done when:** each retained consumer admission is approved and implemented, or +its requesting owner explicitly cancels it (CCR-2026-0020 now satisfies that branch); +actual consumer authentication/delivery succeeds; sibling/listing/wrong-reader +and scope refusals plus reader expiry/revocation/cleanup are evidenced; version-1 +custody and verifier availability remain intact. Return the source and metadata +receipts to HFACT-WP-0001-T03, SECRETS-WP-0009-T03 and APPROVAL-WP-0002-T01/T05. +Audit receiver/sender custody remains AUDIT-WP-0009-T09 and must not be folded +into this client-identity grant. + +2026-10-03: the historical D1 routing was withdrawn because provision/delivery already completed. Owner routing now uses decision `ab85ae8a-12a0-4945-ae64-1d3d86d5b26f`, specifically independent archive readback and coordinated interim audit bearer revocation acceptance. `needs_human` and the wait remain; resolving a decision requires owner receipt re-check, not automatic completion. + +## Admit the two factory audit-sender custody lanes + +```task +id: RPF-WP-0035-T08 +status: wait +decision_id: "ab85ae8a-12a0-4945-ae64-1d3d86d5b26f" +blocking_reason: "Approved conditionally (ab85ae8a, standing change rule): executes once independent archive readback and the interim bearer revocation receipt exist; owner work with audit-core." +priority: high +assignee: railiance-platform +intervention_note: null +blocked_on: message-from:audit-core +state_hub_task_id: "0ef52c26-2669-5cd1-8149-b1f6fcdda6cb" +``` + +2026-10-11: requalified — ab85ae8a resolved under the standing build-mode change rule. See the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +2026-10-03 correction (CUST-WP-0075, informed-decision sitting draft `55fb078`): the D1 routing was wrong. First provision and delivery already ran on 2026-09-11, with seed and delivery receipts, and the review packet says not to repeat them. The task is not a provisioning-window act. It was taken off decision D1, and its blocking_reason now names what actually remains. railiance-platform should re-qualify it further if the receiver rollout has since happened. + +2026-10-03 (CUST-WP-0075): re-qualified. The receiver rollout already happened: Audit Core c82e0442de0f carries evidence_kind and native producer accepted/duplicate and scope/read-refusal checks passed 2026-09-11 10:42 UTC (`docs/credential-lane-designs/factory-audit-senders-review.md`, `factory-native-acceptance.md`). Remaining: independent archive readback and audit bearer-revocation acceptance. Still not a provisioning-window act. + +Consume AUDIT-WP-0009-T09/T11's exact declarations for approval-engine and +informed-decision: tenant:platform, write-only, load-bearing, redact. Source +preparation supplies two approved CCRs, independent exact-path policies/ESO +projections, and the attended `factory_audit_custody.py` first-provision helper. +Its CAS and request-provenance checks preserve unrelated senders and recover +interrupted writes without generating replacements. The user approved all named review roles on 2026-09-11. Native +provision/delivery/receiver-ingestion acceptance remains open. + +The 2026-09-11 native read-only check found an additional deployment dependency: +receiver image c2fe39a is 1/1 Ready but does not support evidence_kind. The +synthetic native probe now refuses before any credential read. Current receiver +source passes. AUDIT T09/T11 retain compatible release/source-manifest rollout; +Approval Engine's missing namespace remains its owner prerequisite. + +[Review packet](../docs/credential-lane-designs/factory-audit-senders-review.md). +[Preparation evidence](../docs/evidence/2026-09-11-factory-audit-custody.json). +Do not fold these senders into CCR-2026-0019 or the cancelled CCR-2026-0020. + +2026-10-03: the historical D1 routing was withdrawn because provision/delivery already completed. Owner routing now uses decision `ab85ae8a-12a0-4945-ae64-1d3d86d5b26f`, specifically independent archive readback and coordinated interim audit bearer revocation acceptance. `needs_human` and the wait remain; resolving a decision requires owner receipt re-check, not automatic completion. + +## Dependency review — 2026-09-06 + +### 2026-09-09 tenant question resolved — no change needed + +The `tenant:coulomb` / `tenant:platform` discrepancy raised against T02 is not a +discrepancy. KeyCape confirms decision `5ed3fb35-eca9-413a-82b9-95171ba85bf6` +binds the *approval chain* to the landlord zone and was applied to exactly two +registrations, `secrets-engine-approval` and `approval-engine-operator`. +`codex-railiance-platform` is not in that chain and correctly stays +`tenant:coulomb`, as do `secrets-engine-openbao` and the human directory default. +KEY-WP-0013-T04 records this and their +`TestServiceRegistrationTenantsAreExactPerDecision` pins every reviewed client's +tenant against the real fixture, so a reintroduced alias fails their build. + +`docs/credential-lane-designs/secrets-engine-service-jwt.md` already says +`tenant:coulomb` and is therefore correct as written. Bind the exact role to +`tenant:coulomb`. Do not "correct" it to `tenant:platform` later; that would +break the issued claim. + +SECRETS-WP-0008-T02 now records the local PIP claim/validation join implemented +and tested. Its remaining gate is the unreachable approval-engine claim endpoint +and access-engine Check (SECRETS-WP-0007-T04). Do not carry forward the old local +stub as a blocker. T02 still needs the accepted service issuer/JWKS, claims, +audience and consumer binding. T03 still needs confirmed operator group/tenant +and consumer semantics; T04 is already complete. No new owner acceptance inferred. + + +### 2026-09-08 attended capability preflight + +HFACT-WP-0001's continued execution verified the existing first-provision +front door without provisioning anything. `warden plan` selected +`openbao-platform-admin-login` / founder_required / one oidc_login. The native +`scripts/openbao-attended-exec.py` supplied the existing WSL browser launcher; +a direct attempt had no launcher and failed before handoff. Its first revocation +result was unconfirmed and is preserved in the receipt rather than silently +reclassified. The two subsequent contained sessions completed self-revocation +and helper cleanup. + +`scripts/keycape-approval-custody-preflight.py --receipt ` is +a silent, read-only command for that envelope. The installed Bao CLI supports +one path per `token capabilities` call; the final run used six single-path calls. +Create/update authority is present on both exact policy paths, both Kubernetes +auth-role paths and both KV data paths from CCR-2026-0017/0018. This is authority +metadata, not a secret-data read or policy/role/KV mutation. Receipt: +`docs/evidence/2026-09-08-keycape-approval-custody-preflight.json`. + +T05 remains wait: both CCRs are still proposed, the actual upstream ID-token +issuer precondition remains open, and no verifier-side credential is provisioned. +Client-side retrieval and audit-sender custody are still separate owner returns. +The capability receipt is not a review approval or service readiness proof. + +### Sender approval recorded — 2026-09-11 + +The user replied "good, go on" to the explicit CCR-2026-0021/0022 question naming +platform-operator, audit-core-owner and both producer owners. Both exact requests +are approved; their existing State Hub decisions are resolved. This clears the +review request only. Receiver rollout, namespace readiness, attended custody and +positive/negative native evidence remain the execution gates. + +### Native receiver and attended execution return — 2026-09-11 + +Audit Core c82e0442de0f is deployed and passes the native synthetic contract. +Its existing 32-event chain/head is unchanged. The owner Approval Engine +namespace now exists and all four ESO objects pass strict server dry-run. +The two exact ingress rules are applied; sender custody/ESO application is not. + +Warden selected founder_required/oidc_login and attempted the reviewed silent +seed command through the contained wrapper. Login failed before command +handoff; no custody receipt was created. Warden could not confirm remote +session revocation. Await operator browser/MFA feedback and login/session +resolution. Approvals remain valid; T08 waits for the identity act, not review. + +The receiver check now selects component=receiver, so retained attestation-job +pods cannot falsely block a stable receiver. Eighteen custody tests pass. +[Native return](../docs/evidence/2026-09-11-factory-receiver-live.json). + +### Attended custody retry succeeded — 2026-09-11 + +The user requested a retry and completed the attended identity act. Both CCRs +are applied: independent version-1 custody and registry CAS 7→8 succeeded, +preserving other senders/fields. Warden exited 0 with self-revocation confirmed +for this session. This does not retrospectively attest the earlier failed +login's remote session state. The old login wait is cleared; T08 is progress +for ESO delivery, exact native reader/namespace refusals, receiver reload and +producer acceptance. No token is reseeded or rotated on continuation. +[Seed receipt](../docs/evidence/2026-09-11-factory-audit-sender-seed.json). + +### Delivery prepared; fresh login did not hand off — 2026-09-11 + +The delivery helper and custody receipt are committed at `44314ca` and exactly +projected on primary/railiance01. Seven delivery tests and 18 custody tests +(including 11 actual disposable OpenBao cases) pass. The fresh attended +delivery invocation exited 5 before command handoff; no native delivery +receipt exists, no ESO application or receiver restart ran. The receiver +remains 1/1 Ready on c82e0442de0f. Warden could not confirm revocation for this +failed login; that is separate from the successful seed session. T08 now waits +for this delivery identity act. Neither CCR review nor first provision reopens. + +[Delivery return](../docs/evidence/2026-09-11-factory-audit-delivery-login.json). +Use the reviewed delivery command with a new receipt after login feedback. +Actual producer ingestion/duplicate/refusal and bearer revocation acceptance +remain open under AUDIT-WP-0009-T09/T11. + +### Native delivery accepted — 2026-09-11 08:27 UTC + +The user returned and requested another login attempt. It succeeded and the +reviewed delivery command completed in 28 seconds. Both native ESO readers +passed exact-path access and explicit sibling/registry/metadata/listing denials, +wrong-SA/namespace refusal and the coding-agent deny check. Each 900-second +reader session was revoked and lookup refusal verified. Both intended +ExternalSecrets are Ready; exact producer value and ESO ownership match. The +disallowed namespace produced an explicit store restriction and no Secret; +the uniquely owned namespace is now absent. + +Registry version 8 matches the delivered receiver JSON. Audit Core reloaded +and remains 1/1 Ready on c82e0442de0f; /readyz reports operational/durable with +tamper_evidence=false, as bounded by AUDIT-WP-0009-T12. Warden exited 0 and +confirmed self-revocation for this successful session. Earlier failed login +receipts remain historical and are not retroactively attested. + +The login wait is cleared. T08 remains progress and CCR21/22 remain applied +for native producer ingestion/duplicate/scope/read-refusal and bearer +revocation acceptance under AUDIT T09/T11. No credentials were reseeded or +rotated. No producer was deployed and no factory attempt or paid call ran. +[Native delivery receipt](../docs/evidence/2026-09-11-factory-audit-delivery-live.json). + +### Native producer return — 2026-09-11 10:42 UTC + +Both actual source adapters used their own ESO-delivered credential inside a +bounded native Job. Each synthetic event received 202, retained its durable +outbox after an injected lost receipt, and received duplicate 200 after a fresh +process reopened the outbox. Each source's reconciliation reported exactly one +record for its unique probe class. Wrong source/tenant, seven archive read +routes, sibling reconciliation and invalid-bearer requests were refused. + +The first Informed Decision probe exposed a private-store startup defect: +fsGroup volumes add inherited setgid to a newly created 0700 directory. +Informed Decision `1a12223` corrects creation without repairing unsafe existing +data. The regression failed before the fix; the available suite now passes +335 tests with 39 optional checks skipped. Native retry verifies the exact +corrected helper. Six probe tests and eleven rebuilt-container checks pass, +including actual setgid-volume startup, restart/restore and cleanup. + +All temporary probe Jobs, Pods, ConfigMaps and NetworkPolicies are verified +absent. Receiver c82e0442 remains operational/durable; tamper_evidence=false. +Producer verification requires no operator registry read or new OpenBao login. +Independent readback is a separate attended command consuming the successful +receipt; it must not rerun the producer jobs. Both attended verification-login +attempts this session ended before handoff (exit 5; remote revocation +unconfirmed), so independent archive readback remains pending. + +This proves synthetic outbox delivery/recovery with native sender credentials, +not domain-transaction atomicity, deployed producer services or human binding. +An invalid bearer is not a revoked formerly valid bearer. AUDIT T09/T11 and +RPF T08 remain progress for independent readback and audit bearer-revocation +acceptance; CCR21/22 remain applied. Service/policy/human admission and native +runtime/spend gates remain separate. Factory attempts and paid calls remain 0. + +[Native producer receipt](../docs/evidence/2026-09-11-factory-native-producers.json). + + +## Independent audit readback — 2026-09-11 13:11 UTC + +The existing attended readback command completed with exit 0 while the user +was present. Independent read-only identity `operator` found both retained +`factory-audit-20260911104152-94aced` producer events with exact source and +`tenant:platform`; receiver integrity is intact across 36 events. The wrapper +confirmed this session's self-revocation and private-helper cleanup. Prior +failed sessions' unconfirmed revocation remains historical unresolved evidence. + +This supersedes the earlier readback-login wait. No producer jobs were rerun, +no credentials were reseeded and no event was written by the reader. The +inherited zero registry-read count belongs to the producer phase; the attended +reader did consume registry version 8. CCR21/22 stay applied and owner tasks +stay progress pending formerly-valid audit-bearer revocation acceptance. +Service/domain-transaction/human and factory runtime/spend admission remain +separate; factory attempts and paid model calls remain zero. + +Receipt: [native readback](../docs/evidence/2026-09-11-factory-native-readback.json). + + +### T06 native reader acceptance — 2026-09-14 + +The scoped Warden login lane `secrets-engine-approval-client-login` now routes +to the applied OIDC reader and the platform's silent preflight. The installed +Warden package still carries an older catalog; use the explicit source catalog +`WARDEN_ROUTING_CATALOG=/home/worsch/ops-warden/registry/routing/catalog.yaml` +until its next normal installation refresh. This lane authenticates the reader; +it is not a raw secret fetch or retained-file delivery interface. + +Live effective-policy and capability checks passed: only exact data/metadata +read, no sibling secret, parent listing, write or control-plane authority. +A second contained session read existing version 1 into an operator-owned 0600 +file in a private 0700 runtime tmpfs directory. The native consumer exchanged +separate read and consume scopes; Approval Engine verified the read token before +returning 404 for a fresh nonexistent approval, and refused the consume-only +token's read request with 403. No approval was created, bound or consumed. +Both Warden sessions exited 0 after self-revocation/helper cleanup; temporary +credential file and directory were removed. Four refusal/path/redirect tests +pass. Receipts are in platform `docs/evidence/2026-09-14-ccr0019-{reader-preflight,delivery-check}.json`. + +Remaining: an actual nonmember login refusal, real approval claim/consume, +separate narrow requester admission and deployed Informed Decision review with +an explicitly admitted human mandate. The reader group alone grants no review +mandate. T03 and CCR delivery activation remain open; no OpenRouter key was read. + + +### T03 scoped review deployment — 2026-09-14 + +The operator explicitly admitted `net-kingdom-admins` as the human review group +for only the T03 apply, verify and read-only key-check records, separately from +its credential-reader membership. The review service is live and ready at +https://decisions.coulomb.social with verified KeyCape groups, fresh MFA and a +dedicated caller-bound Flex Auth policy. Its mandate does not grant consumption. + +The new `secrets-engine-requester` client has subject `secrets-engine`, tenant +`tenant:platform`, role `secrets-engine-requester`, and only `approval:create`. +CCR-2026-0024 and CCR-2026-0025 provide distinct verifier and attended reader +custody. Native signature, subject, scope and TTL checks passed; excess scopes +and a wrong secret were refused. Existing consumer identity is unchanged. +Three real requested approvals were created with human control, required count +one, and zero entries. Platform evidence is +`docs/evidence/2026-09-14-t03-native-approval-requests.json`. + +Review image: sha256:8f55bcecf37a8d65f96e073510b1ffb4636c0a91d75e1ee7d582ad4bce8b953a. +Policy image: sha256:c9f028b49dfcede930a9cc48757ec8371ecc71d20b1bfee2733e55298dffcc7c. +Review tests: 339 passed, 39 optional integration tests skipped; 11 container +checks and HIGH/CRITICAL image scan passed. Policy checks: 57 local and 6 native +caller checks passed, using synthetic subjects, not human binding evidence. +Approval Engine CPU request was reduced from 25m to 10m after observing 1m use; +review requests 20m and its PDP 5m. Limits are unchanged. Native services ready. + +Remaining T03 gate: the operator's exact signed-in account is needed to address +three prepared immutable memos, followed by real acknowledgements and acceptance +in Informed Decision. No human entry or consume has been generated by an agent. +Then execute claim -> validated PDP Check -> CAS consume separately for apply, +verify and exec using scoped attended authority, and capture native denial, +revocation, workload health and key-check evidence. No OpenRouter credential has +been read and no inference or spend was performed. T03 remains waiting; this +entry supersedes earlier statements that requester or group admission is missing. + +### 2026-09-27 T02/T07 source follow-up + +T02 now has the exact proposed RS256 configuration, bounded JWT role and +self-only policy in `openbao/`. Operator correction: platform infrastructure +belongs to `tenant:platform`; KeyCape registration and consumer preflight are +corrected together. Existing live registrations must be migrated and verified. +Public discovery confirms issuer/JWKS/token endpoint. Registration/custody, +attended provisioning and live rejection/cleanup evidence remain required; +T02 stays wait. No service credential or backend entitlement was issued. + +T07 consumed the confirmed legacy consumer return. The stale value-comparison +ask is removed. WARDEN-WP-0037-T03's no-rotation hold stays in force until the +governed native migration is evidenced. Legacy destruction follows migration; +neither source reconciliation nor the historical pilot is that evidence. + +## Loose-end review — 2026-09-27 + +T08 now explicitly waits for formerly-valid audit-bearer revocation acceptance from AUDIT-WP-0009-T09/T11. Native delivery, producer checks and independent readback already passed; do not reopen login, seed or review gates. T02/T03/T06/T07 retain their latest exact service registration, signed-in human acceptance, owner delivery/disposition and governed-consumer migration dependencies. No credential value was read or changed. + +## Founder approval of the CCR-2026-0033 custody child + +```task +id: RPF-WP-0035-T09 +status: done +needs_human: false +priority: high +decision_id: 2ab717e1-7881-491e-aed4-28946550c289 +depends_on: [] +state_hub_task_id: "7c753be6-42f1-58a6-a4a4-a7ed686f461f" +``` + +Packets: `credential-change-requests/CCR-2026-0033.yaml` (custody child, KV +metadata, issuer ESO reader, live_order, rollback) and `CCR-2026-0034.yaml` +(attended operator OIDC reader, in-memory, 5m/4 uses). Revised 2026-10-06 per +founder direction; the consumer file is removed. Exact founder commands: +`docs/provisioning-windows/2026-10-04-1000/keycape/founder-runbook.md`. Live +order: custody child → platform applies policies/roles/ESO (Secret +sso/keycape-secrets-engine-openbao-client exists) → NetKingdom env patch +(NK-WP-0046) → KeyCape registration merge (KEY-WP-0037-T03) → KeyCape restart +immediately → live issuance check (KEY-WP-0037-T04) → OpenBao JWT role/login +proof (RPF-WP-0035-T02). Each live step after the custody run needs its own go. + + +2026-10-11 evidence reconciliation: T09's approval obligation is complete. +Authoritative founder decision 2ab717e1-7881-491e-aed4-28946550c289 is resolved, +decided by Bernd Worsch at2026-10-06T13:07:18.627943Z, and explicitly covers +A1 design, A2 CCR33/CCR34 plus owner reviews/bound claims, and A3 one custody run. +The approval comments in both CCRs record those exact grants; both source records +are applied. MASON-WP-0009-T02/T03 additionally record the October8 approval/owner-delivery +reconciliation and reference KeyCape +`docs/evidence/2026-10-07-secrets-engine-openbao-issuance.json`. Closing this approval task clears +its obsolete human gate. It grants no new run, credential access, rotation or +service execution: RPF35T02/T12, MASON9T05 and SECRETS8T06 retain their actual +native/adoption obligations. Historical per-step exclusions remain above. + +## Retire the approval-engine-operator client delivery and custody (CCR-2026-0018) + +```task +id: RPF-WP-0035-T10 +status: wait +priority: medium +blocked_on: message-from:approval-engine +blocking_reason: "Blue lane under the standing change rule (removing access, with reviewed order, rollback and receipts): executes once approval-engine confirms there is no presenter. No founder window needed." +state_hub_task_id: "af2d4dba-f83a-5819-9a8b-671bae799364" +``` + +2026-10-11: access removal is blue lane (canon build-mode-change-authorization_v0.1); no founder window. + +key-cape proposed a joint disablement on 2026-10-10 (message `7f2128fb`). +Precondition: approval-engine reconfirms there is no presenter. The order is the +reverse of provisioning, so KeyCape never starts with a client whose secret is +missing. key-cape removes the registration and restarts (1), checks that +`invalid_client` is returned (2), and net-kingdom removes +`KEYCAPE_APPROVAL_ENGINE_OPERATOR_CLIENT_SECRET` from Deployment `sso/keycape` +(3). Platform steps, amended from the proposal: + +4. **Delivery.** In one commit, remove ExternalSecret + `sso/keycape-approval-engine-operator-client` from + `argocd/platform-addons/openbao-secretstore/keycape-approval-clients.externalsecrets.yaml` + and ClusterSecretStore `openbao-keycape-approval-engine-operator` from + `openbao-keycape-approval-clients.clustersecretstore.yaml`. Keep the + secrets-engine-approval objects. Then bump `targetRevision` of + `argocd/railiance01/applications/openbao-secretstore.application.yaml`. + The app is pinned and has no automated sync, so nothing changes live until + an attended `argocd app sync openbao-secretstore --prune` runs after step 3. + Verify, value-free, that the ExternalSecret, the store and Secret + `sso/keycape-approval-engine-operator-client` are gone. The target is + `creationPolicy: Owner` and `deletionPolicy: Retain`, so the Secret should + follow its owner; delete it explicitly if it does not. Then delete OpenBao + role `auth/kubernetes/role/external-secrets-keycape-approval-engine-operator` + and policy `workload-kv-read-keycape-approval-engine-operator`, and remove + their source files. Also remove policy + `workload-kv-read-approval-engine-operator-client` (CCR-2026-0020, cancelled) + if it exists live. +5. **Custody.** Run the metadata delete of + `platform/workloads/approval-engine/operator-client`, the destruction + foreseen in `docs/credential-lane-designs/keycape-approval-clients.md`. A + disabled client's secret has no recovery value; a narrowed successor gets a + fresh secret through the mint-secret lane at `platform/workloads/keycape/`. + Only after step 2's `invalid_client` receipt. Keep the agent boundary denies + for that path until the delete is verified, then drop them. + +2026-10-10: key-cape agreed the amended steps 4 and 5 (message `59304e33`, +KEY-WP-0013 c528daa). Waits on approval-engine confirming there is no presenter, +and on the founder's window. + +The manifest edits wait for the scheduled window, so a stray `targetRevision` +bump cannot remove KeyCape's secret before step 3. + + +## Complete independent service-JWT source preparation and execution design + +```task +id: RPF-WP-0035-T11 +status: done +priority: high +state_hub_task_id: "7952c8cd-c066-5b72-a025-78d24341c1ab" +``` + +2026-10-11: Platform-scoped agent loaded this checkout's AGENTS.md and INTENT, +RPF35-T02, actual CCR38/login contract/typed applier and Secrets Engine's native +claim/PDP/CAS/provider/apply flow. Frozen Secrets v2 manifest and all named staged +bytes/proof were hash-verified. Independent tests reproduced three source +counterexamples while retaining the frozen files: close exception can coexist +with native_verified=true; successful result needs no source/session fingerprints; +HTTP200 mixed errors+data envelope is accepted. Original 37 tests plus the three +counterexample tests pass (40 cases, synthetic/local only). Proposed owner design +`docs/credential-lane-designs/secrets-engine-task-execution-entitlement.md` binds +an explicit metadata-only execute-ccr action, immutable typed owner bodies, +CAS/journal replay control, 120s/12-use owner-held task token, independent payload +validation, native ACL endpoint bounds, revoke/readback and recovery. This completed +preparation record is established before the formal source review. It grants no +live authority and does not close T02 or represent acceptance by another owner. +Formal review artifact follows under this work item; all implementation/live +obligations are retained in T12 and existing T02 rather than a finished residual. + +## Implement and prove the separately approved task execution entitlement + +```task +id: RPF-WP-0035-T12 +status: progress +priority: high +depends_on: [RPF-WP-0035-T11] +state_hub_task_id: "914bf383-c13f-5247-9af0-91d7e3a4784a" +``` + +Review the proposed task-execution-grant schema and exact metadata-only execute-ccr +backend with Secrets Engine/access-engine/approval-engine; implement trusted service +subject and served consume verification, durable one-shot reservation, bounded +owner-held token issuer/middleware and exact source/payload enforcement. Obtain +separate exact founder approval/attendance before provisioning or live actions. +Prove disposable intended result and identity/action/target/body/time/replay/crash/ +cleanup negatives, and return owner-native acceptance. Existing service login policy +and defaults stay unchanged. T02 still owns login/claim/TTL/use/MASON acceptance; +Secrets T06 separately owns dispatcher adoption and steady-state default migration. + + +2026-10-16 T12 wave 5 source preparation: disposable adapter now binds owner +canonical before/after metadata snapshots to existing descriptor hashes, rejects +per-target baseline/readback mismatch, and records readback/verified evidence. +Mediator reports cleanup-confirmed only after independent fixed cleanup receipts. +Complete role metadata and policy name/HCL/version/cas are compared; validated +modification timestamp alone is excluded. This is sequential fixture acceptance, +not aggregate CAS, concurrent-writer exclusion or native production completion. +Role conflict may follow a policy write. Restart refuses dispatch and cannot +recover memory-only token/accessor cleanup handles. T12 remains progress; actual +fresh CCR/catalog/grant, source/trust/caller/policy admission, isolated owner custody, +scoped recovery and attended native acceptance remain explicit prerequisites. + + +2026-10-11 T11 refinement (same source-review trial): the exact Secrets Engine +v3 manifest `6bb05bac74e4939c3e42db2ae95c5f9fb4616bb20cc285811a315c26669ebce1` +and all named bytes/proof were verified and independently re-reviewed. The three +v2 counterexamples are corrected: close exceptions cannot pass through stale true +flags, complete typed source/session/attempted/revoke evidence is required, and +mixed HTTP200 errors/data fails closed. 49 maker/current-provider tests plus three +independent regressions passed (52, synthetic/local only). Platform source review +`docs/reviews/2026-10-11-secrets-service-jwt-v3-platform-review.json` approves only +the corrected boundary verifier and truthful packet. Prior changes-requested v2 +review is retained; this is not a second native success or changed authority. +No native or founder go is granted. T02, T12 and Secrets T06 remain open; the +metadata-only execute-ccr pilot is explicitly insufficient for generic lifecycle +adoption. All consume-verification/journal/action/body/backend implementation and +native acceptance gates remain real prerequisites, not architecture promises. + + +2026-10-11 T11 readiness refinement: independently reviewed frozen consumer +manifest `709b9dddd1c8f00a995b1ff14264323fbe080ed95df244270ce9607528878fa7`. +Platform source review `docs/reviews/2026-10-11-secrets-execution-readiness-v2-platform-review.json` +approves the local fail-closed guard and proposed consumer contract direction only. +All ten current protected backend handlers pass provider args through readiness +before authorization/consume; session revoke checks before handle reads. Configured +auto/explicit service-jwt therefore cannot burn a protected-action approval or +open the insufficient login-self backend. Explicit env/bootstrap and self-only +probes retain their existing contracts; local compromise/reactivate and disabled +destroy remain separate. Existing ambient-token route readiness reads are unchanged, +not claimed governed by this guard. 58 isolated tests passed: original36 plus20 +provider/action cases, handler enumeration and actual session-revoke ordering. +Prior v2 changes-requested and v3 boundary source reviews remain unchanged, same +T11 trial. No runtime grant, native acceptance, new Access/Approval semantics, +backend entitlement or full Lifecycle adoption is approved. T02/T12/SecretsT06 and +WP13 implementation/native gates remain open; the metadata pilot substitutes for +none of the ordinary generic lifecycle outcomes. + + +## Complete independent KEY39 v4 lifecycle source review preparation + +```task +id: RPF-WP-0035-T13 +status: done +priority: high +state_hub_task_id: "8f6966fa-6e9a-58b2-8b40-c47340ec19d1" +``` + +2026-10-11: Platform agent loaded its owner instructions/INTENT and RPF35-T02, +actual applied CCR38, exact native role/policy source and frozen KEY39 lifecycle +v4 manifest `d079f85c47d5c2635e1ee633ea4d1346b1737ce2be9ca273f22a38e620f418d8`. +All staged entry hashes were verified without changing the reviewed inputs. +Source role omits expiration_leeway: its observed actual default must be confirmed +natively, with -1→0 and 0→150 normalization preserved as a bounded model. Source +claims and login-only policy are unchanged. The supplied 41 lifecycle tests pass; +five independent cases also pass, including a new exceptional-response-close +elapsed-bound counterexample and four current-leeway normalization checks. +A 10ms HTTP request can take over70ms because exceptional finally response.close +runs outside the hard elapsed timer. Unknown native login is correctly recorded, +but source total elapsed enforcement is incomplete. This completed owner +preparation record exists before the formal exact source review entry. No +credential was requested/read, native action run, owner checkout edited or native +session grant inherited. T02 retains native role/policy/leeway, negative claims, +cleanup acceptance and MASON gates; KEY39 producer handoff and founder attendance +remain prerequisites. Source correction/re-review is required, not a native success. + + +2026-10-11 T13 correction preparation (same trial): exact KEY39 v5 manifest +`d1f997624db46693a7126a6eb6435f6b3a353d5bd67dcc8a539683e4b7147285` +and all entry hashes verified. The v4 exceptional-close finding is addressed: +one 20ms abort is clipped to original remaining time and the nonresettable +aggregate cleanup budget; zero calls after aggregate expiry; failed abort stays +unconfirmed/unknown with signal state restored. 46 supplied lifecycle checks and +five independent regressions pass; the unchanged runner's earlier17 tests remain +valid against identical source SHA. Existing T13 preparation record is retained +before the formal v5 exact source review. V4 changes-requested review and earlier +failed history remain retained, with no native success, inherited grant or scope +promotion. Actual private producer admission, fresh installed role/leeway/policy +observation, authenticated founder window and native refusal/cleanup remain gates. + + +2026-10-11 T11 journal preparation refinement (source-only): independently +inspected frozen root-maker v2 manifest +`341cac1de945d2fbe8f516119909bd44fc37e85dccfb38b451981d4de2d402e7`, +verified all input hashes, and ran14 supplied tests plus5 independent checks. +The actual four-process race admits once; a separately forked process exiting +immediately after pending intent leaves durable unknown/nonresumable state. +Private SQLite modes, lock admission and binding/replay protections remain guarded. +Three independent counterexamples show after_call accepts False,0.0 or text'0' +as persisted integer ordinal0, contrary to before_call's exact integer validation. +Completed preparation under this existing done ownerT11 record precedes formal +review; require identical ordinal/call-digest validation before confirmation so +malformed calls cannot clear pending outcome. RPF35-T12 retains caller/PDP/consume +validation, exact body compiler/adapter and owner-private cleanup/recovery after +unknown; this unintegrated primitive proves none of those or full contract/native +acceptance. Inputs/prior reviews are preserved; no privileged/native action occurred. + + +2026-10-11 T11 journal v3 correction preparation (same trial): frozen manifest +`905ff6666d05df6a19d165a535579d917d7de31a43e066c2afc34a57e8cbdc9d` +verified against every file. Strict after_call integer0..63 and64hex string digest +validation now precedes SQLite confirmation; False,0.0 or text'0' cannot clear +pending external outcome.15 supplied tests plus5 independent regressions pass, +including realfork abrupt exit after durable intent and privatefile checks. +This existing completed ownerT11 refinement precedes the formal corrected-source +review. Prior v2 refusal is retained; no extra success/authority trial is counted. +Acceptance is only unintegrated journal source. Actual caller/PDP/consume validation, +independently compiled body/ordinal plan, restricted adapter, owner-private unknown +cleanup recovery and native/whole-contract adoption remain live RPF35-T12 gates. + + +2026-10-11 T13 node-route source preparation refinement (same trial): exact +successor manifest `23a972abc5175e121e594726d2b7f7a28c62109253f58f12623eaf2e5564a035` +verified against all entries. Platform Service openbao-ui-gateway8080 and its +nginx /v1 proxy agree with the proposed bounded founder-held node port-forward; +workstation tunnel/DNS assumptions are not reused as node evidence.54 supplied +lifecycle/route checks plus6 independent public-health/abort checks pass, offline. +Initial execute/recovery health pin and repeated pre-create check fail before +native/Secret effects; public-preflight reads neither stdin nor Kubernetes. +Completed ownT13 preparation precedes this fresh exact source review, not reuse +of v5 acknowledgment. Main execute currently reads private stdin before execute's +health gate; the packet's pre-token-input phrase is not accepted. Private producer +handoff must preserve actual ordering or move the health gate before credential +input when implemented. Public cluster digest detects drift, not authenticated +estate identity. No route was opened or observed; no source packet authenticates +a founder approval. Native role/plugin version and raw/effective expiration, +clock-skew and not-before leeways require actual owner observation/semantic proof. +Issuer readiness_state/Argo ownership is not established by the inspected source; +unmapped means production-tier. If adopted/production-approved, temporary direct +CAS requires an explicit reviewed one-use maintenance exception and close-down +entry, plus reconciliation, before native go. No helper/source acknowledgment +waives that gate. Private token producer/callback/client/custody admission and +actual native negative/revoke/restoration/cleanup remain prerequisites. + + +2026-10-11 T13 v7 node-route preparation refinement (same trial): exact frozen +manifest `90aabec336008d7d51e37c04b5ff96ba8ed6630821cca1a4c333d803367247f7` +and all entries verified.58 supplied lifecycle/route checks plus9 independent +checks pass offline. Actual main now verifies source/public health before private +stdin; execute preserves the original wall/monotonic window rather than renewing +it. Actual child-process partial-pipe counterexample shows unbounded stdin.read +remains blocked beyond a synthetic20ms original window (still alive after100ms +without EOF). No credential/native/provider access is involved. Before private +producer admission, require byte-capped, deadline-bounded JSON input and EOF within +the original window, with fail-closed fixed receipt and no protected effects. +This completed ownT13 preparation precedes formal v7 source changes-requested +review. Retain v6 qualified health-gate agreement and all prior reviews; neither +v7 health ordering nor any source acknowledgment establishes custody completion, +actual route/plugin/leeway/readiness/Argo identity or founder/runtime authority. +Native and private-producer gates remain open; no owner checkout write occurred. + + +2026-10-11 T13 v8 bounded-input correction preparation (same trial): exact +frozen manifest `316fd6005cc4cb7fe14ea69a5fd408aed13e6122afef60afd13d97952b27cf4a` +and all entry hashes verified.65 supplied tests plus12 fresh independent checks +pass offline, including a standard buffered stdin pipe with complete JSON/noEOF +interrupted within original20ms window and restored SIGALRM state; exact64KiB +JSON/EOF accepted and extra byte refused, UTF8 token bytecap enforced, original +wall deadline clips longer monotonic budget. Original preinput window is retained. +Completed ownT13 preparation precedes fresh exact source review; v7 refusal and +v6 qualified agreement/prior reviews retained. This accepts child bounded-input +source only. No parent-ready handshake exists: producer must not eagerly pipe +private inputs, and producer/session/window readiness protocol remains an +unimplemented admission gate. No custody/native completion, sourcepacket approval +authentication, route/plugin/leeway/readiness/Argo observation or inherited grant. +Native prerequisites and producer handoff remain open; no owner checkout changed. + + +2026-10-11 T11 journal v4 canonical-format preparation refinement (same trial): +exact frozen manifest `22c6d225d393b994ab7b44a43904ced1b6d7f74e0e2bebf71ffe99f87191ef4c` +and entry hashes verified. Actual access-engine pkg/api/canonical.go RequestDigest/ +CanonicalDigest, Approval binding.py and Secrets authorization/approval_consume +all use sha256:<64 lowercase hex> request digests. V4 now preserves this exact +request value without prefix stripping; plan/call/evidence content hashes remain +explicit bare64hex.15 supplied checks plus15 fresh independent checks pass, +including malformed prefix/bare/uppercase/trailing whitespace refusal before +reservation, exact persistent value/reopen/mismatch replay, private-file mode, +real child crash after pending intent, ill-typed confirmations and pending-unknown +refusal. Completed ownT11 preparation precedes formal v4 source review; prior v2 +refusal/v3 approval and T13 v7 refusal/v8 source acknowledgment retained. +Acceptance is unintegrated primitive source only; no data migration/native use +of v3 journal has occurred. RPF35-T12 caller/PDP/consume validation, independent +owner plan compiler/restricted adapter, private runtime custody, bounded execution +and owner-private unknown cleanup recovery remain open. No checkout/native writes. + + +2026-10-11 T13 paired ready-child/launcher preparation refinement (same trial): +exact NetV9 manifest `84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14` +and KeyproducerV2 `55a8e794af983ca2202e7a0054d0415a120d2c95018fb03fdb5f28313a109d58` +verified against all entries.74 Net checks plus31 Key checks and10 independent +checks pass offline including a truthful-unknown counterexample: adapter uncertain +private delivery with confirmed=false is copied into launcher receipt, but +consumer_outcome_unknown incorrectly remains false after local SSH teardown. +Complete bytes may have reached remote child before adapter timeout/EOF; local +terminate does not establish remote no-effects. Require sticky propagation of +uncertain delivery into consumer outcome before early return, retain unknown +unless independently established native outcome/recovery. Bad markers/source +pins/injection reject before private reads; extra marker authority/lines reject; +prohibited child output never forwards. Child-ready synchronization is not +authentication/approval. Proposed founder directSSH profile is incompatible with +warden quiet-output lane and not admitted here. Completed ownT13 preparation +precedes formal paired source review; preserve v7 refusal/v8 acknowledgment and +journal histories. No transport grant, coding-agent/private custody admission, +live SSH, credential/native action or owner checkout write. All native role/plugin/ +leeway/route/issuer readiness/Argo/maintenanceexception gates remain prerequisites. + + +2026-10-11 T13 paired producerV4 correction preparation (same trial): exact +producer manifest `d6f641dc1e4aae7d36658d4199d89af14d2fd7a4bd4e526856eb340234f2d33e` +and unchanged NetV9 `84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14` +entry hashes verified.74 Net tests,40 producer checks,9 actual local fakeSSH/ +realwrapper/child synthetic roundtrip regressions and12 fresh Platform checks +pass (135 total). V2 deliveryunknown now remains sticky consumerunknown with +completion=false after earlyreturn/localteardown. V3 Net FIFO acquisition finding +and originalbudgetreset are corrected: actualCLI starts original5s timer before +regular/nofollow/bytebounded contract acquisition, each later preparation phase +clips remaining time. ActualCLI FIFO refuses promptly; expired original budget +never validates/spawns/reads private files. Completed ownT13 preparation precedes +formal corrected pair source agreement. Preserve V2 Platform refusal, Key old +exactV2 acknowledgment and NetV3 refusal; no old acknowledgment repinned. +Agreement is only reviewed source synchronization/launcher behavior, not admission. +Founder authenticated SSH host/profile/channel/runtime pins, exclusive sameUID +file custody and explicit tmpfs file allowance/cleanup, verified human and +coding-agent producer/client/source, native role/plugin/leeway/route/issuer +readiness/Argo/maintenanceexception, refusal/revoke/restoration/readback and +unknown owner recovery remain prerequisites. Warden quietlane cannot carry ready +controlstdout; no transport/custody/native grant. No owner checkout/liveSSH/native. + + +2026-10-11 RPF35-T12 source implementation progress: durable journal source v4 +was independently accepted/committed; owner-derived typed plan compiler component +v2 is prepared at immutable manifest +`41cda74ab32384c789ea8a760475671aadad4e5121335c8f60567ff53d66665b` +with40 offline tests. Completed own bounded source-preparation ADHOCT02 anchor +was persisted at7adbcb4 before the qualified Platform contract/readiness receipt. +T12 progresses for actual source implementation underway, not native acceptance +or full descriptor/authority readiness. The compiler derives local CCR/HCL/role +bodies, matches actual independently pinned Secrets catalogue and revalidates +source/body before fixed calls; no body/target chosen by service is dispatched. +Independent technical integration review and exact full ExecutionContract/owner +grant/baseline/estate/deadline matching, initiating human/User/Tenant PIP/transport +representation/service identity, served PDP/claim/consume correspondence, journal +call dispatch/restricted adapter, native token TTL/uses/custody/revoke/cleanup and +owner-private unknown recovery remain unimplemented integration/native gates. +Actual CCR42 has no eligible approved pilot/catalogue; no source metadata is +invented. T02 and original negative/capability/native evidence remain unchanged; +T11/T13 history retained, no defaultflip/nativego or SecretsT06 closure follows. + + +2026-10-13 T12 source correction: the compiler hashed the catalogue sources but +used cached Python modules with matching paths, which did not establish executing +those exact bytes. A failing regression reproduced the substitution. Catalogue, +package and dependencies now execute from the verified snapshot in temporary +private modules; ambient modules remain untouched and cleanup runs on refusal. +45 compiler plus 15 journal tests pass. The v2 source review remains historical; +this change needs its own integration review. T12 retains all existing full +contract, identity/consume, dispatch, custody and native acceptance requirements. +RPF-IN-0012 remains open for the independent contract/wrapped-delivery return; +this code correction does not authorize either operation. + +2026-10-16 T12 source preparation (isolated owner checkout; not owner delivery): +added durable precommitted cleanup obligations and separate outcome evidence to +the existing Journal, plus a fixed three-method owner cleanup driver. Same live +postconsume admission can clean after a business timeout/failed/unknown outcome; +cleanup closes business dispatch and cannot replay or restore admission after a +crash. Empty obligations no longer produce cleanup-confirmed. Real SQLite +multiprocess races and abrupt process death before/after a separately durable +synthetic effect verify refusal on reopen. Current compiler/journal/cleanup suite: +73 passed, local source/fixture only. Details: docs/task-execution-cleanup.md. +No native adapter or production mediator exists; full grant/request/cleanup binding, +authenticated consume/identity, ephemeral token issuance, deadline/use checks, +native effect/revoke/absence, audit and protected recovery remain prerequisites. +T12 remains progress. No CCR38 default/entitlement or live grant was changed. + +2026-10-16 T12 second source package: Compiler Plans now bind deterministic cleanup +commitments and can bind the complete independently installed engine execution +descriptor. A fixed disposable-loopback native adapter actually materializes exact +per-operation metadata ACL/task token, executes six source-derived metadata calls, +and verifies self-revocation/accessor invalidation and policy retirement. Each +cleanup request has its own durable intent. Native fault tests cover lost response +after real write and policy deletion while task revoke fails. All initiating +identity/approval/consume/grant/state/source admission in this fixture is synthetic; +no production authority or complete native owner acceptance is claimed. Exact +remaining owner schema/admission and mediator work: docs/task-execution-native-fixture.md. +T12 stays progress; no live grant, credential/default change or owner sync performed. + +2026-10-16 T12 third source package: implemented proposed task-execution-grant +immutable projection and exact compiler/native-fixture integration through the +existing descriptor grant ID/SHA fields. Only typed review.comments/evidence.events +are excluded; separate append-only checks reject removal/rewrite/reordering and +unknown guessed evidence exclusions refuse. Owner-pinned grant bytes and validator +source must match independently reconstructed descriptor/source/cleanup/ACL/token +bodies before a native fixture can materialize. Proposed source records gain no +execution authority; no real grant, policy or legacy applier registration added. +Details and remaining production gates: docs/task-execution-grant-projection.md. +T12 remains progress; no owner sync or production effect performed by this package. + +2026-10-16 T12 fourth source package: connected the Secrets-owned strict task +handoff to actual Approval ExecutionConfirmationClient independent GET before +consume-confirmed/native fixture work. Platform accepts no supplied authorization +boolean/object/callback and preserves its exact owner descriptor/grant/Plan join. +Durable CAS/GET intents precede native ordinals through the repaired journal +prefix API. Actual source-server fixture uses signed Access/enforced synthetic +TokenReview, real Approval WSGI/SQLite with distinct synthetic human/service +identities, actual strict Secrets signature/CAS validation and disposable native +OpenBao. Untouched actual task policy remains signed DENY; separately named +synthetic fixture policy is never production admission. Read-scope denial after +CAS records consumed/unknown with zero native effects. Exact dependency/source +hashes, tests and remaining gates are retained with the source package and in +docs/task-execution-mediator-seam.md. No real grant/custody, policy default, owner +sync or native production acceptance is performed; T12 stays progress. + +2026-10-16 T12 recovery successor source preparation: optional independently +installed fixture custody durably retains operation-bound private accessors and +issuance checkpoints. Fresh cleanup-only owner permits can reconcile after actual +executor process death using fixed revoke/readback and policy delete/readback, +without restoring business/consume admission. Separate durable attempt evidence +retains original unknown outcomes. Lost token-create response remains unresolved +when no accessor was committed. Source-only process-loss fixtures are not native +production custody or recovery-role admission; T12 remains progress. + +2026-10-16 T12 recovery R2 source refinement retains R1's overbroad 404 failure: +policy cleanup now requires exact native empty-errors absence before/after delete; +HCL uses only documented single optional terminal LF normalization. Private +capsules are owner-key HMAC authenticated, strict nested schemas/ordered cleanup +commitments reject damage, and journal history prevents stale prepared capsules +from hiding issuance. Fixture process-loss source proof remains separate from +unadmitted production custody, integrity-key storage and recovery-role scope. + +2026-10-16 T12 independently reviewable budget/source slice: bound native HTTP +header/body/close, compiler work and cleanup through fixed owner main-thread +absolute budgets, with actual task expiry narrowing global authority. Actual v2 +mediator now verifies each independently installed source_bundle byte hash before +authorization/effects. No deadline/TTL extension, remint or generic service added. +Retained registry actual-provider proof still refuses Approval correspondence +before CAS/native; normalized pre-approval + precise immediate CAS whole-stack +positive remains live owner follow-up under CUST-WP-0080. T12 stays progress. + +2026-10-16 T12 actual v2 successor source proof: retained registry signed DENY +normalization from the real Secrets prepare_task_approval builder precedes actual +Approval issue/human approval. Actual Access v2 then signs ALLOW; strict Secrets +CAS and independent confirmation GET precede six disposable native calls, exact +readback and confirmed token/policy cleanup. Approval precision source permits +immediate CAS without sleeps/backdating. The 60-second immutable deadline, +30-second backend TTL, 120-second synthetic observation and existing cleanup +reserve remain bound; issued credential expiry narrows business time. Source, +caller, revoke, source-reader, registry drift and expiry refusals cause no native +effects; revoke between ALLOW/CAS retains unknown without business dispatch. +This owner fixture uses separately installed synthetic identity/key/trust and +loopback OpenBao, grants no production authority and keeps T12 progress. Prior +failed temporal/normalization proofs remain retained. + +2026-10-16 T12 signer custody R3 source preparation rebases the proposal to +integrated Access919ce25 and preserves current workplan state. Added protected +in-memory Ed25519 CAS/readback primitive with durable closed metadata receipts +and fixed disposable-only owner adapter. Actual synthetic OpenBao bootstrap, +rotation, conflict/unknown/readback/receipt/private-output and admission failures +are tested. Production direct entry refuses: exact CCR/founder scope, protected +executor/fencing/receipt custody, independent consumer public admission, migration +debt and native deployment prerequisites remain open. No live key/grant or CCR +admission; RPF-WP-0035-T12 remains progress. + +R3 source metadata correction aligns proposal IDs across JSON/docs/Secret +annotation and documents existing base64url-ASCII public fingerprint hashing. +Frozen R2 source/evidence is preserved; no writer behavior or admission changes. + +2026-10-16 T12 native signer preparation: proposed CCR-2026-0050 and generated +read-only HCL pass real schema checks; current proposed status/unconfirmed claims +keep apply refused. Native candidate uses existing external-secrets-* role +convention with dedicated SA unchanged and projected private field only. Exact +attended CAS0/metadata/fence/receipt/forward-recovery action plan is separate from +read-grant authority; production adapter implementation/independent tests and +founder plus distinct owner reviews remain necessary. Access observed zero PVCs; +new outbox storage/retention/runtime bounds remain separate Access/cluster scope. +No live credentials, grants, roles, key or deployment changed. T12 stays progress. diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/routing-blocker.json b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/routing-blocker.json new file mode 100644 index 00000000..c6ebf45a --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/routing-blocker.json @@ -0,0 +1,12 @@ +{ + "command": "warden plan \"attended OpenBao platform administration for reviewed flex-auth signer custody CAS0 and fixed KV metadata\" --json", + "observed_lane_id": "openbao-structure-survey", + "observed_verdict": "founder_required", + "observed_founder_act": "approve", + "required_lane_id": "openbao-platform-admin-login", + "required_founder_act": "oidc_login", + "catalog_source": "wheel-bundled fallback", + "package_version": "0.1.2", + "catalog_content_hash": "c47065c0892f", + "action": "reported to coordinator; execution remains refused; no credential-path workaround" +} diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/validation.json b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/validation.json new file mode 100644 index 00000000..aa318646 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r1/validation.json @@ -0,0 +1,49 @@ +{ + "patch_sha256": "f316a53b604f4333414b832691968ede8056d49a61635f0f25831084b1d75f19", + "checks": [ + { + "command": "SECRETS_ENGINE_SOURCE_ROOT=/tmp/netkingdom-secrets-trusted-successor PYTHONPATH=/tmp/netkingdom-secrets-trusted-successor/src pytest -q tests/test_flex_auth_signer_native.py tests/test_flex_auth_signer_custody.py tests/test_flex_auth_signer_native_preparation.py", + "result": "43 passed in 31.09s", + "stage": "final implementation; before adding separate fixed HTTP transport test" + }, + { + "command": "same environment pytest -q tests/test_flex_auth_signer_native.py::test_native_fixed_http_transport_against_disposable_backend", + "result": "1 passed in 0.83s", + "stage": "final test file; exact frozen source" + }, + { + "command": "git apply --check implementation.patch on exact preimages/new-file absence", + "result": "pass" + } + ], + "history": [ + { + "result": "6 failed30passed; Path abstract-class exact-type check rejected PosixPath", + "fix": "require concrete pathlib instance; no authority weakening" + }, + { + "result": "1 failed38passed; denied-read test fault omitted version query suffix", + "fix": "fault exact versioned GET too; no verifier changes" + }, + { + "result": "43passed31.40s", + "stage": "before exact selected receipt-directory check" + } + ], + "proof_scope": [ + "actual fresh disposable KV v2 metadata/CAS0/readback through native production state machine", + "real fork executor process death after actual native CAS; fresh read-only reconciliation preserves original unknown; no POST/remint", + "strict admission/source/image/caller/trust/routing/identity/fence refusals; mid-setup new pod blocks seed CAS", + "damaged and type-damaged receipts/current-version drift/denied read/no fresh review refuse recovery", + "exclusive custody window and operation/recovery replay refusal", + "absolute2s tool timeout/1MiB output bounds and silent failures", + "fixed native HTTP path/status/body handling against disposable backend; socket port redirected only by test" + ], + "synthetic_only": [ + "owner review dispositions", + "founder identity/session", + "Kubernetes fence and deployment observations", + "native transport fixture endpoint redirection" + ], + "live_credentials_grants_deployments": false +} diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/README.md b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/README.md new file mode 100644 index 00000000..05b902ba --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/README.md @@ -0,0 +1,20 @@ +# Native signer adapter R2 + +Frozen R1 and its counterexample remain unchanged. Apply r1-to-r2.patch afterR1, +or implementation-r2.patch after canonical7be8b6e plus native-preparationR1. +Both have exact source/preimages and apply-check receipts in manifest.json. + +R2 closes metadata-only process-loss recovery, without new write/retry authority. +Exact current absence or metadata0/data absence has no key/public admission and +requires a new independently reviewed action. Ambiguous/denied reads remain +unconfirmed. Original uncertainty is preserved. New recover admissions explicitly +bind original_execution as well as the current source bundle. + +The native plan current primitive hash now agrees with actual executed core; +the previous pin is historical, and checked_sources enforces the current join. +No self-reference is introduced: the plan names the primitive, while an external +admission pins the complete executor source bundle. + +120seconds is unchanged. Detailed scheduling assessment and unchanged refusal +requirements are in the source document. Source review/native inputs and reviews +remain distinct; no credential, key, grant, role or deployment was changed live. diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/implementation-r2.patch b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/implementation-r2.patch new file mode 100644 index 00000000..845edf7f --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/implementation-r2.patch @@ -0,0 +1,1002 @@ +--- a/scripts/flex_auth_signer_custody.py ++++ b/scripts/flex_auth_signer_custody.py +@@ -58,6 +58,10 @@ + or '-dev' not in process.args or '-dev-no-store-token' not in process.args + or '-dev-listen-address=127.0.0.1:'+str(admission.port) not in process.args): + raise Refused('live owner-spawned disposable dev process required') ++ self.admission=admission ++ self._initialize_receipt(directory,operation_id,kid=kid,expected_version=expected_version,bindings=bindings) ++ ++ def _initialize_receipt(self,directory,operation_id,*,kid,expected_version,bindings): + if (type(operation_id) is not str or not re.fullmatch(r'[a-zA-Z0-9_-]{1,80}',operation_id) + or type(kid) is not str or not re.fullmatch(r'[a-zA-Z0-9_-]{1,80}',kid) + or type(expected_version) is not int or not 0<=expected_version<2**31 +@@ -66,7 +70,7 @@ + raise Refused('exact signer operation contract required') + if directory.absolute()!=directory.resolve() or directory.is_symlink():raise Refused('indirect receipt custody refused') + Journal._private(directory.stat(),directory=True) +- self.admission=admission;self.directory=directory;self.path=directory/(operation_id+'.json') ++ self.directory=directory;self.path=directory/(operation_id+'.json') + self.expected_version=expected_version;self.kid=kid;self.attempted=False + self.receipt={'schema':'railiance-platform.signer-cas-receipt.v1','operation_id':operation_id, + 'bindings':dict(bindings),'writer_sha256':'sha256:'+hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), +diff --git a/scripts/flex_auth_signer_native.py b/scripts/flex_auth_signer_native.py +new file mode 100644 +index 0000000..c8cf934 +--- /dev/null ++++ b/scripts/flex_auth_signer_native.py +@@ -0,0 +1,417 @@ ++#!/usr/bin/env python3 ++"""Silent attended retained-lifecycle signer custody; never a credential front door. ++ ++Invoke only through the reviewed warden platform-admin envelope. The externally ++reviewed admission SHA is an exact-command input, not approval by JSON shape. ++No private value crosses stdout/stderr, argv, receipt or persistent local storage. ++""" ++from __future__ import annotations ++import argparse ++import base64 ++from datetime import datetime,timezone ++import fcntl ++import hashlib ++import hmac ++import http.client ++import importlib.util ++import json ++import os ++from pathlib import Path ++import re ++import selectors ++import shlex ++import subprocess ++import sys ++import time ++ ++from cryptography.hazmat.primitives import serialization ++from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey ++from flex_auth_signer_custody import SignerWriter,PATH,FIELDS,BINDINGS,encoded,b64 ++from task_execution_journal import Journal,Refused ++from task_execution_native_fixture import _absolute_budget ++from task_execution_recovery import _json_unique,_invalid_constant,_policy_absent,_same_policy ++ ++ROOT=Path(__file__).resolve().parents[1] ++META='platform/metadata/workloads/flex-auth/envelope-signing' ++CCR='credential-change-requests/CCR-2026-0050-flex-auth-envelope-signing.yaml' ++PLAN='docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json' ++CLUSTER='a553c742-0115-43d4-99a4-a5ca56fe0786' ++BAO_CLUSTER='fd28df5d-98ec-57dd-42ec-9b3e4f4e53bf' ++NAME='flex-auth-secrets-engine' ++SECRET='flex-auth-secrets-engine-envelope-signing' ++ROLE='external-secrets-flex-auth-envelope-signing' ++LIFECYCLE='sha256:bd11c5fe77ce6439c65fea225ad6b71d2110efc5e7b5bc9b499c59cd0a53b8b4' ++REVIEWS={'founder','railiance-platform-owner','access-engine-owner','secrets-engine-owner','cluster-gitops-owner'} ++SOURCE_FILES={'scripts/flex_auth_signer_native.py','scripts/flex_auth_signer_custody.py','scripts/task_execution_native_fixture.py','scripts/task_execution_journal.py','scripts/task_execution_recovery.py','scripts/credential-change.py'} ++ ++ ++def require(ok,reason): ++ if not ok:raise Refused(reason) ++ ++ ++def digest(raw):return 'sha256:'+hashlib.sha256(raw).hexdigest() ++def is_digest(value):return type(value) is str and re.fullmatch(r'sha256:[0-9a-f]{64}',value) is not None ++ ++def private_read(path,limit=65536): ++ path=Path(path) ++ require(path.is_absolute() and path.absolute()==path.resolve() and not path.is_symlink(),'indirect private input') ++ Journal._private(path.parent.stat(),directory=True) ++ fd=os.open(path,os.O_RDONLY|os.O_NOFOLLOW|os.O_NONBLOCK) ++ try: ++ before=os.fstat(fd);Journal._private(before) ++ raw=os.read(fd,limit+1);after=os.fstat(fd) ++ require((before.st_dev,before.st_ino,before.st_size,before.st_mtime_ns,before.st_ctime_ns)== ++ (after.st_dev,after.st_ino,after.st_size,after.st_mtime_ns,after.st_ctime_ns) ++ and len(raw)==before.st_size and len(raw)<=limit,'private input changed or oversized') ++ return raw ++ finally:os.close(fd) ++ ++ ++def parsed(raw): ++ try:return json.loads(raw,object_pairs_hook=_json_unique,parse_constant=_invalid_constant) ++ except Exception:raise Refused('invalid closed JSON input') from None ++ ++ ++def validate_admission(value): ++ fields={'schema','action','operation_id','kid','expires_at','founder_entity_id','ccr_sha256','source_bundle','bindings', ++ 'producer_image','caller_binding','deployment_projection_sha256','authority','routing','owner_reviews', ++ 'exclusive_window_sha256','consumer_trust_sha256','original_receipt_sha256','original_execution'} ++ require(type(value) is dict and set(value)==fields,'exact admission schema required') ++ require(value['schema']=='railiance-platform.signer-native-admission.v1' and value['action'] in {'bootstrap','recover'},'native admission action refused') ++ require(type(value['operation_id']) is str and re.fullmatch(r'[A-Za-z0-9_-]{1,80}',value['operation_id']) and ++ type(value['kid']) is str and re.fullmatch(r'[A-Za-z0-9_-]{1,80}',value['kid']),'native operation identity required') ++ require(type(value['founder_entity_id']) is str and re.fullmatch(r'[a-f0-9-]{36}',value['founder_entity_id']),'explicit attended identity required') ++ require(all(is_digest(value[x]) for x in ['ccr_sha256','deployment_projection_sha256','exclusive_window_sha256','consumer_trust_sha256']),'explicit custody/image/trust selections required') ++ require(type(value['producer_image']) is str and re.fullmatch(r'forgejo\.coulomb\.social/coulomb/flex-auth@sha256:[a-f0-9]{64}',value['producer_image']),'immutable producer image required') ++ require(value['caller_binding']=='secrets-engine=system:serviceaccount:secrets-engine:secrets-engine','retained caller binding required') ++ require(value['authority']=='founder-attended-exact-source-scope; no standing grant','independent attended authority required') ++ route=value['routing'];require(type(route) is dict and set(route)=={'lane_id','verdict','founder_act','receipt_sha256'} and ++ route['lane_id']=='openbao-platform-admin-login' and route['verdict']=='founder_required' and route['founder_act']=='oidc_login' and is_digest(route['receipt_sha256']),'routing mismatch refused') ++ reviews=value['owner_reviews'];require(type(reviews) is dict and set(reviews)==REVIEWS,'distinct owner reviews required') ++ for role,review in reviews.items(): ++ require(type(review) is dict and set(review)=={'approved_admission_sha256','approval_ref'} and ++ is_digest(review['approved_admission_sha256']) and type(review['approval_ref']) is str and ++ 00,'absolute custody command timeout') ++ for item,_ in sel.select(remaining): ++ chunk=os.read(item.fileobj.fileno(),65536) ++ if not chunk:sel.unregister(item.fileobj) ++ else: ++ data[item.fileobj].extend(chunk) ++ require(sum(map(len,data.values()))<=1048576,'custody command output bound') ++ code=proc.wait(timeout=max(.001,deadline-time.monotonic())) ++ require(code in allowed,'custody command unconfirmed') ++ return code,bytes(data[proc.stdout]) ++ finally:sel.close() ++ except BaseException: ++ proc.kill();proc.wait(timeout=2);raise Refused('custody command unconfirmed') from None ++ finally: ++ proc.stdout.close();proc.stderr.close() ++ def bao(self,args,payload=None,allowed=(0,)): ++ with _absolute_budget(2): ++ code,raw=self.captured(['bao',*args],payload,allowed=allowed) ++ return code,parsed(raw) ++ def kube(self,resource,name=None): ++ args=['kubectl','--request-timeout=2s'] ++ if resource!='namespace':args+=['-n','flex-auth'] ++ args+=['get',resource] ++ if name:args.append(name) ++ args+=['-o','json'] ++ with _absolute_budget(2): ++ _,raw=self.captured(['ssh','-o','BatchMode=yes','-o','StrictHostKeyChecking=yes','-o','ConnectTimeout=2','railiance01',shlex.join(args)]) ++ return parsed(raw) ++ def http(self,method,path,body=None): ++ require(method in {'GET','POST'} and path in {META,PATH,PATH+'?version=1'},'fixed custody path required') ++ require(type(getattr(self,'_token',None)) is str and self._token,'contained attended session required') ++ with _absolute_budget(2): ++ conn=http.client.HTTPConnection('127.0.0.1',18200,timeout=2) ++ try: ++ conn.request(method,'/v1/'+path,body=None if body is None else encoded(body), ++ headers={'X-Vault-Token':self._token,'Content-Type':'application/json'}) ++ response=conn.getresponse();raw=response.read(1048577) ++ require(len(raw)<=1048576,'custody response bound') ++ return response.status,parsed(raw) if raw else {} ++ finally:conn.close() ++ ++ ++def deployment_projection(deployment): ++ spec=deployment['spec']['template']['spec'];containers=spec.get('containers',[]) ++ require(type(containers) is list and len(containers)==1 and not spec.get('initContainers'),'single fixed signer container required') ++ item=containers[0] ++ # Never hash arbitrary env values or an entire Secret/spec response. ++ return {'service_account':spec.get('serviceAccountName'),'image':item.get('image'), ++ 'args':item.get('args'),'volume_mounts':item.get('volumeMounts',[]), ++ 'volumes':spec.get('volumes',[]),'security_context':spec.get('securityContext')} ++ ++ ++def fence(io,contract): ++ namespace=io.kube('namespace','kube-system') ++ require(namespace.get('metadata',{}).get('uid')==CLUSTER,'wrong target cluster') ++ deployment=io.kube('deployment',NAME);spec=deployment.get('spec',{});meta=deployment.get('metadata',{}) ++ require(type(spec.get('replicas')) is int and spec['replicas']==0 and ++ deployment.get('status',{}).get('observedGeneration',-1)==meta.get('generation') and ++ not deployment.get('status',{}).get('replicas',0),'all signer replicas must be stopped') ++ projection=deployment_projection(deployment) ++ require(digest(encoded(projection))==contract['deployment_projection_sha256'] and ++ projection['service_account']==NAME and projection['image']==contract['producer_image'],'fenced deployment source/image mismatch') ++ args=projection['args'];require(type(args) is list and all(type(x) is str for x in args),'exact signer args required') ++ def option(flag): ++ require(args.count(flag)==1 and args.index(flag)+1=3:self.pods=[{'spec':{'serviceAccountName':m.NAME}}] ++ return deepcopy(self.dep) ++ return {'items':deepcopy({'pods':self.pods,'hpa':self.hpas,'replicasets':self.rs}[resource])} ++ def http(self,method,path,body=None): ++ self.calls.append(('http',method,path)) ++ if self.denied and path in {m.PATH,m.PATH+'?version=1'} and method=='GET':return 403,{'errors':['secret backend detail']} ++ result=call(method,path,body) ++ if self.lost and method=='POST' and path==m.PATH:raise OSError('secret response lost') ++ return result ++ io=IO() ++ c={'schema':'railiance-platform.signer-native-admission.v1','action':'bootstrap','operation_id':'synthetic-native-operation','kid':'synthetic-native-kid', ++ 'expires_at':(datetime.now(timezone.utc)+timedelta(seconds=100)).isoformat(),'founder_entity_id':io.entity, ++ 'ccr_sha256':m.digest((source/m.CCR).read_bytes()),'source_bundle':{n:m.digest((source/n).read_bytes()) for n in m.SOURCE_FILES}, ++ 'bindings':{k:'sha256:'+'2'*64 for k in m.BINDINGS},'producer_image':image,'caller_binding':'secrets-engine=system:serviceaccount:secrets-engine:secrets-engine', ++ 'deployment_projection_sha256':m.digest(m.encoded(m.deployment_projection(dep))), ++ 'authority':'founder-attended-exact-source-scope; no standing grant', ++ 'routing':{'lane_id':'openbao-platform-admin-login','verdict':'founder_required','founder_act':'oidc_login','receipt_sha256':'sha256:'+'3'*64}, ++ 'owner_reviews':{},'exclusive_window_sha256':'sha256:'+'4'*64,'consumer_trust_sha256':'sha256:'+'5'*64,'original_receipt_sha256':None,'original_execution':None} ++ c['bindings'].update(proposal_sha256=m.digest((source/m.PLAN).read_bytes()),policy_sha256=m.LIFECYCLE,image_sha256='sha256:'+'1'*64,trust_sha256=c['consumer_trust_sha256'],deployment_sha256=c['deployment_projection_sha256'],executed_revision_sha256=m.digest(m.encoded(c['source_bundle']))) ++ def approve(value): ++ if value['action']=='recover' and value['original_execution'] is None: ++ old=json.loads((directory/(c['operation_id']+'.json')).read_bytes()) ++ value['original_execution']={key:deepcopy(old[key]) for key in ['bindings','writer_sha256','source_ccr_sha256']} ++ scope=m.digest(m.encoded({k:v for k,v in value.items() if k!='owner_reviews'})) ++ value['owner_reviews']={role:{'approved_admission_sha256':scope,'approval_ref':'synthetic-fixture-'+role} for role in m.REVIEWS} ++ return value ++ approve(c) ++ return c,io,directory,call,approve,source ++ ++ ++def test_actual_native_bootstrap_exact_readback_and_no_retry(native): ++ c,io,directory,call,approve,source=native ++ result=m.execute(c,directory,io=io) ++ assert result['status']=='custody-verified-pending-independent-public-admission' and result['exact_readback'] ++ assert call('GET',m.META)[1]['data']['current_version']==1 ++ assert [(x[1],x[2]) for x in io.calls if x[0]=='http' and x[1]=='POST']==[('POST',m.META),('POST',m.PATH)] ++ private=call('GET',m.PATH)[1]['data']['data']['ED25519_PRIVATE_KEY'] ++ raw=(directory/(c['operation_id']+'.json')).read_bytes();assert private.encode() not in raw ++ before=len(io.calls) ++ with pytest.raises(FileExistsError):m.execute(c,directory,io=io) ++ assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls[before:]) ++ ++ ++def test_actual_process_loss_unknown_fresh_recovery_read_only(native): ++ c,io,directory,call,approve,source=native ++ child=os.fork() ++ if child==0: ++ original_http=io.http ++ def die_after_native_write(method,path,body=None): ++ result=original_http(method,path,body) ++ if method=='POST' and path==m.PATH:os._exit(73) ++ return result ++ io.http=die_after_native_write ++ try:m.execute(c,directory,io=io) ++ except BaseException:os._exit(74) ++ os._exit(75) ++ _,status=os.waitpid(child,0) ++ assert os.waitstatus_to_exitcode(status)==73 ++ old=directory/(c['operation_id']+'.json');original=old.read_bytes();assert json.loads(original)['status']=='write-intent-unknown' ++ recovery=deepcopy(c);recovery.update(action='recover',operation_id='synthetic-independent-recovery',original_receipt_sha256=m.digest(original));approve(recovery) ++ io.lost=False;io.calls.clear() ++ result=m.execute(recovery,directory,io=io,original_receipt=old) ++ assert result['status']=='custody-reconciled-pending-independent-public-admission' ++ assert result['no_write_or_remint'] and old.read_bytes()==original ++ assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls) ++ assert call('GET',m.META)[1]['data']['current_version']==1 ++ assert (directory/(recovery['operation_id']+'.json')).stat().st_mode&0o777==0o600 ++ io.calls.clear() ++ with pytest.raises(FileExistsError):m.execute(recovery,directory,io=io,original_receipt=old) ++ assert not any(x[0]=='http' for x in io.calls) ++ ++ ++@pytest.mark.parametrize('case',['missing-image','missing-trust','mismatched-source','bad-review','bad-route','expired','wrong-entity','wrong-backend','wrong-cluster','root','pod','terminating-pod','hpa','replicas','image-drift','role-drift','pod-after-metadata']) ++def test_refusals_no_seed_effect(native,case): ++ c,io,directory,call,approve,source=native ++ if case=='missing-image':c['producer_image']='' ++ elif case=='missing-trust':c['consumer_trust_sha256']='' ++ elif case=='mismatched-source':(source/'scripts/flex_auth_signer_custody.py').write_text('changed source') ++ elif case=='bad-review':c['owner_reviews']['founder']['approved_admission_sha256']='sha256:'+'f'*64 ++ elif case=='bad-route':c['routing']['lane_id']='openbao-structure-survey';approve(c) ++ elif case=='expired':c['expires_at']=(datetime.now(timezone.utc)-timedelta(seconds=1)).isoformat();approve(c) ++ elif case=='wrong-entity':io.entity='other' ++ elif case=='wrong-backend':io.backend='other' ++ elif case=='wrong-cluster':io.cluster='other' ++ elif case=='root':io.root=True ++ elif case=='pod':io.pods=[{'spec':{'serviceAccountName':m.NAME}}] ++ elif case=='terminating-pod':io.pods=[{'metadata':{'deletionTimestamp':'now'},'spec':{'volumes':[{'secret':{'secretName':m.SECRET}}]}}] ++ elif case=='hpa':io.hpas=[{'spec':{'scaleTargetRef':{'name':m.NAME}}}] ++ elif case=='replicas':io.dep['spec']['replicas']=1 ++ elif case=='image-drift':io.dep['spec']['template']['spec']['containers'][0]['image']='unreviewed' ++ elif case=='role-drift':io.role_drift=True ++ elif case=='pod-after-metadata':io.pod_on_recheck=True ++ with pytest.raises(Refused):m.execute(c,directory,io=io) ++ assert not any(x[0]=='http' and x[1]=='POST' and x[2]==m.PATH for x in io.calls) ++ assert call('GET',m.PATH)[0]==404 ++ ++ ++@pytest.mark.parametrize('case',['damaged-receipt','typed-damaged-receipt','changed-version','read-denied','no-fresh-review']) ++def test_recovery_refuses_without_new_effect(native,case): ++ c,io,directory,call,approve,source=native;io.lost=True ++ with pytest.raises(Refused):m.execute(c,directory,io=io) ++ old=directory/(c['operation_id']+'.json');recovery=deepcopy(c);recovery.update(action='recover',operation_id='recovery',original_receipt_sha256=m.digest(old.read_bytes()));approve(recovery) ++ if case=='damaged-receipt':old.write_text('{}') ++ elif case=='typed-damaged-receipt': ++ damaged=json.loads(old.read_text());damaged['expected_version']=False;old.write_text(json.dumps(damaged));recovery['original_receipt_sha256']=m.digest(old.read_bytes());approve(recovery) ++ elif case=='changed-version': ++ doc=call('GET',m.PATH)[1]['data']['data'];assert call('POST',m.PATH,{'options':{'cas':1},'data':doc})[0]==200 ++ elif case=='read-denied':io.denied=True ++ elif case=='no-fresh-review':recovery['owner_reviews']['founder']['approved_admission_sha256']='sha256:'+'f'*64 ++ io.calls.clear();io.lost=False ++ with pytest.raises(Refused):m.execute(recovery,directory,io=io,original_receipt=old) ++ assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls) ++ ++ ++@pytest.mark.parametrize('bad_args',[False,True]) ++def test_main_missing_approval_silent_and_no_io(tmp_path,capsys,bad_args): ++ if bad_args: ++ assert m.main(['--unrecognized'])==1 ++ output=capsys.readouterr();assert output.out==output.err=='' ++ return ++ assert m.main(['--admission',str(tmp_path/'missing'),'--admission-sha256','sha256:'+'0'*64,'--receipt-directory',str(tmp_path)])==1 ++ output=capsys.readouterr();assert output.out==output.err=='' ++ ++ ++def test_native_command_byte_and_elapsed_bounds_no_output(capsys): ++ io=m.NativeIO() ++ with pytest.raises(Refused):io.captured([sys.executable,'-c',"import sys;sys.stdout.write('x'*1048577)"]) ++ import time ++ started=time.monotonic() ++ with pytest.raises(Refused):io.captured([sys.executable,'-c',"import time;time.sleep(10)"]) ++ assert time.monotonic()-started<3 ++ output=capsys.readouterr();assert output.out==output.err=='' ++ ++ ++def test_exclusive_native_window_refuses_second_writer(native): ++ import fcntl ++ c,io,directory,call,approve,source=native ++ fd=os.open(directory/'.signer-window.lock',os.O_RDWR|os.O_CREAT,0o600) ++ try: ++ fcntl.flock(fd,fcntl.LOCK_EX|fcntl.LOCK_NB) ++ with pytest.raises(BlockingIOError):m.execute(c,directory,io=io) ++ assert io.calls==[] ++ finally:os.close(fd) ++ ++ ++def test_native_fixed_http_transport_against_disposable_backend(bao_dev,monkeypatch,capsys): ++ origin,token,call,process=bao_dev ++ assert call('POST','sys/mounts/platform',{'type':'kv','options':{'version':'2'}})[0] in {200,204} ++ factory=m.http.client.HTTPConnection;port=int(origin.rsplit(':',1)[1]);destinations=[] ++ def fixture_socket(host,requested_port,*args,**kwargs): ++ destinations.append((host,requested_port)) ++ return factory(host,port if requested_port==18200 else requested_port,*args,**kwargs) ++ monkeypatch.setattr(m.http.client,'HTTPConnection',fixture_socket) ++ io=m.NativeIO();io._token=token ++ assert io.http('GET',m.META)==(404,{'errors':[]}) ++ assert io.http('POST',m.META,{'cas_required':True,'max_versions':2,'delete_version_after':'0s'})[0] in {200,204} ++ m.exact_metadata(*io.http('GET',m.META),created=False) ++ assert all(host=='127.0.0.1' and selected_port==18200 for host,selected_port in destinations) ++ with pytest.raises(Refused):io.http('GET','other/path') ++ output=capsys.readouterr();assert output.out==output.err=='' ++ ++ ++def metadata_phase_crash(native,*,after): ++ c,io,directory,call,approve,source=native ++ child=os.fork() ++ if child==0: ++ original=io.http ++ def die(method,path,body=None): ++ if method=='POST' and path==m.META: ++ if after:original(method,path,body) ++ os._exit(73) ++ return original(method,path,body) ++ io.http=die ++ try:m.execute(c,directory,io=io) ++ except BaseException:os._exit(74) ++ os._exit(75) ++ _,status=os.waitpid(child,0);assert os.waitstatus_to_exitcode(status)==73 ++ old=directory/(c['operation_id']+'.json');raw=old.read_bytes();receipt=json.loads(raw) ++ assert receipt['phase']=='metadata-setup' and receipt['status']=='write-intent-unknown' ++ assert receipt['public_key'] is None and receipt['kv_version'] is None ++ recovery=deepcopy(c);recovery.update(action='recover',operation_id='metadata-recovery',original_receipt_sha256=m.digest(raw));approve(recovery) ++ return old,raw,recovery ++ ++ ++@pytest.mark.parametrize('after',[False,True]) ++def test_real_metadata_process_loss_read_only_phase_recovery(native,after): ++ c,io,directory,call,approve,source=native ++ old,raw,recovery=metadata_phase_crash(native,after=after) ++ io.calls.clear();result=m.execute(recovery,directory,io=io,original_receipt=old) ++ assert result['status']==('metadata-only-confirmed' if after else 'current-custody-absent') ++ assert result['public_key'] is result['public_fingerprint'] is result['kv_version'] is None ++ assert result['key_custody_verified'] is False and result['historical_effect']=='unresolved' ++ assert 'fresh independently reviewed exact action required' in result['next_action'] ++ assert old.read_bytes()==raw and result['original_unknown_preserved'] ++ assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls) ++ assert call('GET',m.PATH+'?version=1')==(404,{'errors':[]}) ++ ++ ++@pytest.mark.parametrize('case',['metadata-denied','metadata-misleading404','metadata-misleading200','metadata-malformed','metadata-timeout','data-denied','unexpected-version']) ++def test_metadata_recovery_ambiguous_or_denied_never_classifies_or_writes(native,case): ++ c,io,directory,call,approve,source=native ++ old,raw,recovery=metadata_phase_crash(native,after=True) ++ if case=='unexpected-version': ++ assert call('POST',m.PATH,{'options':{'cas':0},'data':{'ED25519_PRIVATE_KEY':'synthetic-unadmitted','ED25519_PUBLIC_KEY':'synthetic-unadmitted','kid':c['kid']}})[0]==200 ++ original=io.http ++ def faulty(method,path,body=None): ++ if path==m.META: ++ if case=='metadata-denied':return 403,{'errors':['denied']} ++ if case=='metadata-misleading404':return 404,{'errors':['permission denied']} ++ if case=='metadata-misleading200': ++ result=original(method,path,body);result[1]['errors']=['denied'];return result ++ if case=='metadata-malformed':return 200,{'data':{'current_version':False}} ++ if case=='metadata-timeout':raise OSError('synthetic private backend detail') ++ if path==m.PATH+'?version=1' and case=='data-denied':return 404,{'errors':['denied']} ++ return original(method,path,body) ++ io.http=faulty;io.calls.clear() ++ with pytest.raises((Refused,OSError)):m.execute(recovery,directory,io=io,original_receipt=old) ++ evidence=json.loads((directory/(recovery['operation_id']+'.json')).read_bytes()) ++ assert evidence['status']=='recovery-read-intent-unconfirmed' and evidence['key_custody_verified'] is False ++ assert old.read_bytes()==raw ++ assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls) ++ if case=='unexpected-version':assert not any(x[0]=='http' and x[2]==m.PATH+'?version=1' for x in io.calls) ++ ++ ++def test_stale_current_primitive_lineage_refuses_before_native_io(native): ++ c,io,directory,call,approve,source=native ++ plan=json.loads((source/m.PLAN).read_bytes());plan['bootstrap']['source_primitive_sha256']='sha256:'+'8'*64 ++ (source/m.PLAN).write_text(json.dumps(plan));c['bindings']['proposal_sha256']=m.digest((source/m.PLAN).read_bytes());approve(c) ++ with pytest.raises(Refused,match='primitive lineage'):m.execute(c,directory,io=io) ++ assert io.calls==[] ++ ++ ++def test_recovery_explicitly_binds_historical_execution_and_current_source(native): ++ c,io,directory,call,approve,source=native ++ old,raw,recovery=metadata_phase_crash(native,after=True) ++ # Model a separately retained older executed bundle/proposal. It must be ++ # explicitly selected in fresh recovery review, never treated as current. ++ original=json.loads(raw);original['bindings']['executed_revision_sha256']='sha256:'+'6'*64 ++ original['bindings']['proposal_sha256']='sha256:'+'7'*64 ++ old.write_text(json.dumps(original));recovery['original_receipt_sha256']=m.digest(old.read_bytes()) ++ recovery['original_execution']={key:deepcopy(original[key]) for key in ['bindings','writer_sha256','source_ccr_sha256']};approve(recovery) ++ result=m.execute(recovery,directory,io=io,original_receipt=old) ++ assert result['status']=='metadata-only-confirmed' ++ assert result['original_execution']['bindings']['executed_revision_sha256']!=recovery['bindings']['executed_revision_sha256'] ++ assert json.loads(old.read_text())==original ++ ++ ++def test_generated_but_unstored_seed_phase_recovers_without_public_admission(native): ++ c,io,directory,call,approve,source=native ++ io.pod_on_recheck=True ++ with pytest.raises(Refused):m.execute(c,directory,io=io) ++ old=directory/(c['operation_id']+'.json');raw=old.read_bytes();receipt=json.loads(raw) ++ assert receipt['phase']=='seed-cas' and receipt['public_key'] is not None ++ assert call('GET',m.PATH+'?version=1')==(404,{'errors':[]}) ++ io.pod_on_recheck=False;io.pods=[];io.calls.clear() ++ recovery=deepcopy(c);recovery.update(action='recover',operation_id='unstored-seed-recovery',original_receipt_sha256=m.digest(raw));approve(recovery) ++ result=m.execute(recovery,directory,io=io,original_receipt=old) ++ assert result['status']=='metadata-only-confirmed' and result['key_custody_verified'] is False ++ assert result['public_key'] is None and result['public_fingerprint'] is None ++ assert old.read_bytes()==raw ++ assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls) +--- a/docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json ++++ b/docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json +@@ -55,7 +55,9 @@ + "purpose": "exact private readback in custody, closed public receipt only" + } + ], +- "source_primitive_sha256": "sha256:8ed281a49c1f1cdb23772efe3593e75c62572a12b8d7a6a4c574f27b38722e75" ++ "source_primitive_sha256": "sha256:f169ad12f90d729b647085c3bed2c0d8d005db23a2341b6d3d5f1793bcfd110c", ++ "historical_source_primitive_sha256": "sha256:8ed281a49c1f1cdb23772efe3593e75c62572a12b8d7a6a4c574f27b38722e75", ++ "source_lineage_rule": "source_primitive_sha256 must equal current admitted source_bundle[scripts/flex_auth_signer_custody.py] and exact writer receipt; historical_source_primitive_sha256 is non-authoritative R1 evidence only" + }, + "fencing": { + "before_key_generation": [ +diff --git a/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md b/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md +new file mode 100644 +index 0000000..9dcfe1b +--- /dev/null ++++ b/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md +@@ -0,0 +1,187 @@ ++# Attended native signer custody adapter source ++ ++RPF-WP-0035-T12 / CUST-WP-0080. This source implements the protected native ++adapter described by the separate frozen native-preparation R1. It does not ++admit an execution. Its CLI is silent and intended only as the exact reviewed ++child of `warden access openbao-platform-admin-login --exec` in the founder's ++attended OIDC envelope. The existing Warden owner contains the token helper, ++checks child output and revokes/removes the session on exit. No new service, ++credential broker, standing grant, API or key-returning interface is created. ++ ++## Current routing blocker ++ ++During preparation the required `warden plan` query for attended OpenBao ++platform administration of signer CAS0/metadata selected `openbao-structure-survey` ++with an approve ceremony, rather than `openbao-platform-admin-login` with ++`oidc_login`. The installed CLI reports wheel-bundled catalog0.1.2 fallback. ++This is preserved as a live refusal, not routed around. Exact `route show` names ++the existing active attended login, but that pointer does not cure dispatch. ++The adapter requires an independently retained routing receipt selecting the ++correct lane/verdict/identity act. No founder execution step is ready until the ++routing defect and all other native approvals are resolved by their owners. ++ ++## Independent input and authority boundary ++ ++The CLI requires an absolute owner-private admission file, its independently ++approved exact SHA256, the exact private receipt directory selected in the ++reviewed native proposal, and an original receipt only for recovery. No default ++image/package/caller trust, founder identity, approval, route or source pin is ++usable. The admission schema is closed in `validate_admission`; it includes the ++immutable published producer image, retained caller, deployment projection, ++selected consumer trust baseline, exact native plan/CCR/source bundle, fresh ++UTC authority expiry (5..120seconds), founder entity and five distinct externally ++reviewed owner dispositions. Each disposition binds the same approval-free ++scope digest. An admission shape, local digest or review string never approves ++itself: the founder and owners must independently review the exact supplied ++command/file hash through existing governance before attended invocation. ++ ++The trust hash selects the independently reviewed consumer verifier/policy/trust ++baseline for this custody action. It is not a claim that the newly generated ++public key is already online: generation happens later, and independent delivery ++and successor trust installation are required after the public receipt. The ++writer never reads consumer private credentials or discovers trust from KV. ++All successful custody states remain pending independent public admission. ++ ++`checked_sources` verifies the actual selected native action plan, exact proposed ++kid, read CCR hash/status/binding, generated policy source, and source bundle. ++The read CCR must independently be approved/binding-confirmed; the canonical ++proposed CCR remains unapproved, so ordinary source checkout refuses. Source ++bundle pins execution modules, not arbitrary request-selected code. The native ++image/caller/seed projection is compared to the actual stopped Deployment. ++The lifecycle policy digest/version stays unchanged; execute-ccr probes must ++prove no ALLOW/effect. Current generic runtime guard can return HTTP503 before ++the lifecycle evaluator, so signed unknown_action is not promised. ++ ++## Actual checks and effects ++ ++Before private work, the child checks OpenBao cluster ID, unsealed state, exact ++non-root platform-admin OIDC entity, enabled audit, actual exact read-policy HCL ++and role bindings/15m limits. The selected fixed loopback transport is the existing ++owner-admin bridge; Kubernetes reads use fixed strict-host SSH to railiance01. ++The OpenBao token lookup-self identifier stays only in the contained custody ++process to authenticate fixed HTTP calls; it never reaches the agent, a receipt, ++argv or another token file. This is a native protected-process implementation, ++not evidence that agent runtime isolation has been promoted or granted. ++ ++The fence checks the pinned kube-system UID, stopped Deployment generation and ++replica status, exact immutable image/caller/seed mount/kid projection, zero owned ++ReplicaSet replicas, no live or terminating signer-SA/owned/seed-mount pods, and ++no targeting HPA. It rechecks before metadata setup and immediately before CAS. ++A private filesystem lock excludes a second local custody window. The lock and ++observations do not provide atomic Kubernetes fencing: the independently reviewed ++exclusive window must keep GitOps/Helm/other creators stopped. No rollout or ++cluster mutation is performed by this adapter, and no concurrency guarantee is ++inferred from source alone. Access/cluster owners retain that admission. ++ ++Bootstrap requires the exact OpenBao empty-errors HTTP404 metadata absence. A ++durable private intent precedes exact CAS-required/max_versions2/no-auto-delete ++metadata setup, followed by exact native readback. Only then does the shared ++Ed25519 primitive generate one in-memory seed and CAS0 the fixed three-field ++KV document. Independent version1 private readback and final metadata verification ++precede the durable success receipt. The seed is never put in argv/env/local ++files or output. The receipt carries public key, ASCII-base64url fingerprint, ++version, bindings and closed phases only. The old fixture's live-dev-process gate ++is preserved; its shared receipt initialization was extracted without weakening ++that gate. Python cannot promise seed zeroization. ++ ++Every backend/body/close and tool call has a two-second absolute budget and ++1MiB combined output bound. The complete operation is bounded by the supplied ++fresh expiry. CLI validation and runtime failures remain silent. Existing0600/ ++0700 no-follow/ownership checks, exclusive creation, fsync/atomic replacement and ++directory fsync retain evidence. Same-UID hostile code is not isolated by modes; ++Warden's contained home, trusted runtime and independently reviewed custody ++location are required, not inferred from approval frequency or shell prefixes. ++ ++## Process loss and independent read-only recovery ++ ++Any failed/ambiguous metadata/write/readback/final receipt outcome remains ++unconfirmed. A success receipt is withheld until final metadata verification. ++A child death immediately after the real native CAS leaves the earlier public ++intent with its derived public key and no private value. A fresh `recover` ++admission must bind that exact original receipt SHA and the same immutable scope. ++It reserves a new durable recovery intent before private reads, verifies current ++version1 metadata and exact private seed/public/kid correspondence, and records ++separate public reconciliation. It never creates a writer, generates a seed, ++POSTs metadata/data, restores a seed, consumes approval or dispatches business ++operations. Original unknown evidence is never rewritten. Changed versions, ++damaged/typed-invalid receipts, missing fresh reviews and denied reads refuse; ++replaying a recovery ID cannot repeat even the private backend read. ++ ++This source implements bootstrap and read-only version1 reconciliation only. ++Rotation needs a separately reviewed exact-version native action; the disposable ++primitive's CAS1 test is not a native rotation grant. No automatic retry, remint, ++rollback or general recovery API exists. Metadata-only setup uncertainty without ++a public seed intent requires separate attended reconciliation, not this path. ++ ++Access observed zero PVCs in flex-auth. Its proposed new1Gi/local-path outbox, ++PV Retain/reclaim disposition and runtime process-lock/capacity/startup bounds ++remain separate reviews. This writer grants no PVC, audit egress, policy role, ++SecretStore/Secret or producer/consumer deployment admission. ++ ++## R2 phase-aware recovery and source lineage ++ ++Frozen R1's metadata-only crash counterexample remains valid historical evidence. ++R2 accepts a strict original metadata-setup receipt with no public key, or a ++seed-cas receipt with a canonical derived public key. Fresh recovery reserves ++durable evidence before target reads. Exact current metadata absence AND exact ++version1 data absence yields `current-custody-absent`. Exact configured metadata ++with current_version0 AND exact version1 data absence yields ++`metadata-only-confirmed`. Both results have no public key/fingerprint/KV version, ++key_custody_verified=false, historical_effect=unresolved, original_unknown_preserved, ++and an explicit fresh independently reviewed action requirement. A locally ++generated but unstored seed's public key is not promoted into public admission. ++Neither observation means the original attempt historically made no effects. ++ ++Denied/malformed/misleading404 metadata or data, timeout, changed configuration, ++unexpected versions, or version1 after a metadata-only/no-public phase keep the ++new recovery attempt unconfirmed. They never grant generation, write, retry, ++remint, consume or business authority. A subsequent metadata-only bootstrap is ++not silently enabled: existing metadata still refuses CAS0 bootstrap admission. ++A distinct exact reviewed action/source revision must choose any cleanup/reuse ++or generation step. The original receipt remains byte-for-byte unchanged. ++ ++Native plan bootstrap.source_primitive_sha256 now equals the actual shared ++primitive in the admitted source bundle and writer receipt; checked_sources ++enforces the join. The prior8ed pin is explicitly historical. The plan pins the ++shared primitive, not itself or the complete native executor, so no self-hash ++cycle exists. The exact native executor is independently pinned by source_bundle ++and its digest in bindings. A recover admission must additionally supply ++original_execution (original receipt bindings, writer SHA and CCR SHA). Fresh ++owner reviews bind both original and current lineages. This can describe an older ++executed source/proposal without labeling it current. Image/deployment/policy/ ++consumer trust bindings must still match; recovery cannot change that authority. ++ ++## Exact120-second expiry and attended scheduling assessment ++ ++The unchanged validate_admission rule requires an absolute UTC expires_at with ++5 < expires_at-now <=120seconds, and the entire child runs beneath that fixed ++remaining absolute/monotonic budget. The five external reviews cover the scope ++digest including expires_at. No deadline is generated, refreshed or widened by ++the child; rechecking cannot extend it. ++ ++Existing ops-warden proxy.proxy_attended_login_exec runs the OIDC client before the child. ++Its _contained_run captures output through subprocess.run without a timeout. ++Therefore neither OIDC/MFA nor five external reviews have a demonstrated bound ++that fits120seconds from preparing an admission. Creating a now+120seconds ++admission before unbounded review/login is not a reliable operational ceremony. ++Source success tests start from synthetic ready identities; they prove no human ++OIDC/review timing SLO. ++ ++A coherent ceremony under the current rule is to pre-review one exact future ++absolute expiry/window, including all artifact/source/image/trust/identity and ++review references, then arrange attended login so the child starts within its ++implicit [expires_at-120seconds, expires_at-5seconds) interval. Review may occur ++before that interval; it does not change runtime authority. The founder must aim ++for the beginning of the interval, not its last five seconds. The fixed path has ++26 bounded native/tool requests before success (52seconds at their2second caps), ++plus key/source/receipt work. Its expiry still wins if those operations cannot ++finish; no completion or filesystem timing guarantee is inferred. ++ ++If login completes too early/late, a review changes any bytes, or adequate time ++remains uncertain, refuse this revision. A new expires_at changes the approved ++scope digest and needs explicit dispositions for the new revision; existing ++source-only reviews cannot be copied into native approval. Do not silently ++refresh after OIDC, reinterpret expiry as start-only, widen120seconds, skip ++reviews or start a general window-grant service. An alternative authority/window ++contract would itself require separate owner/founder design and is not supplied ++by R2. Current native admission remains unapproved. +--- a/workplans/RPF-WP-0035-credential-lane-implementation.md ++++ b/workplans/RPF-WP-0035-credential-lane-implementation.md +@@ -1354,3 +1354,24 @@ + founder plus distinct owner reviews remain necessary. Access observed zero PVCs; + new outbox storage/retention/runtime bounds remain separate Access/cluster scope. + No live credentials, grants, roles, key or deployment changed. T12 stays progress. ++ ++2026-10-16 T12 native signer adapter source: silent fixed-scope attended child ++checks exact independent admission/source/CCR/image/caller/trust/identity inputs, ++actual backend/reader role/policy, signer fence and private exclusive receipt ++custody before fixed metadata/CAS0 effects. Separate fresh read-only recovery ++reconciles real process loss after native write without remint/retry/new effects. ++Disposable tests exercise actual KV while owner reviews/identity/fence facts are ++explicitly synthetic. Current warden plan dispatch selects structure-survey, not ++OIDC admin login; mismatch remains a live refusal. Canonical proposed CCR, native ++owner/founder approval and Access/cluster/outbox/PVC gates stay open; no live ++key, credential read, grant, role, storage or deployment action performed. ++ ++2026-10-16 T12 native signer R2 source correction preserves R1 failures: exact ++phase-aware read-only recovery classifies current metadata-only/absent states, ++never admits a key or retry and preserves original uncertainty. Fresh recovery ++explicitly binds historical execution plus current source; current primitive ++plan/source/receipt join is enforced and old pin labeled historical. Real fork ++metadata-loss and denied/ambiguous tests added.120second expiry is unchanged; ++external reviews and unbounded OIDC require a pre-reviewed exact scheduled ++window, otherwise refuse/new explicit revision. No native or owner approval ++inferred; no live action. diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/manifest.json b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/manifest.json new file mode 100644 index 00000000..2e126f76 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/manifest.json @@ -0,0 +1,67 @@ +{ + "schema": "railiance-platform.signer-native-adapter-r2.v1", + "proposal_id": "RPF35-PDP-SIGNER-NATIVE-ADAPTER-20261016-R2", + "preserved_R1_patch_sha256": "f316a53b604f4333414b832691968ede8056d49a61635f0f25831084b1d75f19", + "canonical_base": "7be8b6e76d602a5306052f9e42881fbea250ede8", + "requires_native_preparation_sha256": "a9d4631d3320ac3fa56f5a61965005c546eae241d2004cc1e6385e04668b7f7f", + "isolated_source": "/tmp/netkingdom-platform-signer-native-adapter-r2-20261016", + "delta": { + "patch_sha256": "81f4c2867d09accc33a22f7537526c0bcf86c4e45803639af0c602b6446c9ab1", + "files": { + "scripts/flex_auth_signer_native.py": { + "before_sha256": "11418b56bf5b5b44d926d8ad7f40c478cfb8f85189ca2ca03826bd0c05fc28c1", + "after_sha256": "5a3b3b33bcad45ef2939413bfd3db76e5ee70e3b815d0d64af53147851aa3a0d" + }, + "tests/test_flex_auth_signer_native.py": { + "before_sha256": "a368dfaebaa88621b5800236a96ec27efa4b8c568de39bb5108dc84457b7ef2f", + "after_sha256": "8a99d1819c54fc20660cd6d16e8b429e2fc9f30cf4cefc90704201a588c825a6" + }, + "docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json": { + "before_sha256": "abc7c97eee8c059ee1d93b6e48e6f6277c4b8810623510d5cede20fd889feb44", + "after_sha256": "5f8c37a7d9781884bf06050be80ca192a3b92eab2d20e28f9b304e57e7456844" + }, + "docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md": { + "before_sha256": "8a33a92c928d9e78d57d996dc0323045f608fe8ffdd247221d78e1973f44a724", + "after_sha256": "0e185a651fbbef96996c38ff18ce338f4d6c0117c3fb069a43e766816e56d5db" + }, + "workplans/RPF-WP-0035-credential-lane-implementation.md": { + "before_sha256": "19184125dfefdcb71b0be0263c3225a014e6c8cd93185f15b9e65a331ae1e5ed", + "after_sha256": "180731a9ac1a2b4ccb4458c6cee54151f43e63008e2c35a33db7f01ea9e9d768" + } + }, + "apply_check": "pass" + }, + "full": { + "patch_sha256": "c5b8f0d10650f13eb5939874bda1fb457b3dc5835e63e043af9824e43edb9f80", + "files": { + "scripts/flex_auth_signer_custody.py": { + "before_sha256": "8ed281a49c1f1cdb23772efe3593e75c62572a12b8d7a6a4c574f27b38722e75", + "after_sha256": "f169ad12f90d729b647085c3bed2c0d8d005db23a2341b6d3d5f1793bcfd110c" + }, + "scripts/flex_auth_signer_native.py": { + "before_sha256": null, + "after_sha256": "5a3b3b33bcad45ef2939413bfd3db76e5ee70e3b815d0d64af53147851aa3a0d" + }, + "tests/test_flex_auth_signer_native.py": { + "before_sha256": null, + "after_sha256": "8a99d1819c54fc20660cd6d16e8b429e2fc9f30cf4cefc90704201a588c825a6" + }, + "docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json": { + "before_sha256": "abc7c97eee8c059ee1d93b6e48e6f6277c4b8810623510d5cede20fd889feb44", + "after_sha256": "5f8c37a7d9781884bf06050be80ca192a3b92eab2d20e28f9b304e57e7456844" + }, + "docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md": { + "before_sha256": null, + "after_sha256": "0e185a651fbbef96996c38ff18ce338f4d6c0117c3fb069a43e766816e56d5db" + }, + "workplans/RPF-WP-0035-credential-lane-implementation.md": { + "before_sha256": "bab368699a4f80ac0f9092a467c7f4b50c9831c4543dc86a3f51eabb82fdf320", + "after_sha256": "180731a9ac1a2b4ccb4458c6cee54151f43e63008e2c35a33db7f01ea9e9d768" + } + }, + "apply_check": "pass" + }, + "source_primitive_sha256": "sha256:f169ad12f90d729b647085c3bed2c0d8d005db23a2341b6d3d5f1793bcfd110c", + "execution_authority_granted": false, + "native_accepted": false +} diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/README.md b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/README.md new file mode 100644 index 00000000..65e1e333 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/native-packet-p2/README.md @@ -0,0 +1,38 @@ +# Exact Platform custody packet P2 + +`RPF35-PDP-SIGNER-NATIVE-PACKET-20261016-P2` proposes one attended bootstrap under native action `RPF35-PDP-SIGNER-NATIVE-20261016-R1`. It selects the existing legacy flex-auth repository's immutable candidate `forgejo.coulomb.social/coulomb/flex-auth@sha256:09a83b273740133518cc7e7915fb211381e06545d347d2dd1974042525ac981f`, source `84c78e072c8f3daf2bc3b90f8efc8fbeb16c3cf0`. Ordinary publisher402 and both Smoke401 jobs succeeded; independent public package metadata reports the same sole digest and explicit revision label. P1 candidate0a and its post-push failed400 evidence stay unchanged. Candidate provenance grants no runtime/custody/trust admission. + +`evidence-pins.json` binds exact committed Platform a3e8 source modules/plan, installed routing receipt, published candidate and local package d52/tree d4fb. Package baseline2b/current05a remains frozen; its local draft resolution is not adoption of84 or signer activation. `admission-scope.incomplete.json` is approval-free preparation and intentionally cannot execute. Missing nulls require the separate inputs below. Proposed failclosed pre-key consumer baseline and source projection, if filled, are pinned for review; they do not attest live installation or actual native fence. No new public key/fingerprint exists before custody. + +## Next actual scoped owner-review inputs + +1. Platform + founder: independently disposition exact CCR0050/read-policy/role/delivery scope and distinct one-use CAS0 writer scope. Current CCR remains proposed with bound_claims_confirmed=false; its current hash is evidence only and is not inserted as an approved CCR hash. After separately authorized apply/readback, bind exact approved/binding-confirmed bytes in ccr_sha256. Verify dedicated ESO SA/namespace/audience, exact policy, role15m ttl/max/explicit-max/no-default, no metadata/list/sibling/write grants. Source status edits are not native binding evidence. +2. Access + cluster/GitOps: review exact P2 rollout source render and candidate image/kid/caller/mount/security/outbox values. Approve actual stopped deployment/frozen competing writers, stopped consumer, zero signer-SA/seed-mount/owned or terminating pods, no HPA, all owned ReplicaSets0 and deployment observed generation caught up. Supply authenticated exact future native deployment_projection artifact computed by the committed projection function and show it equals the proposed hash. A local source projection cannot establish these current observations. Supply exclusive-window artifact/hash naming founder executor/abort owner, competing controllers, readiness120s abort and recovery10m holdfenced. PVC1Gi/local-path/Helmkeep plus actual dynamically bound PV Retain, headroom/server-dry-run/client-diff and rollback are distinct approvals. +3. Secrets: review exact built-wheel/helper/verifier/config/empty-trust baseline and planned install location. Pre-key empty trust is proposed failclosed and grants no signer acceptance. After authenticating Platform's public receipt, independently admit new key/kid/publickey fingerprint and successor trust, never discover from KV/responder. Fingerprint is SHA256 of canonical unpadded base64url public-key ASCII43bytes. Bounded TokenRequest/callerfile custody/installed trust/named-pod literal-loopback session remain separate approvals; no session is minted here. +4. Founder/Platform: independently identify exact non-root OpenBao founder entity UUID, trusted runtime/dependencies/private custody directory, exact fixed command and admission file hash. No agent token lookup/login is required to prepare it. The child later verifies auth/netkingdom/platform-admin/entity and backend identity. Existing supervised record and Warden containment do not establish same-UID hostile-code isolation. +5. Five distinct owner dispositions (Platform, Access, Secrets, cluster/GitOps, founder) must bind the completed approval-free scope SHA256, including exact approved CCR, source/image/projection/trust/window/expiry/entity. Platform's packet assent is preparation only. Collect actual external reference strings after their reviews; never manufacture them. Founder disposition must approve the exact private file hash and command/source plus high-risk custody/outage/loss scope. +6. Select a future absolute UTC expires_at after coordinating the ceremony, not by auto-filling now+120. Reviews may finish before its window. Warden OIDC precedes child without proven timing bound; child must start at565536:raise Refused('receipt bound exceeded') + if initial: + target=self.path + else: + fd=os.open(self.path,os.O_RDONLY|os.O_NOFOLLOW|os.O_NONBLOCK) + try:Journal._private(os.fstat(fd)) + finally:os.close(fd) + target=self.directory/('.pending-'+secrets.token_hex(16)) + fd=os.open(target,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600) + try: + with os.fdopen(fd,'wb',closefd=False) as stream:stream.write(raw);stream.flush();os.fsync(fd) + finally:os.close(fd) + if not initial:os.replace(target,self.path) + fd=os.open(self.directory,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW) + try:os.fsync(fd) + finally:os.close(fd) + + def _http(self,method,path,body=None): + # Fixed loopback owner process and fixed data path; never arbitrary URL. + if self.admission.server_process.poll() is not None:raise Refused('fixture custody backend unavailable') + with _absolute_budget(2.0): + conn=http.client.HTTPConnection('127.0.0.1',self.admission.port,timeout=2) + try: + conn.request(method,'/v1/'+path,body=None if body is None else encoded(body),headers={ + 'X-Vault-Token':self.admission.owner_token,'Content-Type':'application/json'}) + response=conn.getresponse();raw=response.read(1048577) + if len(raw)>1048576:raise Refused('backend response bound exceeded') + value=json.loads(raw,object_pairs_hook=_json_unique,parse_constant=_invalid_constant) if raw else {} + return response.status,value + finally:conn.close() + + def write(self): + if self.attempted:raise Refused('signer operation already attempted') + self.attempted=True + # All source/receipt checks precede generation; no seed import, argv, + # environment, temporary file or public output interface exists. + private=Ed25519PrivateKey.generate() + seed=b64(private.private_bytes(serialization.Encoding.Raw,serialization.PrivateFormat.Raw,serialization.NoEncryption())) + public=b64(private.public_key().public_bytes(serialization.Encoding.Raw,serialization.PublicFormat.Raw)) + document={'ED25519_PRIVATE_KEY':seed,'ED25519_PUBLIC_KEY':public,'kid':self.kid} + self.receipt.update(status='write-intent-unknown',public_key=public, + public_fingerprint='sha256:'+hashlib.sha256(public.encode()).hexdigest()) + self._save() # A durable intent must exist before any possible effect. + try: + status,result=self._http('POST',PATH,{'options':{'cas':self.expected_version},'data':document}) + if status!=200 or type(result) is not dict:raise Refused('signer write unconfirmed') + version=result.get('data',{}).get('version') + if type(version) is not int or version!=self.expected_version+1:raise Refused('signer write version unconfirmed') + self.receipt['kv_version']=version + status,result=self._http('GET',PATH+'?version='+str(version)) + if status!=200 or type(result) is not dict:raise Refused('signer readback unconfirmed') + data=result.get('data',{});stored=data.get('data') if type(data) is dict else None + metadata=data.get('metadata') if type(data) is dict else None + if (type(stored) is not dict or set(stored)!=FIELDS or any(type(v) is not str for v in stored.values()) + or type(metadata) is not dict or type(metadata.get('version')) is not int or metadata['version']!=version + or any(not hmac.compare_digest(stored[name],document[name]) for name in FIELDS)): + raise Refused('signer readback mismatch') + self.receipt.update(status='custody-verified-pending-independent-public-admission',exact_readback=True) + self._save() + return dict(self.receipt) + except BaseException: + # Persist only closed metadata; unknown never implies absence or retry. + # If receipt storage fails, the durable earlier intent remains unknown. + self.receipt.update(status='write-intent-unknown',exact_readback=False) + self._save() + raise Refused('signer custody outcome unconfirmed') from None + + +if __name__=='__main__': + raise SystemExit('production signer custody unadmitted; no live entry point') diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-base/workplans/RPF-WP-0035-credential-lane-implementation.md b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-base/workplans/RPF-WP-0035-credential-lane-implementation.md new file mode 100644 index 00000000..da4e2ded --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-base/workplans/RPF-WP-0035-credential-lane-implementation.md @@ -0,0 +1,1356 @@ +--- +id: RPF-WP-0035 +type: workplan +title: "Implement reviewed credential lanes with separate owner gates" +domain: financials +repo: railiance-platform +status: blocked +flavor: implementation +owner: codex +created: "2026-09-05" +updated: "2026-10-13" +related: + - RPF-WP-0032 + - RPF-WP-0033 + - RPF-WP-0034 +state_hub_workstream_id: "975db491-5412-5e27-8e34-14a2417bb039" +--- + +# Credential lane implementation + +One S3 queue for three designed lanes; each task keeps its own approval, +execution and closure boundary. This replaces the implementation tasks in the +three completed design workplans, not the designs themselves. No approval is +inherited by consolidation. INTENT binding: secure custody, dependable delivery, +stable consumer interfaces. Incident custody remains in RPF-WP-0027/0029. + +## Consolidate completed designs and owner dependencies + +```task +id: RPF-WP-0035-T01 +status: done +priority: medium +state_hub_task_id: "0f3606bb-e95b-5484-8a57-bcdd6e3916fd" +``` + +Completed 2026-09-05. Preserved the three designs under +`docs/credential-lane-designs/`, identified native owner responsibilities and +linked each superseded task below. Owners have not been sent new requests and +no new external acceptance is claimed. STATE-WP-0085-T09 is already done; +the signing dependency belongs to the proposed FLEX-WP-0020-T05 cutover. + +## Accept and provision secrets-engine service JWT login + +```task +id: RPF-WP-0035-T02 +status: wait +decision_id: 62aa95e4-3ccc-4867-8806-5e3db005b483 +depends_on: [KEY-WP-0039-T02, MASON-WP-0009-T05] +blocking_reason: "Agent work, not a human gate: claim refusals (KEY-WP-0039-T02 probe) and capabilities-self deny, then ops-mason MASON-WP-0009-T05." +priority: high +state_hub_task_id: "e0c82ea9-05a5-537e-8fbf-67534263572e" +``` + +2026-10-11: requalified — the remaining waits are other owners' tasks, not a human gate. See the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +Supersedes RPF-WP-0032-T02. Design: +`docs/credential-lane-designs/secrets-engine-service-jwt.md`. + +Platform owns the exact JWT mount/role/policy, effective-policy negative tests +and a metadata-only custody receipt. KeyCape owns issuer/JWKS and service +registration (KEY-WP-0009); secrets-engine owns service authentication and +authority consumption (SECRETS-WP-0008-T06, SECRETS-WP-0007-T04). + +**Unblock:** live registration and protected client custody, reviewed exact source +and attended apply authority. Issuer/JWKS and consumer source claims now agree; +see the 2026-09-27 return below. A service login does +not grant lane mutation authority. Do not build another identity provider or +lifecycle engine here. + +**Done when:** approved exact role succeeds for the intended service, wrong +issuer/audience/subject/claims and unrelated secret access fail, bounded TTL +and revocation are proven, the consumer explicitly opts into the verified +contract, and rollback/cleanup receipts contain no secret material. + +2026-10-09 (T03 source): founder ruled the tenant segment stays `coulomb` +(ops-mason `b72ff77d`). New CCR request type `workload-kv-operator-matrix` +(`scripts/operator_matrix_lane.py`): exact per-entry capabilities, OIDC role on +the existing `netkingdom` mount only, and exact agent denies on all four data +and metadata paths appended to the live `agent-high-risk-boundary` (live content +preserved; partial presence refused). `scripts/fluid_telegram_custody_move.py` +copies the four undocumented `infotech` entries with CAS 0, verifies all, then +metadata-deletes the sources. `scripts/kv_duplicate_retire.py` retires +`activity-core/default/llm-connect-provider-secrets` only if no live non-admin +policy grants it. Founder session (each helper prints nothing; read the receipts): + +```bash +cd ~/railiance-platform +export BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200 +W='warden access openbao-platform-admin-login --exec --' +# 1. dry-runs (no value reads, no writes) +$W python3 scripts/fluid_telegram_custody_move.py --dry-run --confirm 'MOVE fluid-telegram hall-of-helix to coulomb' --receipt ~/ft-move-dry.json +$W python3 scripts/kv_duplicate_retire.py --dry-run --confirm 'RETIRE activity-core/default/llm-connect-provider-secrets' --receipt ~/kv-retire-dry.json +# 2. lane: approve, confirm binding, apply +python3 scripts/credential-change.py approve CCR-2026-0039 --reviewer "platform-owner, fluid-telegram-owner, key-cape-owner (founder Bernd Worsch)" --comment "Approve ops-mason plan fluid-telegram-operator-credential-lane (spec 41a0ca27): four-entry matrix at coulomb/fluid-telegram/hall-of-helix, OIDC role on netkingdom, agent denies." \ + && python3 scripts/credential-change.py confirm-binding CCR-2026-0039 --reviewer founder --comment "groups=[fluid-telegram-operators] (LLDAP, member tegwick) and /assurance/level=aal2 match key-cape b2ed890f." \ + && $W python3 scripts/credential-change.py applier-apply CCR-2026-0039 --confirm "DELEGATED APPLY CCR-2026-0039" --actor founder --record-state-hub --quiet +# 3. custody move, then duplicate retirement +$W python3 scripts/fluid_telegram_custody_move.py --confirm 'MOVE fluid-telegram hall-of-helix to coulomb' --receipt ~/ft-move.json +$W python3 scripts/kv_duplicate_retire.py --confirm 'RETIRE activity-core/default/llm-connect-provider-secrets' --receipt ~/kv-retire.json +``` + +2026-10-09 (T03 founder session): CCR-2026-0039 applied at 10:30Z; readback +matched for the 8 boundary denies, policy and role. Custody move `moved`: all +four entries copied at coulomb v1 (operator-session from infotech v4) and the +infotech entries metadata-deleted. Duplicate +`activity-core/default/llm-connect-provider-secrets` retired; its first dry-run +refused on mount-wide `platform/metadata/*` survey grants, after which the check +was narrowed to data-path grants (`64ae594`). Receipts: +`docs/evidence/2026-10-09-fluid-telegram-t03-founder-session.json`. + +2026-10-03: the historical D1 routing was withdrawn because provision/delivery already completed. Owner routing now uses decision `ab85ae8a-12a0-4945-ae64-1d3d86d5b26f`, specifically independent archive readback and coordinated interim audit bearer revocation acceptance. `needs_human` and the wait remain; resolving a decision requires owner receipt re-check, not automatic completion. + +2026-10-03 (CUST-WP-0075): gate check. SECRETS-WP-0007-T04 is done (2026-09-27), so the gate named in the design is open. It is not the last one: the design says to confirm the exact live client registration and protected client-side custody before writing, and positive-login proof needs a real KeyCape service JWT. KeyCape's contract (`openbao-service-auth-contract.md`) and KEY-WP-0009 claim source registration only; the live registration of `secrets-engine-openbao` and its client-credential custody are "a separate approved custody action" that no workplan task owns yet (SECRETS-WP-0008-T06 waits on this task). Re-qualified with `blocked_on: message-from:key-cape`; key-cape was asked for the owning task id, which will replace it as `depends_on`. The design stays proposed and no child command was written. Not approvable in D1 yet. + +2026-10-04: Founder authorized the prepared coordination request. Sent +`b4fc62ea-f92c-4410-919a-9f3cce2d406b` to key-cape on preparation thread +`f84637fa-2355-4971-a2dc-7f1fd01710a8`, referencing platform source +`6b91d510395215d178d60ee8884e7fc00930a0cf`. Requested actual registration and +protected-custody owning tasks/status/revisions and non-secret receipts. Source +registration is not live custody; no value fetch or live registration was +requested. T02 remains waiting on the owner return and separate execution gates. + +2026-10-04 blocked-task review: KeyCape returns 58826056/eb20a78c now identify +KEY-WP-0037-T02/T03/T04, replacing the unowned-registration wait with real +dependencies. Prepared proposed CCR-2026-0033 and exact-path issuer policy/auth, +sso-only ESO and evidence checklist from the returned candidate coordinates. +No issuer/consumer value, registration or native issuance is supplied by them. +secrets-engine must return independent source acceptance of consumer host/path, +protected delivery and rotation/revocation ownership; awaiting that source phase +does not depend on its full live service-login task. KeyCape's exact-primary sync +remains pending its scoped historical identity repair. Requirements and acceptance +boundaries: `docs/provisioning-windows/2026-10-04-1000/dependency-requirements.md`. +This workplan was already blocked and remains blocked on its open owner/live gates. + +2026-10-06: secrets-engine returned consumer custody source acceptance +(message 680136e2, SECRETS-WP-0012, commit a3897c2). CCR-2026-0033 finalized as +**proposed**: KV path corrected to `platform/workloads/keycape/secrets-engine-openbao` +(applier scope), consumer copy coordinates with D1-D4 pending founder choice, +rotation/revocation ownership, live order and rollback. Attended custody child +`scripts/keycape_secrets_engine_openbao_custody.py` with fake-only tests +(`tests/test_keycape_secrets_engine_openbao_custody.py`) refuses without an exact +founder decision id recorded in the approved CCR. Nothing executed, generated or +applied; nothing added to active GitOps. The founder approval it needs is T09. + +2026-10-09: KEY-WP-0037 finished 2026-10-07 (registration live, issuance +verified 10/10, key-cape e0b5fae); CCR-2026-0033/0034 applied. Source for this +lane is now complete as **CCR-2026-0038** (proposed, +`credential-change-requests/CCR-2026-0038-secrets-engine-service-jwt-login.yaml`). +The delegated applier gained a narrow `service-jwt-login` request type +(`scripts/service_jwt_lane.py`): auth mount fixed to `keycape-services`, policy +must equal the generated login-self policy, role/config keys allow-listed, +TTLs at most 15m, uses 1..16, `token_no_default_policy`, refusal if the mount +exists with another type, and a value-free readback compare after the writes. +Policy `secrets-engine-login-self` now also carries explicit `deny` on +`platform/{data,metadata}/workloads/keycape/secrets-engine-openbao` so +ops-mason invariant (ii) (no capability on the client-secret path) holds even +if identity groups were ever attached. Tests: `tests/test_service_jwt_lane.py` +(8) plus the updated contract test; full suite unchanged apart from 5 +pre-existing failures unrelated to this lane. + +Founder apply (one line; approval, binding confirmation and silent apply): + +```bash +cd /home/worsch/railiance-platform && python3 scripts/credential-change.py approve CCR-2026-0038 --reviewer "platform-owner, key-cape-owner, secrets-engine-owner (founder Bernd Worsch)" --comment "Approve service-JWT login lane: mount keycape-services, role secrets-engine-openbao, policy secrets-engine-login-self (self endpoints + deny on the client-secret path)." && python3 scripts/credential-change.py confirm-binding CCR-2026-0038 --reviewer founder --comment "Bound claims match KeyCape registration: aud secrets-engine-openbao, sub service:secrets-engine, principal_type service, tenant tenant:platform, roles secrets-engine, scope openbao:login; issuer https://kc.coulomb.social RS256." && warden access openbao-platform-admin-login --exec -- python3 /home/worsch/railiance-platform/scripts/credential-change.py applier-apply CCR-2026-0038 --confirm "DELEGATED APPLY CCR-2026-0038" --actor founder --record-state-hub --quiet +``` + +Done after that: login proof with a real KeyCape service JWT +(SECRETS-WP-0012-T03 probe-openbao; policies exactly +[secrets-engine-login-self], capabilities-self deny on the guarded paths, +revoke-self), negative claim checks, then publish the consumer contract file +and ops-mason MASON-WP-0009-T05 rechecks invariant (ii). + +## Implement the platform operator-write CCR contract and Fluid lane + +```task +id: RPF-WP-0035-T03 +status: wait +decision_id: 62aa95e4-3ccc-4867-8806-5e3db005b483 +blocking_reason: "Founder session done 2026-10-09; waits on ops-mason verification (MASON-WP-0005-T05) and the FT-WP-0002 owner salt CAS probe." +priority: high +depends_on: [MASON-WP-0005-T05, FT-WP-0002] +state_hub_task_id: "f47e5bc5-6f3c-54bb-aa35-260ad03892ba" +``` + +2026-10-11: requalified — founder part done; remaining waits are owner tasks. See the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +Supersedes RPF-WP-0033-T02. Design: +`docs/credential-lane-designs/fluid-telegram-operator-kv.md`. + +Platform owns the per-path capability schema/validator, exact OpenBao policy +and accepted custody coordinates. MASON-WP-0005 owns construction coordination +and engine integration; KeyCape/NetKingdom own OIDC/MFA and group membership; +FT-WP-0002 owns client CAS, prefix correction, output containment and Telegram +application acceptance. Retain the existing read-only CCR semantics. + +**Unblock:** accept tenant/path and per-entry field/capability matrix; confirm +actual group/assurance and callbacks, reviewed construction contract and writer +authority. Contract review can proceed without a live credential; the final +schema cannot be treated as accepted solely because a draft exists. + +**Done when:** validation rejects broad/unsupported grants, the consumer proves +CAS=0 first-write behavior and no value output, approved identities can perform +only the exact matrix, negative/expiry/revocation checks pass, custody is seeded +through the separate writer, and the verified route has a safe handoff receipt. +The unattended adapter remains a separate demand and gets no operator session. + +2026-10-03: the historical D1 routing was withdrawn because provision/delivery already completed. Owner routing now uses decision `ab85ae8a-12a0-4945-ae64-1d3d86d5b26f`, specifically independent archive readback and coordinated interim audit bearer revocation acceptance. `needs_human` and the wait remain; resolving a decision requires owner receipt re-check, not automatic completion. + +## Accept the needed signing lane and deliver it to the owning runtime + +```task +id: RPF-WP-0035-T04 +status: done +priority: medium +state_hub_task_id: "35a85846-61d5-54ce-8b18-ede45733d53c" +``` + +Supersedes RPF-WP-0034-T02. Design: +`docs/credential-lane-designs/state-hub-preflight-signing.md`. + +Platform owns signing-key custody, exact read policy/role and scoped delivery +acceptance. State Hub owns API chart/env wiring, all-replica rotation fencing +and health. FLEX-WP-0020-T05 owns the rename preflight/cutover dependency; +STATE-WP-0085-T09's adoption-plan delivery is already complete. + +**Unblock:** State Hub/repo-manager and the consuming migration owner confirm +that this transitional State Hub lane is still needed during retirement; +record the target runtime, namespace/SA/auth audience and an executable +rotation fence, plus approved writer and deployment window. Do not broaden the +lane into a general repository-rename authority or provision for a stale demand. + +**Done when:** protected one-time generation, API-only ESO delivery, negative +access checks and a non-mutating signed preflight pass; every API replica uses +the accepted version; rotation/invalidation and recovery are evidenced. No +repository rename is part of S3 lane acceptance. If demand is withdrawn, record +the owning decision and cancel this task explicitly rather than provision it. + +2026-09-05 continuation: verified the live primary cluster identity and healthy +single API replica; the signing ExternalSecret is still absent. Added a writer +guard against wrong-cluster kubeconfigs before any OpenBao access. The default +workstation kubeconfig's local port-forward listener was unavailable. Activation +still needs the contained attended OIDC/MFA login and the acceptance evidence +above; source preparation is not live completion. See +`history/2026-09-05-preflight-signing-activation-readiness.md`. + + +Completed 2026-09-05: user-led attended activation generated version 1 and +rotated to version 2 with every API replica stopped. Exact access and negative +identity checks passed; ESO delivery and API-only exposure passed; the recovered +single API replica accepts new signed preflight and rejects its predecessor by +signature, with healthy primary identity and no preflight blockers. State Hub +chart commit `49e3182`, Helm revision 59. No repository rename executed. +Evidence: `docs/evidence/RPF-WP-0035-T04-signing-activation-2026-09-05.json`; +closure: `history/2026-09-05-preflight-signing-activation-complete.md`. + +## Admit KeyCape approval-engine client custody and delivery + +```task +id: RPF-WP-0035-T05 +status: done +needs_human: false +intervention_note: "" +priority: high +state_hub_task_id: "e15d62c9-e5da-5721-a135-87c050f7851c" +``` + +Answers KEY-WP-0013-T02 (State Hub message +`278a3ebe-b529-49f6-bd1a-e3ebcf318260`). Admission: +`docs/credential-lane-designs/keycape-approval-clients.md`; requests +`CCR-2026-0017` (secrets-engine-approval) and `CCR-2026-0018` +(approval-engine-operator). + +Platform owns the two custody paths, exact-path read policies, Kubernetes auth +roles and the KeyCape-side ESO delivery. KeyCape owns the client registrations, +issuance, claim set and disablement; approval-engine owns approval semantics and +audit of emitted actions. + +2026-09-08 admission response: both proposed KV paths confirmed unchanged; field +`client_secret` corrected to `CLIENT_SECRET` for the uppercase KV convention and +CCR validator. Kubernetes delivery references confirmed against the live `sso` +namespace, which already resolves `KEYCAPE_RAPP_QONTO_CLIENT_SECRET` through the +same `secretKeyRef{key: client-secret}` shape on image `main-153258b`. Attended +authority named as the governed `openbao-platform-admin-login` lane +(`founder_required`); KeyCape's refusal to treat its generic `warden plan` +database match as authorization was correct. Rollout agreed as one attended +session with the KeyCape reading build pinned but undeployed, ordered after the +Authelia issuer precondition in message `c8b1ad10-dae8-48fb-a0ea-7e2a101c54bf`. +Policies, ClusterSecretStores and ExternalSecrets are written and validated, +none applied. + +**Unblock:** owner approval of both CCRs, a KeyCape image that reads both +environment names, the settled Authelia `iss` pin, and a founder-attended window +date. Verifier-side custody only — no client-side read lane is admitted, and no +scope beyond the two declared sets. + +**Done when:** both CCRs are approved, the attended window seeds both KV paths +with CAS=0, policies/roles/stores/ExternalSecrets apply and sync, the KeyCape +build resolves both environment names, KeyCape evidences live JWKS signature and +exact claim bindings with excess scopes denied (operator `consume`, human +`consume`), platform evidences cross-path/wrong-identity/out-of-namespace denial, +and every receipt is metadata-only. If either registration is abandoned, KeyCape +disables it before the KV version is destroyed. + +### 2026-09-08 actual upstream issuer returned + +The admitted KeyCape one-shot probe verified the actual signed upstream issuer +as **`https://auth.coulomb.social`** at 21:44:44 UTC. Signature, audience, +validity window and nonce checks passed and the pinned Job exited 0. All +five temporary resources and the Pod were removed; normal KeyCape Deployment +and config Secret metadata are unchanged. See +`docs/evidence/2026-09-08-keycape-upstream-issuer-proof.json`. + +T05's unknown-issuer input is resolved. The configuration owner still ensures +`authelia.issuer` equals that exact HTTPS value before the custody window. +Both CCRs remain proposed and await the named reviews; this probe grants no +custody mutation or client-side read. Keep the current authority preflight and +this signed-token proof as separate receipts. Live ESO/client/approval and +separate audit/client-side custody acceptance remain open. + + +2026-09-09 configuration and review-queue return: NetKingdom pinned the verified +HTTPS issuer, using an atomic UID/resourceVersion test and independent readback. +Secret revision `58713343`; unrelated configuration and signing key unchanged; +no Deployment rollout. Receipt: `docs/evidence/2026-09-09-keycape-upstream-issuer-pin.json`. + +The two existing CCRs remain proposed. They now link to concrete pending review +decisions, with platform-operator and key-cape-owner named explicitly. See +`docs/credential-lane-designs/keycape-approval-clients-review.md`. T05 owns this +human dependency; HFACT consumes it without a duplicate approval request. +Custody/ESO activation, client verification and the separate client-side/audit +lanes remain open. Current CLI apply plans refuse the proposed requests. + + +2026-09-09 admission: the user explicitly approved both CCRs in the named +platform-operator and key-cape-owner roles. Both source requests are approved +and both linked Hub decisions are resolved. Receipt: +`docs/evidence/2026-09-09-keycape-approval-admission.json`. The completed review +intervention is cleared; T05 is progress while the contained first-provision +procedure is exercised and the admitted attended rollout is carried through. +Verifier-side scope, separate client-side/audit lanes and live acceptance remain +as defined in the reviewed requests. + +2026-09-09 verifier-side return: both CCRs are verified after recorded user approval, +CAS=0 version-1 custody, native read/auth denials and revocation, Valid stores, +SecretSynced delivery, compatible KeyCape rollout and live positive/negative +service checks. Existing human OpenBao login passed again on the new image. +Receipt: `docs/evidence/2026-09-09-keycape-verifier-admission.json`. Failed attempts restored the compatible +configuration/image and detached delivery; final resume reused version 1. + +T05 is done against its verifier-only acceptance criteria. Its former +"remains progress for client-side reads" statement expanded the task past its +reviewed scope; that residual now has the live owner task RPF-WP-0035-T06 below. +Neither Warden fetch selector is resolvable through these verifier-only CCRs. +Do not re-request the completed two named reviews or reseed these paths. +Rotation is a distinct, version-guarded operation. + +## Dispose of the ungoverned whynot-design npm duplicate + +```task +id: RPF-WP-0035-T07 +status: wait +decision_id: 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa +blocking_reason: "Hold kept by D3 until SECRETS-WP-0006-T06 moves publishing off the legacy whynot-design npm path; then rotate and prove a fresh publish." +priority: high +depends_on: [SECRETS-WP-0006-T06] +state_hub_task_id: "0dd7c9a5-65a0-53fc-b6c3-5ad96ee56f7b" +``` + +2026-10-11: requalified after founder decision D3 (trust root, build-mode default) resolved — see the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +Found by the attended session on 2026-09-10 while settling the npm field +question. `secret/coulomb/whynot-design/npm/publish` exists at version 1, +created 2026-07-03T15:00:44Z and never updated — five days after the governed +lane at `platform/workloads/coulomb/whynot-design/npm-publish` was verified +(CCR-2026-0001, 2026-06-28). It sits outside that lane's exact-path policy and +outside any CCR here. Receipt: +`docs/evidence/2026-09-10-npm-lane-field-resolution.json`. + +Only metadata was read. Its field names were not enumerated, its value was not +read, and nothing was deleted — a location holding real credential material is +disposed of deliberately, not tidied away in the session that found it. + +The likely explanation, unconfirmed: secrets-engine reports the lane's field +under a lowercase name that is absent from the governed path, and their catalog +declares this legacy location. If their proven pilot publish read from here, +then a working production lane has been running off an ungoverned duplicate, +and the governed lane's acceptance evidence describes a path the consumer does +not use. That is worth establishing before anything is removed. + +**Operator decision, 2026-09-15:** destroy the legacy path after confirming the +governed lane is the live consumer. Do not wrap `secret/coulomb/whynot-design/npm/publish` +in a CCR. Value remains unread. Platform will ask secrets-engine which path +publish actually reads before any attended destroy. + +**Unblock:** admit the governed exact-path AppRole policy and coordinated catalog +path/field migration under SECRETS-WP-0006-T06; prove native delivery from the +governed lane before the attended legacy destroy. secrets-engine confirmed the +legacy source path on 2026-09-21 (message `355424d4-17ab-435e-9e1d-6921775cb4a2`). +No comparison of values, fingerprints, lengths or shapes is needed or authorized. + +**Done when:** the legacy path's provenance and consumer are established, the +governed lane is confirmed as the one in use or the consumer is moved to it as a +reviewed lane change, the duplicate is destroyed under the September 15 operator decision and the +disposition is recorded. Do not bring the legacy duplicate under a CCR. If the value proves to be live and +ungoverned, treat it as an exposure with the same custody rules as RPF-WP-0027: +never record the value, fingerprint, length or shape. + +2026-10-03: human gate routed to hub decision 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa (D3: Trust root and secret custody: unseal/recovery holders, break-glass, and the deferred rotation of exposed material) by CUST-WP-0075; resolving that decision raises C-40 here. + +## Admit the separate approval client-side readers + +```task +id: RPF-WP-0035-T06 +status: done +decision_id: 62aa95e4-3ccc-4867-8806-5e3db005b483 +priority: high +intervention_note: "" +state_hub_task_id: "68bff751-e48b-548b-8fb4-dfb3b16210c2" +``` + +2026-10-11: requalified after founder decision D1 (attended window standing rule) resolved — see the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +**Current return, 2026-09-10:** CCR-2026-0020 is cancelled on the requesting +Approval Engine owner's explicit withdrawal, source +`849c75bb094613ff6ac1a1d4cda56a745520c5a1:docs/keycape-service-registrations.md`. +No presenter exists and no reader is wanted. The validator now accepts terminal +cancellation of an incomplete request only with owner/source/reason evidence, +retained declared omissions and a disabled, non-resolvable front door. Apply +remains refused. No live identity, policy, role, custody or verifier was changed. +Human approval follows existing INFD-WP-0001-T07/T08; future service requesters +need a separate narrow registration, not this withdrawn bundle. + +**Operator binding confirmed, 2026-09-14:** The user explicitly selected +`net-kingdom-admins` and authorized applying CCR-2026-0019. Its OIDC role is +`secrets-engine-approval-client-workload-kv-read`, aligned with the platform +applier naming rule; policy and exact KV scope are unchanged. The metadata dry +run passes with no warnings. Attended apply and exact role/policy readback passed; the enclosing Warden +command exited successfully after its self-revocation/cleanup. Receipt: +`docs/evidence/2026-09-14-ccr0019-operator-binding.json`. Scoped delivery proof +remains pending; the front door stays non-resolvable. Completed CCR-2026-0017/0018 +remain closed and T06 stays `wait`. + +Consumer procedure returned in source, 2026-09-10: +`secrets-engine@98d72ceb1dbcff2d2a80fb8c3058d76777a0ac93:docs/approval-service-auth.md` +specifies the requested private 0700 runtime directory, 0600 file outside Git, +path-only use, claim/consume lifetime and attended cleanup including hard-stop +residual inspection. CCR-2026-0019 retains this source-review comment without +changing admission status. Exact group, required-owner review, attended apply and +native positive/negative/cleanup evidence remain. No role or credential changed. + +Separate retained owner decision: KeyCape's 2026-09-10 return +`21427688-725f-4dea-aab4-7c78fd4328d2` identifies the already-live, unpresented +CCR-2026-0018 registration. Approval Engine, KeyCape and Platform must explicitly +decide retention/expiry or coordinated disablement. Reader cancellation neither +disables that live registration nor accepts indefinite retention. Keep this +disposition in T06; it is separate from the wanted CCR-2026-0019 factory reader. +No unilateral issuer/config/Secret change is authorized by this closeout. + +**Operator decision, 2026-09-15:** coordinated disablement with KeyCape and +Approval Engine. Platform will not disable the live registration or verifier +delivery unilaterally. T06 stays `wait` until both owners confirm the joint +disablement sequence. + +Residual handoff from RPF-WP-0035-T05; consumes the completed verifier custody +without extending CCR-2026-0017/0018. Owner: railiance-platform with the named +secrets-engine and approval-engine operator consumers. + +Prepare separate exact-reader admissions for existing version-1 paths: +`platform/workloads/secrets-engine/approval-client` and +`platform/workloads/approval-engine/operator-client`, field `CLIENT_SECRET`. +Name each actual actor/placement, bounded authentication/reader policy, protected +consumer delivery, cleanup/revocation and rollback, then obtain the required +owner reviews for those concrete requests. No reseeding, rotation, shared reader, +reuse of the sso verifier Secret, or implicit operator consume grant. + +2026-09-09 preparation return: both exact-reader admissions are prepared as +`CCR-2026-0019` (secrets-engine) and `CCR-2026-0020` (approval-engine-operator), +with their exact-path read policies written and committed. Design: +`docs/credential-lane-designs/keycape-approval-client-side-readers.md`. Both +reuse existing version-1 custody; no reseed, rotation, shared reader or verifier +Secret reuse. Both are `in_flight` and unapproved; nothing is applied. + +Read-only survey findings that decided the two shapes. Namespace +`secrets-engine` holds only ServiceAccount `secrets-engine` with no workload, +and `flex-auth/flex-auth-secrets-engine` is that consumer's PDP, not the +service; secrets-engine consumes the client secret through an operator-run CLI +reading `SECRETS_ENGINE_APPROVAL_CLIENT_SECRET_FILE` (SECRETS-WP-0009-T03, +revision `9eb07fd`). So reader 1 is an attended operator-workstation OIDC lane, +not an ESO lane. approval-engine has no namespace, workload or Service; its +manifest is unapplied, and no owner source names who presents the operator +client — approval-engine verifies these tokens and never holds them. + +**Unblock:** reader 1 needs the exact NetKingdom/KeyCape group claim for the +authorized operator, plus secrets-engine confirming the file mode and removal +step; `openbao.auth` is declared missing rather than filled with a placeholder +that would later read as a confirmed binding. Reader 2 needs its owner to name +the presenting actor and placement, or to record that no client-side reader is +wanted so the request is cancelled. Naming a reader for the widest approval +scope without that decision is the failure this task exists to avoid. + +**Done when:** each reader has a named actor and placement, a completed and +reviewed auth binding, admitted delivery, and its owner approvals; positive and +negative checks pass, including cross-path, wrong-identity and parent-list +denial and operator `consume` denial; or the request is explicitly cancelled by +its owner. Rotation stays a distinct version-guarded operation shared with +CCR-2026-0017/0018. + + +Consumer input supplied 2026-09-09: secrets-engine now implements per-request +`secrets-engine-approval` exchange from a protected temporary client-secret file, +with exact approval-engine / tenant:platform / read-or-consume scope, no token +file and no fallback. The pinned KeyCape image and actual Approval Engine source +passed its disposable component exercise; only the PDP was a sequencing double. +See `secrets-engine/docs/approval-service-auth.md` and the metadata receipt +`secrets-engine/docs/evidence/2026-09-09-approval-identity-exercise.json`. + +Routing check: `warden route show keycape-secrets-engine-approval-client` is +unknown; generic `openbao-api-key` routes ownership only and is not a delegable +lane. Do not advertise a working fetch command before this task supplies its +own accepted native delivery return. Client-side admission is not ready for a +new human decision until exact requests and contained execution/rollback checks +are reviewable; the completed verifier reviews must not recur in that queue. + +**Done when:** each retained consumer admission is approved and implemented, or +its requesting owner explicitly cancels it (CCR-2026-0020 now satisfies that branch); +actual consumer authentication/delivery succeeds; sibling/listing/wrong-reader +and scope refusals plus reader expiry/revocation/cleanup are evidenced; version-1 +custody and verifier availability remain intact. Return the source and metadata +receipts to HFACT-WP-0001-T03, SECRETS-WP-0009-T03 and APPROVAL-WP-0002-T01/T05. +Audit receiver/sender custody remains AUDIT-WP-0009-T09 and must not be folded +into this client-identity grant. + +2026-10-03: the historical D1 routing was withdrawn because provision/delivery already completed. Owner routing now uses decision `ab85ae8a-12a0-4945-ae64-1d3d86d5b26f`, specifically independent archive readback and coordinated interim audit bearer revocation acceptance. `needs_human` and the wait remain; resolving a decision requires owner receipt re-check, not automatic completion. + +## Admit the two factory audit-sender custody lanes + +```task +id: RPF-WP-0035-T08 +status: wait +decision_id: "ab85ae8a-12a0-4945-ae64-1d3d86d5b26f" +blocking_reason: "Approved conditionally (ab85ae8a, standing change rule): executes once independent archive readback and the interim bearer revocation receipt exist; owner work with audit-core." +priority: high +assignee: railiance-platform +intervention_note: null +blocked_on: message-from:audit-core +state_hub_task_id: "0ef52c26-2669-5cd1-8149-b1f6fcdda6cb" +``` + +2026-10-11: requalified — ab85ae8a resolved under the standing build-mode change rule. See the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. + +2026-10-03 correction (CUST-WP-0075, informed-decision sitting draft `55fb078`): the D1 routing was wrong. First provision and delivery already ran on 2026-09-11, with seed and delivery receipts, and the review packet says not to repeat them. The task is not a provisioning-window act. It was taken off decision D1, and its blocking_reason now names what actually remains. railiance-platform should re-qualify it further if the receiver rollout has since happened. + +2026-10-03 (CUST-WP-0075): re-qualified. The receiver rollout already happened: Audit Core c82e0442de0f carries evidence_kind and native producer accepted/duplicate and scope/read-refusal checks passed 2026-09-11 10:42 UTC (`docs/credential-lane-designs/factory-audit-senders-review.md`, `factory-native-acceptance.md`). Remaining: independent archive readback and audit bearer-revocation acceptance. Still not a provisioning-window act. + +Consume AUDIT-WP-0009-T09/T11's exact declarations for approval-engine and +informed-decision: tenant:platform, write-only, load-bearing, redact. Source +preparation supplies two approved CCRs, independent exact-path policies/ESO +projections, and the attended `factory_audit_custody.py` first-provision helper. +Its CAS and request-provenance checks preserve unrelated senders and recover +interrupted writes without generating replacements. The user approved all named review roles on 2026-09-11. Native +provision/delivery/receiver-ingestion acceptance remains open. + +The 2026-09-11 native read-only check found an additional deployment dependency: +receiver image c2fe39a is 1/1 Ready but does not support evidence_kind. The +synthetic native probe now refuses before any credential read. Current receiver +source passes. AUDIT T09/T11 retain compatible release/source-manifest rollout; +Approval Engine's missing namespace remains its owner prerequisite. + +[Review packet](../docs/credential-lane-designs/factory-audit-senders-review.md). +[Preparation evidence](../docs/evidence/2026-09-11-factory-audit-custody.json). +Do not fold these senders into CCR-2026-0019 or the cancelled CCR-2026-0020. + +2026-10-03: the historical D1 routing was withdrawn because provision/delivery already completed. Owner routing now uses decision `ab85ae8a-12a0-4945-ae64-1d3d86d5b26f`, specifically independent archive readback and coordinated interim audit bearer revocation acceptance. `needs_human` and the wait remain; resolving a decision requires owner receipt re-check, not automatic completion. + +## Dependency review — 2026-09-06 + +### 2026-09-09 tenant question resolved — no change needed + +The `tenant:coulomb` / `tenant:platform` discrepancy raised against T02 is not a +discrepancy. KeyCape confirms decision `5ed3fb35-eca9-413a-82b9-95171ba85bf6` +binds the *approval chain* to the landlord zone and was applied to exactly two +registrations, `secrets-engine-approval` and `approval-engine-operator`. +`codex-railiance-platform` is not in that chain and correctly stays +`tenant:coulomb`, as do `secrets-engine-openbao` and the human directory default. +KEY-WP-0013-T04 records this and their +`TestServiceRegistrationTenantsAreExactPerDecision` pins every reviewed client's +tenant against the real fixture, so a reintroduced alias fails their build. + +`docs/credential-lane-designs/secrets-engine-service-jwt.md` already says +`tenant:coulomb` and is therefore correct as written. Bind the exact role to +`tenant:coulomb`. Do not "correct" it to `tenant:platform` later; that would +break the issued claim. + +SECRETS-WP-0008-T02 now records the local PIP claim/validation join implemented +and tested. Its remaining gate is the unreachable approval-engine claim endpoint +and access-engine Check (SECRETS-WP-0007-T04). Do not carry forward the old local +stub as a blocker. T02 still needs the accepted service issuer/JWKS, claims, +audience and consumer binding. T03 still needs confirmed operator group/tenant +and consumer semantics; T04 is already complete. No new owner acceptance inferred. + + +### 2026-09-08 attended capability preflight + +HFACT-WP-0001's continued execution verified the existing first-provision +front door without provisioning anything. `warden plan` selected +`openbao-platform-admin-login` / founder_required / one oidc_login. The native +`scripts/openbao-attended-exec.py` supplied the existing WSL browser launcher; +a direct attempt had no launcher and failed before handoff. Its first revocation +result was unconfirmed and is preserved in the receipt rather than silently +reclassified. The two subsequent contained sessions completed self-revocation +and helper cleanup. + +`scripts/keycape-approval-custody-preflight.py --receipt ` is +a silent, read-only command for that envelope. The installed Bao CLI supports +one path per `token capabilities` call; the final run used six single-path calls. +Create/update authority is present on both exact policy paths, both Kubernetes +auth-role paths and both KV data paths from CCR-2026-0017/0018. This is authority +metadata, not a secret-data read or policy/role/KV mutation. Receipt: +`docs/evidence/2026-09-08-keycape-approval-custody-preflight.json`. + +T05 remains wait: both CCRs are still proposed, the actual upstream ID-token +issuer precondition remains open, and no verifier-side credential is provisioned. +Client-side retrieval and audit-sender custody are still separate owner returns. +The capability receipt is not a review approval or service readiness proof. + +### Sender approval recorded — 2026-09-11 + +The user replied "good, go on" to the explicit CCR-2026-0021/0022 question naming +platform-operator, audit-core-owner and both producer owners. Both exact requests +are approved; their existing State Hub decisions are resolved. This clears the +review request only. Receiver rollout, namespace readiness, attended custody and +positive/negative native evidence remain the execution gates. + +### Native receiver and attended execution return — 2026-09-11 + +Audit Core c82e0442de0f is deployed and passes the native synthetic contract. +Its existing 32-event chain/head is unchanged. The owner Approval Engine +namespace now exists and all four ESO objects pass strict server dry-run. +The two exact ingress rules are applied; sender custody/ESO application is not. + +Warden selected founder_required/oidc_login and attempted the reviewed silent +seed command through the contained wrapper. Login failed before command +handoff; no custody receipt was created. Warden could not confirm remote +session revocation. Await operator browser/MFA feedback and login/session +resolution. Approvals remain valid; T08 waits for the identity act, not review. + +The receiver check now selects component=receiver, so retained attestation-job +pods cannot falsely block a stable receiver. Eighteen custody tests pass. +[Native return](../docs/evidence/2026-09-11-factory-receiver-live.json). + +### Attended custody retry succeeded — 2026-09-11 + +The user requested a retry and completed the attended identity act. Both CCRs +are applied: independent version-1 custody and registry CAS 7→8 succeeded, +preserving other senders/fields. Warden exited 0 with self-revocation confirmed +for this session. This does not retrospectively attest the earlier failed +login's remote session state. The old login wait is cleared; T08 is progress +for ESO delivery, exact native reader/namespace refusals, receiver reload and +producer acceptance. No token is reseeded or rotated on continuation. +[Seed receipt](../docs/evidence/2026-09-11-factory-audit-sender-seed.json). + +### Delivery prepared; fresh login did not hand off — 2026-09-11 + +The delivery helper and custody receipt are committed at `44314ca` and exactly +projected on primary/railiance01. Seven delivery tests and 18 custody tests +(including 11 actual disposable OpenBao cases) pass. The fresh attended +delivery invocation exited 5 before command handoff; no native delivery +receipt exists, no ESO application or receiver restart ran. The receiver +remains 1/1 Ready on c82e0442de0f. Warden could not confirm revocation for this +failed login; that is separate from the successful seed session. T08 now waits +for this delivery identity act. Neither CCR review nor first provision reopens. + +[Delivery return](../docs/evidence/2026-09-11-factory-audit-delivery-login.json). +Use the reviewed delivery command with a new receipt after login feedback. +Actual producer ingestion/duplicate/refusal and bearer revocation acceptance +remain open under AUDIT-WP-0009-T09/T11. + +### Native delivery accepted — 2026-09-11 08:27 UTC + +The user returned and requested another login attempt. It succeeded and the +reviewed delivery command completed in 28 seconds. Both native ESO readers +passed exact-path access and explicit sibling/registry/metadata/listing denials, +wrong-SA/namespace refusal and the coding-agent deny check. Each 900-second +reader session was revoked and lookup refusal verified. Both intended +ExternalSecrets are Ready; exact producer value and ESO ownership match. The +disallowed namespace produced an explicit store restriction and no Secret; +the uniquely owned namespace is now absent. + +Registry version 8 matches the delivered receiver JSON. Audit Core reloaded +and remains 1/1 Ready on c82e0442de0f; /readyz reports operational/durable with +tamper_evidence=false, as bounded by AUDIT-WP-0009-T12. Warden exited 0 and +confirmed self-revocation for this successful session. Earlier failed login +receipts remain historical and are not retroactively attested. + +The login wait is cleared. T08 remains progress and CCR21/22 remain applied +for native producer ingestion/duplicate/scope/read-refusal and bearer +revocation acceptance under AUDIT T09/T11. No credentials were reseeded or +rotated. No producer was deployed and no factory attempt or paid call ran. +[Native delivery receipt](../docs/evidence/2026-09-11-factory-audit-delivery-live.json). + +### Native producer return — 2026-09-11 10:42 UTC + +Both actual source adapters used their own ESO-delivered credential inside a +bounded native Job. Each synthetic event received 202, retained its durable +outbox after an injected lost receipt, and received duplicate 200 after a fresh +process reopened the outbox. Each source's reconciliation reported exactly one +record for its unique probe class. Wrong source/tenant, seven archive read +routes, sibling reconciliation and invalid-bearer requests were refused. + +The first Informed Decision probe exposed a private-store startup defect: +fsGroup volumes add inherited setgid to a newly created 0700 directory. +Informed Decision `1a12223` corrects creation without repairing unsafe existing +data. The regression failed before the fix; the available suite now passes +335 tests with 39 optional checks skipped. Native retry verifies the exact +corrected helper. Six probe tests and eleven rebuilt-container checks pass, +including actual setgid-volume startup, restart/restore and cleanup. + +All temporary probe Jobs, Pods, ConfigMaps and NetworkPolicies are verified +absent. Receiver c82e0442 remains operational/durable; tamper_evidence=false. +Producer verification requires no operator registry read or new OpenBao login. +Independent readback is a separate attended command consuming the successful +receipt; it must not rerun the producer jobs. Both attended verification-login +attempts this session ended before handoff (exit 5; remote revocation +unconfirmed), so independent archive readback remains pending. + +This proves synthetic outbox delivery/recovery with native sender credentials, +not domain-transaction atomicity, deployed producer services or human binding. +An invalid bearer is not a revoked formerly valid bearer. AUDIT T09/T11 and +RPF T08 remain progress for independent readback and audit bearer-revocation +acceptance; CCR21/22 remain applied. Service/policy/human admission and native +runtime/spend gates remain separate. Factory attempts and paid calls remain 0. + +[Native producer receipt](../docs/evidence/2026-09-11-factory-native-producers.json). + + +## Independent audit readback — 2026-09-11 13:11 UTC + +The existing attended readback command completed with exit 0 while the user +was present. Independent read-only identity `operator` found both retained +`factory-audit-20260911104152-94aced` producer events with exact source and +`tenant:platform`; receiver integrity is intact across 36 events. The wrapper +confirmed this session's self-revocation and private-helper cleanup. Prior +failed sessions' unconfirmed revocation remains historical unresolved evidence. + +This supersedes the earlier readback-login wait. No producer jobs were rerun, +no credentials were reseeded and no event was written by the reader. The +inherited zero registry-read count belongs to the producer phase; the attended +reader did consume registry version 8. CCR21/22 stay applied and owner tasks +stay progress pending formerly-valid audit-bearer revocation acceptance. +Service/domain-transaction/human and factory runtime/spend admission remain +separate; factory attempts and paid model calls remain zero. + +Receipt: [native readback](../docs/evidence/2026-09-11-factory-native-readback.json). + + +### T06 native reader acceptance — 2026-09-14 + +The scoped Warden login lane `secrets-engine-approval-client-login` now routes +to the applied OIDC reader and the platform's silent preflight. The installed +Warden package still carries an older catalog; use the explicit source catalog +`WARDEN_ROUTING_CATALOG=/home/worsch/ops-warden/registry/routing/catalog.yaml` +until its next normal installation refresh. This lane authenticates the reader; +it is not a raw secret fetch or retained-file delivery interface. + +Live effective-policy and capability checks passed: only exact data/metadata +read, no sibling secret, parent listing, write or control-plane authority. +A second contained session read existing version 1 into an operator-owned 0600 +file in a private 0700 runtime tmpfs directory. The native consumer exchanged +separate read and consume scopes; Approval Engine verified the read token before +returning 404 for a fresh nonexistent approval, and refused the consume-only +token's read request with 403. No approval was created, bound or consumed. +Both Warden sessions exited 0 after self-revocation/helper cleanup; temporary +credential file and directory were removed. Four refusal/path/redirect tests +pass. Receipts are in platform `docs/evidence/2026-09-14-ccr0019-{reader-preflight,delivery-check}.json`. + +Remaining: an actual nonmember login refusal, real approval claim/consume, +separate narrow requester admission and deployed Informed Decision review with +an explicitly admitted human mandate. The reader group alone grants no review +mandate. T03 and CCR delivery activation remain open; no OpenRouter key was read. + + +### T03 scoped review deployment — 2026-09-14 + +The operator explicitly admitted `net-kingdom-admins` as the human review group +for only the T03 apply, verify and read-only key-check records, separately from +its credential-reader membership. The review service is live and ready at +https://decisions.coulomb.social with verified KeyCape groups, fresh MFA and a +dedicated caller-bound Flex Auth policy. Its mandate does not grant consumption. + +The new `secrets-engine-requester` client has subject `secrets-engine`, tenant +`tenant:platform`, role `secrets-engine-requester`, and only `approval:create`. +CCR-2026-0024 and CCR-2026-0025 provide distinct verifier and attended reader +custody. Native signature, subject, scope and TTL checks passed; excess scopes +and a wrong secret were refused. Existing consumer identity is unchanged. +Three real requested approvals were created with human control, required count +one, and zero entries. Platform evidence is +`docs/evidence/2026-09-14-t03-native-approval-requests.json`. + +Review image: sha256:8f55bcecf37a8d65f96e073510b1ffb4636c0a91d75e1ee7d582ad4bce8b953a. +Policy image: sha256:c9f028b49dfcede930a9cc48757ec8371ecc71d20b1bfee2733e55298dffcc7c. +Review tests: 339 passed, 39 optional integration tests skipped; 11 container +checks and HIGH/CRITICAL image scan passed. Policy checks: 57 local and 6 native +caller checks passed, using synthetic subjects, not human binding evidence. +Approval Engine CPU request was reduced from 25m to 10m after observing 1m use; +review requests 20m and its PDP 5m. Limits are unchanged. Native services ready. + +Remaining T03 gate: the operator's exact signed-in account is needed to address +three prepared immutable memos, followed by real acknowledgements and acceptance +in Informed Decision. No human entry or consume has been generated by an agent. +Then execute claim -> validated PDP Check -> CAS consume separately for apply, +verify and exec using scoped attended authority, and capture native denial, +revocation, workload health and key-check evidence. No OpenRouter credential has +been read and no inference or spend was performed. T03 remains waiting; this +entry supersedes earlier statements that requester or group admission is missing. + +### 2026-09-27 T02/T07 source follow-up + +T02 now has the exact proposed RS256 configuration, bounded JWT role and +self-only policy in `openbao/`. Operator correction: platform infrastructure +belongs to `tenant:platform`; KeyCape registration and consumer preflight are +corrected together. Existing live registrations must be migrated and verified. +Public discovery confirms issuer/JWKS/token endpoint. Registration/custody, +attended provisioning and live rejection/cleanup evidence remain required; +T02 stays wait. No service credential or backend entitlement was issued. + +T07 consumed the confirmed legacy consumer return. The stale value-comparison +ask is removed. WARDEN-WP-0037-T03's no-rotation hold stays in force until the +governed native migration is evidenced. Legacy destruction follows migration; +neither source reconciliation nor the historical pilot is that evidence. + +## Loose-end review — 2026-09-27 + +T08 now explicitly waits for formerly-valid audit-bearer revocation acceptance from AUDIT-WP-0009-T09/T11. Native delivery, producer checks and independent readback already passed; do not reopen login, seed or review gates. T02/T03/T06/T07 retain their latest exact service registration, signed-in human acceptance, owner delivery/disposition and governed-consumer migration dependencies. No credential value was read or changed. + +## Founder approval of the CCR-2026-0033 custody child + +```task +id: RPF-WP-0035-T09 +status: done +needs_human: false +priority: high +decision_id: 2ab717e1-7881-491e-aed4-28946550c289 +depends_on: [] +state_hub_task_id: "7c753be6-42f1-58a6-a4a4-a7ed686f461f" +``` + +Packets: `credential-change-requests/CCR-2026-0033.yaml` (custody child, KV +metadata, issuer ESO reader, live_order, rollback) and `CCR-2026-0034.yaml` +(attended operator OIDC reader, in-memory, 5m/4 uses). Revised 2026-10-06 per +founder direction; the consumer file is removed. Exact founder commands: +`docs/provisioning-windows/2026-10-04-1000/keycape/founder-runbook.md`. Live +order: custody child → platform applies policies/roles/ESO (Secret +sso/keycape-secrets-engine-openbao-client exists) → NetKingdom env patch +(NK-WP-0046) → KeyCape registration merge (KEY-WP-0037-T03) → KeyCape restart +immediately → live issuance check (KEY-WP-0037-T04) → OpenBao JWT role/login +proof (RPF-WP-0035-T02). Each live step after the custody run needs its own go. + + +2026-10-11 evidence reconciliation: T09's approval obligation is complete. +Authoritative founder decision 2ab717e1-7881-491e-aed4-28946550c289 is resolved, +decided by Bernd Worsch at2026-10-06T13:07:18.627943Z, and explicitly covers +A1 design, A2 CCR33/CCR34 plus owner reviews/bound claims, and A3 one custody run. +The approval comments in both CCRs record those exact grants; both source records +are applied. MASON-WP-0009-T02/T03 additionally record the October8 approval/owner-delivery +reconciliation and reference KeyCape +`docs/evidence/2026-10-07-secrets-engine-openbao-issuance.json`. Closing this approval task clears +its obsolete human gate. It grants no new run, credential access, rotation or +service execution: RPF35T02/T12, MASON9T05 and SECRETS8T06 retain their actual +native/adoption obligations. Historical per-step exclusions remain above. + +## Retire the approval-engine-operator client delivery and custody (CCR-2026-0018) + +```task +id: RPF-WP-0035-T10 +status: wait +priority: medium +blocked_on: message-from:approval-engine +blocking_reason: "Blue lane under the standing change rule (removing access, with reviewed order, rollback and receipts): executes once approval-engine confirms there is no presenter. No founder window needed." +state_hub_task_id: "af2d4dba-f83a-5819-9a8b-671bae799364" +``` + +2026-10-11: access removal is blue lane (canon build-mode-change-authorization_v0.1); no founder window. + +key-cape proposed a joint disablement on 2026-10-10 (message `7f2128fb`). +Precondition: approval-engine reconfirms there is no presenter. The order is the +reverse of provisioning, so KeyCape never starts with a client whose secret is +missing. key-cape removes the registration and restarts (1), checks that +`invalid_client` is returned (2), and net-kingdom removes +`KEYCAPE_APPROVAL_ENGINE_OPERATOR_CLIENT_SECRET` from Deployment `sso/keycape` +(3). Platform steps, amended from the proposal: + +4. **Delivery.** In one commit, remove ExternalSecret + `sso/keycape-approval-engine-operator-client` from + `argocd/platform-addons/openbao-secretstore/keycape-approval-clients.externalsecrets.yaml` + and ClusterSecretStore `openbao-keycape-approval-engine-operator` from + `openbao-keycape-approval-clients.clustersecretstore.yaml`. Keep the + secrets-engine-approval objects. Then bump `targetRevision` of + `argocd/railiance01/applications/openbao-secretstore.application.yaml`. + The app is pinned and has no automated sync, so nothing changes live until + an attended `argocd app sync openbao-secretstore --prune` runs after step 3. + Verify, value-free, that the ExternalSecret, the store and Secret + `sso/keycape-approval-engine-operator-client` are gone. The target is + `creationPolicy: Owner` and `deletionPolicy: Retain`, so the Secret should + follow its owner; delete it explicitly if it does not. Then delete OpenBao + role `auth/kubernetes/role/external-secrets-keycape-approval-engine-operator` + and policy `workload-kv-read-keycape-approval-engine-operator`, and remove + their source files. Also remove policy + `workload-kv-read-approval-engine-operator-client` (CCR-2026-0020, cancelled) + if it exists live. +5. **Custody.** Run the metadata delete of + `platform/workloads/approval-engine/operator-client`, the destruction + foreseen in `docs/credential-lane-designs/keycape-approval-clients.md`. A + disabled client's secret has no recovery value; a narrowed successor gets a + fresh secret through the mint-secret lane at `platform/workloads/keycape/`. + Only after step 2's `invalid_client` receipt. Keep the agent boundary denies + for that path until the delete is verified, then drop them. + +2026-10-10: key-cape agreed the amended steps 4 and 5 (message `59304e33`, +KEY-WP-0013 c528daa). Waits on approval-engine confirming there is no presenter, +and on the founder's window. + +The manifest edits wait for the scheduled window, so a stray `targetRevision` +bump cannot remove KeyCape's secret before step 3. + + +## Complete independent service-JWT source preparation and execution design + +```task +id: RPF-WP-0035-T11 +status: done +priority: high +state_hub_task_id: "7952c8cd-c066-5b72-a025-78d24341c1ab" +``` + +2026-10-11: Platform-scoped agent loaded this checkout's AGENTS.md and INTENT, +RPF35-T02, actual CCR38/login contract/typed applier and Secrets Engine's native +claim/PDP/CAS/provider/apply flow. Frozen Secrets v2 manifest and all named staged +bytes/proof were hash-verified. Independent tests reproduced three source +counterexamples while retaining the frozen files: close exception can coexist +with native_verified=true; successful result needs no source/session fingerprints; +HTTP200 mixed errors+data envelope is accepted. Original 37 tests plus the three +counterexample tests pass (40 cases, synthetic/local only). Proposed owner design +`docs/credential-lane-designs/secrets-engine-task-execution-entitlement.md` binds +an explicit metadata-only execute-ccr action, immutable typed owner bodies, +CAS/journal replay control, 120s/12-use owner-held task token, independent payload +validation, native ACL endpoint bounds, revoke/readback and recovery. This completed +preparation record is established before the formal source review. It grants no +live authority and does not close T02 or represent acceptance by another owner. +Formal review artifact follows under this work item; all implementation/live +obligations are retained in T12 and existing T02 rather than a finished residual. + +## Implement and prove the separately approved task execution entitlement + +```task +id: RPF-WP-0035-T12 +status: progress +priority: high +depends_on: [RPF-WP-0035-T11] +state_hub_task_id: "914bf383-c13f-5247-9af0-91d7e3a4784a" +``` + +Review the proposed task-execution-grant schema and exact metadata-only execute-ccr +backend with Secrets Engine/access-engine/approval-engine; implement trusted service +subject and served consume verification, durable one-shot reservation, bounded +owner-held token issuer/middleware and exact source/payload enforcement. Obtain +separate exact founder approval/attendance before provisioning or live actions. +Prove disposable intended result and identity/action/target/body/time/replay/crash/ +cleanup negatives, and return owner-native acceptance. Existing service login policy +and defaults stay unchanged. T02 still owns login/claim/TTL/use/MASON acceptance; +Secrets T06 separately owns dispatcher adoption and steady-state default migration. + + +2026-10-16 T12 wave 5 source preparation: disposable adapter now binds owner +canonical before/after metadata snapshots to existing descriptor hashes, rejects +per-target baseline/readback mismatch, and records readback/verified evidence. +Mediator reports cleanup-confirmed only after independent fixed cleanup receipts. +Complete role metadata and policy name/HCL/version/cas are compared; validated +modification timestamp alone is excluded. This is sequential fixture acceptance, +not aggregate CAS, concurrent-writer exclusion or native production completion. +Role conflict may follow a policy write. Restart refuses dispatch and cannot +recover memory-only token/accessor cleanup handles. T12 remains progress; actual +fresh CCR/catalog/grant, source/trust/caller/policy admission, isolated owner custody, +scoped recovery and attended native acceptance remain explicit prerequisites. + + +2026-10-11 T11 refinement (same source-review trial): the exact Secrets Engine +v3 manifest `6bb05bac74e4939c3e42db2ae95c5f9fb4616bb20cc285811a315c26669ebce1` +and all named bytes/proof were verified and independently re-reviewed. The three +v2 counterexamples are corrected: close exceptions cannot pass through stale true +flags, complete typed source/session/attempted/revoke evidence is required, and +mixed HTTP200 errors/data fails closed. 49 maker/current-provider tests plus three +independent regressions passed (52, synthetic/local only). Platform source review +`docs/reviews/2026-10-11-secrets-service-jwt-v3-platform-review.json` approves only +the corrected boundary verifier and truthful packet. Prior changes-requested v2 +review is retained; this is not a second native success or changed authority. +No native or founder go is granted. T02, T12 and Secrets T06 remain open; the +metadata-only execute-ccr pilot is explicitly insufficient for generic lifecycle +adoption. All consume-verification/journal/action/body/backend implementation and +native acceptance gates remain real prerequisites, not architecture promises. + + +2026-10-11 T11 readiness refinement: independently reviewed frozen consumer +manifest `709b9dddd1c8f00a995b1ff14264323fbe080ed95df244270ce9607528878fa7`. +Platform source review `docs/reviews/2026-10-11-secrets-execution-readiness-v2-platform-review.json` +approves the local fail-closed guard and proposed consumer contract direction only. +All ten current protected backend handlers pass provider args through readiness +before authorization/consume; session revoke checks before handle reads. Configured +auto/explicit service-jwt therefore cannot burn a protected-action approval or +open the insufficient login-self backend. Explicit env/bootstrap and self-only +probes retain their existing contracts; local compromise/reactivate and disabled +destroy remain separate. Existing ambient-token route readiness reads are unchanged, +not claimed governed by this guard. 58 isolated tests passed: original36 plus20 +provider/action cases, handler enumeration and actual session-revoke ordering. +Prior v2 changes-requested and v3 boundary source reviews remain unchanged, same +T11 trial. No runtime grant, native acceptance, new Access/Approval semantics, +backend entitlement or full Lifecycle adoption is approved. T02/T12/SecretsT06 and +WP13 implementation/native gates remain open; the metadata pilot substitutes for +none of the ordinary generic lifecycle outcomes. + + +## Complete independent KEY39 v4 lifecycle source review preparation + +```task +id: RPF-WP-0035-T13 +status: done +priority: high +state_hub_task_id: "8f6966fa-6e9a-58b2-8b40-c47340ec19d1" +``` + +2026-10-11: Platform agent loaded its owner instructions/INTENT and RPF35-T02, +actual applied CCR38, exact native role/policy source and frozen KEY39 lifecycle +v4 manifest `d079f85c47d5c2635e1ee633ea4d1346b1737ce2be9ca273f22a38e620f418d8`. +All staged entry hashes were verified without changing the reviewed inputs. +Source role omits expiration_leeway: its observed actual default must be confirmed +natively, with -1→0 and 0→150 normalization preserved as a bounded model. Source +claims and login-only policy are unchanged. The supplied 41 lifecycle tests pass; +five independent cases also pass, including a new exceptional-response-close +elapsed-bound counterexample and four current-leeway normalization checks. +A 10ms HTTP request can take over70ms because exceptional finally response.close +runs outside the hard elapsed timer. Unknown native login is correctly recorded, +but source total elapsed enforcement is incomplete. This completed owner +preparation record exists before the formal exact source review entry. No +credential was requested/read, native action run, owner checkout edited or native +session grant inherited. T02 retains native role/policy/leeway, negative claims, +cleanup acceptance and MASON gates; KEY39 producer handoff and founder attendance +remain prerequisites. Source correction/re-review is required, not a native success. + + +2026-10-11 T13 correction preparation (same trial): exact KEY39 v5 manifest +`d1f997624db46693a7126a6eb6435f6b3a353d5bd67dcc8a539683e4b7147285` +and all entry hashes verified. The v4 exceptional-close finding is addressed: +one 20ms abort is clipped to original remaining time and the nonresettable +aggregate cleanup budget; zero calls after aggregate expiry; failed abort stays +unconfirmed/unknown with signal state restored. 46 supplied lifecycle checks and +five independent regressions pass; the unchanged runner's earlier17 tests remain +valid against identical source SHA. Existing T13 preparation record is retained +before the formal v5 exact source review. V4 changes-requested review and earlier +failed history remain retained, with no native success, inherited grant or scope +promotion. Actual private producer admission, fresh installed role/leeway/policy +observation, authenticated founder window and native refusal/cleanup remain gates. + + +2026-10-11 T11 journal preparation refinement (source-only): independently +inspected frozen root-maker v2 manifest +`341cac1de945d2fbe8f516119909bd44fc37e85dccfb38b451981d4de2d402e7`, +verified all input hashes, and ran14 supplied tests plus5 independent checks. +The actual four-process race admits once; a separately forked process exiting +immediately after pending intent leaves durable unknown/nonresumable state. +Private SQLite modes, lock admission and binding/replay protections remain guarded. +Three independent counterexamples show after_call accepts False,0.0 or text'0' +as persisted integer ordinal0, contrary to before_call's exact integer validation. +Completed preparation under this existing done ownerT11 record precedes formal +review; require identical ordinal/call-digest validation before confirmation so +malformed calls cannot clear pending outcome. RPF35-T12 retains caller/PDP/consume +validation, exact body compiler/adapter and owner-private cleanup/recovery after +unknown; this unintegrated primitive proves none of those or full contract/native +acceptance. Inputs/prior reviews are preserved; no privileged/native action occurred. + + +2026-10-11 T11 journal v3 correction preparation (same trial): frozen manifest +`905ff6666d05df6a19d165a535579d917d7de31a43e066c2afc34a57e8cbdc9d` +verified against every file. Strict after_call integer0..63 and64hex string digest +validation now precedes SQLite confirmation; False,0.0 or text'0' cannot clear +pending external outcome.15 supplied tests plus5 independent regressions pass, +including realfork abrupt exit after durable intent and privatefile checks. +This existing completed ownerT11 refinement precedes the formal corrected-source +review. Prior v2 refusal is retained; no extra success/authority trial is counted. +Acceptance is only unintegrated journal source. Actual caller/PDP/consume validation, +independently compiled body/ordinal plan, restricted adapter, owner-private unknown +cleanup recovery and native/whole-contract adoption remain live RPF35-T12 gates. + + +2026-10-11 T13 node-route source preparation refinement (same trial): exact +successor manifest `23a972abc5175e121e594726d2b7f7a28c62109253f58f12623eaf2e5564a035` +verified against all entries. Platform Service openbao-ui-gateway8080 and its +nginx /v1 proxy agree with the proposed bounded founder-held node port-forward; +workstation tunnel/DNS assumptions are not reused as node evidence.54 supplied +lifecycle/route checks plus6 independent public-health/abort checks pass, offline. +Initial execute/recovery health pin and repeated pre-create check fail before +native/Secret effects; public-preflight reads neither stdin nor Kubernetes. +Completed ownT13 preparation precedes this fresh exact source review, not reuse +of v5 acknowledgment. Main execute currently reads private stdin before execute's +health gate; the packet's pre-token-input phrase is not accepted. Private producer +handoff must preserve actual ordering or move the health gate before credential +input when implemented. Public cluster digest detects drift, not authenticated +estate identity. No route was opened or observed; no source packet authenticates +a founder approval. Native role/plugin version and raw/effective expiration, +clock-skew and not-before leeways require actual owner observation/semantic proof. +Issuer readiness_state/Argo ownership is not established by the inspected source; +unmapped means production-tier. If adopted/production-approved, temporary direct +CAS requires an explicit reviewed one-use maintenance exception and close-down +entry, plus reconciliation, before native go. No helper/source acknowledgment +waives that gate. Private token producer/callback/client/custody admission and +actual native negative/revoke/restoration/cleanup remain prerequisites. + + +2026-10-11 T13 v7 node-route preparation refinement (same trial): exact frozen +manifest `90aabec336008d7d51e37c04b5ff96ba8ed6630821cca1a4c333d803367247f7` +and all entries verified.58 supplied lifecycle/route checks plus9 independent +checks pass offline. Actual main now verifies source/public health before private +stdin; execute preserves the original wall/monotonic window rather than renewing +it. Actual child-process partial-pipe counterexample shows unbounded stdin.read +remains blocked beyond a synthetic20ms original window (still alive after100ms +without EOF). No credential/native/provider access is involved. Before private +producer admission, require byte-capped, deadline-bounded JSON input and EOF within +the original window, with fail-closed fixed receipt and no protected effects. +This completed ownT13 preparation precedes formal v7 source changes-requested +review. Retain v6 qualified health-gate agreement and all prior reviews; neither +v7 health ordering nor any source acknowledgment establishes custody completion, +actual route/plugin/leeway/readiness/Argo identity or founder/runtime authority. +Native and private-producer gates remain open; no owner checkout write occurred. + + +2026-10-11 T13 v8 bounded-input correction preparation (same trial): exact +frozen manifest `316fd6005cc4cb7fe14ea69a5fd408aed13e6122afef60afd13d97952b27cf4a` +and all entry hashes verified.65 supplied tests plus12 fresh independent checks +pass offline, including a standard buffered stdin pipe with complete JSON/noEOF +interrupted within original20ms window and restored SIGALRM state; exact64KiB +JSON/EOF accepted and extra byte refused, UTF8 token bytecap enforced, original +wall deadline clips longer monotonic budget. Original preinput window is retained. +Completed ownT13 preparation precedes fresh exact source review; v7 refusal and +v6 qualified agreement/prior reviews retained. This accepts child bounded-input +source only. No parent-ready handshake exists: producer must not eagerly pipe +private inputs, and producer/session/window readiness protocol remains an +unimplemented admission gate. No custody/native completion, sourcepacket approval +authentication, route/plugin/leeway/readiness/Argo observation or inherited grant. +Native prerequisites and producer handoff remain open; no owner checkout changed. + + +2026-10-11 T11 journal v4 canonical-format preparation refinement (same trial): +exact frozen manifest `22c6d225d393b994ab7b44a43904ced1b6d7f74e0e2bebf71ffe99f87191ef4c` +and entry hashes verified. Actual access-engine pkg/api/canonical.go RequestDigest/ +CanonicalDigest, Approval binding.py and Secrets authorization/approval_consume +all use sha256:<64 lowercase hex> request digests. V4 now preserves this exact +request value without prefix stripping; plan/call/evidence content hashes remain +explicit bare64hex.15 supplied checks plus15 fresh independent checks pass, +including malformed prefix/bare/uppercase/trailing whitespace refusal before +reservation, exact persistent value/reopen/mismatch replay, private-file mode, +real child crash after pending intent, ill-typed confirmations and pending-unknown +refusal. Completed ownT11 preparation precedes formal v4 source review; prior v2 +refusal/v3 approval and T13 v7 refusal/v8 source acknowledgment retained. +Acceptance is unintegrated primitive source only; no data migration/native use +of v3 journal has occurred. RPF35-T12 caller/PDP/consume validation, independent +owner plan compiler/restricted adapter, private runtime custody, bounded execution +and owner-private unknown cleanup recovery remain open. No checkout/native writes. + + +2026-10-11 T13 paired ready-child/launcher preparation refinement (same trial): +exact NetV9 manifest `84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14` +and KeyproducerV2 `55a8e794af983ca2202e7a0054d0415a120d2c95018fb03fdb5f28313a109d58` +verified against all entries.74 Net checks plus31 Key checks and10 independent +checks pass offline including a truthful-unknown counterexample: adapter uncertain +private delivery with confirmed=false is copied into launcher receipt, but +consumer_outcome_unknown incorrectly remains false after local SSH teardown. +Complete bytes may have reached remote child before adapter timeout/EOF; local +terminate does not establish remote no-effects. Require sticky propagation of +uncertain delivery into consumer outcome before early return, retain unknown +unless independently established native outcome/recovery. Bad markers/source +pins/injection reject before private reads; extra marker authority/lines reject; +prohibited child output never forwards. Child-ready synchronization is not +authentication/approval. Proposed founder directSSH profile is incompatible with +warden quiet-output lane and not admitted here. Completed ownT13 preparation +precedes formal paired source review; preserve v7 refusal/v8 acknowledgment and +journal histories. No transport grant, coding-agent/private custody admission, +live SSH, credential/native action or owner checkout write. All native role/plugin/ +leeway/route/issuer readiness/Argo/maintenanceexception gates remain prerequisites. + + +2026-10-11 T13 paired producerV4 correction preparation (same trial): exact +producer manifest `d6f641dc1e4aae7d36658d4199d89af14d2fd7a4bd4e526856eb340234f2d33e` +and unchanged NetV9 `84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14` +entry hashes verified.74 Net tests,40 producer checks,9 actual local fakeSSH/ +realwrapper/child synthetic roundtrip regressions and12 fresh Platform checks +pass (135 total). V2 deliveryunknown now remains sticky consumerunknown with +completion=false after earlyreturn/localteardown. V3 Net FIFO acquisition finding +and originalbudgetreset are corrected: actualCLI starts original5s timer before +regular/nofollow/bytebounded contract acquisition, each later preparation phase +clips remaining time. ActualCLI FIFO refuses promptly; expired original budget +never validates/spawns/reads private files. Completed ownT13 preparation precedes +formal corrected pair source agreement. Preserve V2 Platform refusal, Key old +exactV2 acknowledgment and NetV3 refusal; no old acknowledgment repinned. +Agreement is only reviewed source synchronization/launcher behavior, not admission. +Founder authenticated SSH host/profile/channel/runtime pins, exclusive sameUID +file custody and explicit tmpfs file allowance/cleanup, verified human and +coding-agent producer/client/source, native role/plugin/leeway/route/issuer +readiness/Argo/maintenanceexception, refusal/revoke/restoration/readback and +unknown owner recovery remain prerequisites. Warden quietlane cannot carry ready +controlstdout; no transport/custody/native grant. No owner checkout/liveSSH/native. + + +2026-10-11 RPF35-T12 source implementation progress: durable journal source v4 +was independently accepted/committed; owner-derived typed plan compiler component +v2 is prepared at immutable manifest +`41cda74ab32384c789ea8a760475671aadad4e5121335c8f60567ff53d66665b` +with40 offline tests. Completed own bounded source-preparation ADHOCT02 anchor +was persisted at7adbcb4 before the qualified Platform contract/readiness receipt. +T12 progresses for actual source implementation underway, not native acceptance +or full descriptor/authority readiness. The compiler derives local CCR/HCL/role +bodies, matches actual independently pinned Secrets catalogue and revalidates +source/body before fixed calls; no body/target chosen by service is dispatched. +Independent technical integration review and exact full ExecutionContract/owner +grant/baseline/estate/deadline matching, initiating human/User/Tenant PIP/transport +representation/service identity, served PDP/claim/consume correspondence, journal +call dispatch/restricted adapter, native token TTL/uses/custody/revoke/cleanup and +owner-private unknown recovery remain unimplemented integration/native gates. +Actual CCR42 has no eligible approved pilot/catalogue; no source metadata is +invented. T02 and original negative/capability/native evidence remain unchanged; +T11/T13 history retained, no defaultflip/nativego or SecretsT06 closure follows. + + +2026-10-13 T12 source correction: the compiler hashed the catalogue sources but +used cached Python modules with matching paths, which did not establish executing +those exact bytes. A failing regression reproduced the substitution. Catalogue, +package and dependencies now execute from the verified snapshot in temporary +private modules; ambient modules remain untouched and cleanup runs on refusal. +45 compiler plus 15 journal tests pass. The v2 source review remains historical; +this change needs its own integration review. T12 retains all existing full +contract, identity/consume, dispatch, custody and native acceptance requirements. +RPF-IN-0012 remains open for the independent contract/wrapped-delivery return; +this code correction does not authorize either operation. + +2026-10-16 T12 source preparation (isolated owner checkout; not owner delivery): +added durable precommitted cleanup obligations and separate outcome evidence to +the existing Journal, plus a fixed three-method owner cleanup driver. Same live +postconsume admission can clean after a business timeout/failed/unknown outcome; +cleanup closes business dispatch and cannot replay or restore admission after a +crash. Empty obligations no longer produce cleanup-confirmed. Real SQLite +multiprocess races and abrupt process death before/after a separately durable +synthetic effect verify refusal on reopen. Current compiler/journal/cleanup suite: +73 passed, local source/fixture only. Details: docs/task-execution-cleanup.md. +No native adapter or production mediator exists; full grant/request/cleanup binding, +authenticated consume/identity, ephemeral token issuance, deadline/use checks, +native effect/revoke/absence, audit and protected recovery remain prerequisites. +T12 remains progress. No CCR38 default/entitlement or live grant was changed. + +2026-10-16 T12 second source package: Compiler Plans now bind deterministic cleanup +commitments and can bind the complete independently installed engine execution +descriptor. A fixed disposable-loopback native adapter actually materializes exact +per-operation metadata ACL/task token, executes six source-derived metadata calls, +and verifies self-revocation/accessor invalidation and policy retirement. Each +cleanup request has its own durable intent. Native fault tests cover lost response +after real write and policy deletion while task revoke fails. All initiating +identity/approval/consume/grant/state/source admission in this fixture is synthetic; +no production authority or complete native owner acceptance is claimed. Exact +remaining owner schema/admission and mediator work: docs/task-execution-native-fixture.md. +T12 stays progress; no live grant, credential/default change or owner sync performed. + +2026-10-16 T12 third source package: implemented proposed task-execution-grant +immutable projection and exact compiler/native-fixture integration through the +existing descriptor grant ID/SHA fields. Only typed review.comments/evidence.events +are excluded; separate append-only checks reject removal/rewrite/reordering and +unknown guessed evidence exclusions refuse. Owner-pinned grant bytes and validator +source must match independently reconstructed descriptor/source/cleanup/ACL/token +bodies before a native fixture can materialize. Proposed source records gain no +execution authority; no real grant, policy or legacy applier registration added. +Details and remaining production gates: docs/task-execution-grant-projection.md. +T12 remains progress; no owner sync or production effect performed by this package. + +2026-10-16 T12 fourth source package: connected the Secrets-owned strict task +handoff to actual Approval ExecutionConfirmationClient independent GET before +consume-confirmed/native fixture work. Platform accepts no supplied authorization +boolean/object/callback and preserves its exact owner descriptor/grant/Plan join. +Durable CAS/GET intents precede native ordinals through the repaired journal +prefix API. Actual source-server fixture uses signed Access/enforced synthetic +TokenReview, real Approval WSGI/SQLite with distinct synthetic human/service +identities, actual strict Secrets signature/CAS validation and disposable native +OpenBao. Untouched actual task policy remains signed DENY; separately named +synthetic fixture policy is never production admission. Read-scope denial after +CAS records consumed/unknown with zero native effects. Exact dependency/source +hashes, tests and remaining gates are retained with the source package and in +docs/task-execution-mediator-seam.md. No real grant/custody, policy default, owner +sync or native production acceptance is performed; T12 stays progress. + +2026-10-16 T12 recovery successor source preparation: optional independently +installed fixture custody durably retains operation-bound private accessors and +issuance checkpoints. Fresh cleanup-only owner permits can reconcile after actual +executor process death using fixed revoke/readback and policy delete/readback, +without restoring business/consume admission. Separate durable attempt evidence +retains original unknown outcomes. Lost token-create response remains unresolved +when no accessor was committed. Source-only process-loss fixtures are not native +production custody or recovery-role admission; T12 remains progress. + +2026-10-16 T12 recovery R2 source refinement retains R1's overbroad 404 failure: +policy cleanup now requires exact native empty-errors absence before/after delete; +HCL uses only documented single optional terminal LF normalization. Private +capsules are owner-key HMAC authenticated, strict nested schemas/ordered cleanup +commitments reject damage, and journal history prevents stale prepared capsules +from hiding issuance. Fixture process-loss source proof remains separate from +unadmitted production custody, integrity-key storage and recovery-role scope. + +2026-10-16 T12 independently reviewable budget/source slice: bound native HTTP +header/body/close, compiler work and cleanup through fixed owner main-thread +absolute budgets, with actual task expiry narrowing global authority. Actual v2 +mediator now verifies each independently installed source_bundle byte hash before +authorization/effects. No deadline/TTL extension, remint or generic service added. +Retained registry actual-provider proof still refuses Approval correspondence +before CAS/native; normalized pre-approval + precise immediate CAS whole-stack +positive remains live owner follow-up under CUST-WP-0080. T12 stays progress. + +2026-10-16 T12 actual v2 successor source proof: retained registry signed DENY +normalization from the real Secrets prepare_task_approval builder precedes actual +Approval issue/human approval. Actual Access v2 then signs ALLOW; strict Secrets +CAS and independent confirmation GET precede six disposable native calls, exact +readback and confirmed token/policy cleanup. Approval precision source permits +immediate CAS without sleeps/backdating. The 60-second immutable deadline, +30-second backend TTL, 120-second synthetic observation and existing cleanup +reserve remain bound; issued credential expiry narrows business time. Source, +caller, revoke, source-reader, registry drift and expiry refusals cause no native +effects; revoke between ALLOW/CAS retains unknown without business dispatch. +This owner fixture uses separately installed synthetic identity/key/trust and +loopback OpenBao, grants no production authority and keeps T12 progress. Prior +failed temporal/normalization proofs remain retained. + +2026-10-16 T12 signer custody R3 source preparation rebases the proposal to +integrated Access919ce25 and preserves current workplan state. Added protected +in-memory Ed25519 CAS/readback primitive with durable closed metadata receipts +and fixed disposable-only owner adapter. Actual synthetic OpenBao bootstrap, +rotation, conflict/unknown/readback/receipt/private-output and admission failures +are tested. Production direct entry refuses: exact CCR/founder scope, protected +executor/fencing/receipt custody, independent consumer public admission, migration +debt and native deployment prerequisites remain open. No live key/grant or CCR +admission; RPF-WP-0035-T12 remains progress. + +R3 source metadata correction aligns proposal IDs across JSON/docs/Secret +annotation and documents existing base64url-ASCII public fingerprint hashing. +Frozen R2 source/evidence is preserved; no writer behavior or admission changes. + +2026-10-16 T12 native signer preparation: proposed CCR-2026-0050 and generated +read-only HCL pass real schema checks; current proposed status/unconfirmed claims +keep apply refused. Native candidate uses existing external-secrets-* role +convention with dedicated SA unchanged and projected private field only. Exact +attended CAS0/metadata/fence/receipt/forward-recovery action plan is separate from +read-grant authority; production adapter implementation/independent tests and +founder plus distinct owner reviews remain necessary. Access observed zero PVCs; +new outbox storage/retention/runtime bounds remain separate Access/cluster scope. +No live credentials, grants, roles, key or deployment changed. T12 stays progress. diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-r1/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-r1/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md new file mode 100644 index 00000000..2d88649b --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-r1/docs/credential-lane-designs/flex-auth-envelope-signing-native-adapter.md @@ -0,0 +1,119 @@ +# Attended native signer custody adapter source + +RPF-WP-0035-T12 / CUST-WP-0080. This source implements the protected native +adapter described by the separate frozen native-preparation R1. It does not +admit an execution. Its CLI is silent and intended only as the exact reviewed +child of `warden access openbao-platform-admin-login --exec` in the founder's +attended OIDC envelope. The existing Warden owner contains the token helper, +checks child output and revokes/removes the session on exit. No new service, +credential broker, standing grant, API or key-returning interface is created. + +## Current routing blocker + +During preparation the required `warden plan` query for attended OpenBao +platform administration of signer CAS0/metadata selected `openbao-structure-survey` +with an approve ceremony, rather than `openbao-platform-admin-login` with +`oidc_login`. The installed CLI reports wheel-bundled catalog0.1.2 fallback. +This is preserved as a live refusal, not routed around. Exact `route show` names +the existing active attended login, but that pointer does not cure dispatch. +The adapter requires an independently retained routing receipt selecting the +correct lane/verdict/identity act. No founder execution step is ready until the +routing defect and all other native approvals are resolved by their owners. + +## Independent input and authority boundary + +The CLI requires an absolute owner-private admission file, its independently +approved exact SHA256, the exact private receipt directory selected in the +reviewed native proposal, and an original receipt only for recovery. No default +image/package/caller trust, founder identity, approval, route or source pin is +usable. The admission schema is closed in `validate_admission`; it includes the +immutable published producer image, retained caller, deployment projection, +selected consumer trust baseline, exact native plan/CCR/source bundle, fresh +UTC authority expiry (5..120seconds), founder entity and five distinct externally +reviewed owner dispositions. Each disposition binds the same approval-free +scope digest. An admission shape, local digest or review string never approves +itself: the founder and owners must independently review the exact supplied +command/file hash through existing governance before attended invocation. + +The trust hash selects the independently reviewed consumer verifier/policy/trust +baseline for this custody action. It is not a claim that the newly generated +public key is already online: generation happens later, and independent delivery +and successor trust installation are required after the public receipt. The +writer never reads consumer private credentials or discovers trust from KV. +All successful custody states remain pending independent public admission. + +`checked_sources` verifies the actual selected native action plan, exact proposed +kid, read CCR hash/status/binding, generated policy source, and source bundle. +The read CCR must independently be approved/binding-confirmed; the canonical +proposed CCR remains unapproved, so ordinary source checkout refuses. Source +bundle pins execution modules, not arbitrary request-selected code. The native +image/caller/seed projection is compared to the actual stopped Deployment. +The lifecycle policy digest/version stays unchanged; execute-ccr probes must +prove no ALLOW/effect. Current generic runtime guard can return HTTP503 before +the lifecycle evaluator, so signed unknown_action is not promised. + +## Actual checks and effects + +Before private work, the child checks OpenBao cluster ID, unsealed state, exact +non-root platform-admin OIDC entity, enabled audit, actual exact read-policy HCL +and role bindings/15m limits. The selected fixed loopback transport is the existing +owner-admin bridge; Kubernetes reads use fixed strict-host SSH to railiance01. +The OpenBao token lookup-self identifier stays only in the contained custody +process to authenticate fixed HTTP calls; it never reaches the agent, a receipt, +argv or another token file. This is a native protected-process implementation, +not evidence that agent runtime isolation has been promoted or granted. + +The fence checks the pinned kube-system UID, stopped Deployment generation and +replica status, exact immutable image/caller/seed mount/kid projection, zero owned +ReplicaSet replicas, no live or terminating signer-SA/owned/seed-mount pods, and +no targeting HPA. It rechecks before metadata setup and immediately before CAS. +A private filesystem lock excludes a second local custody window. The lock and +observations do not provide atomic Kubernetes fencing: the independently reviewed +exclusive window must keep GitOps/Helm/other creators stopped. No rollout or +cluster mutation is performed by this adapter, and no concurrency guarantee is +inferred from source alone. Access/cluster owners retain that admission. + +Bootstrap requires the exact OpenBao empty-errors HTTP404 metadata absence. A +durable private intent precedes exact CAS-required/max_versions2/no-auto-delete +metadata setup, followed by exact native readback. Only then does the shared +Ed25519 primitive generate one in-memory seed and CAS0 the fixed three-field +KV document. Independent version1 private readback and final metadata verification +precede the durable success receipt. The seed is never put in argv/env/local +files or output. The receipt carries public key, ASCII-base64url fingerprint, +version, bindings and closed phases only. The old fixture's live-dev-process gate +is preserved; its shared receipt initialization was extracted without weakening +that gate. Python cannot promise seed zeroization. + +Every backend/body/close and tool call has a two-second absolute budget and +1MiB combined output bound. The complete operation is bounded by the supplied +fresh expiry. CLI validation and runtime failures remain silent. Existing0600/ +0700 no-follow/ownership checks, exclusive creation, fsync/atomic replacement and +directory fsync retain evidence. Same-UID hostile code is not isolated by modes; +Warden's contained home, trusted runtime and independently reviewed custody +location are required, not inferred from approval frequency or shell prefixes. + +## Process loss and independent read-only recovery + +Any failed/ambiguous metadata/write/readback/final receipt outcome remains +unconfirmed. A success receipt is withheld until final metadata verification. +A child death immediately after the real native CAS leaves the earlier public +intent with its derived public key and no private value. A fresh `recover` +admission must bind that exact original receipt SHA and the same immutable scope. +It reserves a new durable recovery intent before private reads, verifies current +version1 metadata and exact private seed/public/kid correspondence, and records +separate public reconciliation. It never creates a writer, generates a seed, +POSTs metadata/data, restores a seed, consumes approval or dispatches business +operations. Original unknown evidence is never rewritten. Changed versions, +damaged/typed-invalid receipts, missing fresh reviews and denied reads refuse; +replaying a recovery ID cannot repeat even the private backend read. + +This source implements bootstrap and read-only version1 reconciliation only. +Rotation needs a separately reviewed exact-version native action; the disposable +primitive's CAS1 test is not a native rotation grant. No automatic retry, remint, +rollback or general recovery API exists. Metadata-only setup uncertainty without +a public seed intent requires separate attended reconciliation, not this path. + +Access observed zero PVCs in flex-auth. Its proposed new1Gi/local-path outbox, +PV Retain/reclaim disposition and runtime process-lock/capacity/startup bounds +remain separate reviews. This writer grants no PVC, audit egress, policy role, +SecretStore/Secret or producer/consumer deployment admission. diff --git a/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-r1/docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-r1/docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json new file mode 100644 index 00000000..ed8c74f6 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-16/platform-signer-custody/native-adapter-r2/preimages-r1/docs/credential-lane-designs/flex-auth-envelope-signing-native-plan.json @@ -0,0 +1,150 @@ +{ + "schema": "railiance-platform.signer-native-action-proposal.v1", + "proposal_id": "RPF35-PDP-SIGNER-NATIVE-20261016-R1", + "status": "prepared-unapproved", + "read_ccr": "CCR-2026-0050", + "proposal_scope": "attended bootstrap of retained lifecycle PDP seed; no taskpilot enablement, rotation requires a new exact-version action revision", + "actor": "founder attended OIDC via warden openbao-platform-admin-login; reviewed silent Platform custody child", + "executor_ownership": "railiance-platform; founder executes exact child; agent receives closed metadata only", + "abort_owner": "founder; Platform preserves unknown custody/evidence, Access keeps signer/consumers fenced", + "target": { + "cluster": "primary/railiance01", + "kube_system_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786", + "openbao_cluster_id": "fd28df5d-98ec-57dd-42ec-9b3e4f4e53bf", + "openbao_origin": "http://127.0.0.1:18200", + "namespace": "flex-auth", + "deployment": "flex-auth-secrets-engine", + "signer_sa": "flex-auth-secrets-engine" + }, + "credential_route": "openbao-platform-admin-login; flex-auth-decision-envelope-signing-key remains draft/nonresolvable; route is not a seed vending service", + "bootstrap": { + "action": "CAS0 fresh in-memory Ed25519 seed", + "kid": "flex-auth-lifecycle-20261016-r1", + "expected_version": 0, + "data_path": "platform/data/workloads/flex-auth/envelope-signing", + "document_fields": [ + "ED25519_PRIVATE_KEY", + "ED25519_PUBLIC_KEY", + "kid" + ], + "metadata_path": "platform/metadata/workloads/flex-auth/envelope-signing", + "metadata_contract": { + "cas_required": true, + "max_versions": 2, + "delete_version_after": "0s" + }, + "allowed_native_methods": [ + { + "method": "POST", + "path": "platform/metadata/workloads/flex-auth/envelope-signing", + "purpose": "CAS-required/version-retention configuration after absence/no-drift validation" + }, + { + "method": "GET", + "path": "platform/metadata/workloads/flex-auth/envelope-signing", + "purpose": "exact metadata readback, no private value output" + }, + { + "method": "POST", + "path": "platform/data/workloads/flex-auth/envelope-signing", + "purpose": "single CAS0 seed document write" + }, + { + "method": "GET", + "path": "platform/data/workloads/flex-auth/envelope-signing?version=1", + "purpose": "exact private readback in custody, closed public receipt only" + } + ], + "source_primitive_sha256": "sha256:8ed281a49c1f1cdb23772efe3593e75c62572a12b8d7a6a4c574f27b38722e75" + }, + "fencing": { + "before_key_generation": [ + "Verify cluster/backend IDs, exact current source/CCR and founder disposition hashes.", + "Read exact deployment/ReplicaSets/pods by ownerReference and SA; refuse a second workload/pod using signer SA or selecting signer Secret.", + "Access stops protected consumers and scales retained deployment0 through its reviewed release path; this child does not mutate replicas.", + "Verify deployment spec replicas0, observed generation caught up, no live or terminating owned ReplicaSet/pods, no matching signer-SA pods and no HPA targeting deployment.", + "Reject a differing/previously existing KV entry at bootstrap. Hold exclusive owner action receipt lock and recheck fence immediately before CAS." + ], + "after_cas": "Keep consumers/signer stopped until independent public admission and exact ESO/readback/source/image verification. Recreate1 is Access-owned; any drift or uncertain outcome keeps fence closed. Access reports current outbox lacks OS process lock, byte ceiling and bounded startup/compaction; Recreate1 alone is not bounded durable acceptance. Keep protected acceptance closed until reviewed source hardening or explicit bounded attended fixture disposition.", + "concurrency": "Single attended owner window/exclusive receipt; GitOps/Helm autosync/other writers must be paused by Access/cluster owner under distinct reviewed action. Plan is not a Kubernetes atomic fence or same-UID isolation." + }, + "protected_adapter": { + "state": "implementation/independent tests still required before executable approval; fixture code must never be promoted by removing its dev-process check", + "reuse": [ + "scripts/state_hub_preflight_lane.py attended silent child/cluster/platform-admin/fencing patterns", + "scripts/flex_auth_signer_custody.py protected Ed25519 CAS/readback and receipt state machine", + "scripts/task_execution_native_fixture.py absolute main-thread2s I/O budget", + "scripts/task_execution_recovery.py strict bounded JSON/no-follow/private custody patterns" + ], + "requirements": [ + "New fixed native adapter consumes exact approved CCR/source/native-action digest; cannot accept arbitrary URL/path/command/payload/seed.", + "Read OIDC token only within warden child from attended context; require platform-admin and reject root; never print/store bearer. No credential comes back to agent.", + "Pin exact kube-system/OpenBao cluster IDs before private calls, refuse ambient address override; enforce2s absolute reads and1MiB cap; no redirect/shell/tracing.", + "Verify metadata absence/exact admitted values before CAS-required change; any differing existing object refuses. Exact response contracts and duplicate/nonfinite JSON rejection.", + "Private seed is generated once, never imported or persisted outside OpenBao; no subprocess argv/env seed; readback compares exact version/fields and derived public correspondence.", + "Receipt intent is durable before native effect; final success requires exact KV/metadata correspondence and receipt fsync. Process loss/error remains unknown without remint/retry." + ] + }, + "receipts": { + "directory": "/home/worsch/.local/state/railiance-platform/flex-auth-envelope-signing", + "mode_directory": "0700", + "mode_file": "0600", + "native_execution_location": "founder workstation inside reviewed warden child; no agent-owned shared /tmp custody", + "basename": "RPF35-PDP-SIGNER-NATIVE-20261016-R1.json", + "maximum_bytes": 65536, + "atomic": "exclusive initial receipt, fsync-before-effect, atomic replacement and directory fsync, no-follow/owner/mode/nlink validation", + "public_fields": [ + "proposal/executed source/CCR/identity/cluster/image/policy/trust digests", + "actor/time", + "closed phase/status", + "exact KV path/version/kid", + "public key and explicitly encoded fingerprint", + "fence/metadata/readback checks", + "rollback or unknown recovery disposition" + ], + "fingerprint": "sha256: lowercase SHA256 of canonical unpadded base64url public-key ASCII, exactly43bytes; independent Secrets owner agreement before admission", + "delivery": "Founder/Platform separately authenticate metadata receipt to Secrets owner; public receipt shape/file does not create consumer trust; raw private receipt directory is not a shared agent intake" + }, + "rollback": { + "before_cas": "Abort without private write; retain receipt/fence; restore prior Access image/values only via reviewed Access action.", + "after_cas_unknown": "Retain unknown and fence; independently attended owner reconciles exact metadata/version/public correspondence. Never rerun CAS0 or restore prior seed automatically.", + "compromise": "Remove online old public key immediately; stop signer, independent new reviewed forward-only action; old private seed never restored." + }, + "requested_scope": { + "read_lane": "Exact CCR0050 policy/role/delivery source only after separate founder review. No extra ESO RBAC permitted.", + "custody_writer": "One attended exact-target CAS0 plus fixed KV metadata setup/readback; no standing writer grant or broker role. This authority is separate from read CCR.", + "kubernetes": "Metadata-only fence observations by child; Access/cluster separately approve stop/restart/delivery manifests and sync control.", + "new_infrastructure_spend_eur": 0, + "new_resources": "Platform creates no storage resources. Access reports zero flex-auth PVCs; Access proposes separate exact new flex-auth-secrets-engine-outbox1Gi local-path Helmkeep. Provisioning, PV reclaim/Delete/WaitForFirstConsumer retention and runtime log bounds require separate founder/cluster/Access review; no durable outbox acceptance yet.", + "risk_bound": "Controlled loss of retained PDP availability during explicit attended fence; seed compromise can forge lifecycle decisions until independent public trust withdrawal; founder must approve this concrete high-risk scope." + }, + "reviews_required": [ + { + "role": "railiance-platform-owner", + "disposition": "pending exact source/artifact review; no approval recorded" + }, + { + "role": "access-engine-owner", + "disposition": "pending exact source/artifact review; no approval recorded" + }, + { + "role": "secrets-engine-owner", + "disposition": "pending exact source/artifact review; no approval recorded" + }, + { + "role": "cluster-gitops-owner", + "disposition": "pending exact source/artifact review; no approval recorded" + }, + { + "role": "founder", + "disposition": "pending exact source/artifact review; no approval recorded" + } + ], + "authority_granted": false, + "candidate_delivery_amendments": { + "supersedes_unadmitted_R3_role": "external-secrets-flex-auth-envelope-signing replaces flex-auth-envelope-signing-eso to fit existing delegated-applier role convention; dedicated SA unchanged", + "read_ccr_field_projection": "Only ED25519_PRIVATE_KEY is delivered; public sibling fields remain visible to dedicated document-reader identity but never become consumer trust discovery", + "projection_source": "docs/credential-lane-designs/flex-auth-envelope-signing-native-projection.yaml.proposed", + "managed_declaration": "Missing rapp declaration remains migration debt; retain actual Access919ce25 workload identity, do not create package tuple" + } +}