From be0f8916192fb0b636601f0d0b8e872682ae4fd3 Mon Sep 17 00:00:00 2001 From: codex Date: Sun, 1 Nov 2026 23:36:38 +0100 Subject: [PATCH] docs: preserve reviewed NetKingdom session artifacts --- .../tls-staging-cleanup-r1/OWNER-REVIEW.md | 198 ++++++++ .../cmctl-public-source.go | 340 ++++++++++++++ .../delete-request-contract.json | 58 +++ .../local-tmpfs-readonly-observation.json | 8 + .../tls-staging-cleanup-r1/manifest.json | 17 + .../owner-boundary.preimage.md | 51 +++ .../owner-boundary.proposed.md | 143 ++++++ .../tls-staging-cleanup-r1/owner-doc.patch | 122 +++++ .../tls-staging-cleanup-r1/review.json | 28 ++ .../tls-staging-cleanup-r1/source-pins.json | 62 +++ .../staging-reaper-contract.json | 71 +++ ...fied-client-cluster-consistency.stderr.txt | 1 + ...ified-client-cluster-projection.stderr.txt | 0 .../verify_current_rows_at_close.py | 34 ++ .../WORK-RECORDS.md.backup | 188 ++++++++ .../consistency-backup/.custodian-brief.md | 60 +++ .../consistency-backup/WORK-RECORDS.md | 188 ++++++++ .../workplans/ADHOC-2026-06-27.md | 41 ++ .../workplans/ADHOC-2026-06-29.md | 40 ++ .../workplans/ADHOC-2026-08-11.md | 145 ++++++ .../workplans/ADHOC-2026-08-17.md | 129 ++++++ .../workplans/ADHOC-2026-09-08.md | 179 ++++++++ .../workplans/ADHOC-2026-10-03.md | 31 ++ ...EN-WP-0016-ops-bridge-tunnel-cert-pilot.md | 124 +++++ ...-0017-access-front-door-discoverability.md | 120 +++++ ...-0018-whynot-design-npm-lane-activation.md | 103 +++++ .../WARDEN-WP-0019-route-to-secrets-engine.md | 89 ++++ .../WARDEN-WP-0020-ops-warden-worker.md | 176 +++++++ ...EN-WP-0021-enable-scheduled-worker-tick.md | 142 ++++++ ...WARDEN-WP-0022-audit-trail-and-activity.md | 119 +++++ ...WP-0023-intent-scope-alignment-closeout.md | 222 +++++++++ ...-experiential-memory-and-agent-sessions.md | 269 +++++++++++ ...EN-WP-0025-forgejo-admin-api-token-lane.md | 118 +++++ ...N-WP-0026-credential-disclosure-hygiene.md | 261 +++++++++++ ...-WP-0027-credential-governance-lockdown.md | 303 +++++++++++++ .../WARDEN-WP-0028-tenant-secret-custody.md | 421 +++++++++++++++++ ...9-policy-front-door-and-founder-surface.md | 159 +++++++ .../WARDEN-WP-0030-delegation-register.md | 270 +++++++++++ .../WARDEN-WP-0031-policy-caller-identity.md | 170 +++++++ .../WARDEN-WP-0032-security-zones.md | 429 ++++++++++++++++++ .../WARDEN-WP-0033-native-lane-handoff.md | 344 ++++++++++++++ ...DEN-WP-0034-layer-model-v07-conformance.md | 354 +++++++++++++++ ...-policy-nexus-forgejo-source-read-route.md | 46 ++ ...N-WP-0036-attended-login-openbao-output.md | 131 ++++++ ...-WP-0037-whynot-design-forgejo-npm-lane.md | 191 ++++++++ .../WARDEN-WP-0038-plan-mutation-intent.md | 149 ++++++ .../WARDEN-WP-0039-explicit-policy-refusal.md | 159 +++++++ ...-0040-unknown-zone-fail-closed-adoption.md | 240 ++++++++++ ...WARDEN-WP-0041-catalog-lane-scaffolding.md | 100 ++++ ...-WP-0042-openbao-structure-survey-route.md | 55 +++ 50 files changed, 7398 insertions(+) create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/OWNER-REVIEW.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/cmctl-public-source.go create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/delete-request-contract.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/local-tmpfs-readonly-observation.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/manifest.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-boundary.preimage.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-boundary.proposed.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-doc.patch create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/review.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/source-pins.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/staging-reaper-contract.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/verified-client-cluster-consistency.stderr.txt create mode 100644 docs/changes/netkingdom-target-2026-10-17/verified-client-cluster-projection.stderr.txt create mode 100644 docs/changes/netkingdom-target-2026-10-17/verify_current_rows_at_close.py create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/WORK-RECORDS.md.backup create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/.custodian-brief.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/WORK-RECORDS.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-06-27.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-06-29.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-08-11.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-08-17.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-09-08.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-10-03.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0017-access-front-door-discoverability.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0019-route-to-secrets-engine.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0020-ops-warden-worker.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0022-audit-trail-and-activity.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0027-credential-governance-lockdown.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0028-tenant-secret-custody.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0030-delegation-register.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0031-policy-caller-identity.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0032-security-zones.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0033-native-lane-handoff.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0034-layer-model-v07-conformance.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0036-attended-login-openbao-output.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0038-plan-mutation-intent.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0039-explicit-policy-refusal.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0042-openbao-structure-survey-route.md diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/OWNER-REVIEW.md b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/OWNER-REVIEW.md new file mode 100644 index 00000000..5b1d8eef --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/OWNER-REVIEW.md @@ -0,0 +1,198 @@ +# T03: protect the earlier cmctl key and reconcile its exact public request + +Source review only under existing RCLUSTER-WP-0018-T03 / NK-WP-0049-T35/T33. +No canonical source changed, cmctl installed/executed, key generated/read, +CertificateRequest created, cluster mutation or residual implementation occurred. +Frozen TLS disposition and all native-runtime R1–R3 receipts stay untouched. + +The missing behavior is small but real: cmctl writes its local private key +before its CertificateRequest Create. The existing NetKingdom session registers +its own later archive/Docker workdir and reaper; it does not cover those earlier +key bytes or a Kubernetes request accepted after a lost client response. + +## Existing source and exact reuse + +- NetKingdom isolated-keycape-session.py: register_workdir and cleanup_workdir + already bind /dev/shm/nk49-keycape-{run_id}-{eight_random_chars}, UID/mode0700, + device/inode and refuse replacement, symlink, hardlink, cross-device/special + objects. Its dirfd-based recursive cleanup can remain unchanged. +- Its isolate_execution / process_facts / pidfd_dead / quiesce_execution show + the existing fresh-session and pidfd contract. Its start_reaper/reaper_main + are specifically Docker/session-bound and must not be called with an invented + empty Docker session for issuance. Group-only membership also does not prove + removal of session-escaped credential-plugin descendants. +- Its persist_receipt/checkpoint seam records obligations before archive + plaintext. T03 must similarly register *before cmctl*, not after output exists. +- NetKingdom capture-identity.delete_created and Platform + native_factory_acceptance use Kubernetes raw DELETE with DeleteOptions UID + preconditions (the latter also Foreground propagation). Reuse that exact API + idiom in the TLS owner helper; do not broaden identity-capture's Pod/NP whitelist. +- The locally tested native-runtime R3 supervisor demonstrates subreaper/pidfd + descendant cleanup, including dead-orphan reaping and live-leftover refusal. + That is relevant source evidence, not an admitted TLS utility or native cause + proof. Do not import a Custodian packet at runtime or silently copy its grant. + +## Minimal owner source delta, before any key + +Implement one bounded T03 orchestration helper through the existing Cluster / +NetKingdom ownership boundary; retain the six-argument original recovery launcher. +No new broker, CA provider, auth method, TLS policy enum or approval field. +The reviewable interfaces are: + +1. `register_tls_staging(run_id, caller_binding, deadline)` creates only the + existing guard-compatible fresh0700 directory. Before creation/key access, + verify the actual selected /dev/shm mount is writable tmpfs, bind mount ID / + device, owner UID, no aliases, and available bounded space. Then call existing + register_workdir and checkpoint only public path/device/inode/run facts. + The existing register_workdir alone does NOT check tmpfs before use; current + cleanup_workdir checks it only at deletion. Move that check earlier in this + new caller; no disk /tmp fallback. This sandbox's /dev/shm is actually ro, + so no usable private staging or local tmpfs lifecycle proof is claimed here. +2. `start_tls_reaper(staging, execution, request_intent)` starts an independent + surviving observer and waits for its registration acknowledgment BEFORE + spawning cmctl. Bind controller pidfd/start/UID and a single monotonic deadline. + The observer owns/reaps the exact cmctl and subsequent original-launcher + process trees as a subreaper; pidfd-bound actual descendants cover setsid + escapes. Preserve existing fresh-session guard and avoid inherited/shared + process-group kills. On timeout/parent loss stop/wait those exact descendants + before cleanup. A missing mapping/observer or survivor means cleanup unverified, + never an inferred success. Reap already-dead adopted direct-child zombies + without stealing managed leader exit status; retain the R3 local counterexample. +3. `run_issuance(binding, staging, run_id)` uses the admitted exact cmctl binary, + unchanged R1 flags and original Certificate spec, but puts one unique run label + and source/proposal annotation in its *local template*. The pinned cmctl source + copies those labels/annotations into the CertificateRequest. Pre-register + exact target/ns/name, template/spec hash, expected issuer and an unresolved + submit obligation before spawn. Output key/cert paths must be absent, under + the held private directory, with umask077. Discard raw stdout/stderr; no private + path/content/diagnostic dump enters shared receipts. The binary source uses + os.WriteFile0600 without O_EXCL/O_NOFOLLOW, so it relies on this previously + verified private directory/absent-output boundary; it is not a safe arbitrary + output-path primitive by itself. +4. `observe_request(intent, private_custody)` uses only the bound owner API, + exact name and bounded public field projection. Require same cluster identity, + namespace/name, fresh run marker, fixed issuer/usages/SAN/CSR semantics and + the admitted API caller. Inside future approved private custody, derive only + the held key's public SPKI commitment and compare it with the actual signed + CSR; expose only public commitment/CSR hash and pairing boolean. Check the + CSR signature/SANs. Checkpoint the actual UID/resourceVersion and expected + public spec hash before any remote delete or private-directory cleanup. + The run marker alone is not proof of key/caller ownership. +5. `delete_request_uid(bound)` uses the exact contract in delete-request-contract.json, + then independently verifies that UID's absence and the actual owner-UID + descendant chain. Normal cert-manager garbage collection is preferred; explicit + cleanup of a stuck child needs its recorded UID/owner chain and scoped owner + review. Do not delete by label, prefix, wildcard or name alone. +6. `finish_or_abort(...)` persists an immutable bounded public checkpoint BEFORE + private deletion: tool/source/target/run, process exits/public facts, + certificate/trust hashes, request UID/spec/CSR commitments, descendant cleanup + dispositions, pending API/daemon duties. Reuse cleanup_workdir only after exact + local child quiescence and verified staging identity. If public remote cleanup + is uncertain, local key/plaintext cleanup can still proceed after quiescence, + PROVIDED the exact public request obligations/commitments have been durably + retained; report separate local and remote cleanup results, not global success. + If required commitments cannot be retained, fail closed and leave the exact + protected staging for attended custody recovery, rather than losing ownership + proof or broadly deleting unknown resources. No blind retry after uncertainty. + +`staging-reaper-contract.json` fixes the proposed nonrenewable bounds: issuance +330 seconds including cmctl's inner300-second fetch wait; existing recovery +child at most1800 seconds; one total private execution deadline2130 seconds, +then at most60 seconds of clipped cleanup (2190 total). TERM0.5, KILL/reap3, +watchdog wait8; each API request at most30 seconds clipped to cleanup remainder. +Set umask077, disable core dumps, and bound each cmctl output to1MiB with the +same bounded child runner before generation. Tmpfs is +not claimed unswappable or isolated from host root/hypervisor/crash custody. +These exact proposed bounds need source lifecycle proof before use; they are +not a statement that today's helper already enforces them. + +The cmctl child gets DEVNULL input/output/error and no custody fd. Do not copy +that IO policy onto the original six-argument launcher: it explicitly requires +an attended TTY and invokes the existing hidden age prompt / sealed-fd custody +helper. Preserve that original owner terminal path and its existing custody +contract, without a new PTY proxy, prompt capture or key passage to the observer. +The observer gets only pidfds/public metadata and must close every unrelated fd; +its deadline also bounds a stalled attended prompt. Prove this exact distinction +with a synthetic terminal fixture before integration; the runtime R3 runner's +DEVNULL default is not an admitted drop-in for the attended recovery launcher. + +The independent observer must outlive the creator, not rely on a shell trap or +SIGTERM-only child wait. It must not receive a newly fetched kube credential or +private key in argv/environment/receipt. Exact use of the existing bound owner +API caller remains in that owner's attended execution scope. If that caller +uses an exec auth plugin, its actual descendants are covered by the same reaper; +there is no implicit admission for unrelated credential helpers or new routes. + +## One custody host and explicit Kubernetes binding + +R1's candidate /home/worsch cmctl path and --context default do not establish +where the private key and original local-Docker recovery run will live. R1's +observed default context was on railiance01. Current environment orientation says +workstation kubeconfig was repaired in September but still requires explicit +node-IP verification and node-local mutation practice; a context name alone is +not a cluster binding. This is an unverified command binding, not proof that +workstation/default presently targets a different cluster. + +Keep cmctl, tmpfs/reaper and the original six-argument launcher on ONE actually +admitted custody host. Do not move only cmctl to railiance01 and invent a private +key SCP/download. The existing T33/T35 exact action review must bind that host, +account, cmctl absolute path/hash, API server/CA public identity and actual node +92.205.62.239 through the existing owner profile. If the actual launcher is +workstation-local, direct networked issuance needs that explicit owner/founder +execution disposition under the existing change gate; if all run node-local, +first demonstrate the existing launcher/Docker/independent-owner interfaces there. +No host choice, kube credential read or private transfer is assumed by this packet. +This is why the source delta is reviewable while a native argv cannot yet be +honestly called executable. + +## Exact lifecycle/counterexamples to require from T03 implementation + +- Observer/mount/target/source refusal: zero cmctl spawn and zero key output. +- Success: fake network child writes a synthetic PRIVATE_SENTINEL under actual + guarded tmpfs, public fixture API returns the exact UID, original launcher + consumer reads through the same custody boundary, UID-delete body matches, + held inode removed after positive process proof. No real admin canary/key. +- Failure before API, key-only failure, timeout, controller SIGKILL, setsid child, + dead adopted zombie, uninterruptible/unknown child and output bound. Verify + no leaked sentinel and no unrelated sibling signaled. Replaced inode, + symlink/hardlink or wrong mount must refuse deletion/use. +- API accepted but reply lost: preserve submit uncertainty, later exact-name + reconciliation accepts only held SPKI/run/spec/caller binding and actual UID. + A single NotFound after killed client does not establish no late Create. +- Wrong cluster/ns/name/run/SPKI/spec or swapped UID: no delete. UID-precondition + conflict leaves replacement untouched. GC/finalizer timeout and unreachable + API retain outstanding request/child UIDs, not successful cleanup. +- Independent immutable public receipt exists before private cleanup; receipt + write failure leaves protected staging. Real issuance and cluster cleanup + remain separate supervised native tests after source proof/review. + +These are requested meaningful generated lifecycle tests, not tests run by this +source-only packet. Existing native session/daemon cleanup facts and R3 process +fixtures are reused with their limits; no broad dummy rerun was performed. + +## Safe source-only owner publication now + +The one-file owner-doc.patch is ready for source-owner review against its captured +preimage. It clarifies renewable transport versus archived signing identity, +retains per-attempt TLS/trust hashes and all existing T02–T04/native duties, records +the already-located guide, and names the concrete T03 delta above. It makes no +owner/founder assent or native compatibility claim. No task status/UUID change or +new T06 is needed for this clarification; do not publish the old R1 task addition +as completed native/staging work. Root may review/publish that doc alone using +normal owner publication while canonical code and frozen packets remain unchanged. + +The original disaster guide is already located: publication commit +31f483966cdfca4df1d326dee3ec0b6d33ea0e5e, Backup account, +railiance-backups/net-kingdom-identity/net-kingdom-recovery-57d1940947aa25ff-START-HERE.md. +The recorded three-object readback is historical; this source work does not +re-read StorageShare or request another original TLS backup. The guide is +identity-only and does not establish ingress TLS-key coverage. + +Renewed trusted leaf material remains compatible with the existing per-attempt +admission; no historical leaf-byte equality or extra TLS mode is introduced. +Archived original OIDC issuer/signing keys/JWKS and registration/policy checks +remain unchanged. HTTP-01 still depends on a surviving Kubernetes/cert-manager/ +Traefik/DNS/domain-routing/port80/ACME path. It neither causes nor proves recovery +from cluster loss, and today's Ready/public-chain observations do not establish +original TLS custody, a future issuance result or an external-vantage HTTP01 test. +Independent cluster-loss recovery/provider/domain-control remains T02–T04 scope. diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/cmctl-public-source.go b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/cmctl-public-source.go new file mode 100644 index 00000000..9a1157af --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/cmctl-public-source.go @@ -0,0 +1,340 @@ +/* +Copyright 2020 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package certificaterequest + +import ( + "context" + "encoding/pem" + "errors" + "fmt" + "os" + "time" + + apiutil "github.com/cert-manager/cert-manager/pkg/api/util" + cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" + "github.com/cert-manager/cert-manager/pkg/util/pki" + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/resource" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/cert-manager/cmctl/v2/pkg/build" + "github.com/cert-manager/cmctl/v2/pkg/convert" + "github.com/cert-manager/cmctl/v2/pkg/factory" +) + +var ( + // Dedicated scheme used by the ctl tool that has the internal cert-manager types, + // and their conversion functions registered + scheme = convert.Scheme +) + +// Options is a struct to support create certificaterequest command +type Options struct { + // Name of file that the generated private key will be stored in + // If not specified, the private key will be written to .key + KeyFilename string + // If true, will wait for CertificateRequest to be ready to store the x509 certificate in a file + // Command will block until CertificateRequest is ready or timeout as specified by Timeout happens + FetchCert bool + // Name of file that the generated x509 certificate will be stored in if --fetch-certificate flag is set + // If not specified, the private key will be written to .crt + CertFileName string + // Path to a file containing a Certificate resource used as a template + // when generating the CertificateRequest resource + // Required + InputFilename string + // Length of time the command blocks to wait on CertificateRequest to be ready if --fetch-certificate flag is set + // If not specified, default value is 5 minutes + Timeout time.Duration + + genericclioptions.IOStreams + *factory.Factory +} + +// NewOptions returns initialized Options +func NewOptions(ioStreams genericclioptions.IOStreams) *Options { + return &Options{ + IOStreams: ioStreams, + } +} + +// NewCmdCreateCR returns a cobra command for create CertificateRequest +func NewCmdCreateCR(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { + o := NewOptions(ioStreams) + + cmd := &cobra.Command{ + Use: "certificaterequest", + Aliases: []string{"cr"}, + Short: "Create a cert-manager CertificateRequest resource, using a Certificate resource as a template", + Long: templates.LongDesc(` +Create a new CertificateRequest resource based on a Certificate resource, by generating a private key locally and create a 'certificate signing request' to be submitted to a cert-manager Issuer.`), + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Create a CertificateRequest with the name 'my-cr', saving the private key in a file named 'my-cr.key'. +{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml + +# Create a CertificateRequest in namespace default, provided no conflict with namespace defined in file. +{{.BuildName}} create certificaterequest my-cr --namespace default --from-certificate-file my-certificate.yaml + +# Create a CertificateRequest and store private key in file 'new.key'. +{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --output-key-file new.key + +# Create a CertificateRequest, wait for it to be signed for up to 5 minutes (default) and store the x509 certificate in file 'new.crt'. +{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --output-cert-file new.crt + +# Create a CertificateRequest, wait for it to be signed for up to 20 minutes and store the x509 certificate in file 'my-cr.crt'. +{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --timeout 20m +`)), + ValidArgsFunction: factory.ValidArgsListCertificateRequests(&o.Factory), + PreRunE: func(cmd *cobra.Command, args []string) error { + return o.Validate(args) + }, + //nolint:contextcheck // False positive + RunE: func(cmd *cobra.Command, args []string) error { + return o.Run(cmd.Context(), args) + }, + } + cmd.Flags().StringVar(&o.InputFilename, "from-certificate-file", o.InputFilename, + "Path to a file containing a Certificate resource used as a template when generating the CertificateRequest resource") + cmd.Flags().StringVar(&o.KeyFilename, "output-key-file", o.KeyFilename, + "Name of file that the generated private key will be written to") + cmd.Flags().StringVar(&o.CertFileName, "output-certificate-file", o.CertFileName, + "Name of the file the certificate is to be stored in") + cmd.Flags().BoolVar(&o.FetchCert, "fetch-certificate", o.FetchCert, + "If set to true, command will wait for CertificateRequest to be signed to store x509 certificate in a file") + cmd.Flags().DurationVar(&o.Timeout, "timeout", 5*time.Minute, + "Time before timeout when waiting for CertificateRequest to be signed, must include unit, e.g. 10m or 1h") + + o.Factory = factory.New(cmd) + + return cmd +} + +// Validate validates the provided options +func (o *Options) Validate(args []string) error { + if len(args) < 1 { + return errors.New("the name of the CertificateRequest to be created has to be provided as argument") + } + if len(args) > 1 { + return errors.New("only one argument can be passed in: the name of the CertificateRequest") + } + + if o.InputFilename == "" { + return errors.New("the path to a YAML manifest of a Certificate resource cannot be empty, please specify by using --from-certificate-file flag") + } + + if o.KeyFilename != "" && o.CertFileName != "" && o.KeyFilename == o.CertFileName { + return errors.New("the file to store private key cannot be the same as the file to store certificate") + } + + if !o.FetchCert && o.CertFileName != "" { + return errors.New("cannot specify file to store certificate if not waiting for and fetching certificate, please set --fetch-certificate flag") + } + + return nil +} + +// Run executes create certificaterequest command +func (o *Options) Run(ctx context.Context, args []string) error { + builder := new(resource.Builder) + + // Read file as internal API version + r := builder. + WithScheme(scheme, schema.GroupVersion{Group: cmapi.SchemeGroupVersion.Group, Version: runtime.APIVersionInternal}). + LocalParam(true).ContinueOnError(). + NamespaceParam(o.Namespace).DefaultNamespace(). + FilenameParam(o.EnforceNamespace, &resource.FilenameOptions{Filenames: []string{o.InputFilename}}).Flatten().Do() + + if err := r.Err(); err != nil { + return err + } + + singleItemImplied := false + infos, err := r.IntoSingleItemImplied(&singleItemImplied).Infos() + if err != nil { + return err + } + + // Ensure only one object per command + if len(infos) == 0 { + return fmt.Errorf("no objects found in manifest file %q. Expected one Certificate object", o.InputFilename) + } + if len(infos) > 1 { + return fmt.Errorf("multiple objects found in manifest file %q. Expected only one Certificate object", o.InputFilename) + } + info := infos[0] + // Convert to v1 because that version is needed for functions that follow + crtObj, err := scheme.ConvertToVersion(info.Object, cmapi.SchemeGroupVersion) + if err != nil { + return fmt.Errorf("failed to convert object into version v1: %w", err) + } + + // Cast Object into Certificate + crt, ok := crtObj.(*cmapi.Certificate) + if !ok { + return errors.New("decoded object is not a v1 Certificate") + } + + crt = crt.DeepCopy() + if crt.Spec.PrivateKey == nil { + crt.Spec.PrivateKey = &cmapi.CertificatePrivateKey{} + } + + signer, err := pki.GeneratePrivateKeyForCertificate(crt) + if err != nil { + return fmt.Errorf("error when generating new private key for CertificateRequest: %w", err) + } + + keyData, err := pki.EncodePrivateKey(signer, crt.Spec.PrivateKey.Encoding) + if err != nil { + return fmt.Errorf("failed to encode new private key for CertificateRequest: %w", err) + } + + crName := args[0] + + // Storing private key to file + keyFileName := crName + ".key" + if o.KeyFilename != "" { + keyFileName = o.KeyFilename + } + if err := os.WriteFile(keyFileName, keyData, 0600); err != nil { + return fmt.Errorf("error when writing private key to file: %w", err) + } + fmt.Fprintf(o.ErrOut, "Private key written to file %s\n", keyFileName) + + // Build CertificateRequest with name as specified by argument + req, err := buildCertificateRequest(crt, keyData, crName) + if err != nil { + return fmt.Errorf("error when building CertificateRequest: %w", err) + } + + ns := crt.Namespace + if ns == "" { + ns = o.Namespace + } + req, err = o.CMClient.CertmanagerV1().CertificateRequests(ns).Create(ctx, req, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("error creating CertificateRequest: %w", err) + } + fmt.Fprintf(o.ErrOut, "CertificateRequest %s has been created in namespace %s\n", req.Name, req.Namespace) + + if o.FetchCert { + fmt.Fprintf(o.ErrOut, "CertificateRequest %v in namespace %v has not been signed yet. Wait until it is signed...\n", + req.Name, req.Namespace) + err = wait.PollUntilContextTimeout(ctx, time.Second, o.Timeout, false, func(ctx context.Context) (done bool, err error) { + req, err = o.CMClient.CertmanagerV1().CertificateRequests(req.Namespace).Get(ctx, req.Name, metav1.GetOptions{}) + if err != nil { + return false, nil //nolint: nilerr // Retry and keep polling until context is cancelled + } + return apiutil.CertificateRequestHasCondition(req, cmapi.CertificateRequestCondition{ + Type: cmapi.CertificateRequestConditionReady, + Status: cmmeta.ConditionTrue, + }) && len(req.Status.Certificate) > 0, nil + }) + if err != nil { + return fmt.Errorf("error when waiting for CertificateRequest to be signed: %w", err) + } + fmt.Fprintf(o.ErrOut, "CertificateRequest %v in namespace %v has been signed\n", req.Name, req.Namespace) + + // Fetch x509 certificate and store to file + actualCertFileName := req.Name + ".crt" + if o.CertFileName != "" { + actualCertFileName = o.CertFileName + } + err = fetchCertificateFromCR(req, actualCertFileName) + if err != nil { + return fmt.Errorf("error when writing certificate to file: %w", err) + } + fmt.Fprintf(o.ErrOut, "Certificate written to file %s\n", actualCertFileName) + } + + return nil +} + +// Builds a CertificateRequest +func buildCertificateRequest(crt *cmapi.Certificate, pk []byte, crName string) (*cmapi.CertificateRequest, error) { + csrPEM, err := generateCSR(crt, pk) + if err != nil { + return nil, err + } + + cr := &cmapi.CertificateRequest{ + ObjectMeta: metav1.ObjectMeta{ + Name: crName, + Annotations: crt.Annotations, + Labels: crt.Labels, + }, + Spec: cmapi.CertificateRequestSpec{ + Request: csrPEM, + Duration: crt.Spec.Duration, + IssuerRef: crt.Spec.IssuerRef, + IsCA: crt.Spec.IsCA, + Usages: crt.Spec.Usages, + }, + } + + return cr, nil +} + +func generateCSR(crt *cmapi.Certificate, pk []byte) ([]byte, error) { + csr, err := pki.GenerateCSR(crt) + if err != nil { + return nil, err + } + + signer, err := pki.DecodePrivateKeyBytes(pk) + if err != nil { + return nil, err + } + + csrDER, err := pki.EncodeCSR(csr, signer) + if err != nil { + return nil, err + } + + csrPEM := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE REQUEST", Bytes: csrDER, + }) + + return csrPEM, nil +} + +// fetchCertificateFromCR fetches the x509 certificate from a CR and stores the +// certificate in file specified by certFilename. Assumes CR is ready, +// otherwise returns error. +func fetchCertificateFromCR(req *cmapi.CertificateRequest, certFileName string) error { + // If CR not ready yet, error + if !apiutil.CertificateRequestHasCondition(req, cmapi.CertificateRequestCondition{ + Type: cmapi.CertificateRequestConditionReady, + Status: cmmeta.ConditionTrue, + }) || len(req.Status.Certificate) == 0 { + return errors.New("CertificateRequest is not ready yet, unable to fetch certificate") + } + + // Store certificate to file + err := os.WriteFile(certFileName, req.Status.Certificate, 0600) + if err != nil { + return fmt.Errorf("error when writing certificate to file: %w", err) + } + + return nil +} diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/delete-request-contract.json b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/delete-request-contract.json new file mode 100644 index 00000000..2dd5afc0 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/delete-request-contract.json @@ -0,0 +1,58 @@ +{ + "schema": "custodian.keycape-tls-request-cleanup-source-proposal.v1", + "status": "not executed; no actual request UID exists", + "target": { + "node_ip": "92.205.62.239", + "namespace": "sso", + "name": "nk49-kc-drill-20261017-r1", + "group_version": "cert-manager.io/v1", + "resource": "certificaterequests" + }, + "create_binding": { + "run_label": "net-kingdom/recovery-run=", + "source_annotation": "net-kingdom/tls-reissue-source=", + "expected_issuer": { + "group": "cert-manager.io", + "kind": "ClusterIssuer", + "name": "letsencrypt-prod" + }, + "public_spki_and_csr_hash": "derived/verified inside separately approved private custody; no key exposed", + "caller_and_template_spec_hash": "exact admitted owner caller plus frozen public input" + }, + "delete_argv_template": [ + "", + "--request-timeout=30s", + "delete", + "--raw", + "/apis/cert-manager.io/v1/namespaces/sso/certificaterequests/nk49-kc-drill-20261017-r1", + "-f", + "-" + ], + "stdin_payload_template": { + "apiVersion": "v1", + "kind": "DeleteOptions", + "preconditions": { + "uid": "" + }, + "propagationPolicy": "Foreground" + }, + "required_before_delete": [ + "fresh cluster/account binding", + "exact observed UID plus held run/spec/SPKI/CSR/caller commitments", + "durable public request and descendant obligations; local writer quiescent if submission was uncertain" + ], + "required_after_delete": [ + "same recorded UID is absent or deletion remains uncertain", + "different UID at same name remains untouched; record collision", + "actual Order->CertificateRequest, Challenge->Order and solver->Challenge ownerReference UID chains are reconciled; do not infer from name/label", + "controller/API/finalizer timeout remains unresolved; no wildcard cleanup" + ], + "forbidden": [ + "kubectl delete certificaterequest NAME without UID preconditions", + "production Certificate/Secret/Ingress mutation", + "broad Order/Challenge/solver deletion", + "one post-timeout NotFound treated as proof no late Create" + ], + "unknown_uid": "No delete. Preserve exact name/run/spec/SPKI intent and reconcile actual UID through owner API; unresolved if ownership cannot be established.", + "native_api_calls": 0 +} diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/local-tmpfs-readonly-observation.json b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/local-tmpfs-readonly-observation.json new file mode 100644 index 00000000..a5fa9f77 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/local-tmpfs-readonly-observation.json @@ -0,0 +1,8 @@ +{ + "scope": "this source-preparation sandbox only, not an admitted native custody host", + "mountinfo": [ + "945 943 0:65 / /dev/shm ro,nosuid,nodev,noatime master:20 - tmpfs none rw" + ], + "usable_private_staging_claimed": false, + "mount_or_tmpfs_write_attempts": 0 +} diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/manifest.json b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/manifest.json new file mode 100644 index 00000000..c01a52f2 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/manifest.json @@ -0,0 +1,17 @@ +{ + "schema": "custodian.tls-staging-cleanup-source.v1", + "status": "source prepared only", + "native_execution_authorized": false, + "files": { + "OWNER-REVIEW.md": "sha256:f2380217eef95148951f00d0a01b634fe9a2af1cda93bca5ed0652f92157e6e6", + "cmctl-public-source.go": "sha256:0ba0c2d3d4f8530514c8d864b2a9e056f14f763a0b314aa05998f3169ee5bc32", + "delete-request-contract.json": "sha256:8dae54b516d67c2069eeffbf6a3ab9ac391e4f386971cddb4dfbb587143afa86", + "local-tmpfs-readonly-observation.json": "sha256:e7cbc7bd1e1d3e4a4282c87da6c689f341a06a74840ee0ed770368ff0c809270", + "owner-boundary.preimage.md": "sha256:f4bcb1d1832c566f9c87793ed2a461c8cd8a00859dc4ae66cd3c160d7ceefa70", + "owner-boundary.proposed.md": "sha256:6daec76f0c220e433dcc0bfafbd4bb922a4a19606cbd74e76e50be9883ae796b", + "owner-doc.patch": "sha256:df565c58026150cd95833b4472610fc90db1ab5fccc90d2bca36494ca77f3c4f", + "review.json": "sha256:5e72c13f4284fe6c4a418a8af93aacbe3ebdce05b3536723f2626354e3fbec6a", + "source-pins.json": "sha256:de93f3cc6689fad2ee00e39ea93d135950fa13e9cdc32a4718f4bf2f4e7b00ab", + "staging-reaper-contract.json": "sha256:c4d0ce5159708303e1d376ab384a483ac79325b11c85dbd5840891667d65beed" + } +} diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-boundary.preimage.md b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-boundary.preimage.md new file mode 100644 index 00000000..40953976 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-boundary.preimage.md @@ -0,0 +1,51 @@ +# Original KeyCape TLS recovery boundary + +Source disposition, 2026-10-17, scoped to railiance-cluster INTENT: cluster runtime, +ingress/certificate plumbing and backup posture. This is source preparation only. +It is not native acceptance, an issuer/key custody assent, a reissue decision or +permission to mutate the cluster. + +NetKingdom's ingress source names `kc.coulomb.social`, `sso/kc-tls`, +`ClusterIssuer/letsencrypt-prod` and Traefik termination before KeyCape8080. +NetKingdom owns that namespace intent; railiance-cluster owns cert-manager, +ingress controller and cluster backup posture. No inspected source establishes +who independently holds the original private TLS recovery material when the +ordinary issuer/cluster is unavailable. A missing exact routing-catalog entry +cannot prove absence of an owning subsystem. + +The identity archive excludes `kc-tls`. Current S2 backup source encrypts SQLite +state, Helm values and kubeconfig to the same host's `/opt/backup/railiance/cluster` +and retains seven versions. No inspected source proves an actually fresh, +independent offsite object or original certificate/key/trust recovery. Archived +RAIL-BS-WP-0004 is historical local-backup delivery; backlog RCLUSTER-WP-0007-T05 +is gated HA issuance/renewal; active RCLUSTER-WP-0017 is signer runtime/storage. +None is an existing live task for this original TLS recovery demand. + +`railiance-backup-s2` also stages raw state/Helm output in named `/tmp` paths +without early hard-loss cleanup; `railiance-restore-s2` prints whole-state restore +instructions. Do not use either as an isolated TLS extraction path. RCLUSTER-WP-0018 +tracks exact inventory, safe private staging/extraction preparation where required, +independent outage proof and future archive-boundary disposition. No original +ciphertext or historical outcome is rewritten by that work. + +`tools/public-tls-metadata.py` is an offline public-only step. After the source +owner identifies independent original **public certificate/chain and trust files**: + +```sh +python3 tools/public-tls-metadata.py --public-cert ORIGINAL_PUBLIC_CERT_CHAIN.pem --public-trust ORIGINAL_PUBLIC_TRUST.pem +``` + +It accepts no private-key argument, bounds regular-file reads, refuses symlinks and +non-certificate PEM material, and reports public hashes/SANs/validity/counts only. +The file names are owner-local placeholders, not a key request. Output establishes +public metadata, not originality, hostname/chain acceptance, reissue permission or +custody. Do not supply a Secret object or combined certificate/key PEM. Fail closed +when original source, trust or exact bindings are missing; no fresh self-signed +trust workaround is admitted. + +For FUTURE NetKingdom archives, the source owners must explicitly disposition +original TLS coverage or a reviewed reissue contract: producer/custody owner, +private artifact boundary, offline recovery independence, original public hashes, +scoped capture/read permissions, retention and native verification. Merely adding +`kc-tls` to secret_refs would change capture/permission/custody scope and is not +authorized by this source review. It cannot repair the current archive retroactively. diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-boundary.proposed.md b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-boundary.proposed.md new file mode 100644 index 00000000..5a3be359 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-boundary.proposed.md @@ -0,0 +1,143 @@ +# Original KeyCape TLS recovery boundary + +Source disposition, 2026-10-17, scoped to railiance-cluster INTENT: cluster runtime, +ingress/certificate plumbing and backup posture. This is source preparation only. +It is not native acceptance, an issuer/key custody assent, a reissue decision or +permission to mutate the cluster. + +NetKingdom's ingress source names `kc.coulomb.social`, `sso/kc-tls`, +`ClusterIssuer/letsencrypt-prod` and Traefik termination before KeyCape8080. +NetKingdom owns that namespace intent; railiance-cluster owns cert-manager, +ingress controller and cluster backup posture. No inspected source establishes +who independently holds the original private TLS recovery material when the +ordinary issuer/cluster is unavailable. A missing exact routing-catalog entry +cannot prove absence of an owning subsystem. + +The identity archive excludes `kc-tls`. Current S2 backup source encrypts SQLite +state, Helm values and kubeconfig to the same host's `/opt/backup/railiance/cluster` +and retains seven versions. No inspected source proves an actually fresh, +independent offsite object or original certificate/key/trust recovery. Archived +RAIL-BS-WP-0004 is historical local-backup delivery; backlog RCLUSTER-WP-0007-T05 +is gated HA issuance/renewal; active RCLUSTER-WP-0017 is signer runtime/storage. +None is an existing live task for this original TLS recovery demand. + +`railiance-backup-s2` also stages raw state/Helm output in named `/tmp` paths +without early hard-loss cleanup; `railiance-restore-s2` prints whole-state restore +instructions. Do not use either as an isolated TLS extraction path. RCLUSTER-WP-0018 +tracks exact inventory, safe private staging/extraction preparation where required, +independent outage proof and future archive-boundary disposition. No original +ciphertext or historical outcome is rewritten by that work. + +`tools/public-tls-metadata.py` is an offline public-only step. After the source +owner supplies the **selected public certificate/chain and independent trust files**: + +```sh +python3 tools/public-tls-metadata.py --public-cert SELECTED_PUBLIC_CERT_CHAIN.pem --public-trust SELECTED_PUBLIC_TRUST.pem +``` + +It accepts no private-key argument, bounds regular-file reads, refuses symlinks and +non-certificate PEM material, and reports public hashes/SANs/validity/counts only. +The file names are owner-local placeholders, not a key request. Output establishes +public metadata, not originality, hostname/chain acceptance, reissue permission or +custody. Do not supply a Secret object or combined certificate/key PEM. Fail closed +when selected source, independent trust or exact attempt bindings are missing; +no fresh self-signed trust workaround is admitted. This utility does not require +historical ingress leaf/key bytes when a trusted renewed leaf is selected under +the existing reviewed attempt. + +For FUTURE NetKingdom archives, the source owners must explicitly disposition +original TLS coverage or a reviewed reissue contract: producer/custody owner, +private artifact boundary, offline recovery independence, original public hashes, +scoped capture/read permissions, retention and native verification. Merely adding +`kc-tls` to secret_refs would change capture/permission/custody scope and is not +authorized by this source review. It cannot repair the current archive retroactively. + +## Renewable TLS leaf and original OIDC signing identity + +The archived KeyCape RS256 signing key, issuer URL, service registrations and +policy state are distinct from the public HTTPS leaf and its TLS private key. +The current identity archive has no ingress TLS leaf to compare. A separately +reviewed trusted reissue can preserve kc.coulomb.social and the archived OIDC +signing identity without reproducing historical TLS leaf/key bytes. This is an +explicit owner continuity disposition under NK49-T35, not implicit permission +to replace custody, trust or an outage claim. + +The existing isolated admission pins the exact certificate-chain and trust PEM +bytes selected for that attempt; it does not compare them with an archived leaf +fingerprint. Those hashes, certificate/key pairing, hostname/CA/validity checks, +archived issuer equality and original signer/JWKS verification remain required. +The receipt's original HTTPS issuer/trust wording does not assert original leaf +byte equality. +Current source and public resource inventory establish a concrete standard path: +ClusterIssuer/letsencrypt-prod uses ACME HTTP-01 with Traefik. Upstream cmctl +create certificaterequest can generate a dedicated TLS key locally, send only a +public CSR to that existing issuer and return the signed certificate locally, +without reading or replacing sso/kc-tls. This creates a new public request and +normal temporary ACME resources and requires separate actual owner/founder +live authority. A Certificate YAML used as cmctl input is a local template, not +an apply of a Certificate or Secret. No issuance occurred in this source work. + +The reviewed candidate is cmctl v2.6.1 Linux amd64, published checksum +sha256:0af054c26a2b64ce286fa868d029164867695a93c3eb893662ce16f35e708db0, +source commit 7e56321dbec4f62ea5428b8656c871c6dc0cc112. It is not installed or +admitted by this document; signature-bundle verification remains unperformed. +Its key file is written before API submission, so protected tmpfs staging and +independent cleanup must precede invocation. T03 must admit the existing session +staging/reaper adaptation for that earlier networked child, with success, +refusal, timeout and parent-loss proof; a shell trap alone is insufficient. + +This is a supported candidate for a standalone drill while the cluster, DNS, +external HTTP-01 port 80, Traefik, cert-manager and ACME provider are available. +It proves no independence during cluster loss. Do not switch to DNS-01 or a new +provider, read an account key, delete the production Secret or call a surviving- +cluster reissue an independent cluster-loss recovery. T02/T03/T04 retain that +actual independent custody/provider/domain-control and native acceptance scope. + +Timestamped current public Certificate/issuer/controller/solver metadata, public +CA/hostname observation, source hashes, upstream contract and exact unexecuted +command/lifecycle proposal are retained in Custodian +`docs/changes/netkingdom-target-2026-10-17/tls-recovery-disposition-r1/`. +This source inventory is neither historical original-key custody nor owner +acceptance of reissue; T35 requires the explicit reviewed disposition before +T33 can bind the selected TLS material to an actual owner-held attempt. + +## Earlier private staging and exact public request cleanup + +T03 source preparation must register the original guard-compatible private0700 +/dev/shm directory and independently surviving pidfd/descendant reaper before +cmctl can write a key. Verify actual writable tmpfs/mount/device/inode before +use; the existing later session reaper is Docker-bound and is not already an +issuance guard. Preserve exact child quiescence and an immutable public checkpoint +before inode-guarded deletion. Reap dead adopted zombies; still refuse live or +unmapped descendants. A shell trap or immediate-child timeout is insufficient. + +Keep cmctl, TLS staging and the original six-argument local recovery launcher on +one admitted custody host. A workstation context name is not cluster identity; +bind the existing owner API profile to verified node92.205.62.239. Moving only +cmctl to another host would introduce a separate private-key transfer and is not +part of this source disposition. The existing T33/T35 native review binds the +actual host/tool/target; this paragraph creates no new TLS mode or policy gate. + +The source copies local template run labels/annotations to its CertificateRequest. +Record exact public request namespace/name, run/spec/CSR/public-key commitments, +admitted caller and actual UID. Cleanup uses the existing Kubernetes raw DELETE +idiom with DeleteOptions.preconditions.uid and Foreground propagation, then checks +that UID and its actual owner-UID descendants. Never delete by prefix/label/name +alone or touch production kc-tls. A killed client or one NotFound cannot prove +no late accepted Create; preserve the exact unresolved obligation and reconcile +through the owner API. Local plaintext cleanup and remote resource cleanup have +separate verified/uncertain outcomes, with no blind retry or false global success. + +The concrete T03 source delta, UID-delete contract and required generated lifecycle +counterexamples are in Custodian +`docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/`. +It is a source proposal, not implemented/native cleanup proof. Existing T02–T04 +and NK49T35/T33 gates/statuses remain unchanged; no new task or UUID is needed. + +The original disaster guide is already located in publication commit +31f483966cdfca4df1d326dee3ec0b6d33ea0e5e at Backup account path +`railiance-backups/net-kingdom-identity/net-kingdom-recovery-57d1940947aa25ff-START-HERE.md`. +Historical readback does not establish current remote visibility or ingress TLS +coverage. No renewed request for an unspecified original TLS backup is needed +to prepare this separate trusted-leaf path; genuine cluster-loss independence +and actual provider/domain-control/custody proof remain existing owner work. diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-doc.patch b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-doc.patch new file mode 100644 index 00000000..2a1e2a8f --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/owner-doc.patch @@ -0,0 +1,122 @@ +--- a/docs/keycape-tls-recovery-boundary.md ++++ b/docs/keycape-tls-recovery-boundary.md +@@ -29,10 +29,10 @@ + ciphertext or historical outcome is rewritten by that work. + + `tools/public-tls-metadata.py` is an offline public-only step. After the source +-owner identifies independent original **public certificate/chain and trust files**: ++owner supplies the **selected public certificate/chain and independent trust files**: + + ```sh +-python3 tools/public-tls-metadata.py --public-cert ORIGINAL_PUBLIC_CERT_CHAIN.pem --public-trust ORIGINAL_PUBLIC_TRUST.pem ++python3 tools/public-tls-metadata.py --public-cert SELECTED_PUBLIC_CERT_CHAIN.pem --public-trust SELECTED_PUBLIC_TRUST.pem + ``` + + It accepts no private-key argument, bounds regular-file reads, refuses symlinks and +@@ -40,8 +40,10 @@ + The file names are owner-local placeholders, not a key request. Output establishes + public metadata, not originality, hostname/chain acceptance, reissue permission or + custody. Do not supply a Secret object or combined certificate/key PEM. Fail closed +-when original source, trust or exact bindings are missing; no fresh self-signed +-trust workaround is admitted. ++when selected source, independent trust or exact attempt bindings are missing; ++no fresh self-signed trust workaround is admitted. This utility does not require ++historical ingress leaf/key bytes when a trusted renewed leaf is selected under ++the existing reviewed attempt. + + For FUTURE NetKingdom archives, the source owners must explicitly disposition + original TLS coverage or a reviewed reissue contract: producer/custody owner, +@@ -49,3 +51,93 @@ + scoped capture/read permissions, retention and native verification. Merely adding + `kc-tls` to secret_refs would change capture/permission/custody scope and is not + authorized by this source review. It cannot repair the current archive retroactively. ++ ++## Renewable TLS leaf and original OIDC signing identity ++ ++The archived KeyCape RS256 signing key, issuer URL, service registrations and ++policy state are distinct from the public HTTPS leaf and its TLS private key. ++The current identity archive has no ingress TLS leaf to compare. A separately ++reviewed trusted reissue can preserve kc.coulomb.social and the archived OIDC ++signing identity without reproducing historical TLS leaf/key bytes. This is an ++explicit owner continuity disposition under NK49-T35, not implicit permission ++to replace custody, trust or an outage claim. ++ ++The existing isolated admission pins the exact certificate-chain and trust PEM ++bytes selected for that attempt; it does not compare them with an archived leaf ++fingerprint. Those hashes, certificate/key pairing, hostname/CA/validity checks, ++archived issuer equality and original signer/JWKS verification remain required. ++The receipt's original HTTPS issuer/trust wording does not assert original leaf ++byte equality. ++Current source and public resource inventory establish a concrete standard path: ++ClusterIssuer/letsencrypt-prod uses ACME HTTP-01 with Traefik. Upstream cmctl ++create certificaterequest can generate a dedicated TLS key locally, send only a ++public CSR to that existing issuer and return the signed certificate locally, ++without reading or replacing sso/kc-tls. This creates a new public request and ++normal temporary ACME resources and requires separate actual owner/founder ++live authority. A Certificate YAML used as cmctl input is a local template, not ++an apply of a Certificate or Secret. No issuance occurred in this source work. ++ ++The reviewed candidate is cmctl v2.6.1 Linux amd64, published checksum ++sha256:0af054c26a2b64ce286fa868d029164867695a93c3eb893662ce16f35e708db0, ++source commit 7e56321dbec4f62ea5428b8656c871c6dc0cc112. It is not installed or ++admitted by this document; signature-bundle verification remains unperformed. ++Its key file is written before API submission, so protected tmpfs staging and ++independent cleanup must precede invocation. T03 must admit the existing session ++staging/reaper adaptation for that earlier networked child, with success, ++refusal, timeout and parent-loss proof; a shell trap alone is insufficient. ++ ++This is a supported candidate for a standalone drill while the cluster, DNS, ++external HTTP-01 port 80, Traefik, cert-manager and ACME provider are available. ++It proves no independence during cluster loss. Do not switch to DNS-01 or a new ++provider, read an account key, delete the production Secret or call a surviving- ++cluster reissue an independent cluster-loss recovery. T02/T03/T04 retain that ++actual independent custody/provider/domain-control and native acceptance scope. ++ ++Timestamped current public Certificate/issuer/controller/solver metadata, public ++CA/hostname observation, source hashes, upstream contract and exact unexecuted ++command/lifecycle proposal are retained in Custodian ++`docs/changes/netkingdom-target-2026-10-17/tls-recovery-disposition-r1/`. ++This source inventory is neither historical original-key custody nor owner ++acceptance of reissue; T35 requires the explicit reviewed disposition before ++T33 can bind the selected TLS material to an actual owner-held attempt. ++ ++## Earlier private staging and exact public request cleanup ++ ++T03 source preparation must register the original guard-compatible private0700 ++/dev/shm directory and independently surviving pidfd/descendant reaper before ++cmctl can write a key. Verify actual writable tmpfs/mount/device/inode before ++use; the existing later session reaper is Docker-bound and is not already an ++issuance guard. Preserve exact child quiescence and an immutable public checkpoint ++before inode-guarded deletion. Reap dead adopted zombies; still refuse live or ++unmapped descendants. A shell trap or immediate-child timeout is insufficient. ++ ++Keep cmctl, TLS staging and the original six-argument local recovery launcher on ++one admitted custody host. A workstation context name is not cluster identity; ++bind the existing owner API profile to verified node92.205.62.239. Moving only ++cmctl to another host would introduce a separate private-key transfer and is not ++part of this source disposition. The existing T33/T35 native review binds the ++actual host/tool/target; this paragraph creates no new TLS mode or policy gate. ++ ++The source copies local template run labels/annotations to its CertificateRequest. ++Record exact public request namespace/name, run/spec/CSR/public-key commitments, ++admitted caller and actual UID. Cleanup uses the existing Kubernetes raw DELETE ++idiom with DeleteOptions.preconditions.uid and Foreground propagation, then checks ++that UID and its actual owner-UID descendants. Never delete by prefix/label/name ++alone or touch production kc-tls. A killed client or one NotFound cannot prove ++no late accepted Create; preserve the exact unresolved obligation and reconcile ++through the owner API. Local plaintext cleanup and remote resource cleanup have ++separate verified/uncertain outcomes, with no blind retry or false global success. ++ ++The concrete T03 source delta, UID-delete contract and required generated lifecycle ++counterexamples are in Custodian ++`docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/`. ++It is a source proposal, not implemented/native cleanup proof. Existing T02–T04 ++and NK49T35/T33 gates/statuses remain unchanged; no new task or UUID is needed. ++ ++The original disaster guide is already located in publication commit ++31f483966cdfca4df1d326dee3ec0b6d33ea0e5e at Backup account path ++`railiance-backups/net-kingdom-identity/net-kingdom-recovery-57d1940947aa25ff-START-HERE.md`. ++Historical readback does not establish current remote visibility or ingress TLS ++coverage. No renewed request for an unspecified original TLS backup is needed ++to prepare this separate trusted-leaf path; genuine cluster-loss independence ++and actual provider/domain-control/custody proof remain existing owner work. diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/review.json b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/review.json new file mode 100644 index 00000000..cd4c6d02 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/review.json @@ -0,0 +1,28 @@ +{ + "status": "exact source delta ready for owner review; no staging implementation or native proof claimed", + "canonical_source_edits": false, + "runtime_private_or_cluster_calls": 0, + "native_certificate_request_download_install_or_credential_reads": false, + "redundant_tls_mode_or_policy_gate_added": false, + "original_archive_oidc_signing_key_and_issuer_invariants_preserved": true, + "source_only_publication_recommendation": "One existing Cluster boundary doc can be reviewed/published now after actual source-owner review; captured preimage/postimage/patch only. No WP status/UUID/T06 addition needed.", + "concrete_gaps": [ + "pre-key actual rw tmpfs registration and observer acknowledgment", + "Docker-specific existing reaper cannot supervise earlier networked CSR child; exact descendant adoption/parent-loss cleanup needed", + "cmctl output-file writes require protected absent-name boundary", + "CertificateRequest lost-create response / exact run-SPKI-spec-caller UID ownership / Foreground delete and actual descendant cleanup", + "one admitted custody host and bound API target; no invented private-key transfer", + "preserve original attended TTY / hidden prompt / sealed-fd launcher contract, not DEVNULL wrapper" + ], + "actual_native_cause_limit": "source and prior local process fixture evidence only; no native TLS issuance/recovery cause diagnosed", + "cluster_loss_limit": "existing surviving-cluster HTTP01 route unavailable during cluster loss; independent custody/provider/domain-control remains existing T02\u2013T04 work", + "guide_source_located": { + "commit": "31f483966cdfca4df1d326dee3ec0b6d33ea0e5e", + "path": "Backup/railiance-backups/net-kingdom-identity/net-kingdom-recovery-57d1940947aa25ff-START-HERE.md", + "remote_reread": false, + "another_original_tls_backup_request": false + }, + "tests": "No new permanent or dummy tests; exact generated lifecycle/TTY/UID-negative proof is an explicit T03 implementation deliverable, not claimed here.", + "next_owner_source_scope": "existing T03 bounded issuance custody adapter using existing NetKingdom inode cleanup and owner Kubernetes UID-delete idiom; original T33 launcher interface unchanged", + "authority": "fresh actual owner/founder approval remains required for any native issuance/action; this packet grants none" +} diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/source-pins.json b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/source-pins.json new file mode 100644 index 00000000..b443a1a6 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/source-pins.json @@ -0,0 +1,62 @@ +{ + "observed_at": "2026-10-17T10:47:12.320878+00:00", + "references": [ + { + "path": "/home/worsch/net-kingdom/AGENTS.md", + "sha256": "sha256:95158b1d5c15e6cf8be980f5c0e3b48aeef252654846273887f40516b3fa6a78" + }, + { + "path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/isolated-keycape-session.py", + "sha256": "sha256:8fa38efe28167b59a6307f342b2ac8fcda78ecda60e6228f22017424d2343c22" + }, + { + "path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/isolated-keycape.py", + "sha256": "sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718" + }, + { + "path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/prepare-isolated-keycape.py", + "sha256": "sha256:5098bdfa4e0ad30627c1716e5e355a2c78dca6ccc607bd2148a2e06126632288" + }, + { + "path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/run-isolated-keycape.sh", + "sha256": "sha256:0d994c9c14ebdffdbf7879bd7562042531083d0e8955424d0ae099898a141668" + }, + { + "path": "/home/worsch/net-kingdom/tools/bootstrap-recovery/capture-identity.py", + "sha256": "sha256:47dca7c4dc96fa7eb9fb02c81fca9ca8dc5281aac918979eb7367148168ba705" + }, + { + "path": "/home/worsch/railiance-platform/scripts/native_factory_acceptance.py", + "sha256": "sha256:291646308a2a749f858638f9f4fa0db33cf545e8b4a0c09c30e884a7be8e4bc0" + }, + { + "path": "/home/worsch/railiance-cluster/AGENTS.md", + "sha256": "sha256:5cc7808a6d0e5cdebc7b3f13a0d7dce9cee5441ed6de4703b67cf3fe1800d45b" + }, + { + "path": "/home/worsch/railiance-cluster/docs/keycape-tls-recovery-boundary.md", + "sha256": "sha256:f4bcb1d1832c566f9c87793ed2a461c8cd8a00859dc4ae66cd3c160d7ceefa70" + }, + { + "path": "/home/worsch/railiance-cluster/workplans/RCLUSTER-WP-0018-keycape-original-tls-recovery.md", + "sha256": "sha256:96d52b6dbae056399159632d50b32ccc6662e4f6d3677af154f7c8a3d618334b" + }, + { + "path": "/home/worsch/the-custodian/docs/agent-environment-orientation.md", + "sha256": "sha256:6eb712593adaeb2efd8c69edb22b02662e6c9b155f84f1559e7bdaeb76730439" + }, + { + "path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/storage-share-tls-r1/source-history-followthrough-r2.json", + "sha256": "sha256:51a6cf3547f0b9aac1620c472c933bd3eb7213200d78397bf8d851ea4f3f861a" + }, + { + "path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-runtime-install-r3/local-fixture-results.json", + "sha256": "sha256:339b2fcfd8d407e09874592b681830c605a463a88841351eed494a182d677219" + } + ], + "upstream_cmctl_source_url": "https://raw.githubusercontent.com/cert-manager/cmctl/7e56321dbec4f62ea5428b8656c871c6dc0cc112/pkg/create/certificaterequest/certificaterequest.go", + "public_source_sha256": "sha256:0ba0c2d3d4f8530514c8d864b2a9e056f14f763a0b314aa05998f3169ee5bc32", + "matches_frozen_upstream_pin": true, + "tls_r1_all_frozen_entries_unchanged": true, + "owner_boundary_canonical_equals_preimage": true +} diff --git a/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/staging-reaper-contract.json b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/staging-reaper-contract.json new file mode 100644 index 00000000..5f0288bc --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/tls-staging-cleanup-r1/staging-reaper-contract.json @@ -0,0 +1,71 @@ +{ + "schema": "custodian.tls-staging-reaper-source-boundary.v1", + "status": "owner source proposal; no implementation/native lifecycle proof claimed", + "existing_tasks": [ + "RCLUSTER-WP-0018-T03", + "NK-WP-0049-T35", + "NK-WP-0049-T33" + ], + "execution_locus": "one admitted host for cmctl/tmpfs/original launcher; exact host/account/tool/API profile unresolved, no private transfer assumed", + "staging": { + "root": "/dev/shm", + "name_pattern": "nk49-keycape-{run_uuid}-{eight_random_chars}", + "mode": "0700", + "key_mode": "0600", + "mount_checks_before_key": [ + "actual writable tmpfs", + "mount ID/device and owner UID bound", + "no parent alias/replacement", + "bounded free space" + ], + "file_rules": "absent output names; regular owner-only single-link; 1MiB per-file child RLIMIT_FSIZE; disable core dumps before private output", + "read_limit_bytes": 1048576, + "receipt": "bounded immutable public-only metadata checkpoint before private cleanup; no private material" + }, + "states": [ + "public_source_and_owner_target_bound", + "tmpfs_inode_registered", + "observer_acknowledged", + "submit_intent_durable", + "cmctl_started", + "request_uid_observed_or_submit_uncertain", + "certificate_verified_or_failed", + "original_launcher_consumed_or_not_started", + "exact_local_children_quiescent", + "public_commitments_and_outstanding_duties_durable", + "registered_private_inode_removed_or_cleanup_unverified", + "request_and_owned_children_absent_or_remote_cleanup_uncertain" + ], + "absolute_bounds_seconds": { + "issuance_total_from_private_staging_start": 330, + "cmctl_fetch_flag": 300, + "existing_recovery_child_maximum": 1800, + "single_private_execution_deadline": 2130, + "nonrenewable_cleanup_maximum": 60, + "total_including_cleanup": 2190, + "term_grace": 0.5, + "kill_reap": 3, + "watchdog_wait_maximum": 8, + "api_request_maximum_clipped_to_cleanup_remaining": 30 + }, + "deadline_rules": [ + "one original monotonic private execution budget, no renewal across phases", + "no new child after deadline", + "subreaper stops and waits exact trees before local delete", + "cleanup operations clipped to same original 60s cleanup remainder; outstanding remote duties survive timeout", + "existing original launcher reaper and Docker obligations remain separately receipt-bound" + ], + "readiness": "no observer ack means zero cmctl/key generation", + "creation_uncertainty": "kill/client timeout does not cancel accepted API mutation; preserve pending creation obligation if UID not durably reconciled", + "authority": "existing T33/T35/RCLUSTER18 source/native owner process; no new TLS mode or approval field", + "observed_local_sandbox_tmpfs": "/dev/shm actual mount is ro,nosuid,nodev,noatime; no usable local private staging or tmpfs proof asserted", + "limitations": [ + "local tmpfs does not establish unswappable memory, root/hypervisor isolation or host-loss receipts", + "surviving-cluster HTTP01 path only; independent cluster-loss recovery remains open" + ], + "child_io": { + "cmctl": "stdin/stdout/stderr DEVNULL; no custody fd", + "original_launcher": "existing attended TTY path preserved; original hidden prompt/sealed fd; no PTY proxy/logging", + "observer": "pidfds and public metadata only; close unrelated/secret fds" + } +} diff --git a/docs/changes/netkingdom-target-2026-10-17/verified-client-cluster-consistency.stderr.txt b/docs/changes/netkingdom-target-2026-10-17/verified-client-cluster-consistency.stderr.txt new file mode 100644 index 00000000..3345563f --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/verified-client-cluster-consistency.stderr.txt @@ -0,0 +1 @@ +WARN: git commit failed for writeback: Generated-only commits rejected: staged diff --git a/docs/changes/netkingdom-target-2026-10-17/verified-client-cluster-projection.stderr.txt b/docs/changes/netkingdom-target-2026-10-17/verified-client-cluster-projection.stderr.txt new file mode 100644 index 00000000..e69de29b diff --git a/docs/changes/netkingdom-target-2026-10-17/verify_current_rows_at_close.py b/docs/changes/netkingdom-target-2026-10-17/verify_current_rows_at_close.py new file mode 100644 index 00000000..b6d74a65 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/verify_current_rows_at_close.py @@ -0,0 +1,34 @@ +"""Read-only fresh comparison against the retained verified-client baseline.""" +from pathlib import Path +import hashlib +import json +import shlex +import subprocess + +BASE = Path(__file__).resolve().parent +RECEIVER = BASE / 'receiver-rollout-r4' +pod = json.loads((RECEIVER / 'delivered-runtime.json').read_text())['api_pod'] + +def owner(args, content=None): + r = subprocess.run(['ssh', 'railiance01', + 'KUBECONFIG=/etc/rancher/k3s/k3s.yaml ' + shlex.join(args)], + input=content, capture_output=True, text=True, timeout=45) + assert r.returncode == 0, 'private-owner-read-refused' + return json.loads(r.stdout) + +actual = owner(['kubectl', '-n', 'state-hub', 'get', 'pod', pod['name'], '-o', 'json']) +assert actual['metadata']['uid'] == pod['uid'] +helper = BASE.parent / 'netkingdom-target-2026-10-16/cluster-historical-publication-r1/postdeployment-verifier-r1/snapshot_full_row_hashes.py' +assert hashlib.sha256(helper.read_bytes()).hexdigest() == 'f01e93c0fcb4ca155bdf76813626c33e4343f6a8caec2870ab1d785243c60479' +result = owner(['kubectl', '-n', 'state-hub', 'exec', '-i', pod['name'], '-c', 'state-hub', '--', 'python', '-'], helper.read_text()) +assert result['status'] == 'captured_readonly' +baseline = json.loads((RECEIVER / 'after-verified-client.json').read_text()) +original = json.loads((RECEIVER / 'before-full-row-hashes.json').read_text()) +result.update(current_verified_baseline_equal=result['tables'] == baseline['tables'], + original_rows_equal=result['tables'] == original['tables'], + original_failed_comparison_retained=True, original_preimages_restored=False) +(BASE / 'rollout-close-current-full-row-hashes.json').write_text(json.dumps(result, indent=2) + '\n') +assert result['current_verified_baseline_equal'] +print(json.dumps({'status': 'verified-current-baseline', 'historical_rows': 18, + 'original_failed_comparison_retained': True, + 'original_preimages_restored': False})) diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/WORK-RECORDS.md.backup b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/WORK-RECORDS.md.backup new file mode 100644 index 00000000..8b5226ae --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/WORK-RECORDS.md.backup @@ -0,0 +1,188 @@ +# Work Records — ops-warden + +> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record +> stage 3). Do not edit by hand — edit the source file/block listed for +> each record and re-run fix-consistency to refresh this index. Archived +> workplans are omitted; closed decisions/intakes/engagements stay listed +> so recently-resolved work is still visible. [auto] + +| Kind | ID | Status | Lane | Source | +| --- | --- | --- | --- | --- | +| workplan | WARDEN-WP-ADHOC-2026-06-27 | finished | — | workplans/ADHOC-2026-06-27.md | +| workplan | WARDEN-WP-ADHOC-2026-06-29 | finished | — | workplans/ADHOC-2026-06-29.md | +| workplan | WARDEN-WP-ADHOC-2026-08-11 | finished | — | workplans/ADHOC-2026-08-11.md | +| workplan | WARDEN-WP-ADHOC-2026-08-17 | finished | — | workplans/ADHOC-2026-08-17.md | +| workplan | WARDEN-WP-ADHOC-2026-09-08 | finished | — | workplans/ADHOC-2026-09-08.md | +| workplan | WARDEN-WP-ADHOC-2026-10-03 | finished | — | workplans/ADHOC-2026-10-03.md | +| workplan | WARDEN-WP-0016 | finished | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| workplan | WARDEN-WP-0017 | finished | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md | +| workplan | WARDEN-WP-0018 | finished | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md | +| workplan | WARDEN-WP-0019 | finished | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md | +| workplan | WARDEN-WP-0020 | finished | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| workplan | WARDEN-WP-0021 | finished | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| workplan | WARDEN-WP-0022 | finished | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| workplan | WARDEN-WP-0023 | finished | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| workplan | WARDEN-WP-0024 | finished | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| workplan | WARDEN-WP-0025 | finished | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| workplan | WARDEN-WP-0026 | finished | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| workplan | WARDEN-WP-0027 | blocked | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md | +| workplan | WARDEN-WP-0028 | finished | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| workplan | WARDEN-WP-0029 | finished | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| workplan | WARDEN-WP-0030 | finished | — | workplans/WARDEN-WP-0030-delegation-register.md | +| workplan | WARDEN-WP-0031 | finished | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| workplan | WARDEN-WP-0032 | finished | — | workplans/WARDEN-WP-0032-security-zones.md | +| workplan | WARDEN-WP-0033 | finished | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| workplan | WARDEN-WP-0034 | active | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| workplan | WARDEN-WP-0035 | finished | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md | +| workplan | WARDEN-WP-0036 | finished | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md | +| workplan | WARDEN-WP-0037 | blocked | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md | +| workplan | WARDEN-WP-0038 | finished | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md | +| workplan | WARDEN-WP-0039 | finished | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md | +| workplan | WARDEN-WP-0040 | active | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| workplan | WARDEN-WP-0041 | finished | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| workplan | WARDEN-WP-0042 | finished | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md | +| workplan | WARDEN-WP-0043 | finished | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md | +| workplan | WARDEN-WP-0044 | active | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| task | WARDEN-WP-ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md | +| task | WARDEN-WP-ADHOC-2026-06-29-T01 | done | — | workplans/ADHOC-2026-06-29.md | +| task | WARDEN-WP-ADHOC-2026-08-11-T01 | done | — | workplans/ADHOC-2026-08-11.md | +| task | WARDEN-WP-ADHOC-2026-08-11-T02 | done | — | workplans/ADHOC-2026-08-11.md | +| task | WARDEN-WP-ADHOC-2026-08-11-T03 | done | — | workplans/ADHOC-2026-08-11.md | +| task | WARDEN-WP-ADHOC-2026-08-17-T01 | done | — | workplans/ADHOC-2026-08-17.md | +| task | WARDEN-WP-ADHOC-2026-08-17-T02 | done | — | workplans/ADHOC-2026-08-17.md | +| task | WARDEN-WP-ADHOC-2026-08-17-T03 | done | — | workplans/ADHOC-2026-08-17.md | +| task | WARDEN-WP-ADHOC-2026-08-17-T04 | done | — | workplans/ADHOC-2026-08-17.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T01 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T02 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T03 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T04 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T05 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T06 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-10-03-T01 | done | — | workplans/ADHOC-2026-10-03.md | +| task | WARDEN-WP-0016-T01 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| task | WARDEN-WP-0016-T02 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| task | WARDEN-WP-0016-T03 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| task | WARDEN-WP-0016-T04 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| task | WARDEN-WP-0017-T01 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md | +| task | WARDEN-WP-0017-T02 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md | +| task | WARDEN-WP-0017-T03 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md | +| task | WARDEN-WP-0018-T01 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md | +| task | WARDEN-WP-0018-T02 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md | +| task | WARDEN-WP-0018-T03 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md | +| task | WARDEN-WP-0019-T01 | done | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md | +| task | WARDEN-WP-0019-T02 | done | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md | +| task | WARDEN-WP-0020-T01 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0020-T02 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0020-T03 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0020-T04 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0020-T05 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0021-T01 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0021-T02 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0021-T03 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0021-T04 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0021-T05 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0022-T01 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| task | WARDEN-WP-0022-T02 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| task | WARDEN-WP-0022-T03 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| task | WARDEN-WP-0022-T04 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| task | WARDEN-WP-0023-T01 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T02 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T03 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T04 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T05 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T06 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T07 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0024-T01 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T02 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T03 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T04 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T05 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T06 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T07 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0025-T01 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0025-T02 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0025-T03 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0025-T04 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0025-T05 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0026-T01 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T02 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T03 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T04 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T05 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T06 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T07 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0027-T01 | cancel | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md | +| task | WARDEN-WP-0027-T02 | todo | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md | +| task | WARDEN-WP-0027-T03 | cancel | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md | +| task | WARDEN-WP-0028-T01 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T02 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T03 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T04 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T05 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T06 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T07 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0029-T01 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0029-T02 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0029-T03 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0029-T04 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0029-T05 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0030-T01 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0030-T02 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0030-T03 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0030-T04 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0030-T05 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0031-T01 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0031-T02 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0031-T03 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0031-T04 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0031-T05 | cancel | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0032-T01 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T02 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T03 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T04 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T05 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T06 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T07 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0033-T01 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T02 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T03 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T04 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T05 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T06 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0034-T01 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T02 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T03 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T04 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T05 | wait | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T06 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0035-T01 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md | +| task | WARDEN-WP-0035-T02 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md | +| task | WARDEN-WP-0036-T01 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md | +| task | WARDEN-WP-0036-T02 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md | +| task | WARDEN-WP-0037-T01 | done | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md | +| task | WARDEN-WP-0037-T02 | done | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md | +| task | WARDEN-WP-0037-T03 | wait | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md | +| task | WARDEN-WP-0038-T01 | done | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md | +| task | WARDEN-WP-0039-T01 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md | +| task | WARDEN-WP-0039-T02 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md | +| task | WARDEN-WP-0039-T03 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md | +| task | WARDEN-WP-0040-T01 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| task | WARDEN-WP-0040-T02 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| task | WARDEN-WP-0040-T03 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| task | WARDEN-WP-0040-T04 | done | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| task | WARDEN-WP-0041-T01 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| task | WARDEN-WP-0041-T02 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| task | WARDEN-WP-0041-T03 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| task | WARDEN-WP-0041-T04 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| task | WARDEN-WP-0042-T01 | done | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md | +| task | WARDEN-WP-0042-T02 | done | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md | +| task | WARDEN-WP-0043-T01 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md | +| task | WARDEN-WP-0043-T02 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md | +| task | WARDEN-WP-0043-T03 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md | +| task | WARDEN-WP-0044-T01 | done | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| task | WARDEN-WP-0044-T02 | done | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| task | WARDEN-WP-0044-T03 | progress | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| task | WARDEN-WP-0044-T04 | wait | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| intake | WARDEN-IN-0001 | closed | — | intakes/intakes.md | +| intake | WARDEN-IN-0002 | closed | — | intakes/intakes.md | +| intake | WARDEN-IN-0003 | closed | — | intakes/intakes.md | diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/.custodian-brief.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/.custodian-brief.md new file mode 100644 index 00000000..34573d26 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/.custodian-brief.md @@ -0,0 +1,60 @@ + +# Custodian Brief — ops-warden + +**Domain:** infotech +**Last synced:** 2026-10-16 00:05 UTC +**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)* + +## Active Workstreams + +### Adopt unknown -> fail_closed behind signing-target classification coverage +Progress: 1/4 done | workplan_id: `c8ee441e-1be1-5219-910c-e79ff23cc9ec` + +**Open tasks:** +- ! Tasks `611f0901` + *(wait: Warden's own declaration cannot classify the repair-path target workloads; the owner must declare the continuity actor/target and its z2-continuity resolution (see 2026-09-28 review).)* +- ! Tasks `54ad4864` + *(wait: Owners of agt-codex-interhub-bootstrap (ops-hub) and agt-state-hub-bridge (ops-bridge) must publish authoritative workload identity declarations; atm-backup-daily declared by activity-core and compiled 2026-10-09 (z2-protected, admission unsatisfied: M1 below M2 floor).)* +- ! Tasks `93eaf1f2` + *(wait: Gated on T01 and on layer model v0.8 (or successor) reaching accepted; never convert against a proposed standard.)* + +### Layer model v0.7 conformance — state the deadline, bind the agent boundary, steward the estate's newest rule +Progress: 5/6 done | workplan_id: `ae3ff76f-883d-5e2f-b6aa-144d61e8fdef` + +**Open tasks:** +- ! Tasks `7d1b3c82` + *(wait: Two items to route, not absorb: ops-mason has published no stance map; the second is another repository's to own.)* + +### Follow through on KnownSecurityCases along their type's route +Progress: 2/4 done | workplan_id: `f7e81013-6868-5d99-8528-ba75a442eca9` + +**Open tasks:** +- ! T03 — Run and verify a case `4a0fa4a7` + *(wait: Catalog integration follows a proven run.)* +- ► T02 — Plan a case run `bcbf6c91` + +### Tamper-resistant credential governance + mass rotation/lockdown (Strand B) +Progress: 2/3 done | workplan_id: `21528e8d-a049-523d-9ae1-da7a27cb8bbf` + +**Open tasks:** +- · Task: Graded lockdown / break-glass with explicit trust-root `cae498ee` + +### Repoint the whynot-design npm lane to Forgejo +Progress: 2/3 done | workplan_id: `42a097db-1c24-558e-a724-030bb2b4443e` + +**Open tasks:** +- ! Prove routing and publication `a8b1b855` + *(wait: 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.)* + +## Inbox Hygiene + +**Stale unread:** 2 message(s) older than 3 day(s) — triage at session start. +**Missing thread_id:** 3 unread message(s) lack supersession chains. + +--- +## MCP Orientation (when available) + +If the state-hub MCP server is reachable, call: +`get_domain_summary("infotech")` +This provides richer cross-domain context. +If the MCP call fails, use this file as your orientation source. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/WORK-RECORDS.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/WORK-RECORDS.md new file mode 100644 index 00000000..8b5226ae --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/WORK-RECORDS.md @@ -0,0 +1,188 @@ +# Work Records — ops-warden + +> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record +> stage 3). Do not edit by hand — edit the source file/block listed for +> each record and re-run fix-consistency to refresh this index. Archived +> workplans are omitted; closed decisions/intakes/engagements stay listed +> so recently-resolved work is still visible. [auto] + +| Kind | ID | Status | Lane | Source | +| --- | --- | --- | --- | --- | +| workplan | WARDEN-WP-ADHOC-2026-06-27 | finished | — | workplans/ADHOC-2026-06-27.md | +| workplan | WARDEN-WP-ADHOC-2026-06-29 | finished | — | workplans/ADHOC-2026-06-29.md | +| workplan | WARDEN-WP-ADHOC-2026-08-11 | finished | — | workplans/ADHOC-2026-08-11.md | +| workplan | WARDEN-WP-ADHOC-2026-08-17 | finished | — | workplans/ADHOC-2026-08-17.md | +| workplan | WARDEN-WP-ADHOC-2026-09-08 | finished | — | workplans/ADHOC-2026-09-08.md | +| workplan | WARDEN-WP-ADHOC-2026-10-03 | finished | — | workplans/ADHOC-2026-10-03.md | +| workplan | WARDEN-WP-0016 | finished | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| workplan | WARDEN-WP-0017 | finished | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md | +| workplan | WARDEN-WP-0018 | finished | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md | +| workplan | WARDEN-WP-0019 | finished | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md | +| workplan | WARDEN-WP-0020 | finished | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| workplan | WARDEN-WP-0021 | finished | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| workplan | WARDEN-WP-0022 | finished | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| workplan | WARDEN-WP-0023 | finished | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| workplan | WARDEN-WP-0024 | finished | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| workplan | WARDEN-WP-0025 | finished | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| workplan | WARDEN-WP-0026 | finished | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| workplan | WARDEN-WP-0027 | blocked | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md | +| workplan | WARDEN-WP-0028 | finished | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| workplan | WARDEN-WP-0029 | finished | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| workplan | WARDEN-WP-0030 | finished | — | workplans/WARDEN-WP-0030-delegation-register.md | +| workplan | WARDEN-WP-0031 | finished | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| workplan | WARDEN-WP-0032 | finished | — | workplans/WARDEN-WP-0032-security-zones.md | +| workplan | WARDEN-WP-0033 | finished | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| workplan | WARDEN-WP-0034 | active | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| workplan | WARDEN-WP-0035 | finished | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md | +| workplan | WARDEN-WP-0036 | finished | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md | +| workplan | WARDEN-WP-0037 | blocked | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md | +| workplan | WARDEN-WP-0038 | finished | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md | +| workplan | WARDEN-WP-0039 | finished | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md | +| workplan | WARDEN-WP-0040 | active | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| workplan | WARDEN-WP-0041 | finished | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| workplan | WARDEN-WP-0042 | finished | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md | +| workplan | WARDEN-WP-0043 | finished | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md | +| workplan | WARDEN-WP-0044 | active | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| task | WARDEN-WP-ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md | +| task | WARDEN-WP-ADHOC-2026-06-29-T01 | done | — | workplans/ADHOC-2026-06-29.md | +| task | WARDEN-WP-ADHOC-2026-08-11-T01 | done | — | workplans/ADHOC-2026-08-11.md | +| task | WARDEN-WP-ADHOC-2026-08-11-T02 | done | — | workplans/ADHOC-2026-08-11.md | +| task | WARDEN-WP-ADHOC-2026-08-11-T03 | done | — | workplans/ADHOC-2026-08-11.md | +| task | WARDEN-WP-ADHOC-2026-08-17-T01 | done | — | workplans/ADHOC-2026-08-17.md | +| task | WARDEN-WP-ADHOC-2026-08-17-T02 | done | — | workplans/ADHOC-2026-08-17.md | +| task | WARDEN-WP-ADHOC-2026-08-17-T03 | done | — | workplans/ADHOC-2026-08-17.md | +| task | WARDEN-WP-ADHOC-2026-08-17-T04 | done | — | workplans/ADHOC-2026-08-17.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T01 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T02 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T03 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T04 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T05 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-09-08-T06 | done | — | workplans/ADHOC-2026-09-08.md | +| task | WARDEN-WP-ADHOC-2026-10-03-T01 | done | — | workplans/ADHOC-2026-10-03.md | +| task | WARDEN-WP-0016-T01 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| task | WARDEN-WP-0016-T02 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| task | WARDEN-WP-0016-T03 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| task | WARDEN-WP-0016-T04 | done | — | workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md | +| task | WARDEN-WP-0017-T01 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md | +| task | WARDEN-WP-0017-T02 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md | +| task | WARDEN-WP-0017-T03 | done | — | workplans/WARDEN-WP-0017-access-front-door-discoverability.md | +| task | WARDEN-WP-0018-T01 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md | +| task | WARDEN-WP-0018-T02 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md | +| task | WARDEN-WP-0018-T03 | done | — | workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md | +| task | WARDEN-WP-0019-T01 | done | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md | +| task | WARDEN-WP-0019-T02 | done | — | workplans/WARDEN-WP-0019-route-to-secrets-engine.md | +| task | WARDEN-WP-0020-T01 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0020-T02 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0020-T03 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0020-T04 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0020-T05 | done | — | workplans/WARDEN-WP-0020-ops-warden-worker.md | +| task | WARDEN-WP-0021-T01 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0021-T02 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0021-T03 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0021-T04 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0021-T05 | done | — | workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md | +| task | WARDEN-WP-0022-T01 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| task | WARDEN-WP-0022-T02 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| task | WARDEN-WP-0022-T03 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| task | WARDEN-WP-0022-T04 | done | — | workplans/WARDEN-WP-0022-audit-trail-and-activity.md | +| task | WARDEN-WP-0023-T01 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T02 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T03 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T04 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T05 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T06 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0023-T07 | done | — | workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md | +| task | WARDEN-WP-0024-T01 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T02 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T03 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T04 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T05 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T06 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0024-T07 | done | — | workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md | +| task | WARDEN-WP-0025-T01 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0025-T02 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0025-T03 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0025-T04 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0025-T05 | done | — | workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md | +| task | WARDEN-WP-0026-T01 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T02 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T03 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T04 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T05 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T06 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0026-T07 | done | — | workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md | +| task | WARDEN-WP-0027-T01 | cancel | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md | +| task | WARDEN-WP-0027-T02 | todo | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md | +| task | WARDEN-WP-0027-T03 | cancel | — | workplans/WARDEN-WP-0027-credential-governance-lockdown.md | +| task | WARDEN-WP-0028-T01 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T02 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T03 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T04 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T05 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T06 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0028-T07 | done | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | +| task | WARDEN-WP-0029-T01 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0029-T02 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0029-T03 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0029-T04 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0029-T05 | done | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | +| task | WARDEN-WP-0030-T01 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0030-T02 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0030-T03 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0030-T04 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0030-T05 | done | — | workplans/WARDEN-WP-0030-delegation-register.md | +| task | WARDEN-WP-0031-T01 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0031-T02 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0031-T03 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0031-T04 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0031-T05 | cancel | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0032-T01 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T02 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T03 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T04 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T05 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T06 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T07 | done | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0033-T01 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T02 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T03 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T04 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T05 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0033-T06 | done | — | workplans/WARDEN-WP-0033-native-lane-handoff.md | +| task | WARDEN-WP-0034-T01 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T02 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T03 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T04 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T05 | wait | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0034-T06 | done | — | workplans/WARDEN-WP-0034-layer-model-v07-conformance.md | +| task | WARDEN-WP-0035-T01 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md | +| task | WARDEN-WP-0035-T02 | done | — | workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md | +| task | WARDEN-WP-0036-T01 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md | +| task | WARDEN-WP-0036-T02 | done | — | workplans/WARDEN-WP-0036-attended-login-openbao-output.md | +| task | WARDEN-WP-0037-T01 | done | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md | +| task | WARDEN-WP-0037-T02 | done | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md | +| task | WARDEN-WP-0037-T03 | wait | — | workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md | +| task | WARDEN-WP-0038-T01 | done | — | workplans/WARDEN-WP-0038-plan-mutation-intent.md | +| task | WARDEN-WP-0039-T01 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md | +| task | WARDEN-WP-0039-T02 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md | +| task | WARDEN-WP-0039-T03 | done | — | workplans/WARDEN-WP-0039-explicit-policy-refusal.md | +| task | WARDEN-WP-0040-T01 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| task | WARDEN-WP-0040-T02 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| task | WARDEN-WP-0040-T03 | wait | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| task | WARDEN-WP-0040-T04 | done | — | workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md | +| task | WARDEN-WP-0041-T01 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| task | WARDEN-WP-0041-T02 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| task | WARDEN-WP-0041-T03 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| task | WARDEN-WP-0041-T04 | done | — | workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md | +| task | WARDEN-WP-0042-T01 | done | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md | +| task | WARDEN-WP-0042-T02 | done | — | workplans/WARDEN-WP-0042-openbao-structure-survey-route.md | +| task | WARDEN-WP-0043-T01 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md | +| task | WARDEN-WP-0043-T02 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md | +| task | WARDEN-WP-0043-T03 | done | — | workplans/WARDEN-WP-0043-platform-supplier-credentials.md | +| task | WARDEN-WP-0044-T01 | done | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| task | WARDEN-WP-0044-T02 | done | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| task | WARDEN-WP-0044-T03 | progress | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| task | WARDEN-WP-0044-T04 | wait | — | workplans/WARDEN-WP-0044-security-case-follow-through.md | +| intake | WARDEN-IN-0001 | closed | — | intakes/intakes.md | +| intake | WARDEN-IN-0002 | closed | — | intakes/intakes.md | +| intake | WARDEN-IN-0003 | closed | — | intakes/intakes.md | diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-06-27.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-06-27.md new file mode 100644 index 00000000..d75908fb --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-06-27.md @@ -0,0 +1,41 @@ +--- +id: WARDEN-WP-ADHOC-2026-06-27 +type: workplan +title: "Ad Hoc Tasks — 2026-06-27" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +created: "2026-06-27" +updated: "2026-06-27" +state_hub_workstream_id: "a222c91f-3bb5-58a4-b6b2-f0fb18cdd5c3" +--- + +# Ad Hoc Tasks — 2026-06-27 + +Low-risk opportunistic fixes completed directly during the consolidation session. + +### T01 — Fix stale `warden` CLI install + make it usable outside the repo + +```task +id: WARDEN-WP-ADHOC-2026-06-27-T01 +status: done +priority: medium +state_hub_task_id: "9176b560-8ca5-5143-888d-479857fe60f0" +``` + +issue-core reported (msg `70bcf238`) that the `warden` CLI on `~/.local/bin` lacked +the `route` subcommand, forcing a `uv run warden` fallback. + +- [x] Root cause: `uv tool install` had reused a **cached wheel** (version stayed + `0.1.0`), so the installed `warden.cli` predated the `route`/`access`/`policy` + subcommands. `uv cache clean ops-warden` + `uv tool install . --reinstall` fixed it. +- [x] Deeper cause: even rebuilt, `warden route`/`policy` failed outside a checkout + because the catalog + posture descriptors live in `registry/` at repo root, + outside the package. Bundled `registry/` into the wheel via hatch + `force-include` → `warden/_registry`, and added a packaged-data fallback in + `find_catalog_path` / `find_posture_path` (after the repo walk, so source runs + still prefer the repo's `registry/` as the single source of truth). +- [x] Verified `warden route list` / `warden policy list` work from `/tmp`; 200 tests + pass, lint clean. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-06-29.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-06-29.md new file mode 100644 index 00000000..b46be0fd --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-06-29.md @@ -0,0 +1,40 @@ +--- +id: WARDEN-WP-ADHOC-2026-06-29 +type: workplan +title: "Ad Hoc Tasks — 2026-06-29" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +created: "2026-06-29" +updated: "2026-06-29" +state_hub_workstream_id: "13fa845f-852e-55ec-a2a5-2296996e0216" +--- + +# Ad Hoc Tasks — 2026-06-29 + +### T01 — Joint-smoke mode for the deployed flex-auth (assist FLEX-WP-0007 T4) + +```task +id: WARDEN-WP-ADHOC-2026-06-29-T01 +status: done +priority: medium +state_hub_task_id: "62540533-f4ca-5176-9237-32adbeb292ee" +``` + +flex-auth (msg `ea00620b`) asked ops-warden to help close FLEX-WP-0007 T4 (joint OpenBao ++ policy-gate production smoke). Their deployed runtime is reachable on CoulombCore via +the flex-auth-coulombcore tunnel at `127.0.0.1:18090`, but `policy_gate_production_smoke.sh` +spawned its **own** local flex-auth binary — so it never exercised the deployed runtime. + +- [x] Added `FLEX_AUTH_EXTERNAL=1` mode to `scripts/policy_gate_production_smoke.sh`: skips + the local `serve`/`load-registry` and runs the allow/deny/vault paths against the + already-running deployed flex-auth, with a `/healthz` precheck that fails fast with a + "is the flex-auth-coulombcore tunnel up?" hint (verified: clean exit 2 when down). +- [x] Verified the committed `production_registry_snapshot.json` is **current** (rebuilt + from `~/.config/warden/inventory.yaml`, diff-clean; 4 actors). +- [x] Answered flex-auth's three questions and handed the operator the exact CoulombCore + runbook (see reply). Remaining T4 steps are operator-gated and cannot run from the + workstation: mint a scoped `VAULT_TOKEN` (ops-warden holds no standing token by + design), run the joint smoke on CoulombCore, then flip `policy.enabled: true`. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-08-11.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-08-11.md new file mode 100644 index 00000000..3d858fe8 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-08-11.md @@ -0,0 +1,145 @@ +--- +id: WARDEN-WP-ADHOC-2026-08-11 +type: workplan +title: "Ad Hoc Tasks — 2026-08-11" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +created: "2026-08-11" +updated: "2026-08-15" +state_hub_workstream_id: "9f99cc64-4682-5f20-b13e-89af2b6f7c70" +--- + +# Ad Hoc Tasks — 2026-08-11 + +### T01 — Repair stale `rapp-qonto-keycape-client` wiki anchor (restore green routing suite) + +```task +id: WARDEN-WP-ADHOC-2026-08-11-T01 +status: done +priority: medium +state_hub_task_id: "0771d121-278c-556e-9509-841cf6e657c3" +``` + +rapp-postgres (msg `96907986`, residual from RAPP-POSTGRES-WP-0002-T04) reported the +focused routing suite at 60/61: `test_every_wiki_ref_anchor_resolves` failed because +`rapp-qonto-keycape-client` pointed at `wiki/CredentialRouting.md#credential-routing-catalog`, +an anchor that does not exist. The intended heading is `## Routing catalog index`. + +- [x] Repointed `rapp-qonto-keycape-client.wiki_ref` to + `wiki/CredentialRouting.md#routing-catalog-index` (the live heading). No other + entry used the stale anchor. +- [x] `uv run pytest tests/test_routing.py -q` → **61 passed**. +- [x] `warden route find "database credential"` still returns the active + `database-dynamic-credentials` rapp-postgres entry; that T04 route is untouched — + still `warden_executes: false` with no `steps:` block (pointer, not procedure). + +### T02 — Triage the stale ops-warden inbox (11 unread, C-28/C-29) + +```task +id: WARDEN-WP-ADHOC-2026-08-11-T02 +status: done +priority: medium +state_hub_task_id: "0ed58145-732f-5102-b6a8-b931d9b6ba08" +``` + +`fix-consistency` flagged 11 unread messages older than 3 days, two of them as possible +work requests (C-29). All eleven triaged, answered where an answer was owed, and marked +read. Inbox is now empty. + +- [x] **railiance-platform front-door thread** (`72d3ee84`, `cb50ea3c`, `6b058584`, + `5d47caaa`, `78c1c075`) — confirmed both lanes active and placeholder-free + (`issue-core-ingestion-api-key` catalog.yaml:219, `openrouter-llm-connect` + catalog.yaml:283, promoted in 364eb7d), closing RAILIANCE-WP-0009-T06 and + RAILIANCE-WP-0010-T06. Answered their open question: the stable ops-warden + selector is **`openrouter-llm-connect`**, not `llm-connect-openrouter-api-key`; + asked them to cross-reference the id in CCR-2026-0003 rather than have ops-warden + rename an active, test-referenced lane. +- [x] **railiance01 / activity-core** (`467153f3`, `3b9c6a77`, `fe796249`, `674f02e0`) — + superseded. STATE-WP-0071 finished; the `.git/FETCH_HEAD` blocker was filesystem + ownership, not SSH, and no `warden sign` was needed. Nothing was ever open for + ops-warden. Pointed activity-core at `warden plan` / `warden route find` instead of + hub round-trips for access questions. +- [x] **llm-connect LLM-WP-0006** (`f5975211`) — superseded: `OPENROUTER_API_KEY` was + provisioned through OpenBao custody 2026-07-02 (CCR-2026-0003), ES synced, + llm-connect rolled out. Restated the boundary — ops-warden does not populate + Secrets — and pointed at the now-active catalog lane. `LLM_CONNECT_URL` wiring + remains activity-core's. +- [x] **secrets-engine warden-sign** (`80456912`) — see T03; replied with status and + referred the live-apply question to the owner. + +### T03 — warden-sign AppRole: PARKED pending WP-0027 break-glass + ops-bridge cutover + +```task +id: WARDEN-WP-ADHOC-2026-08-11-T03 +status: done +priority: medium +state_hub_task_id: "337ae793-c6b0-59e9-8a07-3a7ccba237aa" +``` + +secrets-engine (msg `80456912`, 2026-06-29) is holding a validated non-mutating dry-run +for policy + AppRole `warden-sign` (exact `update` grants on `ssh/sign/{agt,adm,atm}-role`). +It is blocked on two **operator** actions: recording/approving the SECRETS-WP-0004 +decision, and providing the mode-0600 lane bootstrap token +(`~/.secrets-engine/bootstrap/prod-warden-sign.token`). secrets-engine correctly refused +to substitute the broader platform-admin token. + +**The request has been overtaken by events.** Since 2026-07-01 the scoped `VAULT_TOKEN` +need is served by the railiance-platform credential broker +(`ops-warden-warden-sign-token`, active; `credential.py exec --grant ops-warden/warden-sign`, +proven via `make credential-exec-ops-warden-smoke`) — no AppRole involved. + +**Resolved 2026-08-11: parked** — neither withdrawn nor proceeding. Founder decision +after reviewing the mechanics. Communicated to secrets-engine (msg `863c7b57`) with an +explicit instruction to stop holding apply readiness. + +An initial recommendation to **withdraw** was revised on inspection: + +- `warden sign` reads `VAULT_TOKEN` from the environment and has no AppRole login path + (`src/warden/vault.py:24-27`). The AppRole is a way for a *host* to obtain a token, + not an ops-warden code path — withdrawing costs no code and removes no working + capability. For the workstation, the broker plus attended operator OIDC is sufficient. +- The uncovered case is **unattended signing on a remote host** — the pending ops-bridge + cert_command cutover. `wiki/playbooks/ops-bridge-tunnel-cert.md:61` still falls back to + a manually exported `VAULT_TOKEN` there. +- Running the broker on that host means placing the railiance-platform checkout *and its + issuer token* (`credential-broker-warden-sign-issuer` — authority to mint warden-sign + tokens repeatedly) on it. The AppRole exchanges for a `warden-sign`-only token + (`update` on `ssh/sign/{agt,adm,atm}-role`). Both are standing credentials on a remote + host; **the AppRole is the narrower one**, and is the established NetKingdom pattern + for this shape (`rein-openweights-openrouter-approle`, + `agent-harness-binky-mail-approle`). + +No circular dependency exists today: OpenBao is a public endpoint +(`https://bao.coulomb.social`), so obtaining a cert never requires already holding one. + +**Un-park triggers** (either one re-opens the question): + +1. **WARDEN-WP-0027** (backlog) designs the graded lockdown / break-glass path and its + explicit trust-root — a second autonomous path to signing is an input to that design, + not an isolated decision. +2. **ops-bridge cert_command live cutover** reaches unattended signing on a remote host. + +Cheap to reverse: the secrets-engine dry-run plan is validated, re-runnable, and correct +as drafted. The two operator gates (SECRETS-WP-0004 decision, mode-0600 lane bootstrap +token) are deliberately *not* being satisfied while parked. + +**Closed 2026-08-15.** Neither un-park trigger has fired: + +1. `WARDEN-WP-0027` is still `backlog`; T02 (graded lockdown / break-glass) stays + `cancel` with the workplan. The parked AppRole remains an input on that task. +2. ops-bridge live cert_command cutover has not reached unattended signing on a + remote host. WP-0016 is finished as *pilot-ready and handed off*, not migrated. + +This ad-hoc's job was the operator question (withdraw vs keep). The 2026-08-11 +answer stands: **neither — park and hand off**. Applying or withdrawing the +AppRole is out of scope here and would re-open the operator gates that were +deliberately left unsatisfied. Long-term ownership is `WARDEN-WP-0027-T02` +(and the ops-bridge cutover if that arrives first). secrets-engine already has +the park instruction (msg `863c7b57`); no new apply/withdraw ask. + +- [x] Park decision recorded and communicated (2026-08-11) +- [x] Ownership transferred to `WARDEN-WP-0027` T02; playbook pointer updated +- [x] Ad-hoc closed so a `wait` item does not linger past the handoff diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-08-17.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-08-17.md new file mode 100644 index 00000000..65d75959 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-08-17.md @@ -0,0 +1,129 @@ +--- +id: WARDEN-WP-ADHOC-2026-08-17 +type: workplan +title: "Ad Hoc Tasks — 2026-08-17" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +created: "2026-08-17" +updated: "2026-08-17" +state_hub_workstream_id: "5c6c2bbb-b944-5afd-b89c-20d865518849" +--- + +# Ad Hoc Tasks — 2026-08-17 + +Inbox triage session. Three unread messages, all follow-on from the WP-0030 delegation +register plus one new design question that lands on ops-warden as the estate's +workload-identity owner. + +### T01 — Answer flex-auth: how should `/v1/check` authenticate its callers? + +```task +id: WARDEN-WP-ADHOC-2026-08-17-T01 +status: done +priority: high +state_hub_task_id: "04a2f8f9-e70b-5eed-ad87-343c8f9ef501" +``` + +flex-auth (msg `130a148c`, FLEX-WP-0015 T02) reported that `POST /v1/check` and +`/v1/batch_check` authenticate no caller — any workload with cluster network reach can +assert any subject/tenant and receive an authoritative allow. It lands on ops-warden +because ops-warden owns how workloads prove identity in this estate, and because the +ops-warden pre-sign gate is a flex-auth PEP that would implement the calling side. + +Their four questions answered in `wiki/NetKingdomSecurityMap.md` +§ *Service-to-service caller authentication (in-cluster)*: + +- [x] **Q1 — is there an existing estate pattern to adopt?** No. Surveyed what exists: + ops-warden SSH certs (host reachability, not pod→pod HTTP), KeyCape + `client_credentials` (`rapp-qonto-keycape-client` — a custodied client secret per + caller), OpenBao AppRole (host-standing; the WP-0030 register already flags it as + having no owner front door). None covers in-cluster service→service HTTP, so + flex-auth is not growing a parallel mechanism by adopting one. +- [x] **Q2 — which mechanism?** Confirmed their instinct: **(a) Kubernetes + ServiceAccount TokenReview**, with a *projected* token carrying an explicit + `audience`, keeping `automountServiceAccountToken: false` and adding the volume + per Deployment. Rejected (c) shared-secret header — it manufactures a `risk: high` + credential lane with a rotation owner per caller, on the authorization path, which + is exactly the interim-proxy debt WP-0030 exists to stop growing, and ops-warden + would end up fronting it. Deferred (b) mTLS as the stronger end state that first + needs an answer to *who owns the workload X.509 CA* — nobody does; ops-warden + issues SSH certs, not workload X.509. +- [x] **Q3 — authenticate only, or also constrain?** Both, but split: bind the asserted + `system` to the authenticated ServiceAccount and reject a mismatch (identity + binding, no per-consumer operational cost). Keep the *resource-type* allowlist + ("only ops-warden may ask about `ssh-certificate`") in the policy package, not in + the auth middleware — flex-auth is the policy engine, and encoding it in its own + admission layer puts authorization in two places where only one is versioned. +- [x] **Q4 — rollout shape?** Warn-only first, as they proposed; ops-warden adopts the + calling side on its own schedule. Binding condition is sequencing, not a date: + `policy.enabled` must not flip anywhere while `/v1/check` still answers + unauthenticated callers. +- [x] Recorded as a **pattern**, not a catalog entry — `registry/routing/catalog.yaml` + indexes credential needs and their owners; caller authentication is neither. +- [x] Noted the division of the call: mechanism is ops-warden's/architectural; accepting + the pod-spec change and rollout timing are the operator's. + +### T02 — user-engine: USER_ENGINE_PROXY_SECRET stays railiance-apps; record consumer-only + +```task +id: WARDEN-WP-ADHOC-2026-08-17-T02 +status: done +priority: medium +state_hub_task_id: "0e815282-2fad-5c8d-be34-398e492737d0" +``` + +user-engine (msg `2af4a124`) answered the open confirm question on +`coulomb-social-runtime-env`. Decided by Bernd 2026-08-16, State Hub decision +`8fe22037-5bbb-4487-bb86-e4beccee454b` against USER-WP-0021: the secret is +infrastructure trust between ingress and workload, not a user-domain fact; user-engine +consumes it and has no authority over custody, rotation, or issuance. + +- [x] `intended_owner` stays `railiance-apps`; dropped the now-answered + "confirm whether user-engine should front USER_ENGINE_PROXY_SECRET" clause from + `blocked_on`, which now names only the real remaining blocker (CCR not applied). +- [x] Recorded the positive signal they asked for: `consumers: [user-engine]` on the + lane, with the decision id in a comment. +- [x] Their second point — `USER_ENGINE_EVENT_TOKEN`, `USER_ENGINE_MAIL_TOKEN`, and the + transactional SMTP lane gating public registration — checked against the catalog: + `audit-core-senders` (native → ops-mason) and `email-connect-transactional` + (interim → secrets-engine) already cover the event and mail token custody. No new + lane opened; told them which ids to watch. + +### T03 — key-cape: `rapp-qonto-keycape-client` interim accepted; refresh the blocker + +```task +id: WARDEN-WP-ADHOC-2026-08-17-T03 +status: done +priority: medium +state_hub_task_id: "e21781d9-a35d-5916-b335-d12131f97a22" +``` + +key-cape (msg `099b7cba`) acknowledged the lane staying interim on ops-warden. +KEY-WP-0008 is finished and its closeout does **not** include a key-cape-native +`client_secret_basic` exchange/rotation command; that is a separate, not-yet-opened +workplan. + +- [x] Refreshed `blocked_on` so it names the current reality rather than implying an + in-flight KEY-WP-0008 dependency: the native command is unopened work, and + key-cape has acked the interim hold. +- [x] `key-cape-oidc-login` left pointing at `secrets-engine` — key-cape explicitly did + not claim the generic-vs-per-lane custody split, and that lane's blocker is the + same unanswered secrets-engine question as the other six. +- [x] `reviewed` bumped to 2026-08-17 on both touched lanes so `warden route gaps` + staleness reflects a real re-check. + +### T04 — Session hygiene + +```task +id: WARDEN-WP-ADHOC-2026-08-17-T04 +status: done +priority: low +state_hub_task_id: "b15724e0-c27a-5260-a810-4dd25bff2228" +``` + +- [x] `uv run pytest -q` → 338 passed, 4 deselected (routing anchor + no-double-source + checks green after the catalog edits). +- [x] All three messages replied to and marked read; inbox empty. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-09-08.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-09-08.md new file mode 100644 index 00000000..c1ae7c3e --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-09-08.md @@ -0,0 +1,179 @@ +--- +id: WARDEN-WP-ADHOC-2026-09-08 +type: workplan +title: "Ad Hoc Tasks — 2026-09-08" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: netkingdom +created: "2026-09-08" +updated: "2026-09-08" +state_hub_workstream_id: "182f3aff-8c8a-5766-8a68-5fe35f423f7a" +--- + +# Ad Hoc Tasks — 2026-09-08 + +Four key-cape messages, all follow-on from `WARDEN-WP-0033`. Two carry answers +ops-warden's catalog was waiting for; both make a recorded blocker less true than +it reads. This is the T05 mechanism paying out — and this time the owner ran it +against us rather than us running it against them. + +### T01 — Narrow the `rapp-qonto-keycape-client` blocker (msg `08d42f47`) + +```task +id: WARDEN-WP-ADHOC-2026-09-08-T01 +status: done +priority: high +state_hub_task_id: "29cef28a-d93b-5318-bfdb-69dbe11fa3ba" +``` + +The blocker recorded "still no key-cape-native exchange/rotation command", +`verified: source-read` against key-cape source on 2026-08-28. Accurate then; +two things landed after that read: + +- `keycape service-token` (2026-09-05, KEY-WP-0014-T03) — the client_secret_basic + exchange the blocker records as absent. +- `keycape verify-client` (2026-09-08) — rotation step 3 as one command, + including predecessor rejection and identical-secret detection. + +**Narrowed, not cleared**, as key-cape asked. What remains genuinely blocked is +steps 1-2: successor generation and the CAS write to both custodians. Those are +custody and deployment acts, key-cape deliberately ships no command for them, and +no admitted ops-warden lane authorizes them either (T03). + +`verified` moved to `owner-confirmed` — the correction came from the owner. + +`rotation.automatable` flipped `true` → `false`, which key-cape explicitly asked +us not to do "either way" without precision. Done with the precision they wanted, +in the only place the schema has room for it: the flag is a single hint consumed +by a future executable driver (`WARDEN-WP-0027` Strand B), and a driver told +`true` would attempt custody acts with no admitted transport — the dangerous +direction. So the flag fails safe and the *steps* now carry the per-step truth, +each naming whether it is automatable and why. Offered them a schema change if a +per-step field would serve better; not built on speculation. + +### T02 — Record key-cape's acceptance of `key-cape-oidc-login` (msg `12f1bdfa`) + +```task +id: WARDEN-WP-ADHOC-2026-09-08-T02 +status: done +priority: high +state_hub_task_id: "8efb8013-7b90-52ef-a17c-d63f5ce3752c" +``` + +key-cape **accepted** ownership: interactive login, OIDC identity-token issuance +and MFA. This confirms the 2026-08-28 correction of `intended_owner` from +secrets-engine to key-cape, and confirms secrets-engine's 2026-08-21 refusal was +right. `verified: asked-and-waiting` → `owner-confirmed`. + +**The lane stays `interim`.** Acceptance covers the identity half only. The +`fetch_command` yields an *OpenBao* token — the `netkingdom` mount, the +`role=` mapping, the token store and its enforcement are OpenBao's, with +role and policy definition railiance-platform's. `keycape login` yields a +key-cape issuer JWT to a private file: different credential type, different +verifier, different enforcement owner. Accepting an owner is not the same as the +owner fronting the lane, and `ADR-0003` says the interim cover is retired when +the front door exists, not when ownership is agreed. Retirement condition is now +recorded on the entry. + +Their reading of the risk is right and we confirmed it: `warden_executes: false` +with a `wiki_ref` pointer, so per `ADR-0001` this is a pointer layer, not a code +path with programmatic consumers. `risk: standard` and +`workload_ref: not-applicable` are correct — a human identity act with no KV +path, consistent with how `ADR-0008` treats the other non-KV lanes. + +### T03 — Answer "who executes Qonto rotation steps 1-2" (msg `0a6c9d88`) + +```task +id: WARDEN-WP-ADHOC-2026-09-08-T03 +status: done +priority: high +state_hub_task_id: "bd621821-2116-51c9-a09a-a3660b5e5557" +``` + +Answer: **nobody, admittedly, today** — and ops-warden must not invent one. + +Steps 1-2 mutate custody on `platform/workloads/rapp-qonto/keycape-client` and +`sso/keycape-rapp-qonto-client`. Custody of platform workload paths is +railiance-platform's; the admitted execution front door for provisioned +secret-exec is `secrets-engine exec`. ops-warden owns neither and absorbing it +would be `ADR-0002` and `ADR-0005` violated in one act. Routed to +railiance-platform, with secrets-engine named as the transport owner — and +secrets-engine independently confirmed the same boundary three days earlier +(msg `15f0c0ca`): they will not rewrite a production lane's custody state from a +coordination message without owner confirmation. + +key-cape was right not to treat a generic `warden route` match as authorization. +See T04 for what our own tool did when asked. + +### T04 — `warden plan` returned `autonomous` for a custody *write* (defect) + +```task +id: WARDEN-WP-ADHOC-2026-09-08-T04 +status: done +priority: high +state_hub_task_id: "9ada01d2-b14b-579e-921c-275820f255db" +``` + +Verifying T03 against our own front door: + +``` +warden plan "generate a successor client secret ... and CAS-write it to + OpenBao platform/workloads/... and sso/..." --json + verdict: autonomous + lane_id: rapp-qonto-keycape-client + commands: warden access ... --exec / --out / --wrap +``` + +A need that says *generate* and *CAS-write* resolved to `autonomous` and was +answered with three **read** transports. This is the `WARDEN-WP-0033-T06` shape +recurring — a generic keyword match producing a confident wrong act — except T06 +fixed one route by adding an exact lane, and the defect is in the classifier. +`warden plan` has no notion of read versus mutate intent, so every write need +matches the lane that *reads* the same path and comes back `autonomous`. + +Not fixed here: a classifier is design work with an approval-semantics blast +radius, which the convention says is a workplan, not an adhoc. +Promoted to **`WARDEN-WP-0038`** (`proposed`). + +Worth stating plainly: key-cape distrusted this output on principle and was right +to. Had they trusted it, our tool would have told them to proceed autonomously on +an unadmitted custody mutation. + +### T05 — Acknowledge the KEY-WP-0009 handoff (msg `5bc58847`) + +```task +id: WARDEN-WP-ADHOC-2026-09-08-T05 +status: done +priority: low +state_hub_task_id: "06bf8508-d1a2-51b4-b951-02539524ebb9" +``` + +Informational; no route retired or changed. Their routing note matches ours: +"login / OIDC / MFA" → key-cape means **issuance only**, and secret *values* +route to OpenBao custody. Nothing to change in `wiki/CredentialRouting.md`. + +Also records that the KEY-WP-0009 reply ops-warden reported never arriving indeed +never existed (KEY-WP-0014-T02, audited 2026-09-05). Our 2026-08-28 finding was +right, and the correction is theirs, recorded. + +### T06 — Unpin two tests from a transient catalog state + +```task +id: WARDEN-WP-ADHOC-2026-09-08-T06 +status: done +priority: medium +state_hub_task_id: "a0b88db9-2886-54dd-a925-9e0521044aa0" +``` + +`test_stale_gaps_flags_unverified_even_when_the_date_is_today` and +`test_cli_route_gaps_fail_on_stale_exits_3` both asserted that +`key-cape-oidc-login` specifically sat `asked-and-waiting`. T02 answering that +question broke them — **the tests failed on good news**, not on a defect, and a +test that fails when a counterparty replies will get suppressed rather than read. + +Both now assert the property they were always about: any lane whose blocker was +never re-established is stale regardless of its date, over whatever lanes are in +that state. The named-lane version of the claim already exists as a unit test on +`Delegation.is_verified`, which is where a fixture belongs. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-10-03.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-10-03.md new file mode 100644 index 00000000..e76cd016 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/ADHOC-2026-10-03.md @@ -0,0 +1,31 @@ +--- +id: WARDEN-WP-ADHOC-2026-10-03 +type: workplan +title: "Documentary feedback on Emergent Security repository pilot" +domain: infotech +repo: ops-warden +status: finished +owner: codex +topic_slug: ops-warden +created: "2026-10-03" +updated: "2026-10-03" +state_hub_workstream_id: "246dc069-0f9b-516b-9db4-9914323da16f" +--- + +## Review retained pilot evidence against owner boundaries + +```task +id: WARDEN-WP-ADHOC-2026-10-03-T01 +status: done +priority: medium +state_hub_task_id: "c532cd72-88c4-543b-b6db-caf1bcb74a3d" +``` + +Evidence: docs/evidence/2026-10-03-emergent-pilot-owner-feedback.md. +Completed authorized documentary feedback on the retained read-only 0.2.0 +Claude scenario; preserved original version and evidence limits, qualified +owner boundary wording and identified bounded 0.2.2 follow-up scenarios. +No provider session, runtime control, deployment, credential or institutional +adoption was performed. Next pilot/adoption gates remain existing +EMERGENT-WP-0002-T08/T09 and decision d20a9750-2b29-534e-8227-fb866581a6ca. +No new operational residual was created. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md new file mode 100644 index 00000000..a787f1da --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0016-ops-bridge-tunnel-cert-pilot.md @@ -0,0 +1,124 @@ +--- +id: WARDEN-WP-0016 +type: workplan +title: "ops-bridge cert_command pilot — readiness gate + handoff" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +planning_priority: high +planning_order: 16 +created: "2026-06-27" +updated: "2026-06-27" +state_hub_workstream_id: "a56da8db-38bc-4bbe-8671-823360ec9245" +--- + +# WARDEN-WP-0016 — ops-bridge cert_command pilot (readiness gate + handoff) + +**Scope:** Close ops-warden's side of the last **Partial** INTENT criterion — *"ops-bridge +integrates via a stable `cert_command`"*. The migration playbook +(`wiki/playbooks/ops-bridge-tunnel-cert.md`, WP-0013) and the `cert_command` contract +(`wiki/CertCommandInterface.md`) already exist, but the pilot has never been run because +the readiness checks are scattered manual checkboxes across three owners (ops-warden, +ops-bridge, railiance-infra). This WP ships the **automated readiness gate** an operator +runs *before* touching tunnel config, plus an offline `cert_command` contract smoke, and +hands the verified pilot to ops-bridge. + +**Boundary (unchanged):** ops-warden issues certs and verifies its own side is ready. +The **live tunnel cutover is ops-bridge's to execute** — this WP does not (cannot) flip a +running tunnel. "Done" here means *pilot-ready and handed off*, not *tunnel migrated*. + +**Out of scope:** editing `~/.config/bridge/tunnels.yaml` (ops-bridge owns it); deploying +host principals (railiance-infra); requiring a live OpenBao token for the contract smoke +(use the local backend). + +**Depends on:** WP-0013 (playbook + contract), the SSH lane (prod-verified). + +--- + +## Tasks + +### T1 — Read-only `cert_command` readiness preflight + +```task +id: WARDEN-WP-0016-T01 +status: done +priority: high +state_hub_task_id: "fea84495-dbec-480a-b42b-90e39f414b78" +``` + +- [x] `scripts/check_tunnel_cert_readiness.py` — given `--actor`, `--pubkey`, `--config` + (warden.yaml) and optional `--infra` (ssh_principals.yaml), asserts the cert_command + path is ready **without signing anything**: config loads + backend known; actor in + inventory with a valid type + TTL within the type max; pubkey file exists, parses, + and is not a private key; actor principals present; (optional) principals deployed + in the infra file (mirrors `check_principals_drift._infra_principals`). Exit 0/1/2. +- [x] Checklist-style report (✓/✗/·); never prints a private key or token. +- [x] Tests: `tests/test_tunnel_cert_readiness.py` (ready, unknown actor, missing/private + pubkey, infra present/missing, TTL-over-max, cert_command string). 9 unit cases. + +### T2 — Offline cert_command contract smoke + +```task +id: WARDEN-WP-0016-T02 +status: done +priority: medium +state_hub_task_id: "e34ae1a8-2ba9-4324-8d1a-005d61dae478" +``` + +- [x] Opt-in `--sign-smoke` mode runs the actual `cert_command` against the **local** + backend and validates the emitted cert: identity matches the actor, principals match + inventory, validity window within the type's max TTL. Refuses a vault backend (must + be offline). Proves the contract end to end with no live OpenBao. +- [x] Window measured from the cert's own `valid_from`→`valid_before` (via + `parse_cert_metadata`) so it is timezone-robust — fixes a CEST off-by-2h artifact + where local-time ssh-keygen output was read as UTC. +- [x] `integration`-marked test (needs `ssh-keygen`, skipped in the default suite) plus a + non-integration test that `--sign-smoke` refuses a vault backend. + +### T3 — Playbook gate + ops-bridge handoff + +```task +id: WARDEN-WP-0016-T03 +status: done +priority: medium +state_hub_task_id: "330e01f4-4927-4280-b0e0-49d35b4416d6" +``` + +- [x] `wiki/playbooks/ops-bridge-tunnel-cert.md` now leads with **Step 0 — Readiness gate** + (the exact `check_tunnel_cert_readiness.py` invocation + `--sign-smoke` note); the + manual checklist remains as the human-readable backing. +- [x] Sent ops-bridge the coordination handoff (pilot `agt-state-hub-bridge`, the + readiness-gate command, and the cutover steps ops-bridge owns). + +### T4 — INTENT/SCOPE alignment + +```task +id: WARDEN-WP-0016-T04 +status: done +priority: low +state_hub_task_id: "4726f5bb-4ffd-484f-8674-91ee5658434f" +``` + +- [x] SCOPE: INTENT gap row moved from "Partial — tunnels still static-key" to + "Pilot-ready — readiness gate shipped; live cutover handed to ops-bridge"; known-gaps + row updated; readiness script added to the implemented SSH-lane list. + +--- + +## Acceptance + +- `scripts/check_tunnel_cert_readiness.py` gates the pilot read-only and is tested. +- The offline contract smoke validates a real cert against the local backend. +- The playbook leads with the automated gate; ops-bridge has the handoff with exact steps. +- No secret material in any script, test, doc, or log. ops-warden's boundary is intact: + it verifies and hands off; ops-bridge executes the cutover. + +--- + +## See also + +- `wiki/playbooks/ops-bridge-tunnel-cert.md`, `wiki/CertCommandInterface.md` +- `scripts/check_principals_drift.py` (reused helpers) +- `history/2026-06-24-intent-scope-gap-analysis.md` diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0017-access-front-door-discoverability.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0017-access-front-door-discoverability.md new file mode 100644 index 00000000..fe9c5b15 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0017-access-front-door-discoverability.md @@ -0,0 +1,120 @@ +--- +id: WARDEN-WP-0017 +type: workplan +title: "Access front-door discoverability — stop reading as SSH-only" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +planning_priority: high +planning_order: 17 +created: "2026-06-27" +updated: "2026-06-27" +state_hub_workstream_id: "cf8b392e-7624-4585-8935-a85e29202935" +--- + +# WARDEN-WP-0017 — Access front-door discoverability + +**Problem:** WP-0014 made ops-warden the operator **access front door** — for +`exec_capable` lanes (OpenBao reads, key-cape login) `warden access --fetch/--exec` +proxies the fetch **as the caller** and streams the value to them (ops-warden holds +nothing). But every *discovery* surface still tells the pre-WP-0014 story, so agents +(e.g. whynot-design needing `NPM_AUTH_TOKEN`) conclude "ops-warden only issues SSH certs +and replies with a pointer, not a token" and never find the proxy. + +**Fix:** propagate the WP-0014 conduit charter to the surfaces agents actually read. This +is a *messaging/discoverability* change — **no** change to the security model: the conduit +stays a conduit (no custody, no standing broker; the responsibility-map boundary holds). + +**Out of scope:** ops-warden holding/brokering token values (that would override the +WP-0014 charter); shipping the concrete OpenBao npm KV path (railiance-platform infra — +tracked separately); any new fetch capability (the proxy already exists). + +**Depends on:** WP-0014 (the proxy lane being described). + +--- + +## Surfaces that mislead today + +| Surface | Says now | Should say | +| --- | --- | --- | +| `warden route` table `warden` column | binary `issue` / `route` | `issue` / **`assist`** (exec_capable) / `route` | +| `warden route` `--json` | no proxyability field | add `warden_role` + `exec_capable` | +| `warden access` closing line | "warden advises, the owner vends" | for exec_capable: "ops-warden can fetch this for you as the caller…" | +| `.claude/rules/credential-routing.md` | "issues SSH certs **only**… reply is a pointer, not a key" | issues SSH certs **and** is the access front door; exec_capable lanes proxy as you | +| Federated capability registry | only "SSH certificate issuance" | also "Operator access front door / caller-identity fetch proxy" | +| SCOPE one-liner + capability block | SSH + routing + posture | add the access-assist/proxy front door | + +--- + +## Tasks + +### T1 — CLI discoverability: route role + access framing + +```task +id: WARDEN-WP-0017-T01 +status: done +priority: high +state_hub_task_id: "6e98df42-b5b4-49f8-a444-3c6346c8abd7" +``` + +- [x] `warden route` table: three-valued `warden` column — `issue` / `assist` + (exec_capable) / `route`. `_entry_summary` JSON gains `warden_role` + `exec_capable`; + `route show` JSON `next_action` surfaces the proxy for exec_capable lanes. +- [x] `warden access` closing line: for `exec_capable` lanes leads with "ops-warden can + fetch this for you as the caller (`--fetch`/`--exec`); runs the owner's tool with + your identity, value never held/cached/logged." Non-exec lanes keep "advises, owner + vends." `_access_json` `next_action` mirrors it. +- [x] Tests in `tests/test_routing.py` (warden_role issue/assist) and `tests/test_access.py` + (front-door framing for exec lane, owner-vends for route-only lane). 210 pass. + +### T2 — Agent rule + SCOPE reframe + +```task +id: WARDEN-WP-0017-T02 +status: done +priority: high +state_hub_task_id: "6e2a7067-1afc-4f38-8d99-4d5c36a4661c" +``` + +- [x] `.claude/rules/credential-routing.md`: reframed the lead ("issues SSH certs **and** + is the operator access front door…") and the quick routing table (`ops-warden role` + column: Issue / Assist / Route). Kept the true anti-pattern: don't POST a State Hub + message for a secret *value* — it comes from the CLI front door run as you. +- [x] SCOPE one-liner reframed to "steward **and front door**"; added a second `capability` + block "Operator access front door (caller-identity fetch proxy)". + +### T3 — Federated capability registration + +```task +id: WARDEN-WP-0017-T03 +status: done +priority: medium +state_hub_task_id: "7199625b-e78e-4495-8ca0-076100ae9f08" +``` + +- [x] Registered the State Hub capability "Operator access front door (caller-identity + fetch proxy)" (id `708e46f6`, repo ops-warden) — the hub had **no** ops-warden + security capability before, so the front door was undiscoverable cross-domain. +- [x] Sent whynot-design (msg `83a3bb2e`) the corrected path: `warden access "npm auth + token" --fetch/--exec`, the CLI refresh, the OpenBao-auth prereq, and the + railiance-platform path caveat. + +--- + +## Acceptance + +- An agent doing the first-line `warden route find` / `--json` lookup can see ops-warden + *assists* (proxies) the OpenBao lane, not merely points. +- The credential-routing rule and federated capability registry describe the access + front door; none of them say "SSH certificates only". +- The conduit boundary is unchanged and explicit: ops-warden fetches *as the caller* and + holds nothing — no custody, no broker. + +--- + +## See also + +- `WARDEN-WP-0014` (the proxy lane), `wiki/OperatorAccessAssist.md` +- `.claude/rules/credential-routing.md`, `registry/routing/catalog.yaml` diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md new file mode 100644 index 00000000..f923be53 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0018-whynot-design-npm-lane-activation.md @@ -0,0 +1,103 @@ +--- +id: WARDEN-WP-0018 +type: workplan +title: "Activate whynot-design npm publish lane + resolvable readiness flag" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +planning_priority: high +planning_order: 18 +created: "2026-06-29" +updated: "2026-06-29" +state_hub_workstream_id: "1256aca2-5979-4d21-818e-0de42c5d811b" +--- + +# WARDEN-WP-0018 — whynot-design npm lane activation + `resolvable` flag + +**Trigger:** railiance-platform completed provisioning the whynot-design npm publish lane +(CCR-2026-0001, commit 8f617fc): `status=active`, `access_frontdoor.readiness=ready`, +`resolvable=true`, positive fetch passed + negative (non-whynot) login denied. They asked +ops-warden to activate the dedicated catalog selector and notify whynot-design. This is the +first concrete `warden access --fetch`-resolvable non-SSH lane — the end-to-end proof of the +WP-0014 conduit + WP-0017 discoverability work. + +**whynot-design's spec** (msg 2687dc31) drove the shape: zero-placeholder command keyed by a +stable id, owner-confirmed concrete path/field/role, a machine-readable readiness flag, and a +publish-vs-read scope split. + +**Boundary unchanged:** ops-warden holds no token; the lane proxies the read as the caller. + +--- + +## Tasks + +### T1 — Concrete catalog entry + playbook + +```task +id: WARDEN-WP-0018-T01 +status: done +priority: high +state_hub_task_id: "189d0883-22b9-42dc-bda0-89460509a87d" +``` + +- [x] Added `whynot-design-npm-publish` to `registry/routing/catalog.yaml` (`status: active`, + `exec_capable`, `lane: secret`) with the **owner-confirmed, zero-placeholder** handoff: + path `platform/workloads/coulomb/whynot-design/npm-publish` (the superseded + `whynot-design/whynot-design/…` form is **not** used), field `NPM_AUTH_TOKEN`, OIDC + `bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read`, policy + `workload-kv-read-whynot-design-npm-publish`, flex-auth `secret.read:whynot-design`. +- [x] `wiki/playbooks/whynot-design-npm-publish.md` — worker checklist, scopes, operator + go-ahead note (publish is immutable + outward-facing). Catalog `wiki_ref` points to it. +- [x] Passes the `_assert_no_secret_material` guard (templates/identifiers only, no value). + +### T2 — `resolvable` readiness flag + stable-id resolution + +```task +id: WARDEN-WP-0018-T02 +status: done +priority: high +state_hub_task_id: "b5dc1013-5334-43ff-afd6-1f99d521358f" +``` + +- [x] `RouteEntry.resolvable` — true when a lane is active, exec_capable, and its fetch + command/path carry **no** unresolved `<…>` placeholder. Surfaced in the route/access + `--json` (`_entry_summary`). Generic `openbao-api-key` and the `` login lane + report `false`; `whynot-design-npm-publish` reports `true`. +- [x] `Catalog.find` now resolves an **exact catalog-id** match first, so + `warden access whynot-design-npm-publish …` is deterministic regardless of keyword + collisions (whynot-design's "stable keyed command"). +- [x] Tests: `tests/test_routing.py` (concrete+resolvable lane, template lanes not + resolvable, exact-id wins); fixed a `test_access` no-match query that incidentally + substring-collided (`no` ⊂ `whynot`). 213 pass, lint clean. + +### T3 — Close the loop + +```task +id: WARDEN-WP-0018-T03 +status: done +priority: medium +state_hub_task_id: "95b00ef8-477a-4f0d-bd71-6154fba401f5" +``` + +- [x] Notified whynot-design (reply 744977ae) with the zero-placeholder command + `warden access whynot-design-npm-publish --exec -- npm publish`, the `resolvable` gate, + the coulomb-tenant path correction, and the operator-go-ahead reminder. +- [x] Confirmed activation to railiance-platform (reply f76d3a9e). Sibling lanes + (`issue-core-ingestion-api-key`, `openrouter-llm-connect`) stay `draft` per their + deferral, pending CCR-2026-0002/0003 provisioning. + +--- + +## Acceptance + +- `warden access whynot-design-npm-publish` resolves to a concrete, owner-confirmed, + zero-placeholder lane; `--json` reports `resolvable: true`. +- Template/generic lanes report `resolvable: false`; exact-id lookup is deterministic. +- No secret value in catalog, playbook, tests, or logs; ops-warden holds nothing. + +## See also + +- `WARDEN-WP-0014` (proxy lane), `WARDEN-WP-0017` (discoverability) +- railiance-platform CCR-2026-0001, `docs/workload-kv-access-lanes.md` diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0019-route-to-secrets-engine.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0019-route-to-secrets-engine.md new file mode 100644 index 00000000..602fad1b --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0019-route-to-secrets-engine.md @@ -0,0 +1,89 @@ +--- +id: WARDEN-WP-0019 +type: workplan +title: "Route secret-exec lanes to secrets-engine (route-primary, proxy fallback)" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +planning_priority: high +planning_order: 19 +created: "2026-06-29" +updated: "2026-06-29" +state_hub_workstream_id: "5e49abb6-497f-4640-a484-2da5f39a7c4e" +--- + +# WARDEN-WP-0019 — Route secret-exec lanes to secrets-engine + +**Trigger:** secrets-engine (SECRETS-WP-0003, msg 765a03f0) shipped a native secret-exec +front door — `secrets-engine route --json` and `secrets-engine exec --catalog -- +` with canonical decision ids — and asked ops-warden to **route to it**. This is the +owner-native execution lane that ops-warden's `warden access --exec` proxy was filling as a +stopgap (WP-0014). whynot-design already published `@whynot/design@0.4.0` through the proxy +on this same lane, so both paths resolve today. + +**Decision (Bernd, 2026-06-29): route-primary, proxy-fallback.** For lanes secrets-engine +owns, ops-warden surfaces `secrets-engine exec/route` as the **primary** path and keeps its +own `warden access --exec` as a documented **transparent fallback**. ops-warden stays the +discovery front door; secrets-engine is the exec owner. Boundary unchanged: ops-warden holds +or stores no token on either path. + +**Out of scope:** ops-warden invoking `secrets-engine exec` itself (it routes/points, the +caller runs it); changing the proxy's security model; the production policy-gate flip. + +--- + +## Tasks + +### T1 — Catalog + CLI: surface the owner-native exec front door + +```task +id: WARDEN-WP-0019-T01 +status: done +priority: high +state_hub_task_id: "ea153605-7a14-4db7-8bce-d780ea143f8a" +``` + +- [x] `RouteEntry` gains `exec_owner` / `exec_command` / `pointer_command` (pointers only, + screened by `_assert_no_secret_material`) and a `has_native_exec` property. +- [x] `whynot-design-npm-publish` entry: `exec_owner: secrets-engine`, + `exec_command: secrets-engine exec --catalog whynot-design-npm-publish -- `, + `pointer_command: secrets-engine route whynot-design-npm-publish --json`. Keep the + existing `fetch_command`/`exec_capable` (the proxy fallback). +- [x] `warden access`: when `exec_owner` is set, render the secrets-engine exec as the + **primary** line and the `warden access --exec` proxy as the **fallback**; JSON gains + `exec_owner`/`exec_command`/`pointer_command`. `route find/show` JSON too. +- [x] Tests in `tests/test_routing.py` / `tests/test_access.py`. + +### T2 — Agent rule, SCOPE, playbook + +```task +id: WARDEN-WP-0019-T02 +status: done +priority: medium +state_hub_task_id: "96059b8a-8938-4763-b3d0-cc5a0eb2465c" +``` + +- [x] `.claude/rules/credential-routing.md`: add secrets-engine as the secret-exec owner; + for OpenBao-backed secret lanes the route is "secrets-engine `exec` (primary), + ops-warden `warden access --exec` (transparent fallback)". +- [x] SCOPE: add secrets-engine to Related Repos + the routing model; note the + whynot-design lane is **production-exercised** (real 0.4.0 publish), not just resolvable. +- [x] `wiki/playbooks/whynot-design-npm-publish.md`: lead with the secrets-engine exec + command; fix the fallback one-liner per whynot-design's field notes + (`--field NPM_AUTH_TOKEN`, and `--no-policy` while `policy.enabled=false`). + +--- + +## Acceptance + +- `warden access whynot-design-npm-publish` shows the secrets-engine exec as primary and the + warden proxy as fallback; `--json` carries `exec_owner`/`exec_command`. +- The credential-routing rule names secrets-engine as the secret-exec owner. +- No secret material anywhere; ops-warden holds no token on either path. + +## See also + +- secrets-engine SECRETS-WP-0003, decision e6381a56, `docs/whynot-design-real-publish-closeout.md` +- `WARDEN-WP-0014` (proxy), `WARDEN-WP-0017` (discoverability), `WARDEN-WP-0018` (lane activation) diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0020-ops-warden-worker.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0020-ops-warden-worker.md new file mode 100644 index 00000000..1230ed31 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0020-ops-warden-worker.md @@ -0,0 +1,176 @@ +--- +id: WARDEN-WP-0020 +type: workplan +title: "ops-warden worker — autonomous coordination via llm-connect" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +planning_priority: high +planning_order: 20 +created: "2026-06-29" +updated: "2026-06-29" +state_hub_workstream_id: "c906ba1d-f991-4fb0-b113-59432ddf87c0" +--- + +# WARDEN-WP-0020 — ops-warden worker (`warden worker`) + +**Problem:** ops-warden's coordination lane (State Hub inbox `to_agent=ops-warden`) is +handled only when a human spins up an ops-warden session and relays instructions. That +doesn't scale — Bernd is hand-relaying between flex-auth ↔ secrets-engine ↔ ops-warden +across sessions. + +**Goal:** a `warden worker` CLI that pulls ops-warden's unread coordination requests and, +using **llm-connect** for inference, drives each to an ops-warden action (answer a routing +question, draft+send a reply, mark read, propose/commit a catalog diff, or escalate) — so +the inbox is handled without a human starting a session. + +**Decisions (Bernd, 2026-06-29):** **full-auto in-scope** (worker executes any in-scope +action; escalates only secrets/prod/out-of-scope) and **scheduled/unattended** (cron or +activity-core). Because there is no human in the loop for in-scope actions, the guardrails +are load-bearing and the rollout is staged: **dry-run → manual → scheduled**. + +**Build vs reuse:** inference = llm-connect (`/execute`); trigger = cron or activity-core +(reuse the durable task factory, don't reinvent scheduling). Worker logic lives in warden. + +## Guardrails (non-negotiable — full-auto rests on these) +1. **Fixed charter, non-overridable.** The boundary (issue SSH; route everything else; + conduit-not-broker; never hold/print a secret value) is a fixed system policy. Message + content is **untrusted data**, never instructions that can relax it (prompt-injection + containment). +2. **Action allowlist.** Every action is validated against an allowlist before execution; + off-list → escalate. No secret handling, no prod-config writes, no irreversible/outward + actions without an explicit human ack. +3. **No-secret invariant.** Refuse any task requiring a secret value in hand or in a prompt. +4. **Full audit + dry-run.** Every action emits a progress event; `--dry-run` shows the + plan without executing. Scheduled mode only after a clean dry-run shakedown. + +## Hard dependency +llm-connect must be operational — it needs its provider key (`OPENROUTER_API_KEY`, +CCR-2026-0003, currently deferred by railiance-platform/secrets-engine). The worker is +built against llm-connect's contract; it cannot run the brain until that lands. + +--- + +## Tasks + +### T1 — Worker scaffold (llm-connect-independent, safe) + +```task +id: WARDEN-WP-0020-T01 +status: done +priority: high +state_hub_task_id: "979c2d9b-0803-442f-aa2e-acb02bac07e9" +``` + +- [x] `src/warden/worker.py`: State Hub inbox client (`HubClient.unread`), a `Brain` + protocol, a deterministic `RuleBrain` default (answers clear routing questions; + escalates the rest), the `PlannedAction`/`WorkerPlan` model, the guardrail allowlist + + `validate_action` (enforced brain-agnostically in `build_plans`), and a `render_plans` + dry-run renderer (plan only, no execution). +- [x] `warden worker run [--once] [--dry-run]` CLI; `--dry-run` is the default and + `--execute` is refused (exit 2) until the guarded executor lands (T3). +- [x] `tests/test_worker.py` (RuleBrain routing/secret/prod/unknown, guardrail downgrades a + reckless brain on secret/prod, off-allowlist rejection, render, CLI). 18 cases. +- [x] Live dry-run against the real hub verified — read the inbox and produced a guardrailed + plan (it surfaced secrets-engine's OIDC-role reply, demonstrating the value). + +### T2 — llm-connect brain + +```task +id: WARDEN-WP-0020-T02 +status: done +priority: high +state_hub_task_id: "52d281b2-7d48-44f5-b77e-80e3ed500b5f" +``` + +- [x] llm-connect brought operational (operator set OPENROUTER_API_KEY k8s secret + restart). + Contract discovered empirically from the running service: `POST /execute {"prompt":...}` + → `{"content": "", ...}` (no OpenAPI; custom JSON API). End-to-end verified (pong). +- [x] `LlmConnectBrain` (src/warden/worker.py): embeds the fixed charter + the message as + untrusted data into the prompt, calls `/execute`, parses a JSON action plan + (`_extract_json` tolerates fences/prose), and defensively escalates on malformed/empty/ + transport-error. Configurable `LLM_CONNECT_URL`. The guardrail pass still enforces the + allowlist + no-secret invariant on whatever the model returns. +- [x] `warden worker run --brain rule|llm` selector (dry-run default). Tests: + `tests/test_worker.py` (extract_json, parse, escalate-on-flag/malformed/transport, + guardrail-catches-unsafe-LLM-action). **Live verified** against the real inbox: the LLM + brain produced a sensible reply+mark_read for the secrets-engine message and correctly + escalated the llm-connect secret-custody request. 236 tests, lint clean. + +### T3 — Action dispatch + guardrails (full-auto in-scope) + +```task +id: WARDEN-WP-0020-T03 +status: done +priority: high +state_hub_task_id: "3a71965e-42d5-4258-9761-aced804c88e7" +``` + +- [x] `HubClient` gained writes (`mark_read`, `send_reply`, `add_progress`); `execute_plan` + / `execute_plans` run the **safe, allowlisted** actions — route_answer (reply with the + computed answer + auto mark-read), reply (with an LLM-drafted body), progress_note, + mark_read. Escalated plans and non-auto-executable kinds are left for a human. +- [x] **Deliberate guardrail:** `propose_catalog_diff` (and any code/routing change) is NOT + auto-executed even under full-auto — a bad catalog commit could misroute credentials, + so it goes to human review (recoverability over convenience). AUTO_EXECUTABLE is the + messaging/hub tier only. No secret value is ever read, sent, or logged. +- [x] `warden worker run --execute` runs the guarded executor (dry-run still the default); + per-message audit summary. Tests in `tests/test_worker.py` (route_answer reply+mark, + reply-with/without-body, escalated skip, catalog-diff left-for-human, progress_note, + failure-without-crash). 243 pass, lint clean. +- [x] **Conservative tier is now the `--execute` default (Bernd's Option A, 2026-06-30):** + `run_conservative` triages NEW messages into a reviewed digest (`worker-digest.md`) + with drafted replies, posts ONE progress note, tracks seen ids (schedule-safe dedup), + and sends **nothing** to other agents / marks nothing read. `--full-auto` opts into the + auto-send path. Live-verified with the LLM brain: produced a high-quality draft reply + to secrets-engine and flagged the llm-connect request as NEEDS YOU. 244 tests. + Rationale: the guardrails prevent *security* harm but not LLM *content* errors, so replies + stay drafts-for-approval until quality is proven — matches the build-stage/recoverability + posture. Conservative mode is safe to schedule (T4). + +### T4 — Scheduled trigger + +```task +id: WARDEN-WP-0020-T04 +status: done +priority: medium +state_hub_task_id: "7f77ea6d-c281-42c5-ad25-2a0bb9fd68de" +``` + +- [x] `scripts/worker-tick.sh` — scheduled tick for the conservative worker. `flock` + concurrency guard (no overlapping runs); brings up a short-lived kubectl port-forward + to llm-connect (or honors `LLM_CONNECT_URL`, or falls back to the rule brain offline). + Ships **disabled**; the header documents the cron entry to enable it (every 15 min). + Dry-shakedown done (the conservative live run + the rule-brain tick both verified). + Schedules the **conservative** tier only — never the auto-send path. + +### T5 — Docs / SCOPE / INTENT + +```task +id: WARDEN-WP-0020-T05 +status: done +priority: medium +state_hub_task_id: "6e7ae317-7f8b-468a-bb5c-b08093ed43a0" +``` + +- [x] SCOPE: recorded the coordination worker (`warden worker`) as an implemented + capability — conservative triage default, full-auto opt-in, llm-connect brain, the + four guardrails, schedulable tick. The guardrails + the conservative-by-default + posture are documented as the worker's security-model statement (here + in the + build-stage decision 813899f9). + +--- + +## Acceptance + +- `warden worker run --dry-run` reads the real inbox and prints a guardrailed plan. +- Full-auto execution runs only in-scope, allowlisted actions; secrets/prod/out-of-scope + escalate; every action is audited. No secret value ever enters a prompt, log, or commit. +- Scheduled mode is enabled only after a dry-run shakedown. + +## See also + +- llm-connect (inference), activity-core (durable trigger), kaizen-agentic (personas) +- `.claude/rules/credential-routing.md` (the boundary the worker enforces) diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md new file mode 100644 index 00000000..2500d4b3 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0021-enable-scheduled-worker-tick.md @@ -0,0 +1,142 @@ +--- +id: WARDEN-WP-0021 +type: workplan +title: "Enable the scheduled worker tick — conservative inbox triage, unattended" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +planning_priority: high +planning_order: 21 +created: "2026-06-30" +updated: "2026-06-30" +state_hub_workstream_id: "8c487014-b630-4016-a4f0-31b971a473d2" +--- + +# WARDEN-WP-0021 — Enable the scheduled worker tick + +**Goal:** turn the WP-0020 conservative worker from *built-but-disabled* into a reliable, +unattended schedule — so ops-warden's State Hub inbox is auto-triaged into a digest of +**drafted replies** the operator reviews and approves, without anyone starting a session. +This is the payoff of WP-0020: it ends the cross-session relay toil. + +**Posture (unchanged):** schedule the **conservative** tier only — triage + draft, never +auto-send (Option A / build-stage decision `813899f9`). The four guardrails hold. Easy +kill switch is a requirement, not an afterthought (recoverability). + +**What "enabled" means here:** (1) the tick runs on a schedule and survives the failure +modes (hub/llm-connect down → graceful degrade), (2) the operator actually *sees* new +drafts, (3) the operator can *act* on a draft with one command, (4) it's trivial to stop. + +**Out of scope:** the full-auto (auto-send) path; flipping `policy.enabled`; moving the +worker off the workstation. + +**Depends on / relates to:** WP-0020 (the worker + `scripts/worker-tick.sh`); the State +Hub migration to railiance01 (`cust-wp-0011`/`0038`) may change `WARDEN_HUB_URL` later — +the tick already honors that env var. + +--- + +## Decisions to settle (first) + +- **Scheduler:** `systemd --user` timer (recommended — clean logs via `journalctl`, + `systemctl --user status`, built-in scheduling) vs. plain cron (simplest) vs. + activity-core (ecosystem-native durable trigger; heavier for build stage). Recommend the + systemd user timer; cron documented as the one-liner fallback. +- **Cadence:** every 15 min (default) — adjustable. +- **llm-connect reachability:** per-tick short-lived port-forward (current behaviour) with + rule-brain fallback, vs. a persistent forward. Recommend keeping the per-tick forward + + fallback for build stage (no standing process). + +--- + +## Tasks + +### T1 — Scheduler install + enablement + kill switch + +```task +id: WARDEN-WP-0021-T01 +status: done +priority: high +state_hub_task_id: "10451fe6-7fab-4ae0-8494-e6cfdfbcf8cf" +``` + +- [ ] `systemd --user` timer + service units (`ops-warden-worker.{service,timer}`) that run + `scripts/worker-tick.sh` on the chosen cadence, with `WARDEN_HUB_URL` / `WORKER_BRAIN` + from an env file. Install script + documented cron fallback one-liner. +- [ ] Concurrency is already guarded by the tick's `flock`; verify under the timer. +- [ ] **Kill switch:** `systemctl --user disable --now ops-warden-worker.timer` (and the + env-file `WORKER_ENABLED=0` short-circuit) — one command to stop, documented. + +### T2 — Scheduled-run robustness (graceful degradation) + +```task +id: WARDEN-WP-0021-T02 +status: done +priority: high +state_hub_task_id: "1f35f816-1af5-46ff-b48c-1715f3ae5784" +``` + +- [ ] Harden `worker-tick.sh` for unattended runs: bounded timeouts, hub-unreachable → + clean skip + log (no crash loop), llm-connect-unreachable → rule-brain fallback + (already present; verify), non-zero exit only on real faults. +- [ ] End-to-end verify a real timer-fired tick: new message → digest + progress note; + no new message → no-op; hub down → graceful skip. + +### T3 — Operator visibility (see new drafts) + +```task +id: WARDEN-WP-0021-T03 +status: done +priority: medium +state_hub_task_id: "3c7f6423-8db0-4bc6-b67d-078d9d929c6d" +``` + +- [ ] Surface new drafts beyond the file: desktop `notify-send` on new digest (when a + display is present) and/or keep the hub progress note as the durable signal. +- [ ] `warden worker status` — last run time, pending-draft count, digest path, timer state. + +### T4 — Review→send loop (`warden worker approve`) + +```task +id: WARDEN-WP-0021-T04 +status: done +priority: high +state_hub_task_id: "dabc9fc0-abb1-4e9d-b87e-5f0c5950693c" +``` + +- [ ] Persist structured drafts during the tick (`state_dir/worker-drafts.json`: + message_id → to_agent, subject, drafted body, thread_id — no secret material). +- [ ] `warden worker approve [--edit]` — send the reviewed draft as the + caller's reply + mark read; `warden worker drafts` to list pending. This is what makes + the scheduled digest *actionable* in one command instead of hand-composing. + +### T5 — Runbook + SCOPE + +```task +id: WARDEN-WP-0021-T05 +status: done +priority: medium +state_hub_task_id: "9915da96-1b33-4d0f-b752-408ea8d43333" +``` + +- [ ] `wiki/playbooks/scheduled-worker.md` — enable/disable, cadence, the approve workflow, + failure modes, and the build-stage posture (conservative only). SCOPE note. + +--- + +## Acceptance + +- A `systemd --user` timer (or cron) runs the conservative tick unattended; one command + disables it. +- A timer-fired tick triages new messages into a digest + progress note and degrades + gracefully when the hub or llm-connect is down. +- The operator is notified of new drafts and can send a reviewed draft with + `warden worker approve `. +- Still conservative: nothing is auto-sent; no secret value is read, sent, or logged. + +## See also + +- `WARDEN-WP-0020` (the worker + `scripts/worker-tick.sh`), build-stage decision `813899f9` +- `cust-wp-0011`/`cust-wp-0038` (State Hub → railiance01; future `WARDEN_HUB_URL`) diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0022-audit-trail-and-activity.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0022-audit-trail-and-activity.md new file mode 100644 index 00000000..63171f58 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0022-audit-trail-and-activity.md @@ -0,0 +1,119 @@ +--- +id: WARDEN-WP-0022 +type: workplan +title: "Audit trail + `warden activity` — one place to see what ops-warden did" +domain: infotech +repo: ops-warden +status: finished +owner: claude +topic_slug: custodian +planning_priority: high +planning_order: 22 +created: "2026-07-01" +updated: "2026-07-01" +state_hub_workstream_id: "fc8afa28-68a7-4250-a19e-9754829f0cd5" +--- + +# WARDEN-WP-0022 — Audit trail + `warden activity` + +**Problem:** ops-warden's actions are recorded in scattered places — `signatures.log` +`access-audit.log`, the systemd journal (worker ticks), and +State Hub progress notes (the narrative). There is **no single, structured audit trail** +and no one command to answer *"what did ops-warden do in the last N days?"*. For a security +steward, a coherent, metadata-only audit record is table stakes. + +**Goal:** a unified, append-only audit log that captures **every** ops-warden action with a +common shape (never a secret value), and a single `warden activity` command to read it. + +**Non-negotiable (this is a security tool's audit):** the audit record holds **metadata +only** — actor/subject, action, target/path id, decision id, TTL, outcome, timestamp — and +**never** a token, key, cert body, or other secret. A secret-material guard rejects any +event field that looks like a value (mirrors the catalog `_assert_no_secret_material`). + +**Posture:** read/append-only, in-boundary (local logs + optional hub read). Tamper-evident +hash-chaining is noted as an optional hardening for when the ecosystem reaches testing. + +**Relates to:** WP-0014 (`access-audit.log`), the SSH lane (`signatures.log`), WP-0020/0021 +(the worker). Linger is now enabled (worker survives logout); full logged-out value also +needs the State Hub + tunnels to be login-independent (State Hub → railiance01, +`cust-wp-0011`). + +--- + +## Tasks + +### T1 — Unified audit event log + +```task +id: WARDEN-WP-0022-T01 +status: done +priority: high +state_hub_task_id: "7f8f768a-4c62-4096-bad8-912cea0f35a7" +``` + +- [x] `src/warden/audit.py`: append-only JSONL at `state_dir/audit.jsonl`. Common event + schema — `ts`, `kind` (`sign`|`access`|`worker`), `action`, `subject`, `target`, + `decision_id`, `outcome`, `source`. `record_event(**meta)` with a secret-material + guard (reject token prefixes / high-entropy runs) so no value can ever land here. + `read_events(*, since, kinds)` for the reader. +- [x] Log rotation / bound (size or age) so it stays manageable. + +### T2 — Instrument the actions + +```task +id: WARDEN-WP-0022-T02 +status: done +priority: high +state_hub_task_id: "e7ae4037-ca79-4557-81f0-bfb8478ff647" +``` + +- [x] Emit an audit event from each ops-warden action: `warden sign` (cert issued — + actor, type, ttl, backend, policy_decision_id), `warden access --fetch/--exec` + (proxy — need id, owner, decision id), and the worker (`approve` → reply sent to X; + tick → triage summary N/drafted/escalated). Fold the existing `signatures.log` / + `access-audit.log` in as sources (keep back-compat; don't drop a record). +- [x] Assert no secret value reaches the audit in any path (tests). + +### T3 — `warden activity` command + +```task +id: WARDEN-WP-0022-T03 +status: done +priority: high +state_hub_task_id: "4439bdd8-1461-47df-8b0b-048df7384a68" +``` + +- [x] `warden activity [--days N] [--kind sign|access|worker] [--json] [--hub]` — a single + chronological view merging the audit log (and, for back-compat, `signatures.log` / + `access-audit.log`); `--hub` also pulls recent ops-warden State Hub progress notes for + the narrative. Human table by default; stable `--json` for agents. + +### T4 — Tests, runbook, SCOPE + +```task +id: WARDEN-WP-0022-T04 +status: done +priority: medium +state_hub_task_id: "bdfb8703-7a79-43e7-913b-19d61722f164" +``` + +- [x] Tests: audit append/read/rotation, the secret-material guard rejects values, the + instrumented actions emit events, `warden activity` filtering + `--json` shape. +- [x] `wiki/AuditTrail.md` (what's recorded, the no-secret guarantee, how to query, the + linger + login-independence note). SCOPE entry. + +--- + +## Acceptance + +- Every ops-warden action (sign, access proxy, worker send/tick) appends a metadata-only + audit event; the secret-material guard is proven to reject values. +- `warden activity --days 3` answers "what did ops-warden do" in one command; `--json` + gives agents a stable shape. +- No secret value appears in the audit log, ever. + +## See also + +- `WARDEN-WP-0014` (`access-audit.log`), `WARDEN-WP-0020`/`0021` (the worker) +- `wiki/OperatorAccessAssist.md` (the metadata-only audit principle) +- `wiki/AuditTrail.md` \ No newline at end of file diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md new file mode 100644 index 00000000..99278d60 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0023-intent-scope-alignment-closeout.md @@ -0,0 +1,222 @@ +--- +id: WARDEN-WP-0023 +type: workplan +title: "INTENT–SCOPE Alignment Closeout" +domain: infotech +repo: ops-warden +status: finished +owner: codex +topic_slug: custodian +planning_priority: high +planning_order: 23 +created: "2026-07-01" +updated: "2026-07-01" +depends_on_workplans: + - WARDEN-WP-0022 +state_hub_workstream_id: "7bad1ec4-a7c2-4980-b8f9-49a7f5408574" +--- + +# WARDEN-WP-0023 — INTENT–SCOPE Alignment Closeout + +## Goal + +Close the July 2026 INTENT↔SCOPE gaps that ops-warden can address directly: sync +aspirational docs with shipped capabilities, coordinate the remaining production +integration blockers (flex-auth flip, ops-bridge cutover), improve daily operator +UX for broker-backed signing, and establish a repeatable catalog promotion cadence. + +Audit implementation stays in **WARDEN-WP-0022**; this workplan sequences and +surrounds it. + +**Assessment:** `history/2026-07-01-intent-scope-gap-analysis.md` + +## Boundary + +- ops-warden does **not** deploy flex-auth, flip ops-bridge tunnels, or implement + the credential broker — it documents, coordinates, and routes. +- Production cutover evidence is captured here; execution remains with owning repos. + +--- + +## Tasks + +### T01 — Persist gap analysis + +```task +id: WARDEN-WP-0023-T01 +status: done +priority: high +state_hub_task_id: "52485c90-87fe-40b1-9db5-a51ebb957dd5" +``` + +Write and link `history/2026-07-01-intent-scope-gap-analysis.md` with success +criteria matrix, mission pillars, prioritized gaps, and workplan recommendation. + +Acceptance: + +- History file exists and is referenced from SCOPE and this workplan. +- State Hub progress note logged for the assessment. + +**2026-07-01:** Assessment written at +`history/2026-07-01-intent-scope-gap-analysis.md`. + +### T02 — Refresh INTENT.md + +```task +id: WARDEN-WP-0023-T02 +status: done +priority: high +state_hub_task_id: "9a9b3631-8948-45af-ace1-c19ee74ace4d" +``` + +Update `INTENT.md` so the aspirational doc reflects shipped reality without +becoming a second SCOPE: + +- Mission pillar #2: assist layer (`warden access`) and owner-native exec routing + (secrets-engine, railiance-platform credential broker). +- NetKingdom literacy table: add secrets-engine and credential broker rows. +- Credential flow diagram: broker vs secrets-engine vs OpenBao proxy vs SSH issue. +- flex-auth: caller-side policy gate shipped; production flip external (FLEX-WP-0007). +- Workload posture stewardship and coordination worker as steward capabilities. +- Evolution notes pointer to July gap analysis. + +Acceptance: + +- INTENT still describes direction, not implementation inventory. +- No contradiction with SCOPE 2026-07-01 boundary (ops-warden does not mint tokens). + +**2026-07-01:** INTENT.md updated. + +### T03 — Production integration coordination pack + +```task +id: WARDEN-WP-0023-T03 +status: done +priority: high +state_hub_task_id: "26f23798-494b-45fc-baa8-af27bdffa038" +``` + +Prepare operator/coordination artifacts for the two P1 external gaps: + +1. **flex-auth production flip** — checklist in `wiki/PolicyGatedSigning.md` or a + short playbook section: prerequisites, `policy.enabled: true` steps, rollback, + joint smoke with `credential-exec-ops-warden-smoke`, FLEX-WP-0007 cross-link. +2. **ops-bridge live cutover** — evidence template (non-secret): tunnel id, readiness + gate output, first warden-signed connection timestamp, pointer to + `wiki/playbooks/ops-bridge-tunnel-cert.md`. + +Optionally post State Hub coordination messages to `flex-auth` and `ops-bridge` +agents with pointers only (no secrets). + +Acceptance: + +- A human operator can run the flip/cutover checklists without re-deriving steps. +- Evidence fields are defined; completion is recorded via State Hub progress when done. + +**2026-07-01:** Rollback section added to `wiki/PolicyGatedSigning.md`; live cutover +evidence template added to `wiki/playbooks/ops-bridge-tunnel-cert.md`. + +### T04 — `warden sign` broker hint when `VAULT_TOKEN` unset + +```task +id: WARDEN-WP-0023-T04 +status: done +priority: medium +state_hub_task_id: "85e324f9-273d-4740-a202-9c4e8fb122ae" +``` + +When `backend: vault` and `VAULT_TOKEN` (or configured `token_env`) is missing, +emit a structured hint pointing at `ops-warden-warden-sign-token` and the +`railiance-platform` `credential exec` command — not a generic error only. + +Acceptance: + +- Unit test covers the hint text (catalog id + exec shape, no secret placeholders). +- Manual `export VAULT_TOKEN` remains documented as fallback in playbooks. + +**2026-07-01:** `src/warden/vault_hints.py` + `tests/test_vault.py`. + +### T05 — Catalog draft-lane promotion checklist + +```task +id: WARDEN-WP-0023-T05 +status: done +priority: medium +state_hub_task_id: "82608692-2845-41e1-a498-90ed53780748" +``` + +Document the promotion criteria for `registry/routing/catalog.yaml` entries from +`draft` → `active` (concrete path, owner confirmation, `resolvable` or +`exec_owner` native exec, playbook with `#worker-checklist`, tests). Add to +`wiki/CredentialRouting.md` or a short `wiki/playbooks/catalog-lane-promotion.md`. + +If any draft lane has owner-confirmed concrete paths during this WP, promote one +as a worked example (issue-core, OpenRouter, STS, or database — whichever is ready). + +Acceptance: + +- Checklist is reviewable by humans and agents. +- At least one promotion example or explicit “none ready yet” note in the workplan. + +**2026-07-01:** `wiki/playbooks/catalog-lane-promotion.md` — worked example +`ops-warden-warden-sign-token`; four draft lanes explicitly not ready. + +### T06 — SCOPE and workplan consistency + +```task +id: WARDEN-WP-0023-T06 +status: done +priority: medium +state_hub_task_id: "79ca7b9a-554e-4952-9393-a29b100f6190" +``` + +Fix SCOPE inconsistencies noted in the July assessment: + +- “All workplans finished” → acknowledge WP-0022/0023 as active/ready. +- Latest gap analysis pointer → `history/2026-07-01-intent-scope-gap-analysis.md`. +- Link WP-0023 from Getting Oriented. + +Acceptance: + +- SCOPE and gap analysis cross-link correctly. +- Uncommitted SCOPE edits from 2026-07-01 broker routing are committed with this WP. + +**2026-07-01:** SCOPE.md updated. + +### T07 — Sequence WP-0022 audit implementation + +```task +id: WARDEN-WP-0023-T07 +status: done +priority: high +state_hub_task_id: "1f3b3b33-974e-49bf-be4a-9d50b702c2a4" +``` + +Promote `WARDEN-WP-0022` from `proposed` to `ready` (or `active` when T02–T06 allow +bandwidth). Ensure dependency is explicit; log State Hub note that WP-0022 is the +implementation vehicle for INTENT pillar 6 (observable gatekeeping). + +Acceptance: + +- WP-0022 frontmatter status updated. +- WP-0023 `depends_on_workplans` includes WP-0022. +- Hub consistency run syncs both workplans. + +**2026-07-01:** WP-0022 implemented and both workplans marked `finished`. + +--- + +## Exit criteria + +- July gap analysis is the canonical reassessment (linked from SCOPE). +- INTENT.md no longer understates assist, posture, worker, or owner-native exec. +- Production integration checklists exist for flex-auth flip and ops-bridge cutover. +- `warden sign` surfaces the broker path when vault backend lacks a token. +- Catalog promotion cadence is documented; WP-0022 is queued for implementation. + +## See also + +- `history/2026-07-01-intent-scope-gap-analysis.md` +- `WARDEN-WP-0022-audit-trail-and-activity.md` +- `wiki/playbooks/ops-warden-warden-sign-token.md` +- `~/flex-auth/workplans/FLEX-WP-0007-ops-warden-policy-gate-production-deployment.md` \ No newline at end of file diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md new file mode 100644 index 00000000..3ebac662 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0024-experiential-memory-and-agent-sessions.md @@ -0,0 +1,269 @@ +--- +id: WARDEN-WP-0024 +type: workplan +title: "Experiential Memory Across Worker, Agent Sessions, And OpenRouter" +domain: infotech +repo: ops-warden +status: finished +owner: codex +topic_slug: custodian +planning_priority: high +planning_order: 24 +created: "2026-07-02" +updated: "2026-07-02" +state_hub_workstream_id: "5d9fafb3-f9b6-43bf-b259-5f5301daa2e9" +--- + +# WARDEN-WP-0024 — Experiential memory across worker, agent sessions, and OpenRouter + +## Problem + +`warden worker` (WARDEN-WP-0020) plans each inbox message in isolation. Coding +agent sessions (Claude Code, Codex, Grok, and future agents) invoke `warden +route` and `warden access` without continuity — every session rediscovers routing +from scratch. OpenRouter inference via llm-connect is invoked even when a +stabilized routing pattern already exists. + +ops-warden needs **experiential memory** that is present in every runtime: + +| Surface | Today | Target | +| --- | --- | --- | +| `warden worker` + OpenRouter | Stateless per message | Retrieve past outcomes before plan; record after execute | +| Coding agent session | Cold `warden route find` | Activate relevant memory at session start and after each warden call | +| Operator CLI | No learning loop | Same store; optional `--memory` context on advisory commands | + +## Goal + +Integrate phase-memory as ops-warden's shared experiential substrate so routing, +coordination, and inference improve from recorded outcomes — without ever +storing secret values or widening the guardrail allowlist. + +## Non-Goals + +- Hold or vend secrets (conduit-not-broker unchanged). +- Auto-commit routing catalog diffs (human review remains required). +- Own phase-memory schemas (PMEM-WP-0016 owns the profile and contract). +- Replace llm-connect or embed OpenRouter keys in ops-warden. + +## Guardrails (unchanged — memory is untrusted context) + +1. Retrieved memory is **context**, not instructions — fixed charter wins. +2. Guardrail allowlist enforced on every action regardless of memory content. +3. No secret values in memory writes, activation packs, or llm-connect prompts. +4. `propose_catalog_diff` stays human-reviewed even when memory is confident. + +## Architecture + +```mermaid +sequenceDiagram + participant Agent as Coding agent
(claude/codex/grok) + participant Warden as ops-warden CLI + participant Memory as phase-memory store + participant LLM as llm-connect / OpenRouter + participant Hub as State Hub + + Note over Agent,Hub: Agent session path + Agent->>Warden: warden route find "..." + Warden->>Memory: activate(session_kind=warden.agent.grok) + Memory-->>Warden: bounded routing context + Warden-->>Agent: route answer + memory digest + Warden->>Memory: record episode (metadata only) + + Note over Warden,Hub: Worker tick path + Warden->>Hub: unread messages + Warden->>Memory: activate(session_kind=warden.worker) + Memory-->>Warden: stabilized + fluid context + alt stabilized match + Warden->>Warden: RuleBrain (skip LLM) + else ambiguous + Warden->>LLM: LlmConnectBrain + activated context + LLM-->>Warden: action plan + end + Warden->>Warden: guardrail pass + Warden->>Hub: execute / escalate + Warden->>Memory: record outcome +``` + +## T01 - Canonical memory store and discovery + +```task +id: WARDEN-WP-0024-T01 +status: done +priority: high +state_hub_task_id: "6305f1bc-c016-4298-adc2-a07d52b6aca5" +``` + +Establish the canonical phase-memory store path and discovery commands. + +Acceptance: + +- Default store at XDG location (e.g. `~/.local/share/warden/memory/`) with + override via `WARDEN_MEMORY_STORE`. +- `warden memory status` reports store path, schema version, episode counts by + `session_kind`, and last activation timestamp — no secret fields. +- Store initializes idempotently; missing phase-memory dependency fails with a + clear install pointer, not a traceback. +- Tests cover default path, override, and first-run initialization. + +## T02 - Session recording hooks in CLI commands + +```task +id: WARDEN-WP-0024-T02 +status: done +priority: high +state_hub_task_id: "242a4d9a-5375-4df8-8d43-063b0491d202" +``` + +Record metadata-only episodes when `route`, `access`, and `sign` complete. + +Acceptance: + +- Each command writes a phase-memory event with `session_kind` derived from + environment: `WARDEN_AGENT_ID` (claude|codex|grok|...) when set, else + `warden.operator`. +- Recorded fields match `PMEM-WP-0016-T03` schema; secret patterns are rejected. +- Recording is opt-out via `WARDEN_MEMORY=0` for air-gapped/debug use. +- `warden activity` and phase-memory audit export remain consistent (no + duplicate secret-bearing logs). + +## T03 - Memory-aware worker tick + +```task +id: WARDEN-WP-0024-T03 +status: done +priority: high +state_hub_task_id: "176fcae1-e4e5-481f-9a83-e9a7000fac1a" +``` + +Retrieve coordination memory before `Brain.plan` and record outcomes after execute. + +Acceptance: + +- `warden worker run` activates memory with `session_kind=warden.worker` before + planning each message. +- Activated context is passed to `LlmConnectBrain` as bounded, redacted context + — never replacing the fixed charter. +- Post-execute hook records: message id, proposed actions, guardrail outcome, + escalation reason, and route ids referenced. +- Worker tick with empty store degrades gracefully (current behavior). + +## T04 - Agent session activation helper + +```task +id: WARDEN-WP-0024-T04 +status: done +priority: high +state_hub_task_id: "16501557-6cde-44ea-bc6f-1726cb7ec070" +``` + +Expose memory activation for coding agent sessions across Claude, Codex, Grok, and +future agents. + +Acceptance: + +- `warden memory activate [--agent ] [--json]` returns a bounded activation + package for session orientation. +- Agent instructions (AGENTS.md template in consuming repos) document setting + `WARDEN_AGENT_ID` and calling `warden memory activate` at session start. +- Activation works without OpenRouter (local retrieval only). +- Tests cover agent ids: `claude`, `codex`, `grok`, and an unknown future id. + +## T05 - Cross-runtime continuity + +```task +id: WARDEN-WP-0024-T05 +status: done +priority: high +state_hub_task_id: "55ae679c-c08f-4afd-8646-9f5f3019f86e" +``` + +Ensure worker ticks see agent session episodes and vice versa. + +Acceptance: + +- Agent session routing outcomes appear in worker activation within the same + store without manual export/import. +- Worker escalation outcomes are visible to subsequent agent session activations. +- Continuity is verified by an integration test: agent session write → worker + read → agent session read round-trip. +- Episode retention follows the ops-warden profile compaction rules from + PMEM-WP-0016. + +## T06 - OpenRouter efficiency layer + +```task +id: WARDEN-WP-0024-T06 +status: done +priority: medium +state_hub_task_id: "fc2dffcf-7184-4f3d-8653-d26dc18a9afc" +``` + +Skip or downgrade OpenRouter calls when stabilized memory provides a verified match. + +Acceptance: + +- When stabilized memory contains a verified route match for the message need, + `RuleBrain` handles the plan and llm-connect is not called. +- Ambiguous cases still use `LlmConnectBrain`; memory context is additive only. +- Efficiency metrics (llm_calls_avoided, rule_brain_resolution_rate) are + recorded for evaluation scenarios in PMEM-WP-0016. +- Dry-run mode reports whether LLM would have been skipped and why. + +## T07 - Operator and agent documentation + +```task +id: WARDEN-WP-0024-T07 +status: done +priority: medium +state_hub_task_id: "ca2aaf23-833f-49a6-a49b-a0b659208f5f" +``` + +Document the memory workflow for operators and coding agents. + +Acceptance: + +- Wiki page covers: store location, session kinds, agent env vars, memory + activation at session start, and interaction with OpenRouter inference. +- ops-warden AGENTS.md and the state-hub agent template include memory + orientation steps for Claude, Codex, and Grok sessions. +- Credential routing doc cross-links PMEM-WP-0016 contract; anti-patterns + updated (no secret values in memory store). +- Scheduled worker playbook notes memory retention and evaluation gate checks. + +## Acceptance Criteria + +- phase-memory is present and useful in all three runtime surfaces (worker, + agent session, operator CLI) through one canonical store. +- OpenRouter inference cost decreases when stabilized routing memory matches. +- Cross-runtime continuity is tested and regression-gated. +- Security invariants (no-secret, allowlist, conduit-not-broker) are unchanged. + +## Dependencies + +- `PMEM-WP-0016` (phase-memory) — profile, event schema, activation pack, + evaluation scenarios. **Implement contract (T01–T03) before WARDEN T03–T05.** +- `WARDEN-WP-0020` — worker brain and guardrails (finished). +- `WARDEN-WP-0022` — audit trail for correlation (finished). +- llm-connect / OpenRouter — required only for T06 live efficiency measurement; + T01–T05 work offline. + +## Suggested Implementation Order + +1. PMEM-WP-0016 T01–T03 (profile + contract + event schema) +2. WARDEN-WP-0024 T01–T02 (store + CLI recording) +3. PMEM-WP-0016 T04 (activation pack) +4. WARDEN-WP-0024 T03–T05 (worker + agent activation + continuity) +5. PMEM-WP-0016 T05–T06 + WARDEN-WP-0024 T06–T07 (evaluation + docs) + +## Closure Review + +Integrated phase-memory across all ops-warden runtime surfaces: + +- `warden memory status` and `warden memory activate` with canonical XDG store. +- CLI recording hooks on `route find`, `access`, and `sign` (opt-out via + `WARDEN_MEMORY=0`). +- Memory-aware worker planning with stabilized-route RuleBrain short-circuit + and LlmConnectBrain context injection. +- Cross-runtime continuity verified in tests (agent session → worker activation). +- `wiki/OpsWardenMemory.md` and AGENTS.md session orientation for Claude, + Codex, Grok, and future agents. \ No newline at end of file diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md new file mode 100644 index 00000000..5c4e7724 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0025-forgejo-admin-api-token-lane.md @@ -0,0 +1,118 @@ +--- +id: WARDEN-WP-0025 +type: workplan +title: "Forgejo admin PAT OpenBao lane (CCR-2026-0006)" +domain: infotech +repo: ops-warden +status: finished +owner: grok +topic_slug: custodian +planning_priority: high +planning_order: 25 +created: "2026-07-12" +updated: "2026-07-13" +state_hub_workstream_id: "70c11222-d8e7-5936-99f7-7d626a4a5deb" +--- + +# WARDEN-WP-0025 — Forgejo admin PAT OpenBao lane + +**Trigger:** the-custodian CCR request (msg `54125f84`) — establish OpenBao custody +for the Forgejo site-admin PAT at `platform/workloads/forgejo/forgejo-admin`. +Drivers: `ACTIVITY-WP-0020` weekly package prune and railiance-apps/platform tools +still using `/tmp/forgejo-tegwick-api-token` or `FORGEJO_ADMIN_TOKEN`. + +**Boundary:** ops-warden holds no PAT; workstation OIDC fetch mirrors +`railiance-backup-offsite-lane` (CCR-2026-0004). Distinct from `forgejo-mailer` +(SMTP via ESO). Phase 1: no cluster ExternalSecret. + +**Depends on:** platform-operator approval of CCR-2026-0006; attended PAT mint. + +--- + +## Tasks + +### T1 — Draft CCR + policy metadata + +```task +id: WARDEN-WP-0025-T01 +status: done +priority: high +state_hub_task_id: "2c288bf0-b39c-5f5b-ad25-eed3da826dc3" +``` + +- [x] `CCR-2026-0006-forgejo-admin-api-token-lane.yaml` (`status: proposed`) +- [x] `openbao/policies/workload-kv-read-forgejo-admin.hcl` +- [x] `docs/workload-kv-access-lanes.md` section + +### T2 — ops-warden catalog + playbook + +```task +id: WARDEN-WP-0025-T02 +status: done +priority: high +state_hub_task_id: "01b81595-f9e5-5746-b0dd-2075189cb00e" +``` + +- [x] Catalog entry `forgejo-admin-api-token` (`status: draft`) +- [x] `wiki/playbooks/forgejo-admin-api-token.md` + +### T3 — Platform-operator approval + metadata apply + +```task +id: WARDEN-WP-0025-T03 +status: done +priority: high +state_hub_task_id: "279b74d7-3240-5ca0-897d-b1ddffd23c4e" +``` + +- [x] CCR approved by platform-operator (bernd.worsch, 2026-07-12) +- [x] `scripts/credential-change.py applier-dry-run CCR-2026-0006` +- [x] Policy `workload-kv-read-forgejo-admin` + OIDC role `forgejo-admin-workload-kv-read` applied on `bao.coulomb.social` +- [x] Non-secret `delegated_metadata_apply` evidence on CCR + +### T4 — Attended PAT provision + verification + +```task +id: WARDEN-WP-0025-T04 +status: done +priority: high +state_hub_task_id: "4e21232c-62a1-5115-acce-edfbcfa84e48" +``` + +- [x] Mint PAT as Forgejo user `tegwick` (attended, 2026-07-12) +- [x] Stored at `platform/workloads/forgejo/forgejo-admin`, field `API_TOKEN` + (initial provision used field `Token`; re-stored as `API_TOKEN` 2026-07-13 to + match CCR/catalog/playbook `fetch_command`) +- [x] Positive fetch verified 2026-07-13 — `bao kv get -field=API_TOKEN …` returns + non-empty; PAT valid against `forgejo.coulomb.social` (`/api/v1/user` → + `login=tegwick`, `is_admin=true`) +- [x] Negative default-policy denial recorded on CCR +- [x] Promoted catalog `forgejo-admin-api-token` to `active` (`resolvable: true`) + +### T5 — Notify downstream consumers + +```task +id: WARDEN-WP-0025-T05 +status: done +priority: medium +state_hub_task_id: "f8c7c70b-b9b6-5980-a25b-7f11033b81a2" +``` + +- [x] Ack the-custodian with CCR id + catalog id (no secret values) — msg 949e8ed1, 2026-07-13 +- [x] Signal railiance-platform / activity-core / railiance-apps to wire `load_token()` + OpenBao paths — msgs 5be8e500 / 9ed1af98 / 2e47b6e5, 2026-07-13 + +--- + +## Acceptance + +- CCR-2026-0006 approved, policy + OIDC role live, PAT in OpenBao +- `warden route find "forgejo admin pat"` → `forgejo-admin-api-token` +- No PAT in Git, State Hub, workplans, logs, or chat +- Workstation file drop retired as steady-state path after downstream wiring + +## See also + +- `railiance-platform/credential-change-requests/CCR-2026-0006-forgejo-admin-api-token-lane.yaml` +- `activity-core/workplans/ACTIVITY-WP-0020-weekly-forgejo-package-prune.md` +- Custodian message `54125f84-e9df-4fa0-9309-7370633a20d3` \ No newline at end of file diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md new file mode 100644 index 00000000..309f7718 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0026-credential-disclosure-hygiene.md @@ -0,0 +1,261 @@ +--- +id: WARDEN-WP-0026 +type: workplan +title: "Credential disclosure hygiene + rotation guidance (Strand A)" +domain: infotech +repo: ops-warden +status: finished +owner: codex +topic_slug: custodian +planning_priority: high +planning_order: 26 +created: "2026-07-16" +updated: "2026-07-16" +state_hub_workstream_id: "331c7620-bd34-5acd-9135-591985b568e5" +--- + +# Credential disclosure hygiene + rotation guidance (Strand A) + +## Origin + +Follow-up to a credential-disclosure incident on 2026-07-16 while verifying +`CCR-2026-0004` (railiance offsite backup lane). A negative policy test was run +as `BAO_TOKEN=$(bao token create -policy=default -field=token) bao kv get `. +The `token create` was denied (workload role lacks it), `BAO_TOKEN` fell back to +the caller's privileged login token, and `bao kv get` printed all three field +values (`NC_WEBDAV_TOKEN`, `NC_WEBDAV_URL`, `AGE_PRIVATE_KEY`) into an agent +session transcript. Buildup mode — exposure accepted, learnings captured. + +**Root causes:** (1) a deny-test that read the secret *data* path at all; +(2) a silent privileged-token fallback; (3) the read landed in a logged context. + +This is **Strand A** (disclosure hygiene). Tamper-resistant policy governance and +one-command mass rotation/lockdown (Strand B) are deliberately **deferred** — see +"Out of scope" below. + +## Goal + +Make accidental secret disclosure structurally hard, and make ops-warden the +authoritative source for **how each secret is rotated or re-established** — +advisory knowledge held next to the routing catalog, not in OpenBao. + +## Design guardrails (binding on acceptance) + +- **Verification never reads secret data.** Use `bao token capabilities` (allow/deny) + instead of `kv get` for positive/negative lane tests. +- **Masking is defense-in-depth, not a boundary.** Any display filter is a wrapper + convenience; raw `bao kv get ` remains the documented anti-pattern. +- **Rotation guidance covers both `rotate` (provider re-mint) and `re-establish` + (regenerate from source, e.g. a new age keypair).** +- **Coverage gate:** every `active` (and newly promoted) catalog lane must carry + rotation guidance, enforced by a scorecard check. + +## Out of scope (Strand B — deferred, not built here) + +- Executable one-command rotation of all tainted secrets. +- Graded lockdown / break-glass seal + re-key with a designed trust-root. +- Policy time-travel / policy-as-code reconcile-to-past-commit. (Drift *detection* + may be revisited separately; the reconcile machinery is out.) + +## Task: Capabilities-based lane verification + +```task +id: WARDEN-WP-0026-T01 +status: done +priority: high +state_hub_task_id: "1cb22a40-b7c6-560a-a805-7766a5786dcc" +``` + +Done 2026-07-16: canonical capabilities-safe verification pattern added to +`wiki/playbooks/catalog-lane-promotion.md` (fleet promotion checklist criterion 8 ++ dedicated section), and applied to the `railiance-backup-offsite-lane` and +`forgejo-admin-api-token` playbook verify sections. Positive/negative proven via +`bao token capabilities` against the KV v2 data path — never `bao kv get`; the +denied `default` token-create is documented as a pass, not a fallback trigger. +Live CCR-2026-0004 re-verify carried under T07. + +Replace secret-reading verify flows with capability checks. Positive test: +approved identity has `read` on the KV data path. Negative test: a `default`-only +identity is `deny`. Both via `bao token capabilities ` (or the +self endpoint) — **never** `bao kv get`. Update +`wiki/playbooks/*lane*.md` verify sections and any lane-verify helper. + +**Done when:** the documented and tooled verify path for any lane proves +allow/deny without reading a secret value, and the CCR-2026-0004 re-verify uses +it (see T07). + +## Task: Safe access transport (no stdout values) + +```task +id: WARDEN-WP-0026-T02 +status: done +priority: high +state_hub_task_id: "bcb7da96-0a28-5484-bf3e-06e97acf5873" +``` + +Done 2026-07-16: sanctioned transports added to `warden access` so a value never +lands on stdout — `--out FILE` (mode-0600 file), `--exec` (child env, pre-existing), +and `--wrap` (single-use OpenBao response-wrapping token via `bao kv get -wrap-ttl`, +caller `bao unwrap`s in their own context). Raw `--fetch` to a non-TTY stdout is now +refused (exit 6) unless `--unsafe-stdout` is passed (interactive human only). +`proxy_fetch_to_file`/`proxy_fetch_wrapped`/`build_wrapped_fetch` in `proxy.py`; tests +in `tests/test_proxy.py`. Anti-pattern + transports documented fleet-wide in +`.claude/rules/credential-routing.md` and `wiki/OperatorAccessAssist.md` (G2). + +`warden access` / fetch paths must emit values only into an env var, a file, or +a **response-wrapping token** (`bao … -wrap-ttl`), never a stdout table. Add a +wrapping-token transport for values that must move between processes. Record in +canon (`credential-routing` rules) that raw `bao kv get ` (full table) is +the anti-pattern; the sanctioned path is `warden access … --field ` into env. + +**Done when:** the sanctioned fetch path cannot print a value to a terminal, and +the anti-pattern is documented fleet-wide. + +## Task: Masking display filter (defense-in-depth) + +```task +id: WARDEN-WP-0026-T03 +status: done +priority: medium +state_hub_task_id: "d90b0628-fa1d-527d-99c3-28a7ed933e52" +``` + +Done 2026-07-16: `warden/mask.py` (`fingerprint`/`mask_value` — presence, length, +8-char sha256 prefix; never the value) + `proxy_fetch_fingerprint` and a +`warden access … --fingerprint` masked status view (bypasses the stdout guard +because it emits no value). Lets two parties compare sha256 prefixes to confirm a +shared value (e.g. rotation landed) without disclosure. Explicitly labelled +defense-in-depth — raw `bao kv get` bypasses it — in `wiki/OperatorAccessAssist.md` +and the module docstring. Tests in `tests/test_mask.py` + a CLI test in +`tests/test_proxy.py`. + +In the warden wrapper, mask KV data values by default when any listing/status is +shown — display presence, length, and a short non-reversible hash instead of the +value. Explicitly labelled as defense-in-depth (raw bao bypasses it). + +**Done when:** wrapper-mediated output never shows a raw KV value, with the +limitation documented. + +## Task: Agent read-boundary on high-risk lanes + +```task +id: WARDEN-WP-0026-T04 +status: done +priority: high +state_hub_task_id: "827fa67d-5f69-5fac-bdce-9903b1b909fb" +``` + +Done 2026-07-16: Catalog `risk: high|standard` (default standard). High-risk: +`railiance-backup-offsite-lane`, `forgejo-admin-api-token`, `openrouter-llm-connect`. +OpenBao policy `agent-high-risk-boundary` (railiance-platform + live write) grants +metadata/capabilities only and **denies** data-read on those paths — verified with +minted agent token (data=deny, metadata=read). `warden access` with +`WARDEN_AGENT_ID` set refuses raw value stream on high-risk lanes (exit 7); +`--out`/`--exec`/`--wrap`/`--fingerprint` remain. Playbook: +`wiki/playbooks/agent-read-boundary.md`. Tests in `tests/test_routing.py` + +`tests/test_proxy.py`. + +**Repo: railiance-platform (OpenBao policy/roles).** Agent identities receive +`capabilities`/metadata and wrapping tokens on high-risk lanes, not raw data +reads. Align with the existing credential-routing rule ("ops-warden proxies reads +as the caller and must not retain values"). Classify which lanes are high-risk +(recovery escrow like `AGE_PRIVATE_KEY`, upload tokens). + +**Done when:** at least the high-risk lanes deny raw data reads to agent roles +while still allowing wrapped/proxied access, verified via capabilities checks. + +## Task: EXPOSED taint convention + +```task +id: WARDEN-WP-0026-T05 +status: done +priority: medium +state_hub_task_id: "09ef8727-31da-59ac-aac7-2d47924569fe" +``` + +Done 2026-07-16: Convention documented in `wiki/playbooks/exposed-taint.md` +(`exposed_at`, `exposed_version`, `exposed_reason`, `exposed_ref` on KV v2 +custom_metadata). First worked mark applied to +`platform/workloads/railiance/backup/offsite-lane` version 2 (disclosure +incident). `warden taint ` (+ `--json`) reports taint via metadata-only +`bao kv metadata get` — never secret data (`src/warden/taint.py`). Tests in +`tests/test_taint.py`. + +**Repo: railiance-platform (OpenBao) + ops-warden surface.** Establish a KV v2 +`custom_metadata` convention to mark a tainted secret: `exposed_at=` +and the affected `version`. Identify semi-automatic candidates from the OpenBao +audit log (reads from agent/shared contexts). `warden` surfaces taint status for +a lane (advisory; no auto-rotation here). + +**Done when:** a secret can be marked EXPOSED via a documented convention and +`warden` reports whether a lane is currently tainted. + +## Task: Rotation / re-establishment guidance registry + +```task +id: WARDEN-WP-0026-T06 +status: done +priority: high +state_hub_task_id: "a2e1544e-e501-57eb-a40e-9a2147cef12a" +``` + +Done 2026-07-16: `rotation:` block (method rotate|re-establish, ordered steps, +owner, automatable) added to the routing model/parser (`RotationGuide`, +`RouteEntry.rotation`, `vends_secret`), screened for secret material in a prose-safe +mode. `warden rotate-guide ` (human + `--json`) surfaces the guidance; `warden +route show --json` carries `has_rotation` + `rotation`. Coverage enforced by the new +`catalog_rotation_coverage` scorecard check (every active secret-vending lane must +have a block) and promotion checklist criterion 9. Rotation blocks authored for all +7 active vending lanes + the draft railiance-backup lane (re-establish example: age +keypair regen + re-encrypt). Tests in `tests/test_routing.py`. Also fixed a +pre-existing keyword collision (bare `npm` on the forgejo-admin lane → `forgejo-npm`) +so "npm token" routes to the generic lane again. + +Give every catalog lane **structured-but-advisory** renewal guidance, held in the +ops-warden registry (not in OpenBao). Add a `rotation:` block per catalog entry +capturing: `method` (rotate | re-establish), ordered `steps` (provider re-mint / +keygen / OpenBao write / re-encrypt-and-reupload where relevant), `owner`, and +`automatable` (bool, for future Strand-B). Surface via `warden rotate-guide ` +(and/or `warden route … --rotate`). Add a **scorecard coverage check**: every +`active` lane must have a `rotation:` block; flag any that don't. + +**Done when:** `warden rotate-guide ` returns actionable renewal steps for +every active lane, and the scorecard fails if any active lane lacks guidance. + +## Task: Incident lessons + first worked lane (CCR-2026-0004) + +```task +id: WARDEN-WP-0026-T07 +status: done +priority: medium +state_hub_task_id: "62d8286f-7954-52a8-bce6-6a16072e5246" +``` + +Done 2026-07-16: Lessons note present. Capabilities-safe live re-verify on +`bao.coulomb.social`: lane-policy token → `read` on data path; default + agent +boundary → `deny`; field keys present (no values printed). Catalog promoted +`draft`→`active`, `fetch_command` pinned to `NC_WEBDAV_TOKEN` (no placeholders) +so `resolvable: true`; `risk: high`; rotation guidance + EXPOSED taint on v2. +CCR-2026-0004 evidence + `access_frontdoor.resolvable: true` / `readiness: ready`. +Playbook + `wiki/CredentialRouting.md` updated. Operator may still rotate the +exposed values optionally (buildup) — not a promotion blocker. + +Write a short lessons-learned note (buildup context; exposure accepted; the three +root causes). Apply T01 + T06 to `CCR-2026-0004` as the first worked lane: +re-verify it the capabilities-safe way so it can finally promote to +`resolvable: true` (unblocking `RAILIANCE-WP-0015`), and ensure its `rotation:` +block (rotate Nextcloud token; re-establish age keypair + re-encrypt artifacts) +is present. **Rotation of the exposed values is the operator's optional call, not +a blocker** (buildup). + +**Done when:** the lessons note exists, CCR-2026-0004 has capabilities-based +verify + rotation guidance, and its promotion path is unblocked. + +## References + +- `CCR-2026-0004-railiance-backup-offsite-lane.yaml` (railiance-platform) +- `wiki/playbooks/railiance-backup-offsite-lane.md` +- `.claude/rules/credential-routing.md` (the-custodian, fleet-inlined) +- `RAILIANCE-WP-0015` (railiance-apps) — cnpg backup coverage, gated on CCR-2026-0004 +- Strand B (deferred): tamper-resistant governance, one-command rotation/lockdown, + policy time-travel — capture separately if/when justified. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0027-credential-governance-lockdown.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0027-credential-governance-lockdown.md new file mode 100644 index 00000000..c14e9c30 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0027-credential-governance-lockdown.md @@ -0,0 +1,303 @@ +--- +id: WARDEN-WP-0027 +type: workplan +title: "Tamper-resistant credential governance + mass rotation/lockdown (Strand B)" +domain: infotech +repo: ops-warden +status: blocked +flavor: implementation +owner: codex +topic_slug: custodian +planning_priority: medium +planning_order: 27 +created: "2026-07-16" +updated: "2026-10-03" +state_hub_workstream_id: "21528e8d-a049-523d-9ae1-da7a27cb8bbf" +--- + +# Tamper-resistant credential governance + mass rotation/lockdown (Strand B) + +## Origin + +Explicitly deferred from `WARDEN-WP-0026` (credential disclosure hygiene, Strand A). +WP-0026 "Out of scope" carves out the heavyweight governance machinery and directs +that it be "capture[d] separately if/when justified." This workplan is that capture. + +Strand A makes accidental disclosure structurally hard and gives every lane +**advisory** rotation guidance. Strand B is the **executable, tamper-resistant** +layer: turning that advisory guidance into one-command action and hardening policy +governance against silent drift or malicious change. + +## Status: blocked on T02 (reviewed 2026-09-28) + +Activated by the operator on 2026-08-22 after the second activation gate became +concrete. `RAILIANCE-WP-0024-T03` now requires an approved recovery window, +fresh encrypted Raft snapshot evidence, provider-console access, named abort +authority, and the live **2-of-3 Shamir quorum** before a coordinated reboot. +That is fleet policy requiring a designed break-glass path, not speculative +heavyweight machinery. + +Activation is deliberately narrow. No mass-disclosure incident triggers T01, +and no fleet policy currently mandates T03's signed policy-manifest reconcile. +Those tasks remain `cancel`; cancellation here continues to mean deferred, not +abandoned. T02 alone was activated; it now waits on a fresh attended drill. + +## Activation gate (promote to `ready` only when ≥1 holds) + +- A real disclosure incident requires rotating **more than a couple** of secrets at + once, making manual per-lane rotation (Strand A) too slow. +- Fleet policy for OpenBao mandates tamper-evident policy governance or a designed + break-glass path. +- Audit/compliance requires provable "reconcile policy to a known-good commit." + +## Goal + +Make credential response **executable and trustworthy at fleet scale**: one command +rotates or re-establishes a set of tainted secrets; policy changes are tamper-evident +and reconcilable to a known-good state; a graded lockdown / break-glass path exists +with an explicit trust-root. + +## Scope boundary (unchanged from Strand A) + +ops-warden still **custodies no secret values**. Strand B orchestrates the owner's +tools (OpenBao, provider re-mint, railiance-platform credential broker) as the +caller — it does not hold or vend secrets. Rotation execution runs the owner-native +path; ops-warden sequences and verifies it. + +## Task: Executable mass rotation driver + +```task +id: WARDEN-WP-0027-T01 +status: cancel +priority: high +state_hub_task_id: "b5691939-9d84-5115-9618-0f8839010d14" +``` + +Turn Strand A's per-lane `rotation:` guidance (WP-0026 T06) into an executable +driver: `warden rotate ` (single lane) and `warden rotate --tainted` (all lanes +marked EXPOSED per WP-0026 T05). Each step runs the owner-native command +(provider re-mint, `bao kv put`, re-encrypt+reupload for re-establish lanes) as the +caller, verifies via capabilities (never reads the value), and clears the +`exposed_at` taint on success. Dry-run first; idempotent; per-lane failure isolates. + +**Done when:** a tainted set of lanes can be rotated/re-established with one command, +each verified capabilities-safe, taint cleared only on success. + +**Depends on:** WP-0026 T05 (taint convention), T06 (rotation registry). + +## Task: Graded lockdown / break-glass with explicit trust-root + +```task +id: WARDEN-WP-0027-T02 +status: todo +decision_id: 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa +priority: medium +state_hub_task_id: "cae498ee-6307-5d32-9f1b-a471cfcc2536" +``` + +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. + +Design and document a graded lockdown: (a) soft — deny agent roles read on all +high-risk lanes; (b) hard — seal + re-key with a pre-designed trust-root and quorum. +Define the trust-root (who holds unseal shares, recovery keys), the break-glass +invocation, and the re-entry path. **Design + runbook first**; any executable seal +step is opt-in and attended. + +**Done when:** a documented, rehearsed break-glass path exists with a named +trust-root and quorum, and soft-lockdown is executable via capabilities-based +policy toggles. + +**Parked input — the warden-sign AppRole (2026-08-11).** secrets-engine holds a +validated dry-run for a `warden-sign` AppRole (policy + role, `update` on +`ssh/sign/{agt,adm,atm}-role` only). It was **parked** rather than withdrawn +specifically because it is an input to this task: today the credential broker is the +only *autonomous* path to a signing token, so if its issuer lapses, recovery is a +founder OIDC act. Whether a second autonomous path should exist — and whether it is +the AppRole or something this trust-root design supersedes — is a break-glass +question, not a routing one. Resolve it here. Context and the counter-argument +(AppRole is narrower in capability than placing the broker's issuer token on a remote +host) are in `workplans/ADHOC-2026-08-11.md` T03 (ad-hoc **finished** 2026-08-15; +question lives here now); secrets-engine was told to stop holding apply +readiness until this task or the ops-bridge cutover fires (msg `863c7b57`). + +**Rebaselined 2026-08-22.** The July description predates the authoritative +OpenBao migration. The current barrier is a rotated **2-of-3**, not the +aspirational 3-of-5 value still present in ops-warden's legacy posture +descriptor. `RMASTER-WP-0020` records two attended restart/unseal cycles on +2026-08-03 with shares supplied through hidden prompts, matching inventory, +audit continuity, exact-path read, and sibling denial. That is valid rehearsal +evidence for re-entry, but it is not misreported as a current production +emergency-seal drill. + +The soft half is also already live: `RAILIANCE-WP-0022` reports total concrete +high-risk path coverage and a dedicated coding-agent AppRole proving deny-wins +without reading a secret value. ops-warden consumes that owner control through +`scripts/check_agent_read_boundary.py`; it does not take ownership of the live +OpenBao policy. + +The consumer contract and remaining acceptance gate are now documented in +`docs/credential-governance-break-glass.md`. One attended production emergency +seal/unseal drill remains. It must use railiance-platform's evidence template +and validator, have snapshot/quorum/console/driver/abort receipts before the +seal hold point, and be executed by the platform owner—not by a coding agent. + +**Parked AppRole disposition:** do not unpark the standalone `warden-sign` +AppRole for T02 break-glass. The normal broker remains autonomous; an issuer +failure deliberately crosses into attended OIDC and, below that, the 2-of-3 +platform trust-root. A standing AppRole placed outside the broker would weaken +that boundary and still would not recover a sealed OpenBao. A separately +approved ops-bridge unattended-signing design may re-evaluate the narrow +AppRole under its own workplan; that is service access, not recovery authority. + +**Read-only readiness 2026-08-22.** The owner `node-reboot` preflight passed +every automated check without observing a secret value: node/k3s, platform-pg +and continuous archiving, a 16.37-hour successful backup, initialized/unsealed +OpenBao with `shares=3` and `threshold=2`, ESO stores/projections, and the +reviewed audit-core digest were healthy. `ready_for_live_execution` correctly +remained false because no approved window, current encrypted off-host snapshot +receipt, provider-console attestation, quorum attestation, owner-ack flag, or +named abort operator was supplied. + +That preflight also exposed a Warden safety defect: the ceremony request matched +the generic `openbao-api-key` template and proposed paste-once provisioning. +`openbao-shamir-recovery-ceremony` now distinguishes the owner-operated approval +ceremony from secret retrieval. It is a non-value-bearing pointer and can never +offer `--fetch`, `--exec`, `--out`, `--wrap`, or paste-once share transport. + +**Scenario established 2026-08-22.** The operator delegated preparation to the +agent and reserved their involvement for the final GO/NO-GO. The bounded, +non-secret scenario is +`docs/evidence/WARDEN-WP-0027-T02-drill-scenario-2026-08-22.md`: ops-warden +coordinates and enforces the hold point; railiance-platform is the proposed +OpenBao driver; railiance-infra is the proposed independent console/abort owner; +and railiance-master is asked only for a metadata-only 2-of-3 availability +attestation. All three owner receipts and a green fully parameterized preflight +are required before the final operator question. + +The railiance-infra role is scoped by the authoritative review contract +`WARDEN-WP-0027-T02-DRILL-20260822-01-INFRA` in +`interfaces/reviews/WARDEN-WP-0027-T02-DRILL-20260822-01-railiance-infra.json`. +It binds the exact scenario artifact and expiry, requires explicit independent +provider-console and distinct-abort attestations, permits metadata-only evidence, +and states `authorizes_execution: false`. + +**Preparation approved 2026-08-22.** Decision +`9da57559-712a-4521-b46e-a4c69729f9d2` authorizes preparation only and narrows +the possible live scope to one intentional OpenBao seal followed by the existing +2-of-3 unseal ceremony. It excludes a host reboot, re-key, restore, policy +change, PVC mutation, credential disclosure, and general workload restart. +Railiance-infra satisfied its direct contract with receipt +`01a02b4b-7295-7836-b288-f29407008524`. The revisioned, non-authorizing gate +matrix is in +`docs/evidence/WARDEN-WP-0027-T02-drill-preparation-checklist-2026-08-22.md`; +platform snapshot/driver and master quorum contracts remain required before the +fully parameterized read-only preflight. + +**Live attempt terminal NO-GO 2026-08-23.** All owner receipts and the final +read-only preflight became green, and the operator opened the exact bounded +window with decision `449a697a-5303-4582-aa9e-b0bc8b35ab2d`. The platform +driver stopped before seal when attended OIDC succeeded but the read-only agent +home prevented token-helper persistence and the underlying client emitted the +short-lived credential into captured output despite `-no-print`. The credential +was immediately self-revoked. Independent metadata confirmed OpenBao remained +initialized and unsealed with zero unseal progress; no seal, unseal, reboot, +restore, policy, PVC, or workload mutation occurred. NO-GO decision +`85724c0c-e70f-4e2f-a8c6-a9cb1ea6331b` supersedes and consumes the GO; the +scenario and its receipts cannot be reused. + +The direct remediation interface is `RAILIANCE-WP-0026-T01`. Ops-warden commit +`0fae0904ce8d8694338dd53a8a79abec5fec788d` replaces the persistent login-only +handoff with a contained login-plus-reviewed-command envelope. It proves a +private writable helper before OIDC, captures login/child/revocation stdout and +stderr, fails closed on any output or persistence defect, self-revokes, and +removes the helper. No live OIDC was used for verification. The value-safe +owner receipt is +`docs/evidence/RAILIANCE-WP-0026-T01-ops-warden-receipt.json`; a future drill +requires owner acceptance, fresh receipts, a new scenario id, and a new human +decision. + +**Containment review status 2026-08-23.** `railiance-infra` independently +accepted the exact implementation revision at its commit `186b030` and State +Hub message `7b2846dd-4b7c-4933-b61f-921e8ccf9ff2`, after rerunning the 42 +focused tests and lint. Direct platform review request +`9a5f8973-0e74-4df2-8089-5a5bdc42295b` now carries the exact revision, receipt, +test results, and infra acceptance. T02 remains `progress` until +`railiance-platform` accepts or requests changes. No human GO is relevant while +that owner gate is open; acceptance will permit preparation of a new scenario, +not execution or reuse of the terminal one. + +**Owner gate CLOSED — accepted 2026-08-23, found 2026-08-28.** +`railiance-platform` accepted the exact revision `0fae0904`. Recorded in their +`RPF-WP-0017-attended-login-output-containment.md` (`status: finished`), which +also records railiance-infra's independent approval at `186b030` and marks all +five acceptance criteria met. The receipt digest was verified here rather than +taken on trust: `docs/evidence/RAILIANCE-WP-0026-T01-ops-warden-receipt.json` at +ops-warden `bc1966da` hashes to +`d2ba444ed16989590325697e69d25283dc75a9432c29a72e627e80bf9fd987e4`, matching +their record exactly. + +Note the identifier: the remediation interface recorded above as +`RAILIANCE-WP-0026-T01` is `RPF-WP-0017-T01` in the owner's repo. Searching for +the cited id finds an unrelated workplan, which is part of why this sat unnoticed. + +**Their acceptance is source acceptance only and authorizes no live OIDC or +drill** — their words, and the boundary holds. So T02's state changes but its +`Done when` does not: what was blocked was *preparing a new scenario*, and that +is now permitted. The terminal NO-GO scenario and its receipts remain unusable. + +**Third instance of the same failure this session.** The acceptance existed for +five days; no message reached ops-warden. Identically, `key-cape` accepted the +WP-0033-T04 question on 2026-08-23 with no message, and nine unread messages +were sitting on already-superseded threads. The `verified:` field added by +WP-0033-T05 was built for exactly this and it works — what does not work is +waiting for a counterparty to tell you. Re-checking a blocker means reading the +owner's repository. + +**Remaining to close T02:** one attended production emergency seal/unseal drill, +requiring a new scenario id, fresh owner receipts from platform/infra/master, a +fully parameterized green preflight, and a new human GO. It is executed by the +platform owner, never by a coding agent. That is an operator decision, not an +agent one, so T02 stays `progress` and the decision is surfaced rather than taken. + +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. + +## Task: Tamper-evident policy governance + reconcile + +```task +id: WARDEN-WP-0027-T03 +status: cancel +priority: medium +state_hub_task_id: "7dbedcdc-dd5a-551c-bff1-0702fea0a9cf" +``` + +Policy-as-code for OpenBao policies/roles with tamper-evidence: a signed/hashed +manifest of the intended policy set, drift **detection** against live OpenBao, and a +reconcile-to-known-good-commit path. (Drift detection may land independently even if +full reconcile stays gated.) Coordinate ownership with railiance-platform (OpenBao +deployment) — ops-warden contributes the ops-access policy surface, not the cluster. + +**Done when:** live OpenBao policy state is diffable against a signed known-good +manifest, and an attended reconcile can restore it. + +**Cross-repo:** railiance-platform (OpenBao cluster + policy custody). + +## References + +- `WARDEN-WP-0026` — Strand A (disclosure hygiene, advisory rotation) — prerequisite +- `.claude/rules/credential-routing.md` — ops-warden custodies no secret values +- `railiance-platform` — OpenBao cluster, policy custody, credential broker +- `wiki/AccessRouting.md` — issue vs route vs assist boundary +- `workplans/ADHOC-2026-08-11.md` T03 — parked warden-sign AppRole (ad-hoc finished + 2026-08-15); T02 resolves it as unsuitable for break-glass, while a separately + approved ops-bridge unattended-signing design may still re-evaluate it + cert_command cutover +- `secrets-engine` `SECRETS-WP-0004` — the parked AppRole apply/handoff + +### 2026-09-28 loose-end review + +T02 now waits and the workplan is blocked. Source containment acceptance is +already complete in railiance-platform's archived RPF-WP-0017; it is not a live +drill receipt. The terminal August scenario remains consumed. Completion still +requires a fresh platform-driven attended emergency seal/unseal scenario, fresh +platform/infra/master receipts and a new founder GO. The cancelled T01/T03 stay +cancelled. No ceremony, rotation or production mutation was performed. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0028-tenant-secret-custody.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0028-tenant-secret-custody.md new file mode 100644 index 00000000..fe819834 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0028-tenant-secret-custody.md @@ -0,0 +1,421 @@ +--- +id: WARDEN-WP-0028 +type: workplan +title: "Tenant secret custody — NetKingdom pattern for client/tenant secrets" +domain: infotech +repo: ops-warden +status: finished +owner: grok +topic_slug: custodian +planning_priority: high +planning_order: 28 +created: "2026-07-16" +updated: "2026-07-17" +state_hub_workstream_id: "6b66228a-199a-5b85-b5e2-a7afeaab903b" +--- + +# WARDEN-WP-0028 — Tenant secret custody (NetKingdom pattern) + +## Origin + +Founder establishing **binky-control** as the control-plane repo for a Coulomb +client/tenant (Binky-Hedgehog GmbH). Immediate need: store **tenant-specific** +secrets in OpenBao (e.g. company mailbox usernames/passwords for IMAP scan) and +consume them safely via email-connect / agents **without** putting values in +git, State Hub, chat, or workplans. + +BINKY-WP-0003-T01 prepared a draft plan +(`binky-control/integrations/company-email-openbao.md`) that targeted +`secret/prod/binky/...` via secrets-engine. That draft is directionally right on +*workflow*, but it does not match a production-ready custody layout on +`bao.coulomb.social`. This workplan resolves the NetKingdom layout and makes +**tenant** secrets first-class — **separate from** platform workload lanes +(`platform/workloads/...`). + +## Goal + +Define and land a **repeatable, multi-tenant-safe** pattern for: + +1. Where tenant secrets live in OpenBao (path + mount convention) +2. Who owns policy, CCR, catalog, and front door +3. How agents and workloads obtain values (sanctioned transports only) +4. First concrete lane: **binky company email IMAP** (unblocks real-world event + intake for binky-control) + +## Architectural facts (as of 2026-07-16) + +### Planes (ADR-0006) + +| Plane | Role | Example | +| --- | --- | --- | +| Bootstrap | First trust / recovery | unseal, platform-root | +| Platform control | Shared identity, secrets, authz | OpenBao, key-cape, flex-auth, railiance-platform | +| Tenant | Scoped client/workload authority | coulomb products, **binky**, future clients | + +**Binky is a tenant**, not platform-root. Tenant secrets must not require +platform-admin for day-to-day read, and tenant operators must not gain +platform-root grants. + +### OpenBao mounts (live + planned) + +| Mount | Type | Role | +| --- | --- | --- | +| **`platform/`** | KV v2 | **Platform control-plane** secrets: `platform/workloads/...` (fleet CCRs, ESO) and `platform/operators/...` — *not* client/tenant commercial secrets | +| **`secret/`** | KV v2 | secrets-engine stage / pilot paths (`secret/coulomb/...`) — not the tenant home | +| **`tenants/`** | KV v2 (**new**) | **Client/tenant commercial secrets** — explicit multi-tenant namespace | + +Live under `platform/workloads/` today: `activity-core/`, `coulomb/`, `forgejo/`, +`issue-core/`, `railiance/`, `reuse/`. Those stay where they are; we do **not** +migrate them into `tenants/` in this workplan. + +### Dual front-door systems (both real; don't invent a third) + +| Layer | Owns | Entry | +| --- | --- | --- | +| **OpenBao** | Custody, ACL, audit | `bao` CLI / API | +| **railiance-platform CCR** | Approved metadata apply (policy + OIDC role + evidence) | `credential-change-requests/CCR-*.yaml` | +| **ops-warden catalog** | Routing + `warden access` proxy (no custody) | `registry/routing/catalog.yaml` | +| **secrets-engine catalog** | Workflow: decision → plan → provision → exec delivery | `secrets-engine/catalog/*.yaml` | + +**Binding rule (ops-warden):** never vend secret values; only route/proxy as the +caller. **Binding rule (WP-0026):** capabilities-safe verify; agents on +`risk: high` use `--out` / `--exec` / `--wrap` only. + +### Why not bury tenants under `platform/workloads/` + +Earlier draft of this workplan used `platform/workloads//...`. Founder +prefer a **shallower, explicit** namespace. That is sound: + +- **No conflict with Vault/OpenBao best practice.** Separate mounts (or + top-level prefixes) for different security *domains* are common and good. + `platform/workloads` is an *internal fleet convention* for platform services, + not an industry mandate for every secret. +- **Clearer mental model:** platform plane vs tenant plane (ADR-0006) maps to + mount/prefix names operators can see at a glance. +- **Isolation:** ACLs, list boundaries, and future audit queries stay simpler + when tenant material is not mixed under the same path tree as forgejo/ESO + lanes. + +### Decision (2026-07-17) — use dedicated mount `tenants/` + +```text +mount: tenants # KV v2, enable once (platform-admin) +logical path: // +CLI: tenants/// +API data path: tenants/data/// +``` + +**Rejected alternatives (kept for archaeology only):** + +| Option | Why not | +| --- | --- | +| `secret/prod/binky/...` | `secret/prod/` does not exist; stage model not ready as sole production path | +| `platform/workloads/binky/...` | Too deep; conflates tenant clients with platform workloads | +| `platform/tenants/binky/...` | Acceptable fallback if enabling a new mount is blocked; prefer full `tenants/` mount | + +### Tooling debt to clear (not a reason to keep the deep path) + +`railiance-platform/scripts/credential-change.py` currently hard-fails unless: + +- `openbao.mount == "platform"` +- `openbao.kv_path` starts with `platform/workloads/` + +That guard must be **extended** to allow `mount: tenants` and +`kv_path` under `tenants/` (T03). It is an implementation constraint, not a +security reason to force the deep path. + +## Recommended path convention (tenant secrets) + +```text +tenants/// +``` + +| Segment | Rules | Binky email example | +| --- | --- | --- | +| `tenant_slug` | Stable kebab slug; company/client id | `binky` | +| `workload` | Capability or system using the secret | `company-email` | +| `bundle` | Single purpose unit (one CCR / one policy) | `imap` | + +Full CLI path: + +```text +tenants/binky/company-email/imap +``` + +Suggested fields (names only — never values in git): + +| Field | Purpose | +| --- | --- | +| `IMAP_USERNAME` | mailbox login (often the address) | +| `IMAP_PASSWORD` | app password / mailbox password | +| `IMAP_HOST` | optional if not fixed in consumer config | +| `IMAP_PORT` | optional (default 993 in config) | + +Non-secret connection facts (provider host if stable) may live in +`binky-control` config / email-connect yaml as **env names + host**, not +passwords. + +### Future multi-mailbox / multi-tenant + +```text +tenants//mailbox/ +# e.g. tenants/binky/mailbox/founder-primary +# tenants/acme/mailbox/billing +``` + +One CCR + one least-privilege policy **per bundle** (or per mailbox). Do not +grant `tenants/binky/*` list/read to agents — exact-path policies only. + +### Risk class + +Mailbox credentials and similar client secrets are **`risk: high`** (WP-0026 +T04): agent identities get metadata/capabilities only; raw stream refused when +`WARDEN_AGENT_ID` is set. + +## Ownership split + +| Concern | Owner repo | Artifact | +| --- | --- | --- | +| Tenant business need, IMAP host facts, scan config, queues | **binky-control** | `integrations/*`, mailmeta (metadata only), activity defs | +| OpenBao path, policy HCL, OIDC role, CCR lifecycle | **railiance-platform** | `CCR-YYYY-NNNN-…yaml`, `openbao/policies/…` | +| Routing front door + rotation guidance | **ops-warden** | catalog entry, playbook, `warden access` / `rotate-guide` | +| Exec-time delivery workflow (optional same path) | **secrets-engine** | catalog entry pointing at `tenants/...` (same path; no second copy) | +| Identity groups for tenant operators | **net-kingdom / key-cape** | group e.g. `tenant-binky-operators` (near-term may use `net-kingdom-admins` for founder-only) | +| Mailbox scan consumer | **email-connect** | config with `username_env` / `password_env` only | + +## Auth model (near-term vs target) + +**Near-term (founder dogfood):** OIDC `netkingdom` role bound to +`groups=net-kingdom-admins` (same pattern as backup/forgejo lanes). Acceptable +while binky is founder-operated only. + +**Target (real multi-tenant):** + +- IAM group `tenant-binky-operators` (and later per-tenant groups) +- OpenBao OIDC role `binky-company-email-imap-workload-kv-read` bound only to + that group +- flex-auth check `secret.read:binky-company-email` if pre-approval required +- Agents **never** hold the workload-kv-read policy; use operator wrap / exec + injection / AppRole for email-connect scanner only + +## First worked lane (deliverable sketch) + +| Item | Value | +| --- | --- | +| Catalog id | `binky-company-email-imap` | +| CCR | `CCR-2026-0007` (next free) — title: Binky company email IMAP | +| Mount | `tenants` | +| KV path | `tenants/binky/company-email/imap` | +| Policy | `workload-kv-read-binky-company-email-imap` | +| OIDC role | `binky-company-email-imap-workload-kv-read` | +| Consumer | email-connect `scan-mailbox` via env inject | +| Front door | `warden access binky-company-email-imap --out FILE` or `--exec -- …` | +| Provision | **Red lane, founder once** — value via `bao kv put … @file` or secrets-engine provision; never chat | + +## Out of scope + +- Mass rotation / lockdown machinery (WARDEN-WP-0027 Strand B) +- Sending mail / SMTP from company address (separate lane if needed) +- Migrating all `secret/` mount lanes onto `platform/` (separate secrets-engine + / railiance work) +- Full key-cape tenant group productization (may be a net-kingdom follow-on) + +## Tasks + +### T01 — Canon note: tenant secret path + ownership + +```task +id: WARDEN-WP-0028-T01 +status: done +priority: high +state_hub_task_id: "9982a884-7a50-593e-861e-cc8d2343a0ba" +``` + +Done 2026-07-17: `wiki/playbooks/tenant-secret-onboarding.md` + CredentialRouting +tenant paragraph; catalog-lane-promotion draft table updated. + +Land a short ops-warden wiki page (and one paragraph in +`wiki/CredentialRouting.md`) that freezes: + +- mount **`tenants`** + path `tenants///` +- ownership table (binky-control / railiance-platform / ops-warden / secrets-engine) +- link to WP-0026 hygiene (capabilities verify, high-risk, taint) +- **do not** put new client/tenant commercial secrets under + `platform/workloads/` or invent `secret/prod/...` as the production home + +**Done when:** wiki + CredentialRouting pointer exist; binky integration doc +updated to match (or superseded with link). + +### T02 — Align binky-control integration plan to production path + +```task +id: WARDEN-WP-0028-T02 +status: done +priority: high +state_hub_task_id: "d7d7ee9d-2ecf-5492-8a13-0b747d899456" +``` + +Done 2026-07-17: `binky-control/integrations/company-email-openbao.md` rewritten +to `tenants/binky/company-email/imap` + checklist (host confirm + Red provision +still open). + +**Cross-repo: binky-control.** Rewrite +`integrations/company-email-openbao.md` to use +`tenants/binky/company-email/imap`, CCR + ops-warden front door as primary, +secrets-engine as optional exec wrapper on the same path. Confirm non-secret +IMAP host/port with founder (Blue). Keep Red-lane value provision as the last +step. + +**Done when:** binky doc matches this workplan; checklist items re-opened for +implementation (T01 in BINKY was "prepared only"). + +### T03 — Enable `tenants` mount + extend CCR tooling + policy/role + +```task +id: WARDEN-WP-0028-T03 +status: done +priority: high +state_hub_task_id: "e0b675ef-9c08-5f89-8f13-ef4249ca2364" +``` + +Done 2026-07-17: `tenants/` KV v2 mount live; CCR applier allowlist extended; +CCR-2026-0007 + policy + OIDC role applied; lane-policy `read` / default +`deny` / agent boundary on tenants path; `docs/workload-kv-access-lanes.md` +tenant section. + +**Cross-repo: railiance-platform (+ OpenBao admin once).** + +1. **Enable KV v2 mount** `tenants/` on `bao.coulomb.social` (platform-admin / + attended; record non-secret evidence). Versioning + max versions policy + aligned with `platform` if practical. +2. **Extend** `scripts/credential-change.py` allowlist: `mount: tenants` and + `kv_path` under `tenants/` (keep existing `platform/workloads/` rules + intact for fleet lanes). Update dry-run docs and tests. +3. Author `CCR-2026-0007` (or next id) for the binky IMAP path; policy HCL on + exact data/metadata paths under `tenants/…`; OIDC role (founder group + near-term). Dry-run; founder approves; apply metadata only. +4. Document fields without values; add a **tenant lanes** section to + `docs/workload-kv-access-lanes.md` (or sibling doc). + +**Done when:** mount exists; CCR tool accepts tenant paths; CCR approved + +policy/role applied; capabilities-safe positive/negative evidence (no value +reads for verify). + +### T04 — ops-warden catalog + playbook + rotation + +```task +id: WARDEN-WP-0028-T04 +status: done +priority: high +state_hub_task_id: "9405b13d-4045-519b-8e3f-79a891323397" +``` + +Done 2026-07-17: catalog draft `binky-company-email-imap` (`risk: high`, +rotation, path `tenants/binky/...`); playbooks +`binky-company-email-imap.md` + onboarding. Promote to active after T05. + +Add `binky-company-email-imap` to `registry/routing/catalog.yaml`: +`status: draft` until verify, then promote; `risk: high`; `exec_capable: true`; +concrete `fetch_command` for primary field; `rotation:` block (re-establish or +rotate mailbox app-password). Playbook under `wiki/playbooks/`. Scorecard +rotation coverage satisfied on promote. + +**Done when:** `warden route show binky-company-email-imap --json` shows +expected pointers; after T03+T05, `resolvable: true`. + +### T05 — Founder provision (Red) + first scan evidence + +```task +id: WARDEN-WP-0028-T05 +status: done +priority: high +state_hub_task_id: "f17bba95-bc53-5c2a-8b44-7df9e42b2341" +``` + +Done 2026-07-17: Founder provisioned via OpenBao UI (KV version 2; not +placeholder). Capabilities-safe verify pass; catalog + CCR promoted +active/resolvable. Optional follow-up: first email-connect read-only scan into +`binky-control/mailmeta/` (OperatingRhythm), not a custody blocker. + +**Human-only value path.** Founder provisions IMAP username/password into +OpenBao via approved tool (`bao kv put … @file` or secrets-engine provision). +Agents never see the value. Run email-connect read-only scan with +`warden access … --exec` or secrets-engine exec; store **metadata-only** +evidence under `binky-control/mailmeta/`. + +**Done when:** one successful read-only scan evidence note exists; lane +promoted active/resolvable; CCR verification evidence complete. + +### T06 — Generalize "tenant secret onboarding" playbook + +```task +id: WARDEN-WP-0028-T06 +status: done +priority: medium +state_hub_task_id: "76bd01a0-1d03-5ff9-8f59-a1b44763979d" +``` + +Done 2026-07-17 with T01: `wiki/playbooks/tenant-secret-onboarding.md` + +CredentialRouting link. + +From the binky lane, write a reusable playbook: +`wiki/playbooks/tenant-secret-onboarding.md` — steps for any new tenant: +slug, CCR template fields, policy naming, catalog entry, agent boundary, +rotation block, promotion checklist. Intended for the next Coulomb client +without redesign. + +**Done when:** playbook exists and is linked from CredentialRouting + first +session notes for tenant repos. + +### T07 — secrets-engine alignment decision (record only) + +```task +id: WARDEN-WP-0028-T07 +status: done +priority: low +state_hub_task_id: "46c8f8a9-3bbe-568f-8a45-07b690874273" +``` + +Done 2026-07-17: **Decision** — tenant production lanes use `mount: tenants` +and the CCR path only; secrets-engine may wrap exec delivery against that same +path later but must not store a second copy under `secret/`. Until stage roles +gain an approved `tenants/` grant, production path is CCR + ops-warden + +caller `bao`. + +Record a short decision: secrets-engine catalog entries for **tenant** +production lanes **must** use `mount: tenants` and the same path as the CCR +(no second copy under `secret/`). Stage roles may need a later extension to +touch `tenants/` under an approved plan — until then, ops-warden + CCR + +`bao` as caller are the production path. + +**Done when:** decision note in this workplan or `POST /decisions/` + wiki +pointer; no dual-value storage for the IMAP password. + +## Suggested implementation order + +1. T01 canon (unblocks everyone) +2. T02 binky doc alignment +3. T03 mount + CCR tooling + CCR apply (metadata) +4. T04 catalog draft +5. T05 founder provision + verify + promote +6. T06 generalize playbook +7. T07 secrets-engine alignment (can parallel after T01) + +## Acceptance + +- [ ] Documented path convention `tenants//…` used for ≥1 live lane (`binky`) +- [ ] CCR applier accepts `tenants/` without weakening `platform/workloads/` rules +- [ ] No secret values in any git/State Hub artifact +- [ ] Lane is capabilities-verified and agent high-risk safe +- [ ] email-connect can scan with env injection without printing password +- [ ] Next tenant can copy the onboarding playbook without redesign + +## References + +- ADR-0006 recursive multi-tenant identity (`net-kingdom/docs/adr/…`) +- `net-kingdom/docs/secrets-engine-security-infrastructure-boundary.md` +- `railiance-platform/docs/workload-kv-access-lanes.md` +- `railiance-platform/docs/credential-change-approval.md` +- `binky-control/integrations/company-email-openbao.md` (draft to align) +- WARDEN-WP-0026 disclosure hygiene (capabilities, high-risk, taint, rotation) +- WARDEN-WP-0027 Strand B (out of scope here) diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md new file mode 100644 index 00000000..4008d825 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md @@ -0,0 +1,159 @@ +--- +id: WARDEN-WP-0029 +type: workplan +title: "Policy front door: posture-aware access planning + founder interaction surface" +domain: infotech +repo: ops-warden +status: finished +owner: codex +topic_slug: custodian +planning_priority: high +planning_order: 29 +created: "2026-07-18" +updated: "2026-07-18" +state_hub_workstream_id: "bbb3d9ec-d88d-5088-b4c0-55bfba0a10cf" +--- + +# WARDEN-WP-0029 — Policy front door + founder interaction surface + +## Origin + +Founder directive 2026-07-18 (binky-control cutover prep): agents proposed +raw credential mechanics to the founder ("attach the deploy key in the +forgejo UI", "save the PAT to /tmp/...") although a catalogued lane +(`forgejo-admin-api-token`, WARDEN-WP-0025) already covered the need — the +installed CLI's catalog was stale, and nothing forced the ask-warden-first +step. Directive: **ops-warden is the service to ask what can and needs to be +done** per NetKingdom policy; the founder is bothered only when policy makes +it absolutely necessary, and then preferably via a purpose-built interaction +surface, not CLI/file handoffs. The organization is in **build phase** and +ops-warden must know that posture. INTENT.md principles 7 and 8 (added with +this workplan) capture the direction. + +## Goal + +1. `warden plan ""` — a policy decision front door: given a need, answer + *autonomous / founder-act-required / unroutable*, with the exact commands + or the exact founder act, posture-stated. +2. Declared **organization posture** (`build`) as a **third axis** beside env + posture (dev/test/prod) and workload maturity (M0–M3). +3. A **founder interaction surface**: local web page for the rare founder + acts (approve, OIDC-login prompt, paste-once secret capture straight into + OpenBao) — no values through CLI history or files. +4. Catalog freshness + agent guidance so ask-warden-first is the enforced + default. + +## Design constraints (optimized 2026-07-18) + +- **Compose, do not fork:** `warden plan` must call the routing catalog + + `expand_handoff` / `resolvable`; it must not re-implement keyword matching + or invent a second catalog. +- **Org posture is a third axis:** do not overload env posture or maturity. +- **Desk MVP is build-phase only:** localhost, OS-session trust, stdlib HTTP + server (pattern: net-kingdom `security-bootstrap-console`). No core-hub / + whynot dependency for v1. +- **Reuse map (reuse.coulomb.social):** flex-auth (policy-evaluate), key-cape + (OIDC act), net-kingdom bootstrap console (localhost desk shape), + railiance-platform (OpenBao custody). Do not rebuild those owners. + +## Delivery sequence + +```text +T02 (org posture) ─┐ +T05 (catalog freshness) ─┼─→ T01 (warden plan composes both) +T04 (playbook sweep) ───┘ (parallel once plan shape known) +T03 (desk) ← after T01 can emit founder_required with a typed act +``` + +T05 is high priority: catalog staleness was the incident root cause. + +## Tasks + +### T02 — Declared organization posture (build phase) + +```task +id: WARDEN-WP-0029-T02 +status: done +priority: high +state_hub_task_id: "6c213024-6601-5116-b52f-d6711dc0587d" +``` + +Added `organization_posture: build` as axis C in +`registry/policy/security-posture.yaml` (relaxations + graduation triggers). +Surfaced in `warden policy list/show`, scorecard, and `warden plan` output. + +### T05 — Catalog freshness + agent guidance + +```task +id: WARDEN-WP-0029-T05 +status: done +priority: high +state_hub_task_id: "c82d8745-4af4-5b89-ab49-06d8a902e592" +``` + +`Catalog.freshness()` reports source (repo/bundled/override), content hash, +mtime, package version, stale entry count, and warnings for bundled fallback. +Human `warden route list` prints catalog line; plan JSON embeds `catalog`. +Scorecard check `catalog_freshness`. AGENTS.md + credential-routing rules +require `warden plan` before founder credential steps. + +### T01 — `warden plan` decision front door + +```task +id: WARDEN-WP-0029-T01 +status: done +priority: high +state_hub_task_id: "34db38fa-cb99-5ced-9a12-85176a7f2b44" +``` + +`warden plan "" [--actor] [--domain] [--json]` composes catalog find + +handoff + org posture + policy gate. Verdicts: `autonomous` / +`founder_required` (`oidc_login` | `approve` | `paste_once_provision`) / +`unroutable` (CCR stub). Metadata-only audit. Module: `src/warden/plan.py`. + +### T04 — Retire file-drop patterns from playbooks + +```task +id: WARDEN-WP-0029-T04 +status: done +priority: medium +state_hub_task_id: "717f57da-fbc4-5a4d-9f8c-c1c3fa75e0ee" +``` + +`wiki/playbooks/forgejo-admin-api-token.md` rewritten: plan-first, sanctioned +transports (`--exec`/`--out`/`--wrap`), desk paste-once for provision; `/tmp` +file drops marked retired. Consumer follow-ups noted for railiance-platform +and binky-control docs. + +### T03 — Founder interaction surface (local web approval page) + +```task +id: WARDEN-WP-0029-T03 +status: done +priority: medium +state_hub_task_id: "47c781d2-768b-5777-b971-b5227fe41f5c" +``` + +`warden desk` — loopback `ThreadingHTTPServer`, short-lived token URL, acts +approve / oidc_login / paste_once_provision (bao kv put via stdin, dry-run +supported). Metadata-only audit open/close. Module: `src/warden/desk.py`. + +## Acceptance + +- [x] `warden plan "forgejo deploy key for binky-control"` → `autonomous` / + `agent-harness-forgejo-deploy` with access commands +- [x] Provision-style needs → `founder_required` with typed founder act +- [x] Posture `build` in plan + policy + scorecard +- [x] Desk approve flow (unit) with zero secrets in audit +- [x] No in-repo playbook instructs founder file drop as steady state +- [x] Catalog freshness on `warden route list` / plan JSON + +## See also + +- INTENT.md §7 (founder escalated, never tasked) and §8 (build-phase posture) +- WARDEN-WP-0025 (forgejo admin token lane), WARDEN-WP-0026/0027 (disclosure + hygiene, governance lockdown) +- reuse.coulomb.social: `capability.authorization.policy-evaluate`, + `capability.iam.key-cape`, `capability.security.iam-tooling-suite` +- binky-control DEC-2026-003 (first consumer: cutover without founder + mechanics) diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0030-delegation-register.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0030-delegation-register.md new file mode 100644 index 00000000..49612d07 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0030-delegation-register.md @@ -0,0 +1,270 @@ +--- +id: WARDEN-WP-0030 +type: workplan +title: "Delegation register — make gap-covering interim, visible, and retirable" +domain: infotech +repo: ops-warden +status: finished +owner: grok +topic_slug: custodian +planning_priority: high +planning_order: 30 +created: "2026-08-11" +updated: "2026-08-15" +state_hub_workstream_id: "da3367d5-890c-52c6-aa54-1bdd0f277342" +--- + +# WARDEN-WP-0030 — Delegation register + +## Origin + +Founder directive 2026-08-11: **ops-warden should work with, but never replace or +duplicate, secrets-engine, tenant-engine, user-engine and other NetKingdom +components.** It is acceptable for ops-warden to cover a gap where needed security +functionality is not yet systematically provided — *provided* the gap is kept in +mind, filled, and given proper governance, after which ops-warden delegates to the +improved component. + +The directive is already half-lived and nowhere written. Survey of +`registry/routing/catalog.yaml` on 2026-08-11 (24 entries): + +| Execution mode | Count | Meaning | +| --- | --- | --- | +| `warden_executes: true` | 1 | ops-warden's own lane (`ssh-cert-host-access`) | +| `exec_owner:` set | 2 | Delegated — route-primary, proxy-fallback | +| `exec_capable` proxy, no `exec_owner` | 11 | **ops-warden is the de facto front door** | +| route-only | 10 | Pointer, nothing to delegate | + +The delegation primitive already exists and works: `exec_owner` / `exec_command` / +`pointer_command` (`whynot-design-npm-publish` → secrets-engine, WP-0019; +`ops-warden-warden-sign-token` → railiance-platform credential broker, +RAILIANCE-WP-0005 T08). It is used by 2 of 24 lanes. + +Nothing distinguishes the other eleven — "ops-warden proxies because that is the +right end state" reads identically to "ops-warden proxies because no owner front +door was ever built." Supporting evidence of the doctrine gap: + +- `wiki/AccessRouting.md` does not mention secrets-engine at all and has no section + on interim positions. +- `wiki/playbooks/catalog-lane-promotion.md` gates draft→active on the lane + *working*, never on whether ops-warden should be the one running it. + +## Goal + +Make every ops-warden execution position **explicitly interim or explicitly +permanent**, with the intended owner and blocking condition recorded in the +machine-readable layer — so gap-covering is a tracked, retirable state rather than +silent ownership drift. + +Success is not removing proxies. Success is that no proxy exists without an answer +to *"who should own this front door, and what is missing?"* + +## Non-goals + +- Removing or degrading any working lane. Proxies keep working until the owner's + front door exists and is proven. +- Building the missing front doors. That work belongs to secrets-engine, + tenant-engine, user-engine, and railiance-platform — this workplan produces the + register they need, not their implementations. +- A second catalog or a parallel schema. `delegation:` extends the existing entry + shape; `warden route gaps` composes the existing loader. + +## Design constraints + +- **Interim is the default.** A lane without a `delegation:` block is treated as + `interim` with an unknown owner, not as settled. Absence must read as a question. +- **Founder classifies, agent drafts.** Which of the eleven are legitimately + permanent is an architecture judgement (`key-cape-oidc-login` plausibly is; the + tenant/workload secret lanes plausibly are not). T02 lands a *drafted* + classification for review; the founder's answer is authoritative. +- **No restating owner procedure.** The register names the intended owner and the + blocker; it does not describe how that owner will implement their front door. + Same pointer-layer discipline as the rest of the catalog. + +## Tasks + +### T01 — Interim custodianship doctrine + +```task +id: WARDEN-WP-0030-T01 +status: done +priority: high +state_hub_task_id: "6f88876e-434c-5718-9c8d-ec6bf64ae4aa" +``` + +Add a doctrine section to `wiki/AccessRouting.md` stating the boundary: the only +lane ops-warden executes with its own authority is SSH issuance; every other +execution position is interim, held because the owning component does not yet cover +the need, and retired to that owner once it does. Name secrets-engine, +tenant-engine, user-engine, railiance-platform and flex-auth as the delegation +targets. Cross-link INTENT.md §9. + +### T02 — `delegation:` metadata + backfill + +```task +id: WARDEN-WP-0030-T02 +status: done +priority: high +state_hub_task_id: "b02e8da6-57ca-5f9f-9405-9b0624498e3a" +``` + +Extend the catalog entry schema with: + +```yaml +delegation: + mode: native | interim | permanent # native = owner already fronts it + intended_owner: # required unless mode: permanent + blocked_on: # required when mode: interim + reviewed: "YYYY-MM-DD" +``` + +Backfill all 24 entries. `exec_owner` lanes become `mode: native`. +`ssh-cert-host-access` becomes `mode: permanent` (ops-warden's own lane). The +eleven undelegated proxies are classified per the founder review below — five +`interim` now, six held pending secrets-engine's answer. + +**Landed 2026-08-15.** Catalog is now 27 entries. All 27 carry `delegation:`. + +- `permanent` (1): `ssh-cert-host-access` +- `native` (10): both `exec_owner` lanes plus the route-only pointers +- `interim` (16): the five founder-classified now; the six held pending + secrets-engine (still unanswered as of 2026-08-15, msg `7d55d332`) recorded as + `interim` / `intended_owner: secrets-engine` / `blocked_on` the generic-vs-per-lane + question — **not** `permanent`; plus five new-since-survey lanes drafted the same + way (`email-connect-transactional` same held question; two AppRoles; + `coulomb-social-runtime-env`; draft `scaleway-bootstrap`) + +The six are not guessed permanent. Interim is the default until secrets-engine +answers. Reclassify to `permanent` only if they confirm `exec --catalog` stays +per-lane. + +### T03 — `warden route gaps` + conformance test + +```task +id: WARDEN-WP-0030-T03 +status: done +priority: medium +state_hub_task_id: "f5e0f5af-45d8-5c82-9de2-d640d7d0a1f7" +``` + +`warden route gaps [--json]` lists interim lanes with intended owner, blocker, and +age since review — the queryable register. Add a routing test asserting every +`exec_capable` non-`warden_executes` entry declares `delegation`, so a new proxy +cannot be added without answering the ownership question. Surface stale interim +entries in the existing drift/stale review cadence. + +### T04 — Promotion gate + +```task +id: WARDEN-WP-0030-T04 +status: done +priority: medium +state_hub_task_id: "b808a749-e1d7-5708-aabf-91732dd76abd" +``` + +Update `wiki/playbooks/catalog-lane-promotion.md`: draft→active requires a +`delegation` block. If `mode: interim`, the promotion note must state the intended +owner and the retirement condition. Add the matching question to the lane-review +checklist. + +### T05 — Publish the register to the owners + +```task +id: WARDEN-WP-0030-T05 +status: done +priority: medium +state_hub_task_id: "b0188ec4-4860-57c8-8030-45904a132190" +``` + +Once T02 is reviewed, send the interim register to secrets-engine, tenant-engine, +user-engine, railiance-platform and net-kingdom as a coordination message: here is +what ops-warden currently fronts on your behalf, here is what would let us step +back. This is the artefact that converts a private ops-warden position into a +fleet-visible capability gap. + +**Landed 2026-08-15.** Register sent (no secret values): + +| To | Message | +| --- | --- | +| secrets-engine | `9c1d753f` — 1 native + 7 interim pending generic-exec answer | +| tenant-engine | `17c851b1` — 2 Binky tenant lanes | +| user-engine | `38aeccd5` — confirm USER_ENGINE_PROXY_SECRET ownership | +| railiance-platform | `e75793e3` — 1 native + 4 interim | +| net-kingdom | `3fea09df` — object-storage-sts remains native/draft | +| key-cape | `28ded56c` — rapp-qonto-keycape-client (founder-classified interim) | + +## Acceptance + +- [x] `wiki/AccessRouting.md` states the interim-custodianship boundary and names + the delegation targets +- [x] All catalog entries carry `delegation`; `warden route gaps` returns the + interim set with owner + blocker (27 entries; 15 active interim) +- [x] Routing test fails when a proxy lane omits `delegation` +- [x] Promotion playbook gates draft→active on the ownership question +- [x] Founder has reviewed the interim/permanent classification of the eleven + (2026-08-11); the six held lanes stay interim pending secrets-engine, not + marked permanent +- [x] Register delivered to the named owner repos (T05) + +## Classification of the eleven (founder review, 2026-08-11) + +### The test + +An initial draft sorted by *subsystem* (tenant lanes → tenant-engine, workload lanes → +secrets-engine). Inspecting the entries showed that is the wrong axis. Nine of the +eleven share one `auth_method` — "caller's own OpenBao token" (operator OIDC via +key-cape, or a `workload-kv-read-*` policy) — and one `fetch_command` shape, +`bao kv get -field=X `. No owner procedure is duplicated there. Contrast +`whynot-design-npm-publish`, which needs npm config and token injection into a specific +tool; that is a *procedure*, which is why WP-0019 handed it to secrets-engine. + +**Test: owner-specific procedure or lifecycle → `interim`. Generic KV read → +ops-warden's thin wrapper is arguably `permanent`.** + +### Interim — classify now (5) + +| Lane | `intended_owner` | `blocked_on` | +| --- | --- | --- | +| `rapp-qonto-keycape-client` | key-cape | `client_secret_basic` exchange is a key-cape protocol procedure, not a KV read; rotation already `automatable: true`, so key-cape could front it today | +| `binky-company-email-imap` | tenant-engine | Custody at `tenants/binky/...` but rotation owner is `binky-control` — split lifecycle, no front door reconciling it | +| `binky-qonto-api` | tenant-engine | Same split, same tenant | +| `railiance-backup-offsite-lane` | railiance-platform | Rotation is `re-establish`, a multi-step procedure ops-warden only describes | +| `agent-harness-forgejo-deploy` | railiance-platform / agent-harness | `re-establish` plus an alternative host-local key path; two ways in, neither owner-fronted | + +### Held pending secrets-engine (6) + +`openbao-api-key`, `key-cape-oidc-login`, `issue-core-ingestion-api-key`, +`reuse-surface-hub-write-token`, `openrouter-llm-connect`, `forgejo-admin-api-token`. + +These pass the test as `permanent` **only if `secrets-engine exec` stays per-lane and +provisioned.** If secrets-engine intends `exec --catalog ` to generalize over +arbitrary OpenBao lanes, the thin-wrapper argument collapses and all six become +`interim` with `intended_owner: secrets-engine` — ops-warden would then be duplicating +a front door the owner provides. + +Asked directly (msg `7d55d332`, 2026-08-11): generic or per-lane; if generic, is it +near-term enough to mark now; and are there lanes they would decline, so those can be +marked permanent with the owner's position on record rather than ops-warden's inference. + +Supporting detail: for `issue-core-ingestion-api-key`, `reuse-surface-hub-write-token` +and `openrouter-llm-connect`, **production never touches the proxy** — External Secrets +syncs the value into the cluster and the proxy exists for operator verification and +debugging. That weakens the case that they represent a missing front door at all. + +**Do not backfill these six until the answer arrives.** A lane wrongly marked +`permanent` bakes in exactly the ownership drift this register exists to catch. + +### user-engine + +No lane names **user-engine** as owner — it appears only as a consumer inside +`coulomb-social-runtime-env` (`USER_ENGINE_PROXY_SECRET`, rotated at +`user-engine/user-engine-runtime`). Whether user-engine should front that lane itself +is worth confirming. + +## See also + +- INTENT.md §9 (cover gaps, never silently own them) +- WARDEN-WP-0019 (route to secrets-engine — the pattern this generalizes) +- WARDEN-WP-0028 (tenant secret custody pattern; front door still ops-warden's proxy) +- `history/2026-08-11-delegation-surface-assessment.md` +- `registry/routing/catalog.yaml`, `wiki/playbooks/catalog-lane-promotion.md` diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0031-policy-caller-identity.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0031-policy-caller-identity.md new file mode 100644 index 00000000..c4c600c4 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0031-policy-caller-identity.md @@ -0,0 +1,170 @@ +--- +id: WARDEN-WP-0031 +type: workplan +title: "Calling-side identity for flex-auth, so policy.enabled can flip" +domain: infotech +repo: ops-warden +status: finished +owner: ops-warden +topic_slug: netkingdom +planning_priority: P1 +depends_on_workplans: + - WARDEN-WP-0007 +related_workplans: + - WARDEN-WP-0009 +created: "2026-08-19" +updated: "2026-08-19" +state_hub_workstream_id: "739bad25-2345-5f4f-aaa3-cc4cd8c71f6c" +--- + +# WARDEN-WP-0031 — Calling-side identity for flex-auth + +flex-auth shipped `flex-auth-ops-warden` (FLEX-WP-0016 T01/T02): an +independently rollable in-cluster pin carrying ops-warden's production registry +and policy package, on digest `sha256:138aa347…`, at +`flex-auth-ops-warden.flex-auth.svc.cluster.local:8080`. + +It runs `callerAuth.mode: warn`, and it says why in its own logs: + +``` +caller authentication warning: caller is not authenticated +``` + +`src/warden/policy.py` posted `/v1/check` with **no `Authorization` header**. +flex-auth authenticates the caller with a Kubernetes TokenReview and binds +`resource.system: ops-warden` to `system:serviceaccount:ops-warden:ops-warden`; +an unauthenticated caller can only be served in `warn`. So the pin cannot +enforce, and per ADHOC-2026-08-17-T01 — `policy.enabled` must not flip anywhere +while `/v1/check` still answers unauthenticated callers — `policy.enabled` stays +false. The gap is ours, not flex-auth's, and this workplan closes it. + +Warn is also not A2 evidence: a request that succeeds because failures are +downgraded proves nothing about the enforcing path. + +## Ownership + +| Concern | Owner | +| --- | --- | +| The pin, its digest, `callerAuth.mode` | flex-auth | +| Sending a caller identity on `/v1/check` | **ops-warden** (this workplan) | +| Choosing the token source on a given host | ops-warden operator | +| `policy.enabled: true` in `warden.yaml` | ops-warden operator | + +## Design note — fail closed on identity too + +When a caller token is configured but cannot be obtained, `check_sign_policy` +raises under `fail_closed` rather than retrying unauthenticated. Falling back to +an anonymous call is precisely the behaviour that keeps the pin in `warn`; a +gate that silently degrades to the ungated path is not a gate (ADR-0004's choke +point argument, applied to ops-warden as a caller). + +## Tasks + +```task +id: WARDEN-WP-0031-T01 +status: done +priority: high +state_hub_task_id: "d3b7c701-bcdd-53f9-aa72-6f289bf5909b" +``` + +**Caller identity on the outbound policy call.** `policy.caller_auth` in +`warden.yaml` (`mode: none | file | env | command`, `token_path`, `token_env`, +`command`, `audience`); `src/warden/caller_identity.py` resolves the token at +call time and never caches, logs, or echoes it (ADR-0002); both +`check_sign_policy` and `check_fetch_policy` attach `Authorization: Bearer …`. +Whitespace-bearing and empty tokens are rejected before the call, because +flex-auth rejects them outright. + +Done 2026-08-19. `mode: none` remains the default, so behaviour is unchanged +until an operator opts in. Tests in `tests/test_policy.py`. + +```task +id: WARDEN-WP-0031-T02 +status: done +priority: high +state_hub_task_id: "b77b3c80-a168-564a-9b7f-3063aefc3c2e" +``` + +**Readiness gate.** `scripts/check_policy_caller_identity.py` — read-only: +config loads, mode is not `none`, a token is actually obtainable, and with +`--url` a live `/v1/check` against a port-forward of the warn pin. Prints the +token's length and a truncated SHA-256 fingerprint only, so its output is safe +to paste into a handoff. Exit 0 ready / 1 not ready / 2 bad input. Distinguishes +401 (token not accepted — audience or binding) from 403 (authenticated but not +allowed to represent `system: ops-warden`). + +Done 2026-08-19. + +```task +id: WARDEN-WP-0031-T03 +status: done +priority: medium +state_hub_task_id: "4245155e-6c71-5425-b574-11f61e1d4461" +``` + +**Docs.** `examples/warden.production.example.yaml` gains the `caller_auth` +block with both realistic sources, and its `flex_auth_url` is corrected — the +example pointed at `flex-auth.flex-auth.svc.cluster.local`, a Service that does +not exist. `wiki/PolicyGatedSigning.md` gains the caller-identity section and +the flip sequence. + +Done 2026-08-19. + +```task +id: WARDEN-WP-0031-T04 +status: done +priority: high +state_hub_task_id: "f3834af7-2a08-51dd-bf31-8ce8550de699" +``` + +**Pick the token source and prove it against the warn pin.** Operator work on +the real host: `kubectl create token` (workstation) or a projected token +(in-cluster PEP), then +`python scripts/check_policy_caller_identity.py --url http://127.0.0.1:19090` +against a port-forward. Expect `effect=allow` for `agt-state-hub-bridge` while +the warn log stops printing `caller authentication warning` — the absence of +that line, not the allow, is the evidence. + +Done 2026-08-19. Source is `mode: command` — `kubectl create token ops-warden +-n ops-warden --audience flex-auth --duration 10m` against the railiance01 +cluster (tunnel `k3s-api-railiance01`, local `16444`; `16443` was CoulombCore's +k3s, a different cluster, which is why a `system:masters` cert 401s there — +not a port collision, as first reported). +`deploy/kubernetes/caller-identity.yaml` creates the Namespace and +ServiceAccount the binding names — no RBAC, `automountServiceAccountToken: +false`; it exists only to be TokenReviewed. Gate exits 0 live: +`HTTP 200, effect=allow, decision:f3f7c88f9585582a`, and the pin's +`caller authentication warning` count held at 4 across two authenticated runs. +Evidence: `history/2026-08-19-flex-auth-caller-identity-evidence.md`. + +```task +id: WARDEN-WP-0031-T05 +status: cancel +priority: high +state_hub_task_id: "3f6dc609-89db-52eb-a6f9-d2fd271be821" +``` + +**Sequence the flip.** Only after T04: tell flex-auth to set +`callerAuth.mode: enforce` on `flex-auth-ops-warden` (their FLEX-WP-0016 T03), +re-run the gate against the enforcing pin, and only then set +`policy.enabled: true` with `fail_closed: true`. Flipping before enforce buys +nothing; flipping before T04 401s every `warden sign`. + +**Deferred 2026-08-19 under `ADR-0006`** — not blocked, decided against for now. + +flex-auth did enforce (FLEX-WP-0016 T03, Helm rev 2): the pin runs +`--caller-auth-mode enforce`, the gate exits 0 against it +(`HTTP 200, effect=allow, decision:f3f7c88f9585582a`), and an anonymous +`/v1/check` is 401. Everything needed to flip was in place. + +It was not flipped. `policy.enabled` is a single repo-wide boolean, and with +`fail_closed: true` it makes flex-auth a hard dependency of every `warden sign` +— including the certs the ops-bridge tunnels depend on, one of which carries +the policy call itself. Uniform enforcement across an estate being actively +rebuilt would harden the access needed to perform the rebuild. Enforcement +belongs to a zone, not to the repo; that is `ADR-0006`, and the model is +`WARDEN-WP-0032`. This task resumes as WARDEN-WP-0032-T05. + +Also shipped while proving the flip: the gate URL is now a managed ops-bridge +tunnel `flex-auth-ops-warden-railiance01` (`-L 19090:10.43.1.165:8080`) instead +of a hand-run `kubectl port-forward`. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0032-security-zones.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0032-security-zones.md new file mode 100644 index 00000000..6c8000ad --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0032-security-zones.md @@ -0,0 +1,429 @@ +--- +id: WARDEN-WP-0032 +type: workplan +title: "Adopt security zones as a consumer — retire the global policy.enabled" +domain: infotech +repo: ops-warden +status: finished +owner: ops-warden +topic_slug: netkingdom +planning_priority: P1 +depends_on_workplans: + - WARDEN-WP-0031 +created: "2026-08-19" +updated: "2026-08-22" +state_hub_workstream_id: "38c6a5f3-fb0d-5230-be85-f9e3ffc850f6" +quality_dod: DoD-Ok +quality_dod_at: "2026-08-22" +quality_dod_by: codex +quality_dod_note: "All tasks are done; the global switches and trust-zone source are retired, workload references are explicit, the owner policy is total, declarations validate, live caller identity is re-proven, and the full suite passes." +--- + +# WARDEN-WP-0032 — Adopt security zones as a consumer + +`ADR-0006` defers `policy.enabled: true` until enforcement can be scoped to a +zone. **The zone model itself is no longer ops-warden's work.** It moved to +`zone-engine` as `ZONE-WP-0001` on 2026-08-19, where it belongs under `ADR-0005` +— ops-warden implements one lane narrowly and routes the rest, and an +estate-wide enforcement model is not a lane it should absorb. + +What stays here is the consumer side: ops-warden was the repo whose deferred +flip exposed the gap, it holds the controls the model must be able to express, +and it is the first consumer the model has to satisfy. + +## What ops-warden owes zone-engine + +Inputs, not designs. `ZONE-WP-0001-T02` derives the model from the real estate, +and most of that estate is ops-warden's: + +- **27 routing catalog lanes** (`registry/routing/catalog.yaml`) with `risk`, + `status`, and `delegation` already on each — the likeliest membership inputs. +- **The actor inventory** (`adm` / `agt` / `atm`) and its TTL policy. +- **The three posture axes already shipped** — environment and maturity + (WP-0015), `organization_posture` (WP-0029) — including the honest answer to + whether `organization_posture` should be folded into zones rather than run + beside them. +- **Three controls the model must be able to express**: the flex-auth pre-sign + gate (`policy.enabled` + `fail_closed`), the agent read-boundary on + `risk: high` lanes (`ADR-0004`), and the `warden plan` escalation verdicts. +- **The compiled-registry path** (`scripts/build_flex_auth_registry.py`) — how + membership can reach flex-auth without a lookup in a latency-critical decision + path. + +## Tasks + +```task +id: WARDEN-WP-0032-T01 +status: done +priority: high +state_hub_task_id: "b03a5caa-0bb5-5cdd-bb99-32c694b0da29" +``` + +**Hand the estate inputs to `ZONE-WP-0001-T02`.** Not a design proposal — the +lanes, actors, axes, and controls above, with the exceptions ops-warden already +knows do not fit cleanly (the interim delegation lanes from WP-0030 are the +obvious candidates: a lane covered on someone else's behalf may not sit in the +same zone as one ops-warden owns outright). + +Include the `organization_posture` fold-in question honestly, including the case +against keeping it. + +**Answered by net-kingdom 2026-08-19** (canon owner of `tenancy-posture_v0.1`, +answering `ZONE-WP-0001-T01`): **do not fold it in, and do not put it in a +per-repo declaration under any key.** `organization_posture` is a fleet-wide, +time-varying scalar describing the *estate*, not a property of a declaring +service; a per-repo copy of a global goes stale in as many places as there are +repos. It stays what WP-0029 made it — an input to stance selection that the +zone model reads. Hand it over as an input, not as a candidate axis. Environment +posture and `M0`–`M3` are per-workload and remain genuinely composable; those two +are still open for `ZONE-WP-0001-T02`. + +**Done 2026-08-21.** Every input listed above is now carried in `ZONE-WP-0001`, +and `T02` there is `done` — which is the acceptance condition for this task, since +what was owed was inputs rather than a design. + +What actually reached them: the 27 graded lanes with `risk`/`status`/`delegation` +(T05), the `M0`–`M3` ladder in `registry/policy/security-posture.yaml` — which +`ZONE-WP-0001-T02` adopted as the maturity ladder rather than +`.repo-classification.yaml` `category`, on the evidence that the latter grades a +production SSH CA below a documentation repo — the three controls, and the +compiled-registry path including the dormant `trust_zone` constant at +`scripts/build_flex_auth_registry.py:77`. + +Two inputs were handed over as corrections to ops-warden's own earlier claims, +which is the part worth recording. `organization_posture` was offered as a +candidate axis and net-kingdom refused it (above); and ops-warden asserted no +registry carried a workload join key, which was true of its own catalog and false +of the estate — `rapp-*/declarations/rapp.yaml` carries eight +`workload_identity` declarations. `scripts/report_workload_join.py` then measured +the join rather than asserting it: **1 of 27 lanes** matches a declared workload. +That number is `ZONE-WP-0001-T03`'s critical path, and it came out of correcting +this repo's own input rather than out of supplying a new one. + +```task +id: WARDEN-WP-0032-T02 +status: done +priority: high +state_hub_task_id: "b3f41c85-a293-58ad-ac27-9f8110c51266" +``` + +**Replace `policy.enabled` with a zone-aware control.** Waits on +`ZONE-WP-0001-T03` and `T05`. Reads the zone of the actor being signed for and +that zone's failure mode. Ship deprecation and migration in the same change — +leaving both is the second-source-of-truth failure `ADR-0001` exists to prevent. + +Re-run `scripts/check_policy_caller_identity.py` before enabling anything: the +WP-0031 evidence (`decision:f3f7c88f9585582a`, 2026-08-19) will be stale, and +re-establishing it is cheap precisely so this is a re-check rather than a re-do. + +This closes `WARDEN-WP-0031-T05`. + +**Amended by flex-auth 2026-08-19, reviewing `ZONE-WP-0001` as the PDP.** Two +constraints that change what this task can build, both argued in full at +`ZONE-WP-0001-T03` and `T04`: + +1. **The zone-aware control splits across the boundary, it does not move.** + flex-auth will read compiled zone *membership* from the registry and apply the + per-zone *stance* from its policy package, returning an effect plus an + advisory annotation. What stays on the ops-warden side is the axis flex-auth + structurally cannot carry: **`fail_closed` is not expressible by a PDP.** + Fail-open describes what `warden sign` does when flex-auth is *unreachable* — + no decision is rendered, so no compiled data and no policy rule can reach it. + So the replacement for `policy.enabled` is not one zone-derived boolean + either; it is (a) stance, which arrives *in the decision*, and (b) failure + mode, which stays a local ops-warden setting declared per zone. Plan for two, + or T02 will be built expecting flex-auth to answer something it cannot. + +2. **The membership compiler is ops-warden's to change, and it has a name + collision to resolve first.** `scripts/build_flex_auth_registry.py:77` already + emits `"trust_zone": "platform"` as a hardcoded constant on every + ssh-certificate resource. It is a first-class field on flex-auth's `Resource`, + it is surfaced into rego input, and **no policy package reads it**. Before + compiling zone membership, either retire that constant or deliberately + repurpose it — do not add `security_zone` beside a dormant `trust_zone` and + leave the next reader to guess which is real. That is the `ADR-0001` + second-source-of-truth failure in miniature, inside a generated artifact. + +Good news for T03's cost: **no flex-auth registry schema change is required.** +`metadata`, `labels` and `attributes` already flatten into the rego input, so the +compiler can emit membership today. + +**Consumer implementation landed in the working tree 2026-08-22.** The config +loader rejects the retired `policy.enabled` and global `policy.fail_closed` +keys. `scripts/build_flex_auth_registry.py` now emits the normative +`workload_id`, `security_zone`, `security_zone_declared`, +`security_zone_admission`, `security_zone_reason`, and +`security_zone_revision` attributes; the dormant `trust_zone` field is gone. +The PEP reads compiled resource membership and applies its local per-zone +failure mode. Sign and audit records retain the zone, selected failure mode, +outcome, and decision id. + +The legacy `--no-policy` proxy switch remains only as a rejected compatibility +flag. It can no longer bypass the gate: unresolved credential targets take the +explicit `unknown` profile and its configured failure mode. + +**Done 2026-08-22.** flex-auth package v2 (commit `e521e7b`) supplies total +stance over every v0.1 zone plus `unknown`, preserves native enforcement for +`not-applicable`, and returns `audit_only` for advisory decisions. The required +live caller check passed through the existing tunnel with command-mode caller +identity and decision `decision:f3f7c88f9585582a`. The operator config was then +migrated from the two rejected global keys to `zone_registry_path`, and the +same live check passed against that real config. Full repo tests pass and +sign/audit evidence records zone, failure mode, outcome, and decision id. + +```task +id: WARDEN-WP-0032-T03 +status: done +priority: medium +state_hub_task_id: "d04a737b-ecdf-5747-ba25-20dadd99d3bc" +``` + +**Declare ops-warden's zones** in the format `ZONE-WP-0001-T05` settles, +alongside the existing posture descriptors. + +**Amended by net-kingdom 2026-08-19 — the carrier file is already settled, only +its contents are open.** Canon Decision 5.6 (`tenancy-posture_v0.1` draft-9) +rules that zone membership is declared in **`tenancy.yaml` under a reserved +top-level `zones:` key**, sibling to `tenancy:` and `provider:` and never inside +`tenancy.current`. §5.4 makes that file the repo's single posture declaration +surface, and a second root file would be the second-source-of-truth failure +`ADR-0001` exists to prevent — in ops-warden's own idiom. The key is reserved and +deliberately unconstrained in `net-kingdom/canon/schemas/tenancy-posture_v0.1.schema.json`, +so a combined declaration validates today. + +Note the consequence for this repo: **ops-warden does not currently have a +`tenancy.yaml`.** Declaring zones means writing one, which means declaring the +six-axis posture vector too. That is a real and probably overdue cost, not an +accident of this amendment — canon would rather ops-warden declare both +accurately than declare a zone with no posture beside it. + +Note also *why* stance is not something this declaration may set: canon Decision +5.6 rules that a declarer must not be the party that sets the stance, or an +accurately declared `exempt` becomes conformant *and* exempt. ops-warden declares +which zone a lane or actor is in. The stance of the pre-sign gate in that zone is +flex-auth's policy package; the failure mode is ops-warden's own setting, per +flex-auth's T03 amendment. Per flex-auth's T05 amendment, this +declaration must also say whether a zone rides the **actor** (a flex-auth +subject) or the **lane** (a flex-auth per-actor resource) — in the compiled +registry an actor is both, and the compiler needs to be told which record +carries membership. Carry the conformance rule: +*accuracy, not altitude*. Declaring a stricter zone than can be evidenced is the +failure mode that looks like progress. + +**Done 2026-08-22.** `tenancy.yaml` now declares ops-warden as an independently +governed operational execution unit with its Kubernetes service-account +binding, and admits it to `z1-operational` at `M1`, `medium`, `internal`. +`docs/evidence/security-zone-admission-2026-08-22.md` records why this is the +highest evidenced admission rather than an aspirational `M2`. The declaration +passes net-kingdom's current `tenancy-posture_v0.1` validator. + +```task +id: WARDEN-WP-0032-T04 +status: done +priority: medium +state_hub_task_id: "c7879127-3dba-55c0-853c-a10775736873" +``` + +**Amend `ADR-0006`.** Once zones exist and enforcement scoping is owned by +`zone-engine`, ADR-0006 must say that ops-warden *follows* the model rather than +owning it — a superseding record, never an in-place edit. Update `SCOPE.md`, +`wiki/WorkloadSecurityPosture.md`, and `wiki/PolicyGatedSigning.md` with it. + +**Done 2026-08-22.** ADR-0006 is marked superseded without rewriting its +decision. ADR-0009 accepts `security-zones_v0.1` as a consumer, records the +PDP/PEP split and unknown handling, and is indexed as its successor. `SCOPE.md`, +`wiki/WorkloadSecurityPosture.md`, `wiki/PolicyGatedSigning.md`, configuration +guidance, access guidance, and affected playbooks now describe the zone-aware +control and do not instruct operators to use a global bypass. + +```task +id: WARDEN-WP-0032-T05 +status: done +priority: high +state_hub_task_id: "1d968627-83f4-59cd-84ca-0f9f35e435ff" +``` + +**Grade the five exposed lanes now — do not wait for the model.** +`RISK-F-0003`: `is_high_risk` is `risk == "high"` and `risk` is optional, so the +14 ungraded lanes never reach the agent read-boundary. Five are `exec_capable` +and can therefore stream a value to an agent session: `openbao-api-key`, +`whynot-design-npm-publish`, `key-cape-oidc-login`, +`issue-core-ingestion-api-key`, `reuse-surface-hub-write-token`. + +The durable answer is a maturity-derived default (`ZONE-WP-0001-T03`), and it is +the right answer. It is also months away, and this is a live control gap in a +shipped ADR. Grade these five explicitly, then the remaining nine. + +Grading is judgement, not backfill — each lane's grade should be justified in the +entry, and the operator should sanction the high/standard calls rather than +having them inferred. Verify separately whether OpenBao's +`agent-high-risk-boundary` policy covers these paths; `RISK-F-0003` deliberately +does not assume it does, because those paths were graded by the same omission. + +**Done 2026-08-19, operator-sanctioned.** All 14 ungraded lanes graded on merit, +each with its justification in the entry: 17 `high`, 10 `standard`, **0 +ungraded**. `warden access --fetch` with `WARDEN_AGENT_ID` set now exits 7 +on lanes that were silently outside the control an hour earlier. + +Graded on merit, not defensively. A first pass marked +`issue-core-ingestion-api-key` and `reuse-surface-hub-write-token` `high`; the +existing test `test_high_risk_lanes_classified` asserted the opposite and was +right — ordinary internal workload secrets are `standard`. Both were regraded +down. `high` means disclosure into a logged context is damaging beyond what +rotation recovers: provider keys with spend, admin PATs, tenant commercial data, +supply-chain publish rights. `inter-hub-bootstrap-ssh` is `high` **conservatively** +— ops-warden could not establish that no key material moves in the envelope, and +that is recorded in the entry so it is regraded with evidence rather than assumed +down. + +The rule is now `ADR-0007`: build-stage permissiveness stops at credential +disclosure. Not yet verified: whether OpenBao's `agent-high-risk-boundary` +policy covers these paths (T06). + +```task +id: WARDEN-WP-0032-T06 +status: done +priority: medium +state_hub_task_id: "4294084c-bf3f-5aa6-b84d-5173121882ff" +``` + +**Make absence impossible, once the model says what absence means.** Waits on +`ZONE-WP-0001-T03`. Either invert the default (absent `risk` resolves through the +lane owner's maturity, per the operator direction) or require `risk` at catalog +load and in CI. Whichever lands, the failure mode to kill is the current one: +adding a lane without a grade silently places it outside a control, with nothing +at load or in CI noticing. + +Feed back to `ZONE-WP-0001-T03` whether ops-warden can supply the join it needs — +today no lane references a workload or an environment, so the `M0`–`M3` ladder +has nothing to attach to from this side. + +**Enforcement half done 2026-08-20.** It did not need the zone model: `ADR-0007` +already decided absence is a defect, which is enough to make the code fail safe +and to gate CI. + +The real mechanism turned out to be sharper than `RISK-F-0003` described. +`is_high_risk` was `risk == "high"`, but `risk` was **not** absent at the model +layer — `RouteEntry.risk` carried a dataclass default of `"standard"`. So an +omitted grade was not unhandled; it was actively resolved to the permissive +value. Fail-open by construction, which is why nothing warned. + +Now: the default is `"ungraded"`, and `is_high_risk` returns true for anything +not in an explicit low-risk vocabulary (`standard` / `low` / `accepted`). An +omitted grade **and** a grade from a newer catalog both resolve to high, so the +boundary fails safe in both directions. `is_graded` exposes the distinction, and +`test_every_repo_catalog_lane_is_explicitly_graded` is the CI gate that stops an +ungraded lane being committed. Four regression tests cover it. + +`accepted` is in the low-risk vocabulary deliberately, ready for the +maturity-derived default: an experimental-context lane may be explicitly +accepted, which is a graded decision rather than an omission. + +**Second layer checked 2026-08-20 — it does not cover them.** The OpenBao side +was compared statically (policy file vs catalog): `agent-high-risk-boundary` +denies 5 data paths covering **6** of the **17** high-risk lanes. Eight +high-risk lanes with concrete KV paths are not denied — and **four of those were +already graded `high` before the regrade**, so the divergence is pre-existing +rather than something the grading introduced. It had simply never been +comparable before. + +This matters more than the ops-warden half: `warden access` exits 7 for all 17, +but that only protects the ops-warden path. The OpenBao policy is what protects a +direct `bao kv get`, which is the actual 2026-07-16 vector. + +Routed to `risk-nexus` as **`RISK-F-0004`**, `fix_owner: railiance-platform` — +the policy is theirs, and ops-warden does not amend another repo's control. + +**Live confirmation done 2026-08-21 — and the blocker was not real.** The +token was not expired: `bao token lookup` returned a valid `platform-admin` +token from an OIDC login, and `bao policy read agent-high-risk-boundary` +succeeded. No `bao login` was needed. Worth recording as a small instance of the +lesson `.claude/rules/finding-routing.md` already states — *re-read a blocker +before trusting it*. This one was a stale claim about the world, carried for a +day in both this workplan and `RISK-F-0009`. + +The verification script also did not exist. It was described here as "ready", +and nothing was committed. `scripts/check_agent_read_boundary.py` now exists, +with tests, and is the invariant `RISK-F-0009` asked for rather than a one-off +audit: exit 1 when any high-risk lane has no corresponding deny. It prefers the +deployed policy and falls back to the file only with a loud warning, because +deployment drift is the thing it exists to catch. Capabilities-only by +construction — it reads the policy document and lane metadata, never a secret +value, and never mints a token. + +Three results, one against ourselves: + +1. **Coverage confirmed at 6 of 17** against the live policy — the headline was + right and is no longer inferred from a checkout. +2. **Six lanes uncovered, not eight.** `RISK-F-0009` counted `openbao-api-key` + (a `//` pattern) and `ops-warden-warden-sign-token` + (a broker grant, not KV) among the concrete uncovered paths, while its own + prose said the first was a pattern. Neither can be expressed as a deny. + Corrected: 6 covered, 6 uncovered, 5 with no address. +3. **The deployed policy has drifted from the file.** The file denies + `platform/workloads/core-hub/runtime`; the server does not. No ops-warden + lane maps there, so our numbers are unchanged — it matters as evidence, since + `RISK-F-0009` named exactly this divergence as its unconfirmed risk. + +Still not established, and not ops-warden's to establish: whether any agent +token carries `agent-high-risk-boundary`, and whether any carries it together +with a `workload-kv-read-*` policy. Confirming that means minting or inspecting +tokens — a write against railiance-platform's OpenBao. Exposure stays theoretical +to the same degree as before. + +**Platform half closed 2026-08-22.** `RAILIANCE-WP-0022` consumed the generated +high-risk path input and deployed the completed deny policy. The platform-owned +invariants report **19 high-risk lanes, 14 concrete entries, 0 uncovered**. A +dedicated `coding-agent-railiance-platform` AppRole then proved deny-wins with +exactly `agent-high-risk-boundary` plus one workload read policy: data access was +denied while metadata remained readable; its single-use test identity was +self-revoked and no test tokens remained. Decision `f0955252` records the +operational identity. No KV value was read. + +The local invariant agrees against the platform policy file: 19 high-risk lanes, +14 concrete entries covered, 5 without a concrete address, 0 uncovered. This +session could not independently read the deployed policy, so live-state evidence +is the platform-owned readback above rather than a claim inferred from the local +file. + +**Done 2026-08-22.** The settled model makes the two layers complementary: +catalog CI continues to require an explicit `risk` field so omission cannot +silently weaken the agent boundary, while `RouteEntry.risk_for_zone` implements +the normative maturity-derived fallback for consumers evaluating unresolved or +future inputs (`z0` + satisfied + synthetic-only → `standard`; satisfied `z3` +→ `critical`; everything else → `high`). An explicit catalog grade always wins. +The platform deny policy and its live proof above close the direct-OpenBao half. + +```task +id: WARDEN-WP-0032-T07 +status: done +priority: medium +state_hub_task_id: "6b4bbbed-2864-5fe9-82be-22ff9543f6f4" +``` + +**Adopt Repo Manager's workload-reference owner interface.** Accepted with one +documented amendment against repo-manager revision `890f3b0`: managed +deployables use the exact `(rapp_id, workload_identity.name)` pair and optional +deployable name; an independently governed operational execution unit may use +an exact local `tenancy.yaml` declaration. Native actions, actors, grants, +patterns, and non-workload resources are explicitly `not-applicable`; unresolved +workload-applicable references remain `unknown`. No path, owner name, or +repository-name inference is allowed. + +Every one of the 27 catalog lanes now carries an explicit `workload_ref`: 3 +resolved (2 exact managed RAPP references and ops-warden's direct operational +declaration), 17 unknown with reasons, and 7 not-applicable with reasons. +`scripts/report_workload_join.py` resolves only those explicit references, +Repo Manager validates the interface and resolves both managed tuples exactly, +and regression tests reject malformed or inferred joins. This incorporates +net-kingdom's draft-12 correction received 2026-08-22: local tenancy declaration +is not an escape hatch for a managed running deployable. + +## Related + +- `zone-engine` `ZONE-WP-0001` — the model, and where this work is led from +- `ADR-0006` — enforcement is zone-scoped, never a global flag +- `WARDEN-WP-0031` — the deferred flip and its readiness evidence +- `net-kingdom` `tenancy-posture_v0.1` draft-9 Decisions 5.6, 8.4.1, 8.4.2 — canon's + answer to `ZONE-WP-0001-T01`; enforcement stance is a sibling standard, not a + seventh axis, and the declaration surface is `tenancy.yaml` diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0033-native-lane-handoff.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0033-native-lane-handoff.md new file mode 100644 index 00000000..55cd0150 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0033-native-lane-handoff.md @@ -0,0 +1,344 @@ +--- +id: WARDEN-WP-0033 +type: workplan +title: "Native lane handoff — review secrets-engine's catalog admission, and fix what it exposed" +domain: infotech +repo: ops-warden +status: finished +owner: ops-warden +topic_slug: netkingdom +planning_priority: P1 +depends_on_workplans: + - WARDEN-WP-0030 +created: "2026-08-21" +updated: "2026-08-28" +state_hub_workstream_id: "4627d89b-4b00-562a-81e9-76e96f90fa7e" +--- + +# WARDEN-WP-0033 — Native lane handoff + +On 2026-08-20 `secrets-engine` accepted five of ops-warden's seven interim +proxy lanes for catalog admission (`SECRETS-WP-0006`, decision +`ae676382-1826-4e04-aa4e-bb77990c7a0d`), rejected two with reasons ops-warden +agrees with, drafted the five entries itself rather than waiting for the offered +contribution, and asked for a line-by-line review of the non-secret metadata. + +In the same hour `railiance-platform` closed the `RISK-F-0009` coverage gap and +asked ops-warden for two things back. + +This workplan is the response to both, plus the defect the review turned up in +ops-warden's own grading model — which is the most consequential item here and +would not have been found without the second pair of eyes. + +## Why a workplan and not an adhoc + +Four counterparties are waiting, one deliverable is a **cross-repo interface** +another repo will consume on a schedule, and the review carries approval +semantics — `secrets-engine` holds interim proxy ownership open until each lane +has approved native verification. The convention reserves adhocs for low-risk +work completed directly; this is none of those. + +## Tasks + +```task +id: WARDEN-WP-0033-T01 +status: done +priority: high +state_hub_task_id: "154f2f03-387d-5fe6-a0f5-1929c46a2bd8" +``` + +**Review the five drafted catalog entries and reply.** +`issue-core-ingestion-api-key`, `reuse-surface-hub-write-token`, +`openrouter-llm-connect`, `forgejo-admin-api-token`, +`email-connect-transactional` at `secrets-engine@784be97`. + +Review the axes they asked for: owner-repo coordinates, field grouping, workload +consumers, rotation/deactivation owners, delivery intent. Verify claims against +the authoritative `railiance-platform` CCRs — **never against a secret read**; +`bao kv get` on any of these paths is the 2026-07-16 vector and three of the five +are `risk: high`. + +Accept their two rejections. `openbao-api-key` is a routing template rather than +one lane and `key-cape-oidc-login` belongs to key-cape — that is `ADR-0005` +applied to ops-warden by someone else, correctly. + +```task +id: WARDEN-WP-0033-T02 +status: done +priority: high +state_hub_task_id: "6996d07f-63bb-5708-a171-68c4b1bbddde" +``` + +**Correct ops-warden's per-path risk grading — the defect T01 exposed.** + +`secrets-engine` graded `issue-core-ingestion-api-key` **high**; ops-warden grades +it **standard**, and deliberately: WP-0032-T05 regraded it *down* on 2026-08-19, +operator-sanctioned, because `test_high_risk_lanes_classified` asserted standard +and was judged right — "ordinary internal workload secrets are standard". + +That reasoning was incomplete, and CCR-2026-0002 says so explicitly: the path +carries **both** `ISSUE_CORE_API_KEY` **and** `GITEA_BACKEND_TOKEN`, a Forgejo +backend token, and the CCR records keeping both as a deliberate field-set +decision. + +**The root cause is structural, not a single bad call.** ops-warden grades a +*lane* by its headline field — the catalog carries one `fetch_command` naming one +field and no `fields` list at all — but the disclosure unit is the **path**: a +`bao kv get` returns every field stored there. So a lane can be graded on its +least dangerous contents. `ADR-0007` says every lane carries an explicit grade; +it does not say the grade must cover everything a read of that path would +disclose, and it should. + +Fix the grade, then fix the model that produced it: record `fields` per lane and +grade on the union. Check the other 25 lanes for the same shape. + +**Done 2026-08-21 — and it was two lanes, not one.** While verifying +`reuse-surface-hub-write-token` I told secrets-engine their second field was +unevidenced and asked them to confirm it. It was evidenced: `CCR-2026-0005`'s +`kv_path` block lists both fields and its notes describe the HMAC's alignment +with Forgejo org webhook id=1. A truncated grep, and a retraction sent within +twenty minutes so they would not spend time on it. That lane was under-graded on +exactly the same reasoning, and both had been regraded *down* in the same T05 +pass — which is what makes this a systematic flaw rather than one bad call. + +Blast radius checked and bounded: of the 8 remaining `standard` lanes, 6 have no +KV path at all (SSH, policy check, tunnel, principals, issue-sink, key-cape +login) so nothing is disclosed by a read. Two do have paths and no CCR field +evidence — `rein-openweights-openrouter-approle` and `coulomb-social-runtime-env` +(a whole k8s env Secret, which by shape almost certainly holds several fields). +Deliberately **not** regraded: `ADR-0008` §3 says an unknown field set is stated +rather than assumed, and grading is operator-sanctioned judgement, not backfill. +They are the open item on this task. + +Shipped: both regrades with their evidence and the superseded reasoning kept +inline, `fields` recorded with its CCR source, the test that had been holding the +wrong answer inverted with an explanation of why it was wrong to trust it, and +**`ADR-0008`** — a lane's grade covers every field its path discloses. That is a +new binding rule, so it is a record rather than a wiki note. + +```task +id: WARDEN-WP-0033-T03 +status: done +priority: high +state_hub_task_id: "a736f983-94da-5a4a-aaf9-5114485518a6" +``` + +**Emit the generated high-risk data-path artifact for `railiance-platform`.** + +They asked for a versioned artifact of concrete high-risk data paths +(`id` + `data_path` + catalog revision) to consume instead of hand-maintaining +the deny list — the half of the `RISK-F-0009` fix ops-warden explicitly declined +to build *for* them. Emitting the artifact is not the same as amending their +policy: they still own what to deny. That boundary is the point of `ADR-0002` +and must survive this task. + +Must be generated, never hand-edited, and must carry the catalog revision so a +consumer can tell what it was derived from. Depends on T02 — publishing the deny +set before fixing the grades would ship the wrong list to a consumer who will +apply it. + +**Done 2026-08-21.** `scripts/emit_high_risk_paths.py` → +`registry/generated/high-risk-data-paths.yaml`: 19 high-risk lanes, 14 concrete +data paths, 5 with no single KV address listed separately so a consumer does not +read the absence as an omission. Carries `catalog_revision`, its date, and a +`catalog_dirty` flag — a revision that does not describe the file it came from is +worse than none. + +The T02 dependency was not theoretical. The two regrades land in this artifact, +and `check_agent_read_boundary.py` now reports **2 uncovered** against a policy +railiance-platform closed to 0 yesterday. Emitting before regrading would have +handed them a list that confirmed a coverage claim that had just stopped being +true. + +`fields` is emitted as `null` where no CCR declares the set, never as a +single-element guess — `ADR-0008` §3. Two CI tests: the artifact must be current, +and every high-risk lane must appear in it, so a lane graded high after the last +emit cannot silently fail to reach the consumer. + +Boundary held: the header states this is an input and not a policy, and that +railiance-platform may deny more, deny less, or dispute a grade (`ADR-0002`). + +```task +id: WARDEN-WP-0033-T04 +status: done +priority: medium +state_hub_task_id: "5acac140-a586-5db3-b231-bbf236710786" +``` + +**Route the coding-agent issuance identity question.** + +`RAILIANCE-WP-0017` is blocked on defining a distinct coding-agent issuance +identity and proving deny-wins when that identity is combined with workload read. +They asked ops-warden to route ownership. + +Route it; do not absorb it (`ADR-0005`, `ADR-0003`). ops-warden owns actor +identity for `adm`/`agt`/`atm` **SSH certificates** and nothing else — a coding +agent's OpenBao issuance identity is an IAM question. The likely owner is +`key-cape`, with `user-engine` and `zone-engine` both plausibly involved. Say so +with reasoning rather than guessing, and record the answer either way. + +Note the interaction with `ADR-0004`: the agent read-boundary already depends on +`WARDEN_AGENT_ID` being set, which is an honour-system marker on the ops-warden +side. A real issuance identity is what would make that boundary hold on the +OpenBao side too, so ops-warden is an interested consumer, not a bystander. + +**Routed 2026-08-21 to `key-cape` (msg 903b2223); waiting on accept or refuse.** +Reasoning given: it is an identity and issuance question about a principal +authenticating to OpenBao, which is key-cape/Keycloak's. The precedent is an hour +old and runs the same direction — `secrets-engine` declined `key-cape-oidc-login` +as ops-warden's to hand them, on the grounds that login and identity-token +issuance stay with key-cape. Absorbing this would contradict agreeing with them. + +Named the adjacent parties explicitly rather than leaving them to inference: +`zone-engine` has an interest (a coding-agent identity is a strong candidate zone +subject) and `user-engine` is **not** involved — this is a machine principal, not +an end-user account. Stated so nobody concludes it by elimination. + +Asked for a refusal-with-pointer as an equally good answer. The failure mode to +avoid is the 2026-08-17 one recorded in `.claude/rules/finding-routing.md`: +ops-warden answered a question well and never routed it, and another repo ended +up filing it. + +**Followed up 2026-08-23 after the immediate enforcement gap closed.** +`RAILIANCE-WP-0022` no longer waits for this ownership decision: the platform +owner deployed a dedicated coding-agent AppRole, proved deny-wins when it is +combined with workload read, and identified an exact-bound KeyCape JWT role as +the migration target. That makes the remaining question narrower and more +important rather than obsolete: who owns issuance of the durable +KeyCape/Keycloak-backed machine identity? + +Direct follow-up `d25d4604-5713-42a8-8e3a-1ea31b5a5cc7` asks `key-cape` to +accept that target identity with an authoritative workplan/interface, or refuse +and name the actual owner. T04 remains `wait` until one of those two answers is +recorded; the live AppRole is operational evidence, not an ownership answer. + +**Answered — accepted. Closed 2026-08-28.** `key-cape` accepted issuance +ownership in `KEY-WP-0009-T03` (`status: done`, 2026-08-23): the non-secret static +registration `codex-railiance-platform` is published in +`key-cape/config/service-clients.example.yaml` — subject +`service:codex:railiance-platform`, tenant `tenant:coulomb`, role `coding-agent`, +scope `openbao:login`, `client_credentials`, 15-minute lifetime — with the +service-auth claims, renewal, expiry and failure semantics in +`key-cape/docs/openbao-service-auth-contract.md` (`T02`). The split is exactly the +one the routing asked for: KeyCape owns JWT issuance and client disablement, +railiance-platform owns the exact-bound OpenBao role and policy, OpenBao owns +enforcement, and no secret value enters either repository. + +**The answer was found by reading their repo, not by receiving it.** +`KEY-WP-0009-T04` records replying to ops-warden; no such message exists in the +ops-warden inbox — 0 messages from `key-cape`, read or unread. The acceptance had +been sitting done for five days while this task sat `wait` on it. + +That is the T05 lesson landing on T04: a blocker is a claim about the world at a +date, and this one had stopped being true. `verified: source-read` is doing real +work here — it is the difference between "we asked" and "we checked". The +mechanism is right; what it needs is for someone to run it, which is why the +lanes below were re-verified in the same pass rather than date-bumped. + +Consequence for `ADR-0004`: the honour-system `WARDEN_AGENT_ID` marker now has a +real issuance identity behind it on the OpenBao side. ops-warden remains a +consumer of that identity and does not own it. + +```task +id: WARDEN-WP-0033-T05 +status: done +priority: medium +state_hub_task_id: "75051d17-399b-5129-860b-ae00dae91c47" +``` + +**Make blocker staleness a mechanism instead of an intention.** + +Four stale blockers surfaced in twelve hours: an OpenBao token recorded expired +that was valid, a verification script recorded ready that had never been written, +a ten-day `secrets-engine` question answerable from their source, and +`FLEX-WP-0007` cited as blocking `policy.enabled` seven weeks after it read +`finished`. `.claude/rules/finding-routing.md` has said *re-read a blocker before +trusting it* since `RISK-F-0001`. Saying it has not worked. + +`warden route gaps` had a `--stale-days` threshold defaulting to 90, which was +not loose but **inert** — the register was created 2026-08-15, so it could not +fire before November. + +**Done 2026-08-21.** Two changes, and the second matters more: + +1. **Split the cadences.** `DEFAULT_STALE_DAYS` (90) still governs pointer + freshness — "is this the right owner and page" genuinely is quarterly. New + `DEFAULT_BLOCKER_STALE_DAYS` (14) governs interim blockers, calibrated on the + cases that cost something: ten days for the secrets-engine lanes, one day for + `RISK-F-0001`, ~50 for `FLEX-WP-0007`. At ~15 lanes it surfaces about one a + day rather than a wall, and it fires on zero lanes on age today. + + **Then scaled by risk, after risk-nexus answered.** They accepted the offer to + converge and published their convention: 14 days critical/high, 30 medium, 60 + low, with fix state *read* from the owning repo rather than remembered. Their + framing — "point `warden route gaps` at those windows and the two will agree + without either of us building a shared mechanism" — is better than a joint + tool, so `blocker_stale_days()` now maps lane `risk` onto exactly those + windows. `ungraded` takes the *shortest*, not the longest: `ADR-0007` makes an + absent grade a defect, so its blocker is the least trustworthy of all. + +2. **`verified:` distinguishes re-checking from re-editing.** `reviewed` records + when someone touched the entry; nothing recorded whether the claim was + re-established. `owner-confirmed` and `source-read` count; + **`asked-and-waiting` and `unverified` do not**, and a lane in those states is + stale regardless of its date. `key-cape-oidc-login` is the proof: asked today, + zero days old, correctly flagged. + +Current state: 14 non-draft interim lanes — 5 `owner-confirmed`, 1 +`asked-and-waiting`, 8 `unverified`. The 8 are honest; they were carried forward +this session without a check and now say so instead of hiding behind a fresh date. + +`--fail-on-stale` exits 3 so a cron job or gate can act. **Deliberately not a CI +test on age**: a date-triggered failure breaks the build on a calendar day with +no code change, punishing whoever commits next rather than whoever owns the +blocker. The CI test is structural instead — every interim lane must record +*how* it was verified, which fails on the commit that introduces the omission. + +```task +id: WARDEN-WP-0033-T06 +status: done +priority: high +state_hub_task_id: "94f77f5a-f919-5328-832c-ba1d24c6431b" +``` + +**Correct first-time OpenBao administration routing.** `rapp-postgres` reported +on 2026-08-22 that `warden plan` mapped first-time +`database/config/platform-pg-2` administration to the generic +`openbao-api-key` template. It consequently proposed paste-once KV provisioning +and a workload OIDC role, neither of which can configure database connections, +policies, auth roles, or token roles. Their Desk session stopped without an +approval or secret action. + +The authoritative platform runbook and rapp-postgres's live T04 evidence agree +on the missing distinction: this is one attended KeyCape-backed OpenBao identity +act at auth mount `netkingdom`, role `platform-admin`. It is not a credential +value handoff. Root stays offline break-glass authority and a workload role must +never be widened to make the operation pass. + +Add an exact `openbao-platform-admin-login` lane, an operator playbook, and a +regression that makes the reported request resolve to `founder_required` with +`oidc_login` — never `paste_once_provision`. Verify the route, then return the +corrected non-secret command to rapp-postgres. + +**Done 2026-08-22.** The new active lane resolves the exact reported request at +score 20, ahead of the generic KV template at 11, and returns one +`founder_required` act: +`bao login -no-print -method=oidc -path=netkingdom role=platform-admin`. +Planner output offers only `warden access openbao-platform-admin-login --fetch` +and the exact owner command; login lanes no longer inherit secret-value +transports (`--exec`, `--out`, `--wrap`). The lane is explicitly a high-risk, +non-workload human identity act, so the generated boundary artifact lists it as +having no KV address rather than inventing one. + +Verification: 384 tests pass, Ruff passes, workload accounting resolves all 28 +lanes (3 resolved, 17 unknown, 8 not-applicable), and the boundary invariant +reports 20 high-risk lanes, 14 concrete paths covered, 6 non-KV/pattern lanes, +0 uncovered. No login or credential action was performed. + +## Related + +- `secrets-engine` `SECRETS-WP-0006` — catalog admission, decision `ae676382` +- `RISK-F-0009` — closed by railiance-platform 2026-08-21; 0 uncovered +- `railiance-platform` `RAILIANCE-WP-0022` (boundary coverage), `RAILIANCE-WP-0017` +- `ADR-0002`, `ADR-0003`, `ADR-0004`, `ADR-0005`, `ADR-0007` +- `WARDEN-WP-0030` — the delegation register these five lanes retire from diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0034-layer-model-v07-conformance.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0034-layer-model-v07-conformance.md new file mode 100644 index 00000000..d6ebfdce --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0034-layer-model-v07-conformance.md @@ -0,0 +1,354 @@ +--- +id: WARDEN-WP-0034 +type: workplan +title: "Layer model v0.7 conformance — state the deadline, bind the agent boundary, steward the estate's newest rule" +domain: infotech +repo: ops-warden +status: active +flavor: residual +depends_on: + - WARDEN-WP-0030 +owner: ops-warden +topic_slug: netkingdom +planning_priority: P1 +depends_on_workplans: + - WARDEN-WP-0030 +created: "2026-08-29" +updated: "2026-09-28" +state_hub_workstream_id: "ae3ff76f-883d-5e2f-b6aa-144d61e8fdef" +--- + +# WARDEN-WP-0034 — Layer model v0.7 conformance + +`security-layer-model_v0.7` is **accepted**. ops-warden declared Staff and PEP-shaped, +shipped the two declaration artifacts the standard now cites as estate reference forms, +and had four findings adopted into the text between v0.4 and v0.7. + +The assessment in `history/2026-08-29-v07-scope-intent-assessment.md` checked every +v0.7 obligation against shipped code rather than intent. Three gaps survive, plus a +role the companion assigns that no conformance check will ever catch. + +## Why a workplan and not an adhoc + +T01 is a `MUST` that is currently unstated. T02 changes an enforcement boundary and +touches `ADR-0004`. T04 is a cross-repo stewardship commitment against a standard eight +repositories have yet to adopt. The convention reserves adhocs for low-risk work +completed directly; none of these qualify. + +## Tasks + +```task +id: WARDEN-WP-0034-T01 +status: done +priority: high +state_hub_task_id: "8b3bdb9f-d2c2-5b3e-89e2-417bf3e37484" +``` + +**State the revocation visibility deadline (§9.7.2, a MUST).** + +ops-warden states none, and the honest value is the certificate TTL: **up to 48 hours**. +A cert issued under an allow remains valid for its full TTL even if the authorizing +decision is revoked the next minute. There is no CRL, no KRL distribution, and host-side +`auth_principals` belongs to `railiance-infra`. + +Add the deadline to `pep-stance.yaml` as what it is — `adm` 48h / `agt` 24h / `atm` 8h — +with the mechanism named (TTL expiry, no revocation channel) rather than implied. Assert +it against the shipped `ActorType` TTL policy by test, the same way the stance map is +asserted equal to shipped behaviour: a stated deadline free to drift from the code has +the same defect as a stated stance free to drift. + +**Done when:** the deadline is published, test-bound to the TTL policy, and the absence +of a revocation channel is stated rather than left to inference. + +**Not in scope:** shortening it. Whether 48h is acceptable is a joint question with +`railiance-infra` (KRL distribution) and is T05's to raise, not this task's to decide. + +Completed 2026-09-04. `pep-stance.yaml` now publishes TTL expiry as the only +revocation mechanism, explicitly records that no CRL/KRL channel exists, and +states `adm=48h`, `agt=24h`, and `atm=8h`. The conformance test derives the +expected map from `ActorType`/`MAX_TTL_HOURS`, so declaration and issuance +policy cannot drift independently. The layer and stance declarations now name +the accepted v0.7 standard. + +```task +id: WARDEN-WP-0034-T02 +status: done +priority: high +state_hub_task_id: "3318ee1a-b5d9-5d39-baf7-9c42a8bc7b55" +``` + +**Bind the agent read-boundary to an issued identity (§3.4 rule 1).** + +`ADR-0004`'s boundary triggers on `WARDEN_AGENT_ID` — a variable the agent sets about +itself. An agent that omits it is not recognised as one. §3.4 rule 1 now requires +authority to be *issued* per task and attributable to the principal acted for. + +The identity exists as of `KEY-WP-0009-T03`: `codex-railiance-platform`, subject +`service:codex:railiance-platform`, role `coding-agent`, 15-minute lifetime, with +`railiance-platform` enforcing the OpenBao-side policy. + +Key the boundary on the issued identity where one is present; keep `WARDEN_AGENT_ID` as +a fallback that fails **toward** the boundary, never away from it. State plainly in the +ADR trail which half is enforced and which is advisory: the OpenBao-side deny is real, +the ops-warden-side refusal is a courtesy that a determined caller can decline. + +**Done when:** an agent presenting the issued identity is recognised without setting +`WARDEN_AGENT_ID`, the fallback still refuses on `risk: high` lanes, and the +enforced/advisory split is written down. + +**Watch:** do not turn this into ops-warden validating a token — that is verifying an +identity claim, adjacent to deciding, and `ADR-0002`/§6 both point away from it. Read +the identity; do not adjudicate it. + +Completed 2026-09-04. The advisory CLI guard now prefers the exact issued +KeyCape subject `service:codex:railiance-platform` from +`WARDEN_POLICY_SUBJECT`, then falls back to `WARDEN_AGENT_ID`. Tests prove the +issued subject triggers exit 7 without the legacy marker, the fallback remains, +and an operator subject does not manufacture an agent identity. ADR-0004 +revision 2 records the enforced/advisory split: Warden reads the marker and +does not validate a token; OpenBao's `agent-high-risk-boundary` is the real +enforcement. + +```task +id: WARDEN-WP-0034-T03 +status: done +priority: medium +state_hub_task_id: "a891b32c-b0a7-59f6-a5cd-977be65c09ca" +``` + +**Derive an emission cadence, or defer it with a reason (§9.6).** + +ops-warden's trail is attributive, so cadence is a SHOULD rather than v0.7's MUST for +load-bearing sources. It has been silent through two reviews, which is the one outcome +that is not defensible. + +Derive a baseline from the existing `audit.jsonl` and signatures log. If the signal is +too bursty to support a threshold — plausible, since volume is operator-driven — record +that as the finding with the distribution that shows it, and declare the deferral in +`pep-stance.yaml`. A measured "no useful baseline" is a result; silence is not. + +**Done when:** either a declared cadence with its derivation, or a declared deferral +carrying the data that justifies it. + +Completed 2026-09-04 with an explicit measured deferral. The signatures log +contains three issuances across the 79-day observation window, on only two +active days: one on 2026-06-17 and two within 40 minutes on 2026-08-22. The +unified audit carries the latter two events. `pep-stance.yaml` records the +counts, dates, attributive classification, and reason that this sparse, +operator-driven burst cannot support a meaningful rate threshold. + +```task +id: WARDEN-WP-0034-T04 +status: done +priority: medium +state_hub_task_id: "94e73daa-f74d-51fd-8639-68896a4066ee" +``` + +**Answer the question the companion sends the estate here to ask.** + +> *"For how to get something done — which lane, which credential, which route — ask +> `ops-warden`."* + +Today the repo answers credential questions and no others. `warden route` and +`warden plan` cover lanes, owners and acts. Nothing answers *"which layer am I"*, *"how +do I declare"*, *"I am PEP-shaped, what do I owe"* — and eight of fifteen catalogued +repositories have yet to declare. + +Provide the path, not the doctrine (that boundary is `ADR-0010`'s and does not move): +a routing entry and a short playbook that carry a reader from the companion to the files +to copy — `layer.yaml`, `pep-stance.yaml`, `check_layer_conformance.py`, +`test_layer_conformance.py` — and the check to run. The standard already names these in +§11 and §6.4; what is missing is the route to them. + +**Done when:** `warden route find "how do I declare my layer"` resolves, and the +playbook is reachable from the catalog. **Not** a restatement of the companion — a +pointer layer, per `ADR-0001`. + +Completed 2026-09-04. Catalog entry `netkingdom-layer-declaration` resolves the +exact query to `wiki/playbooks/netkingdom-layer-declaration.md`. The short +playbook points at the accepted companion/statute, the four reference artifacts +and checks, and the gate-house review path while explicitly leaving doctrine +with gate-house and declaration truth with each repository. + +```task +id: WARDEN-WP-0034-T05 +status: wait +blocked_on: message-from:ops-mason +blocking_reason: "Two items to route, not absorb: ops-mason has published no stance map; the second is another repository's to own." +priority: low +state_hub_task_id: "7d1b3c82-9b96-5087-a53a-496212909029" +``` + +**Two things to raise rather than absorb.** + +Both are other repositories' to own; ops-warden's obligation is to route them, not to +fix them (`ADR-0003`, `ADR-0005`). + +1. **`ops-mason` has published no stance map.** §13.1's register has one row and the + standard says that is itself the finding. `ops-mason` is catalogued PEP-shaped in + the same paragraph and is ops-warden's peer lane owner. Offer the reference form; + do not write their map. +2. **The 48-hour replay window from T01.** Once stated, raise with `railiance-infra` + whether KRL distribution is worth building, and with `access-engine` whether a + decision lifetime shorter than the cert TTL is meaningful when nothing can recall + the cert. State the question; let the owners answer. + +**Done when:** both are routed with reasoning, and the answers recorded either way — +including a refusal, which is an equally good answer. + +Raised 2026-09-04 and waiting for answers. Ops-mason received the stance-map +reference and classification question (message `6ddd6cc7`). Railiance-infra +received the KRL-versus-TTL question (message `3bfa306e`). Flex-auth, as the +current access-engine implementation, received the decision-lifetime semantics +question (message `02c99a74`). No implementation or policy decision was assigned +to another owner by these messages. + +**One of three answered, 2026-09-09.** `flex-auth` answered the decision-lifetime +question as `FLEX-DEC-2026-004` (flex-auth commit `6a6464f`), and answered it +rather than declining it: a decision lifetime shorter than the certificate TTL is +meaningful, but only as authority to **issue**, never as authority to **use** an +already-issued certificate. The action is `sign` and it completes at issuance, so +the decision is consumed once the certificate exists and no field in the decision +record reaches the artifact. 15m against a 48h `adm` certificate was never an +inconsistency to reconcile — the question mistook a decision lifetime for a +credential lifetime. + +Two obligations land on this side and are accepted: no replay of an allow past +`expires_at`, and a fresh Check per sign. The second is where the value is, and it +is real rather than nominal because claims are not cached PDP-side (deadline 0 for +the claim class), so a revoked principal stops obtaining *new* certificates +immediately. + +`pep-stance.yaml` §9.7.2 is unchanged and stays here: flex-auth explicitly declined +to move the residue to their side, on the ground that a PDP recalling an issued +credential would be "the same shape of lie as fail-open". Declining it was the +right call even though absorbing it would have made their record look tidier. + +The TTL lever they named — capping requested TTL per actor class or zone, already a +policy input since `ttl_out_of_bounds` is denied before OpenBao is reached — is +noted and deliberately not requested. Shortening `adm` from 48h has an operator +cost, and issuance on this lane is too sparse (3 signature records across 79 days, +`pep-stance.yaml` `emission_cadence`) to price it from intuition. + +T05 stays `wait` on the remaining two: `ops-mason` (no stance map published) and +`railiance-infra` (KRL distribution versus TTL expiry). Neither has replied. + +## Await gate-house's §11 precedence and case-sensitivity ruling + +```task +id: WARDEN-WP-0034-T06 +status: done +priority: low +state_hub_task_id: "b3b573df-2d2d-5a2c-9662-a13e435be57b" +``` + +ops-warden declares `layer: Staff` in `INTENT.md` frontmatter and `layer: staff` +in `layer.yaml`. §11 permits both forms and is silent on which governs when both +exist and disagree, so two conformance runs over this repository can disagree +while both follow the standard. Nine of nine repositories carrying both forms do +the same thing (flex-auth `tools/survey_layer_declarations.go`, receipt +`docs/evidence/2026-09-21-layer-declaration-survey.json`). + +**RULED 2026-09-21, APPLIED 2026-09-21.** `GH-DEC-2026-017` +(`gate-house@def0af2`, amendments A9-A13) answers both questions, and the answer +to the second dissolves the first's consequence: + +- **`INTENT.md` governs**; `layer.yaml` is a derived artifact that must be marked + derived, must name `INTENT.md` as its source, and must agree with it. +- **The §3 vocabulary is case-insensitive**, closed, and has four tokens + (`Taxonomy`, `Tooling`, `Engine`, `Staff`). A conformance run MUST ASCII-fold + case before comparing, and **no repository was asked to re-spell anything**. + `Staff` and `staff` are one value. +- **A declaration MUST NOT carry a standard version** — and that field is the + *reference form's*, not this repository's habit, so ops-warden was asked to + remove it here rather than each of seven adopters deciding. + +Verified before editing against gate-house's own committed files rather than the +inbox message: the decision at `gate-house@def0af2`, amendments A9-A13 in +`docs/amendments/v0.8-section-11-declaration-amendments.md`, and §3/§4/§11 of +`net-kingdom/canon/standards/security-layer-model_v0.8.md`. + +**What was applied.** `standard_version` removed from `layer.yaml` **and** from +`INTENT.md` frontmatter (the ruling's subject is the declaration, and `INTENT.md` +is the declaration), with the version-pinned `standard:` path de-versioned for the +same reason; `derived: true` / `derived_from: INTENT.md` added; **no layer value +changed**; `scripts/check_layer_conformance.py` rewritten to read `INTENT.md` as +governing, fold case, validate the closed four-token vocabulary, require the +derived marking, and reject a returning `standard_version` — it previously +*required* that field and so would have rejected the conforming declaration this +ruling produces; `tests/test_layer_conformance.py` asserts the **fold** rather +than equality, because an equality assertion would perform the re-spelling the +ruling declined to order. `pep-stance.yaml` untouched: a stance map is not a layer +declaration, and the schema beyond the derived marking and the version is +explicitly not ruled. + +**Evidence.** `python3 scripts/check_layer_conformance.py --report` exits 0 and +prints the governing form and the derived one separately; `pytest +tests/test_layer_conformance.py` green; full suite and `ruff` green. Reasoning +and the adopter change set: `docs/layer-declaration-precedence.md` and +`wiki/playbooks/netkingdom-layer-declaration.md`. + +**Left open, and not decided here.** Where the removed version now lives. A12 +says version-scoped state belongs in the derived conformance record, which +"already MUST" carry the version it was derived at; ops-warden has a re-runnable +checker that emits nothing durable, not an emitted record. Whether §11 expects an +emitted artifact or a re-runnable check discharges it is asked of gate-house in +message `4220413a` and unanswered. Nothing applied above depends on the answer. +**Closed 2026-09-21 by `GH-DEC-2026-020` §4 (gate-house@104f3fc):** §5 was wrong +that the record exists; a re-runnable checker is sufficient if every run prints +the version it checks against and its scope. Applied: the checker now prints +`VALIDATED_AGAINST` and `SCOPE` on every run and enforces A12 r2 by content, not +key name (versioned `standard:` path, `companion_version`); `pep-stance.yaml` +untouched per §3; the playbook carries the adopter change set. + +**Ruled the same day, and still `wait` — deliberately.** `GH-DEC-2026-017` +(message `3715e247`) landed hours later: `INTENT.md` governs, the sidecar is a +derived artifact that must be marked as such, §3's vocabulary is case-insensitive +so **nobody re-spells anything**, and `standard_version` must come out of the +declaration. Two asks land on ops-warden specifically because `layer.yaml` is the +form seven repositories copied. + +This task stays `wait` rather than flipping to `progress`, because applying it +edits this repository's security-layer declaration — and the estate's reference +shape — on the strength of an instruction delivered in an inbox message. The +session that applies it should be mandated to, and should verify the decision at +`gate-house@def0af2` and amendments A9–A13 in the repository rather than from the +message text. The exact change set and its four conditions are written down in +`docs/layer-declaration-precedence.md`; the casing half of the original "done +when" above is moot rather than outstanding, since the ruling folds case. + +Raised by flex-auth's corrected B1 (message `719b3e9e`, 2026-09-21), which +withdrew an earlier claim that the estate disagreed *across* repositories. The +withdrawal matters to this task: the original finding would have had ops-warden +changing a file to match an estate consensus that did not exist. + +## Related + +Review 2026-09-05: reviewed the pending implementation and fixed the identity +helper so an explicitly empty environment does not inherit the process identity. +Regression coverage also proves an operator subject cannot override the legacy +agent marker. Refreshed the generated high-risk path artifact after the catalog +changes. T05 remains waiting: no corresponding reply was present in the inbox, +and the checked owner workplans contained no resolution of these questions. +Validation: 415 unit tests and four SSH integration tests pass; Ruff, the +layer-conformance script, and the declaration-route CLI smoke check pass. + +- `history/2026-08-29-v07-scope-intent-assessment.md` — the gap analysis behind this plan +- `history/2026-08-29-layer-model-v04-review.md`, `-v06-review.md` — the two prior reviews +- `security-layer-model_v0.7.md` §3.4, §6.4, §9.6, §9.7, §11, §13.1 +- `net-kingdom/SECURITY-COMPANION.md` v0.2 +- `ADR-0002`, `ADR-0003`, `ADR-0004`, `ADR-0005`, `ADR-0009`, `ADR-0010` + +### 2026-09-28 loose-end review + +T05 remains wait; the workplan is blocked on the two outstanding owner answers. +The local ops-mason checkout still has no published stance map, and the available +railiance-infra workplans/docs contain no KRL-versus-TTL acceptance or refusal. +The flex-auth decision-lifetime answer remains accepted. Warden's declaration, +TTL-bound tests and fresh-check behavior are complete; inventing an owner answer +would not satisfy T05. No certificate lifetime or revocation policy was changed. + +> 2026-10-11: demoted to `flavor: residual` / `backlog` by founder-authorized triage — off the +> critical path (identity → authz → secrets → SecurityCase execution). Tasks are unchanged; +> promote back when demand or risk appears. See the-custodian +> `history/20261011-netkingdom-security-progress-assessment.md`. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md new file mode 100644 index 00000000..1210b158 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0035-policy-nexus-forgejo-source-read-route.md @@ -0,0 +1,46 @@ +--- +id: WARDEN-WP-0035 +type: workplan +title: "Register the Policy Nexus Forgejo source-read route" +domain: infotech +repo: ops-warden +status: finished +owner: codex +topic_slug: policy-nexus-forgejo-source-read +created: "2026-09-01" +updated: "2026-09-01" +state_hub_workstream_id: "45aec8d3-94b3-586e-b019-a47e656efafa" +--- + +## Register the exact high-risk lane + +```task +id: WARDEN-WP-0035-T01 +status: done +priority: high +state_hub_task_id: "dd84f2be-0143-540c-9c16-74f0fd129260" +``` + +Add the exact OpenBao path, field, OIDC role, owner pointer, and rotation +boundary from railiance-platform CCR-2026-0014. The entry must be concrete and +resolvable while remaining subject to Warden's high-risk agent read boundary. + +## Verify routing and governed use + +```task +id: WARDEN-WP-0035-T02 +status: done +priority: high +state_hub_task_id: "1fa8f778-3e46-5f44-86c4-cab8628b7e60" +``` + +Pass catalog, route-selection, proxy, and policy tests; reinstall the CLI; prove +the installed route resolves and can hand the value only to a sanctioned child +transport without printing or persisting it. + +Completed 2026-09-01. All 406 selected tests passed, including the generated +high-risk data-path boundary. The no-cache installed CLI resolves the exact +lane, and `warden plan` returns only sanctioned `--exec`, `--out`, and `--wrap` +transports for an agent caller. Policy Nexus Actions run 32 separately proved +the installed credential against the complete private-source fetch and release +path without exposing the value. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0036-attended-login-openbao-output.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0036-attended-login-openbao-output.md new file mode 100644 index 00000000..452eb412 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0036-attended-login-openbao-output.md @@ -0,0 +1,131 @@ +--- +id: WARDEN-WP-0036 +type: workplan +title: "Accept contained OpenBao login output only after helper persistence" +domain: infotech +repo: ops-warden +status: finished +owner: codex +topic_slug: attended-login-openbao-output +created: "2026-09-01" +updated: "2026-10-15" +state_hub_workstream_id: "d844c96e-152d-53fa-bff6-e072125ef66c" +--- + +## Repair attended-login handoff + +```task +id: WARDEN-WP-0036-T01 +status: done +priority: high +state_hub_task_id: "7eb8b9c9-1285-5ada-a17b-1d5bfbb8ba59" +``` + +Allow a successful OpenBao login to proceed when its output is fully contained +and the private mode-0600 token helper is populated. Continue failing closed on +non-zero login, missing persistence, child output, revocation failure, or cleanup +failure. + +## Verify live contained operation + +```task +id: WARDEN-WP-0036-T02 +status: done +priority: high +state_hub_task_id: "d22bab05-c38b-561f-95de-6c146ce7c6cf" +``` + +Run the proxy regression suite, reinstall the CLI, and complete one governed +OpenBao platform-admin operation with deterministic self-revocation. + +Completed 2026-09-01. The installed CLI completed the governed Policy Nexus +Forgejo source bootstrap with all child output contained, then revoked and +removed its isolated helper session. + +### 2026-09-28 contained-result correction (existing T01/T02) + +Addressed the September 21 attended-login failure/audit report under the existing +handoff repair and verification tasks. Failed envelopes now use distinct +non-zero codes 10–14 for login, child failure, child output, unconfirmed revocation +and cleanup failure. Both audit files retain the actual Warden exit code and +phase outcome. Any child bytes, including whitespace, fail closed; the access +advisory now states the silent-child requirement and the playbook documents codes, +retry limits and the WSL tunnel/browser requirements. + +The pre-change checkout already raised exit 5 on ProxyError, so the reported +historical exit-zero failure was not reproduced here. The actual reproduced defect +was unconditional success auditing; the new CLI regression covers failed login +with returncode zero but missing persistence as well as non-zero login, start +failures, child output/failure, revocation and cleanup. Revocation still checks +revoke-self's exit status; it does not misinterpret an arbitrary failed lookup as +proof. The September 23 platform return confirms revoke-self is already granted. + +Validation: focused proxy suite 48 passed; full suite 483 passed, 4 integration +tests deselected by repository default; changed Python files pass Ruff. No live +OIDC, credential read or production operation was used. The earlier September 1 +live operation remains historical evidence, not a live validation of this change. +Automated endpoint/browser preflight and OIDC URL presentation remain optional +inbox suggestions, outside these completed handoff acceptance criteria. + +### 2026-10-14 login-output fail-closed regression and fix (existing T01) + +railiance-platform's RPF-WP-0017 re-acceptance review +(`railiance-platform/reviews/RPF-WP-0017-ops-warden-reacceptance-2026-10-14.json`, +decision `reject`) found that T01's commit `b4c1d39` (2026-09-01) dropped +`login_output.strip()` from the login fail-closed condition. From then until this +fix, a login that exited 0 with a populated helper proceeded to the child whatever +it wrote to stdout/stderr. Output stayed contained (criterion 3 held) but +criterion 4 (non-allowlisted output fails closed with self-revocation) and the +criterion 5 unexpected-output coverage regressed; the existing unexpected-output +test passed only through the empty-helper persistence path. + +Fix: login output is still captured and never forwarded, and is now accepted only +when allowlisted by structure (values are never logged, returned, stored, or put +in exceptions/audit): + +- stdout: empty, or exactly one JSON object with an `auth` object containing + `client_token`; top-level keys limited to `request_id, lease_id, + lease_duration, renewable, data, warnings, wrap_info, mount_type, auth`, auth + keys to `client_token, accessor, policies, token_policies, identity_policies, + metadata, orphan, entity_id, lease_duration, renewable, mfa_requirement, + num_uses`, each type-checked; duplicate keys rejected. +- stderr: empty, or exactly the OpenBao OIDC CLI prompt ("Complete the login via + your OIDC provider. Launching browser to:" or "... Open the following link in + your browser:", one `https://` URL, optional "Waiting for OIDC authentication to + complete..."). These prompt strings were confirmed present in the local `bao` + binary; this stderr allowlist entry is an ops-warden proposal pending + railiance-platform review under RPF-WP-0017. + +Anything else (extra text, other stderr, multiple objects, unexpected keys or +types, parse/decoding failure) fails closed: self-revocation through the existing +path, helper cleanup, exit 10 / `login_failed`, no retry. Added a parametrized +populated-helper test for 13 non-allowlisted shapes and an allowlisted hand-off +test; the success test now uses a full JSON shape plus the OIDC prompt. The +September 1 T02 live operation was recorded in `9770d6a` (00:51 +0200), after +`b4c1d39` (00:13 +0200) and `8f01eef` (00:24 +0200); `proxy.py` at that time +contained the relaxed check (the installed CLI's exact revision was not recorded). No live OIDC, OpenBao call, or credential read was used for this fix. + +Tightened the same day after an independent re-review (containment gap): stdout +`wrap_info` must be null or absent (a wrapping token would survive `token revoke +-self`), `data` null, absent or `{}`, and `auth.client_token` a non-empty string; +the stderr OIDC prompt must start at the first byte (no leading whitespace; +trailing newlines remain fine). The fail-closed and hand-off tests now run through +the CLI and assert sentinel absence from both `access-audit.log` and `audit.jsonl`. + +### 2026-10-15 CUST81 dependency correction (existing T01/T02) + +Prepared source correction after the two CUST81 attended platform-admin attempts +failed before child handoff. The strict login-output allowlist remains unchanged. +Synthesized format flags now precede auth data; the recovery-only matcher handles +OpenBao `s.` tokens; failure messages expose only fixed categories, client exit +code and helper/output-shape booleans. No credential bytes or URLs are surfaced. + +Do not attribute the observed 121-second failure to the argv order: Bao 2.5.5 +scans global format throughout argv. Actual callback/auth failure remains unknown. +Browser profile initialization was verified from metadata only; server revocation +remains unconfirmed and the failed attempts are retained. No login, admin token +read, policy application or provisioning was performed by this correction. + +Source verification is distinct from live verification. The already-approved +CUST81 execution scope and its open attended gate remain with CUST-WP-0081-T02. +Owner evidence: `docs/evidence/2026-10-15-cust81-attended-dependency-repair-r1.json`. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md new file mode 100644 index 00000000..a3eba2df --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md @@ -0,0 +1,191 @@ +--- +id: WARDEN-WP-0037 +type: workplan +title: "Repoint the whynot-design npm lane to Forgejo" +domain: infotech +repo: ops-warden +status: blocked +flavor: planning +owner: codex +topic_slug: whynot-design-forgejo-npm-lane +created: "2026-09-04" +updated: "2026-10-03" +state_hub_workstream_id: "42a097db-1c24-558e-a724-030bb2b4443e" +--- + +## Verify the existing credential against Forgejo + +```task +id: WARDEN-WP-0037-T01 +status: done +priority: high +state_hub_task_id: "afc4d325-1c6d-5c25-aaf7-2118aa8f86c6" +``` + +Use only the governed execution transport to test the existing publish identity +against the canonical Forgejo npm endpoint. Do not print or persist the token. + +2026-09-04: `warden plan` classified the exact verification as autonomous and +selected this lane. A contained login using the documented +`whynot-design-workload-kv-read` role proved `read` on the exact OpenBao data +path, and the governed child proved the secret is present. A real 0.4.2 publish +through that credential then failed. No value was printed or persisted and each +contained session self-revoked. The lane therefore needs token rotation, not an +OpenBao policy repair. + +## Repoint the catalog and playbook + +```task +id: WARDEN-WP-0037-T02 +status: done +priority: high +state_hub_task_id: "7ceb2f74-496c-54e8-bf5a-3c49f994ff23" +``` + +Replace the retired Gitea endpoint and discovery language with Forgejo while +preserving the established OpenBao path, field, and least-privilege boundary. +This delivers the npm facet of routed intake +`01a06e07-f2f9-7586-9745-b359eb0025b6`; its inter-hub SSH facet remains separate. + +Completed 2026-09-04. The catalog title, discovery keywords, rotation guidance, +and worker playbook now name the canonical Forgejo registry at +`https://forgejo.coulomb.social/api/packages/coulomb/npm/`. The OpenBao path, +field, owner, native-exec pointer, and high-risk boundary are unchanged. A +regression assertion prevents the retired Gitea discovery term and guidance +from returning. + +## Prove routing and publication + +```task +id: WARDEN-WP-0037-T03 +status: wait +priority: high +decision_id: 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa +depends_on: [SECRETS-WP-0006-T06] +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." +intervention_note: "HOLD (founder, 2026-09-21): do not rotate yet. secrets-engine exec reads the ungoverned legacy path secret/coulomb/whynot-design/npm/publish (field npm_token); this runbook writes the governed path platform/workloads/coulomb/whynot-design/npm-publish (NPM_AUTH_TOKEN). A rotation now would not reach the live publish path. Resume after SECRETS-WP-0006-T06 moves the lane. Then: rotate the dedicated Forgejo package token, and prove a fresh publish and exact npm view through this lane." +state_hub_task_id: "a8b1b855-ab34-5835-b9fd-5f48bc0b6817" +``` + +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. + +Pass catalog and routing tests, verify the checkout route, and record the exact +Forgejo package release proven through the lane. + +2026-09-04: repo-local verification is complete: the checkout route ranks +`whynot-design-npm-publish` first for a Forgejo npm publish need, reports the +canonical Forgejo title and verification command, all focused +routing/access/proxy tests pass (`145 passed`). + +The sibling repo's `@whynot/design@0.4.2` release (105 files; IR +`designVersion` 0.4.2; five visual tests pass) was published through the +plan-authorized `forgejo-admin-api-token` one-time recovery lane. An +authenticated exact-version lookup proved that Forgejo's remote integrity +matches the local dry-run. T03 waits only on rotating the dedicated package +token and proving the next fresh version through `whynot-design-npm-publish`; +the package migration itself is complete. + +**2026-09-09 — field claim corrected, path routed.** `secrets-engine` (msg +`15f0c0ca`) corrected two things and declined a third, all correctly. + +The KV field is `npm_token`. `NPM_AUTH_TOKEN` is the environment variable their +publication-scope policy injects, and ops-warden had copied the env var in as the +field name — so the catalog's `fetch_command` named a field that does not exist +and could only ever have failed. Corrected in `registry/routing/catalog.yaml` and +`wiki/playbooks/whynot-design-npm-publish.md` from the owner's statement rather +than re-derived here. This was `ADR-0001`'s failure mode rather than a typo: a +pointer layer restating an owner's procedure and getting a detail wrong. + +The endpoint claim already agreed; `delivery_config.npm.registry` has been the +Forgejo URL throughout. + +The **path** is routed to `railiance-platform` and the catalog is unchanged pending +their answer. Which location backs the lane for reads is custody state they own; +`secrets-engine` has no lane read authority to confirm it and refused to rewrite a +production lane pointer from a coordination message (`SECRETS-WP-0006-T06`). Their +reasoning is right, and asserting our own pointer is authoritative because it is +ours would route around it. The ask names a location only and flags that a +`bao kv get` answer would be the 2026-07-16 disclosure vector on a `risk: high` +lane. + +`ready: false` is not being read as path evidence: a source checkout with no +production authority reports not-ready regardless of which path the catalog names. + +T03 still waits on the human rotation of the dedicated Forgejo package token; the +path question does not block that, it determines whether the pointer is correct +once it rotates. + +**2026-09-21 — field reverted to `NPM_AUTH_TOKEN`; path confirmed; a second +location found.** `railiance-platform`, who holds custody of the path, answered +both halves (msgs `c6841bdb`, `79f3e047`) and the answer reverses the 2026-09-09 +change above. + +An attended founder session enumerated the field names present at +`platform/workloads/coulomb/whynot-design/npm-publish`: read-only, no mutation, +no value emitted, `attended_identity` true. **Exactly one field is present, and +it is `NPM_AUTH_TOKEN`.** Receipt: `railiance-platform +docs/evidence/2026-09-10-npm-lane-field-resolution.json`, commit `9d24086`. The +both-fields reconciliation offered the day before is ruled out by the same +enumeration. `CCR-2026-0001` has carried two dated receipts naming that field +since 2026-06-28, one of them an attended founder fetch that exited zero — which +is itself proof the field exists. + +So `npm_token` is wrong *for this path*, and the catalog and playbook are +reverted to `NPM_AUTH_TOKEN`. Reverting is a correction back to the evidenced +value, not a new lane change. + +The lesson is the one this plan already recorded, one level in. On 2026-09-09 +this file wrote that adopting a correction from `secrets-engine` rather than +re-deriving it was the right shape. It was the right *source* and the wrong +*standard of evidence*: a correction adopted from a coordination message is +still an unverified mutation, even when it is only a field name in a catalog, +and this one would have failed at the rotation T03 is waiting for — the moment +it is most expensive to discover. railiance-platform's phrasing, kept because it +is better than ours: it will break "at the moment you least want it to". + +**The second location, which is not ours to dispose of.** +`secret/coulomb/whynot-design/npm/publish` exists — version 1, created +2026-07-03T15:00:44Z, never updated, five days *after* the governed lane was +verified. It sits outside this lane's exact-path policy and outside any CCR. +railiance-platform read metadata only: field names were not enumerated, the +value was not read, nothing was deleted, because a location holding real +credential material is disposed of deliberately by its owner rather than tidied +away by whoever finds it. + +Their unconfirmed hypothesis, recorded because it changes what this lane's +acceptance evidence means if true: `secrets-engine`'s lowercase field may belong +to *that* path, their catalog may declare that location, and the proven pilot +publish may have been reading the duplicate all along. If so, a working +production lane has been running ungoverned and this lane's acceptance evidence +describes a path its consumer does not use. Tracked as `RPF-WP-0035-T07`; +railiance-platform has asked `secrets-engine` which location their publish +reads, and ops-warden has asked the same about the native +`secrets-engine exec` front door this catalog points at (`exec_owner`). + +Recorded in the catalog and in `wiki/playbooks/whynot-design-npm-publish.md` as +an explicit non-lane rather than deleted from the record. Not routed around: the +governed path stays the pointer. + +### 2026-09-27 owner follow-up + +Consumed the September 21 secrets-engine source return: the active catalog +still names `secret/coulomb/whynot-design/npm/publish`, field `npm_token`. +The governed field remains `NPM_AUTH_TOKEN`; no pointer correction is needed +in Warden. RPF-WP-0035-T07 now requires native governed-consumer proof before +legacy destruction and no longer asks for comparison of secret values. + +T03 remains wait and the founder's no-rotation hold remains effective. +Resume only on the SECRETS-WP-0006-T06 migration receipt, then rotate through +the dedicated package lane and prove a fresh publish plus exact npm view. +Do not treat the September 16 OpenRouter key-check receipt as npm acceptance. + +### 2026-09-28 loose-end review + +Workplan state corrected to blocked to match T03's wait and the September 27 +owner return. The governed catalog field and path are already correct. The +founder's no-rotation hold remains binding until SECRETS-WP-0006-T06 supplies +native governed-consumer migration evidence; a dedicated token rotation and a +fresh package publish/exact-version lookup then remain. No credential fetch, +rotation or publication was attempted. + +2026-10-03 (CUST-WP-0075): the gate was only in intervention_note. Encoded as blocking_reason, depends_on SECRETS-WP-0006-T06, and hub decision 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa (D3: trust root and secret custody), which also carries the matching RPF-WP-0035-T07 hold. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0038-plan-mutation-intent.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0038-plan-mutation-intent.md new file mode 100644 index 00000000..8c9c5b6d --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0038-plan-mutation-intent.md @@ -0,0 +1,149 @@ +--- +id: WARDEN-WP-0038 +type: workplan +title: "warden plan must distinguish reading a secret from mutating one" +domain: infotech +repo: ops-warden +status: finished +owner: ops-warden +topic_slug: netkingdom +planning_priority: P1 +depends_on_workplans: + - WARDEN-WP-0029 +created: "2026-09-08" +updated: "2026-10-16" +state_hub_workstream_id: "751ad530-e44b-52c4-b70e-cb47568a0179" +--- + +# WARDEN-WP-0038 — Read versus mutate intent in the policy front door + +## The defect + +`warden plan` scores a need against catalog lanes by keyword overlap and returns +a verdict. It has no notion of what the caller wants to *do*. So a need that +says *generate a successor secret and CAS-write it to two custodians* matches the +lane that **reads** that path, scores well on the shared nouns, and returns: + +``` +verdict: autonomous +commands: warden access --exec / --out / --wrap +``` + +Three read transports offered as the answer to a write, under the verdict that +means "proceed without the founder". Reproduced 2026-09-08 against +`rapp-qonto-keycape-client` (`ADHOC-2026-09-08-T04`). + +## Why this is worse than a bad suggestion + +`warden plan` is the documented first step before drafting any founder credential +step (`.claude/rules/credential-routing.md`), and `autonomous` is consumed as an +authorization signal by agents that have no other check. `WARDEN-WP-0029` shipped +the verdict *because* instinct was not auditable; a verdict that is confidently +wrong in the permissive direction is worse than no verdict. + +key-cape hit this and refused to rely on it — "we are not treating a generic +match as authorization" — which is the only reason it surfaced as a design +question rather than as an unadmitted custody mutation. The control that caught +it was a counterparty's caution. That is not a control. + +`WARDEN-WP-0033-T06` is the same shape (rapp-postgres, generic +`openbao-api-key` match → `paste_once_provision` for an act that could not work) +and was fixed by adding one exact lane plus one regression. That fixed the +instance. This is the class. + +## Shape of the fix (to be designed, not assumed) + +- Classify need intent — read / mutate / establish — before scoring, and never + answer a mutate need with a read lane's transports. +- A mutate need against a lane ops-warden does not own is `unroutable` with a CCR + stub naming the custody owner, not `autonomous`. `ADR-0003`: cover gaps, never + silently own them; a permissive verdict on someone else's custody act is a + silent claim of ownership. +- Consider whether `rotation.steps` should be reachable from `plan` at all, given + they are advisory prose and several are explicitly not automatable. +- Regression from the reproduced case, in the manner of T06. + +## Open question for design + +Whether intent belongs in the matcher or in the lane. A lane could declare which +acts it admits (`read`, `rotate`, `provision`) and `plan` could refuse any act a +lane does not declare — stricter, and it fails closed on lanes that say nothing, +which is the majority today. That is a catalog schema change and needs its own +argument. + +## Confirmed independently, then fixed — 2026-09-09 + +`railiance-platform` hit the same defect from the other side while answering the +Qonto custody routing question (msg `7c7228ac`). Having stated that the correct +verdict is `founder_required` — attended OIDC via `netkingdom` `role=platform-admin`, +through the governed `openbao-platform-admin-login` lane — they added: + +> Note this is the same verdict your `warden plan` should have returned; it +> returning `autonomous` and offering read transports for a write is a real +> defect and WARDEN-WP-0038 is the right place for it. Until that is fixed, do +> not let a plan result stand in for this answer. + +Two counterparties reporting the same wrong verdict in two days, one of whom is +the write authority being wrongly bypassed, moved this from proposed to shipped. + +### What shipped + +`_need_intent()` classifies a need as `mutate` or `read` by token match, and +`_owns_write_authority()` tests `delegation.mode == "permanent"`. A mutating need +on a lane ops-warden does not permanently own can no longer reach any branch that +returns `autonomous`: + +- lane declares a `rotation` → `founder_required`, with an `approve` act naming + the write owner, the rotation method, whether it is automatable, and + `warden rotate-guide` as guidance; +- lane declares none → `unroutable` with a CCR stub whose `owner_hint` names the + write authority. + +**Commands are empty of read transports either way.** That is the half that made +the wrong verdict actionable rather than merely wrong: `--out`, `--exec`, +`--wrap` and a bare `bao kv get` were being offered as the answer to a write, and +a test now asserts none of them appears. + +### The design question in the plan, answered by use + +The plan asked whether intent belongs in the matcher or in the lane. It went in +the matcher, with the *ownership* test doing the work that a verb list cannot: +SSH certificate issuance is itself a mutating act, and `warden sign` must stay +`autonomous`. `delegation.mode: permanent` is what separates ops-warden's own +front door from someone else's custody — not the absence of a verb from a list. +A regression asserts the SSH lane still proceeds, because a guard that refuses +our own lane would be a worse defect than the one it fixes. + +The stricter alternative — lanes declaring which acts they admit, `plan` refusing +anything undeclared — is not built. It is a catalog schema change that would fail +closed on the majority of lanes, which say nothing today, and it needs its own +argument rather than arriving as a side effect of this fix. + +## Recognize explicit attended OpenBao platform administration + +```task +id: WARDEN-WP-0038-T01 +status: done +priority: high +``` + +2026-10-16 source follow-up: the exact request "attended OpenBao platform +administration for reviewed flex-auth signer custody CAS0 and fixed KV metadata" +fell through to keyword ranking and selected `openbao-structure-survey` / +`approve`. The configuration override required policy/auth-role nouns even +though the caller explicitly named attended platform administration. Recognize +that explicit intent before keyword ranking. The plan now selects +`openbao-platform-admin-login` / `founder_required` / `oidc_login`; the governed +reviewed-command transport and identity gate are unchanged. Survey requests +remain metadata-only, and a missing administration lane stays unroutable. + +Prepared and tested in an isolated checkout for independent review. This task +records source repair only; it neither authorizes nor claims installation, +attended login, signer provisioning or full16TSA native acceptance. Integration +and the existing platform custody work retain those next actions. + +### Not claimed + +This narrows what `warden plan` will assert; it does not make the tool an +authority on custody. railiance-platform's instruction stands and is the right +standing posture: a plan result does not substitute for the owner's answer. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0039-explicit-policy-refusal.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0039-explicit-policy-refusal.md new file mode 100644 index 00000000..ca0828d2 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0039-explicit-policy-refusal.md @@ -0,0 +1,159 @@ +--- +id: WARDEN-WP-0039 +type: workplan +title: "Preserve explicit policy caller refusals before credential and CA effects" +domain: infotech +repo: ops-warden +status: finished +flavor: residual +owner: codex +topic_slug: custodian +created: "2026-09-08" +updated: "2026-10-03" +origin: residual +origin_ref: HFACT-WP-0001 +state_hub_workstream_id: "ae44a935-6fca-514c-a385-4550dd2b1fe8" +--- + +The factory critical-path review reproduced a live HTTP 403 from the reachable +PDP for the configured ops-warden caller and a railiance-platform secret read. +`check_fetch_policy` treated it as evaluator unavailability and used unknown-zone +fail-open. Caller-auth rejection is an explicit refusal, not a transport outage. + +## Preserve explicit authentication and binding refusals + +```task +id: WARDEN-WP-0039-T01 +status: done +flavor: residual +priority: high +assignee: the-custodian +state_hub_task_id: "eaad08d9-ae47-5f50-8278-ea402a0e2869" +``` + +HTTP 401 and 403 stop signing and credential fetch irrespective of the outage +profile. Do not expose response bodies or alter system identity to bypass the +refusal. Preserve configured behavior for genuine evaluator failures. Prove +both permissive and closed outage profiles and refusal before child execution. + +## Verify and publish the correction + +```task +id: WARDEN-WP-0039-T02 +status: done +flavor: residual +priority: high +assignee: the-custodian +state_hub_task_id: "ac85cf00-391c-5c63-b8f4-ed5bd57684e5" +``` + +Run the policy and proxy suites, retain a value-free live refusal receipt, +publish the reviewed source, and verify the installed CLI refuses before any +credential transport. A refusal is not a successful credential-read admission. + +The owner installer initially reused a cached wheel despite `--force`, leaving +the pre-fix policy code installed. Both Makefile installation targets now use +`--reinstall-package ops-warden` to refresh this package from the reviewed source. +Verify the installed module as well as the checkout before the live refusal test. + +## Resolve the credential proxy's admitted policy binding + +```task +id: WARDEN-WP-0039-T03 +status: done +flavor: residual +priority: high +assignee: the-custodian +state_hub_task_id: "8ca28b63-2e04-5333-b635-011b124c1806" +``` + +Consume the existing native-lane handoff (WARDEN-WP-0033 / SECRETS-WP-0006) +and flex-auth caller contract. Establish whether this interim transport needs an +admitted dedicated policy route or must finish its native handoff. Retain the +refusal until that contract yields positive and wrong-caller/owner/tenant +negative evidence. No credential read, secret generation, or policy grant is +authorized by this workplan alone. HFACT-WP-0001-T03 consumes this return. + +Validation: 429 tests passed (4 integration tests deselected by the repository default); Ruff passed for changed Python files. Full tests used the declared phase-memory source and an isolated temporary memory store. The focused policy/proxy suite passed 69 tests. The existing authenticated SSH policy probe still returns HTTP 200/ALLOW, decision:f3f7c88f9585582a; the credential-owner request returns 403. No CA issue or credential read was performed by these probes. + +Installed verification: source guard present after refreshed owner installation (`19bb75c`). `warden access forgejo-admin-api-token --exec --field API_TOKEN -- true` exits 4 with explicit HTTP 403 before credential transport or child execution. The previous fail-open warning is absent. The probe requested no output value; no credential was fetched. T01/T02 are complete; T03 owns the remaining exact policy-binding admission. + +**T03 routed 2026-09-09.** Asked `flex-auth` whether an admitted contract exists +for a delegated credential read where the caller (ops-warden) and the resource +owner differ, since that is exactly the shape drawing the live 403. Three outcomes +were named as equally acceptable answers, with no preference stated between the +first two: an existing contract to conform to; no contract yet, making this a +design question they should raise rather than one ops-warden invents a shape for; +or that there should be **no** such contract — the interim proxy transport is +itself the defect and the answer is to finish the native handoff +(`WARDEN-WP-0033` / `SECRETS-WP-0006`). + +The third is a real possibility and was not argued against. Eleven catalog lanes +are ops-warden proxies with a named intended owner precisely because no owner +front door exists; if delegated reads should not be made policy-admissible, that +shortens WP-0033 rather than blocking it. + +Two fixes were explicitly ruled out in the message rather than left unmentioned: +broadening the ops-warden caller binding so it may read other systems' resources, +and relabelling `resource.system` as ops-warden so the existing binding matches. +The second is worse — it would make the audit trail assert ops-warden owns +credentials it deliberately does not, which is the claim `ADR-0002` exists to +prevent, achieved by editing a field instead of making an argument. + +The refusal stays in place until an answer yields positive evidence plus +wrong-caller, wrong-owner and wrong-tenant negatives. No grant was requested. +`secrets-engine` was told this bears on SECRETS-WP-0007-T04 and on how many lanes +stay proxied; `gate-house` was told it may reach how the signing lane's +approval-consume is built (GH-DEC-2026-005). + +### 2026-09-28 loose-end review + +T03 remains wait and the workplan remains blocked. Re-read the owner's finished +FLEX-WP-0026: no admitted delegated-read binding exists, and its native OpenRouter +contract explicitly does not close WARDEN-WP-0039-T03. FLEX-DEC-2026-015 also +confirms resource.system is runtime policy vocabulary, not a repository rename. +Retain the explicit refusal. A native owner route's success does not grant this +interim proxy general delegated-read authority; exact positive and caller/owner/ +tenant negative evidence is still required for the route that replaces it. + +**T03 code side done 2026-10-03 (CUST-WP-0075, founder build-mode directive).** +access-engine answered the contract question with a dedicated fetch evaluator: +pin `flex-auth-ops-warden-fetch` (access-engine 02b15a7, `values/ops-warden-fetch.yaml`), +same caller (ops-warden SA, audience flex-auth), owner systems bound per lane, +request shape unchanged. ops-warden now sends `check_fetch_policy` only to the new +key `policy.fetch_flex_auth_url`; signing keeps `policy.flex_auth_url`. An unset or +unreachable fetch evaluator fails closed with a message naming it, with no fallback +to the signing pin and no fail-open. 401/403 keep the existing refusal text. +`warden access ` names the fetch evaluator on its `gate` (or `policy`) line. Tests: +`tests/test_policy_fetch_evaluator.py`, plus updated proxy and refusal tests. Full +suite: 494 passed, 4 deselected. Docs: `wiki/OpsWardenConfig.md` ("Two +evaluators", tunnel example), `wiki/CredentialRouting.md`, production example. + +Still open (founder go, `needs_human`): deploy the pin (access-engine +ADHOC-2026-10-03-T02), add the ops-bridge tunnel (local 19091 → the pin's Service +ClusterIP:8080), set `fetch_flex_auth_url: http://127.0.0.1:19091` in the live +`~/.config/warden/warden.yaml`, then record exact positive evidence and +wrong-owner/caller negative evidence before T03 closes. Until the key is set, +every proxied fetch refuses with "secret-read evaluator not configured". Before +that change, those fetches got a 403 from the signing pin. + +**T03 done 2026-10-10.** access-engine reported the fetch pin +`flex-auth-ops-warden-fetch` live since 2026-10-03 (Helm revision 1). The tunnel +`flex-auth-ops-warden-fetch-railiance01` (127.0.0.1:19091) is connected, and the +live `~/.config/warden/warden.yaml` carries +`fetch_flex_auth_url: http://127.0.0.1:19091`. Receipts were taken with +ops-warden's own caller token (SA `ops-warden/ops-warden`, audience +`flex-auth`, 10m). The requests are access-engine's fixtures in +`examples/ops-warden-fetch/`. Policy decisions only; no credential was read. + +| Case | Result | +| --- | --- | +| Positive: `forgejo-admin-api-token`, owner railiance-platform | HTTP 200 allow `secret_read_lane_matched`, `decision:014afa428f776db5` | +| Unknown need | HTTP 200 deny `unknown_need`, `decision:d792b0d6b1cb8122` | +| Wrong owner: `resource.system` ops-warden | HTTP 403 | +| Wrong tenant: `tenant:binky` on subject and resource | HTTP 200 deny `wrong_tenant`, `decision:71da3ff8b50dad74` | +| Wrong caller: anonymous | HTTP 401 | + +This is the exact positive evidence plus the caller, owner and tenant negatives +this task required. The explicit refusal stays for anything the pin does not +admit. access-engine closes its ADHOC-2026-10-03-T02 on this reply. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md new file mode 100644 index 00000000..f07fb535 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0040-unknown-zone-fail-closed-adoption.md @@ -0,0 +1,240 @@ +--- +id: WARDEN-WP-0040 +type: workplan +title: "Adopt unknown -> fail_closed behind signing-target classification coverage" +domain: infotech +repo: ops-warden +status: active +flavor: residual +depends_on: + - WARDEN-WP-0032 + - WARDEN-WP-0034 +owner: ops-warden +topic_slug: netkingdom +planning_priority: P1 +depends_on_workplans: + - WARDEN-WP-0032 + - WARDEN-WP-0034 +created: "2026-09-09" +updated: "2026-09-28" +state_hub_workstream_id: "c8ee441e-1be1-5219-910c-e79ff23cc9ec" +--- + +# WARDEN-WP-0040 — `unknown` → `fail_closed`, in the right order + +security-layer-model v0.8 §6.4 obligation 3 (proposed, 2026-09-06) rules that +`unknown` is not a zone and must resolve to `fail_closed`. ops-warden's +`pep-stance.yaml` declares `unknown: fail_open` under `ADR-0009`. + +**We agree with the rule.** `history/2026-09-09-layer-model-v08-review.md` records +the assent and why our falsifier check failed: the cell governs certificate +issuance, not a §5.1 read-only diagnostic, so nothing rescues it. + +**We disagree with adopting it first.** Measured 2026-09-09: of four signing +targets, zero resolve to a zone, three are `unknown`, one is `not-applicable`. +Flipping the cell today makes flex-auth a hard dependency of essentially every +certificate — `ADR-0006`'s rejected configuration, reached by a different route, +including the continuity path needed to repair flex-auth itself. + +So: coverage first, then the cell. That ordering is the whole holding of +`ADR-0006` and the reason `ADR-0009` replaced a global switch with a zone map. + +## Tasks + +```task +id: WARDEN-WP-0040-T01 +status: wait +blocked_on: message-from:ops-bridge +blocking_reason: "Warden's own declaration cannot classify the repair-path target workloads; the owner must declare the continuity actor/target and its z2-continuity resolution (see 2026-09-28 review)." +priority: high +state_hub_task_id: "611f0901-9fb5-5954-8dd0-a860c5f0cbec" +``` +2026-09-30: gate stated. The 2026-09-28 review found the classification is not ours to make (target workloads belong to ops-bridge, the Inter-Hub execution owner and the backup owner), so T01 waits on the owner declaration, same as T02. Qualified per Task Wait Qualifiers v0.1. + + +**Classify the continuity path before anything else changes.** + +The deadlock is specific and worth naming before it is designed around: flex-auth +unreachable → operator needs an SSH certificate to reach the host → target is +`unknown` because nobody classified the repair path → `fail_closed` denies it. + +`z2-continuity` exists for this and its stance is `fail_open`, so the fix is +classification, not an exception. Determine which actor(s) constitute the +repair path, establish whether the declaration is ops-warden's to make (our own +`tenancy.yaml` covers ops-warden as a workload; the actors' target workloads may +not be ours), and route what is not. + +Blocks T03. Converting the cell with the repair path unclassified is the one +outcome this workplan exists to prevent. + +```task +id: WARDEN-WP-0040-T02 +status: wait +blocked_on: message-from:ops-bridge +blocking_reason: "Owners of agt-codex-interhub-bootstrap (ops-hub) and agt-state-hub-bridge (ops-bridge) must publish authoritative workload identity declarations; atm-backup-daily declared by activity-core and compiled 2026-10-09 (z2-protected, admission unsatisfied: M1 below M2 floor)." +priority: high +state_hub_task_id: "54ad4864-7bcf-592e-a187-9239a81a0b11" +``` + +**Raise signing-target coverage, by asking owners — never by inferring.** + +Three actor resources report `workload_resolution_absent`: +`agt-codex-interhub-bootstrap`, `agt-state-hub-bridge`, `atm-backup-daily`. +Their owners (ops-bridge and the backup execution unit among them) have not +published an authoritative workload identity declaration. + +`ADR-0009` rule 3 forbids closing this with path or repository-name inference, +and that prohibition holds under pressure from this workplan specifically — +adopting a stricter stance is not a licence to manufacture the membership that +makes it survivable. + +Route to each owner with the concrete consequence: while the declaration is +absent their actor cannot be issued a certificate during a flex-auth outage once +the cell converts. That is a better ask than a generic request to publish a +declaration, and it is true. + +Report coverage with `scripts/report_workload_join.py`; this task is done when +coverage is stated, not when it reaches a threshold — the threshold is T03's +gate, and owners may legitimately decline. + +```task +id: WARDEN-WP-0040-T03 +status: wait +depends_on: [WARDEN-WP-0040-T01] +blocking_reason: "Gated on T01 and on layer model v0.8 (or successor) reaching accepted; never convert against a proposed standard." +priority: high +state_hub_task_id: "93eaf1f2-daaa-5e22-8804-85ca9433571c" +``` + +**Convert the cell and supersede `ADR-0009`'s unknown row.** + +Gated on T01, and on v0.8 (or its successor) reaching `accepted`. Do not convert +against a `proposed` standard. + +`ADR-0009` is `owner: ops-warden`, so changing it means a superseding ADR, never +an in-place edit (`.claude/rules/architecture.md`). The superseding record should +carry the v0.8 argument rather than restate it: unknown is not a zone, so a §9.3 +per-zone trade was never made for that request. + +`pep-stance.yaml` is asserted equal to `PolicyConfig.failure_modes` by +`tests/test_layer_conformance.py`, so the map and the code convert in one commit +or the test fails — which is the property that makes the map worth publishing. + +```task +id: WARDEN-WP-0040-T04 +status: done +priority: medium +state_hub_task_id: "222a8c5d-0c0f-5a1d-98d8-02be7dca3358" +``` + +**Return findings to gate-house and track the transition ask.** + +Sent 2026-09-09 with the review. Two asks, in preference order: obligation 3 +names a dated transitional state gated on coverage; or failing that, §13.1 +records classification coverage alongside stance, so a register row cannot read +`unknown: fail_closed` while every target is unknown. + +If both are declined, that is an answer and this workplan proceeds unchanged — +the cell stays a **declared gap** under §11 with this workplan as its route, +which is what the `declared-gap` mark (our own v0.6 finding) exists to express. + +**Answered 2026-09-09 — GH-DEC-2026-011.** Ask 1 declined, ask 2 adopted; +standard amended at `net-kingdom@64394e9`. + +Ask 1's refusal is correct and we are not appealing it: a sanctioned transitional +`fail_open` is indistinguishable at runtime from the stance the rule forbids, and +would make the rule optional at the only moment it costs anything. Ask 2 gave us +what we actually needed — §13.1 carries a Coverage column with this repo's +figures as its first entries, guarded so that coverage never softens a stance, +never gates one, and never makes a non-conformant cell conformant. + +The reversal condition on that column binds ops-warden first, since the column +exists because we asked: if a row is ever argued conformant *because* its coverage +is low, the column comes out. Our row reads non-conformant and low-coverage, and +the second is not a defence of the first. + +gate-house confirmed explicitly that they are **not** asking for the cell to be +flipped before coverage exists, and that this workplan's order is right. The cell +stays a declared gap under §11 with WP-0040 recorded as its route — the outcome +this task named as acceptable if both asks were declined, reached with one of them +adopted. + +T01–T03 are unchanged and still gate the conversion. Coverage is now measured +rather than asserted (`scripts/report_coverage.py`), so T02's reporting obligation +has a tool behind it and the published figure cannot drift from the register's. + +### 2026-09-28 loose-end review + +T04 is done: GH-DEC-2026-011 already answered both transition asks on September 9; +the accepted coverage column and declared-gap disposition are recorded above. +No additional response is required to meet that task's acceptance criterion. + +T01/T02 now wait; the workplan is blocked. Re-ran both coverage reports: +signing targets = 0 resolved / 3 unknown / 1 not-applicable; routing lanes = +3 resolved / 20 unknown / 15 not-applicable. Refreshed pep-stance.yaml's measured +date. These figures describe the checked-in registry and local owner declarations, +not a live PDP query. No zone membership was inferred or changed. + +The exact missing workload resolutions are `ops-bridge-tunnel` for +`agt-state-hub-bridge`, `codex-interhub-bootstrap` for +`agt-codex-interhub-bootstrap`, and `backup-daily` for `atm-backup-daily`. +The seed inventory's `adm-example` is not an admitted repair actor. +Warden's own workload declaration cannot classify those target workloads. +T01 needs an owner-declared continuity actor/target and its authoritative +z2-continuity resolution; T02 retains the owner-routing/declaration follow-up +(ops-bridge, the Inter-Hub execution owner and the backup execution owner). +Without it, changing unknown to fail_closed would deny their issuance during a +PDP outage. Coverage reporting is complete, but owner coordination is not. + +T03 also remains gated on standard acceptance: the local authoritative +net-kingdom/canon/standards/security-layer-model_v0.8.md still says proposed. +No superseding ADR or runtime stance change is warranted before these gates. + +### 2026-09-30 owner asks sent + +Routed the concrete-consequence ask (T01 classification + T02 declaration) to `ops-bridge` (agt-state-hub-bridge), `ops-hub` (agt-codex-interhub-bootstrap; owner unconfirmed, asked to name the owner if not theirs) and `railiance-platform` (atm-backup-daily; same caveat). Declining is an accepted answer. No membership inferred. T01/T02 stay `wait` on these replies. + +### 2026-10-08 owner replies recorded + +`atm-backup-daily`: railiance-platform declined in its replies of 2026-10-02 +(msgs 53234ede, a3691df9). It declares only the credential lane +`railiance-backup-offsite-lane`, and no workload in railiance-platform has that +name. It names activity-core as the declaring owner, because activity-core is +the source repo of `daily-cnpg-option-a-backup`. It classifies the actor as +**ordinary**, not z2-continuity repair-path. activity-core will not declare +without founder confirmation (ACTIVITY-WP-0042-T03, decision 89f1058f). So this +actor now waits on that founder decision, not on railiance-platform. No +membership is inferred. `agt-state-hub-bridge` (ops-bridge) and +`agt-codex-interhub-bootstrap` (ops-hub) are still unanswered. + +2026-10-08 (later): the founder confirmed in session that activity-core's +`daily-cnpg-option-a-backup` worker is the `atm-backup-daily` unit, and that it +is classed as ordinary. The confirmation was relayed to activity-core for +ACTIVITY-WP-0042-T03. Decision 89f1058f (D2) was deliberately left open, +because it also gates production ArgoCD go-aheads. `atm-backup-daily` now waits +only on activity-core publishing its declaration. + +### 2026-10-09 atm-backup-daily compiled + +activity-core published `declarations/backup-daily/tenancy.yaml` (c1533fe). +zone-engine's `resolve_zones.py` resolves it with the +`netkingdom-build-v0.1` profile: + +- declared zone: `z2-protected` (ordinary, not z2-continuity) +- admission: `unsatisfied`, reason `M1_below_M2_zone_floor` +- effective zone: `unknown` + +The resolved view is committed as `registry/flex-auth/zone-resolutions.json`, +and the snapshot was rebuilt from it. Resolution is no longer absent. The actor +stays `unknown` because the owner declared M1, below the M2 floor, which is +accurate rather than a gap ops-warden may close. Coverage, stated as T02 +requires: signing targets 0/3 resolved, 3 unknown, 1 not-applicable. The +figure is unchanged because `report_coverage.py` counts effective zones. +`atm-backup-daily` now waits on owner M2 evidence. It does not wait on a +declaration. Still unanswered: `agt-state-hub-bridge` (ops-bridge) and +`agt-codex-interhub-bootstrap` (ops-hub). + +> 2026-10-11: demoted to `flavor: residual` / `backlog` by founder-authorized triage — off the +> critical path (identity → authz → secrets → SecurityCase execution). Tasks are unchanged; +> promote back when demand or risk appears. See the-custodian +> `history/20261011-netkingdom-security-progress-assessment.md`. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md new file mode 100644 index 00000000..8a1ca341 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0041-catalog-lane-scaffolding.md @@ -0,0 +1,100 @@ +--- +id: WARDEN-WP-0041 +type: workplan +title: "Draft catalog lane scaffolding with platform-owned credential rendering" +domain: infotech +repo: ops-warden +status: finished +flavor: implementation +owner: ops-warden +topic_slug: netkingdom +created: "2026-10-03" +updated: "2026-10-04" +depends_on: [] +state_hub_workstream_id: "eb42b59c-1e32-5e1b-917d-34625f7a041d" +--- + +Accepts the ops-warden portion of P4 from CUST-WP-0075, proposal message +`79549660-4fc8-44d5-989e-074f6c7b6f07`. The platform owns its renderer and +CCR schema; no production act or approval is included here. + +## Establish the catalog and platform seam + +```task +id: WARDEN-WP-0041-T01 +status: done +priority: medium +state_hub_task_id: "85bfd209-d2f1-59e4-aa02-e8e374598538" +``` + +Reviewed existing catalog validation, plan CCR stub, promotion checklist and +platform CCR rendering. The stub does not scaffold; platform rendering already +exists for reviewed CCRs. Proposed exact owner seam, inputs, fail-safe draft +outputs and offline acceptance in `wiki/CatalogLaneScaffoldContract.md`. +Platform's matching owner task is `RPF-WP-0050-T04`. + +## Implement offline draft catalog and playbook generation + +```task +id: WARDEN-WP-0041-T02 +status: done +priority: medium +state_hub_task_id: "68bf72d8-a798-5e88-bfda-79b8910f7cda" +``` + +Implement the ops-warden portion of the seam proposal: deterministic staging +output, validated catalog fields, draft-only defaults, collision refusal, +explicit workload unknowns and risk, no secret inputs, no credential execution. +Add meaningful rejection/round-trip fixtures; reuse catalog validation. Do not +write platform-owned artifacts or invent its CLI. The local fragment generator +can progress independently while platform contract review is pending. + +## Verify the accepted cross-owner scaffold + +```task +id: WARDEN-WP-0041-T03 +status: done +priority: medium +depends_on: + - WARDEN-WP-0041-T02 + - RPF-WP-0050-T04 +state_hub_task_id: "33587361-2b8a-5540-9c4f-d7b4f8ef25e0" +``` + +Integrate through reviewed owner references and demonstrate one exact KV-v2 +workload-read fixture end to end. Record both owner commits and validation +results. Generation success alone does not admit or activate a lane. Update +`warden plan`'s unroutable guidance only once a real supported command exists. + +## Report owner uptake and gates + +```task +id: WARDEN-WP-0041-T04 +status: done +priority: medium +state_hub_task_id: "4bc926af-04d4-5a27-9578-d2f83c0ecf9c" +``` + +Return the scoped P4 acceptance and this live owner record to the-custodian's +original proposal thread. Existing admission, approval, identity confirmation, +attended values and deployment evidence gates remain; no secret read or +production action was taken. Source/knowledge receipt is in the seam document. + +## Offline delivery acceptance — 2026-10-04 + +T02 and T03 completed the bounded draft-generation scope. Actual-source +generator/routing/plan tests: 139 passed. Both actual owner CLIs staged the +paired synthetic fixture; lane/consumer/owner/risk/CCR pointer and manifest +digest match, unknown workload remains unknown, catalog execution is disabled, +CCR remains proposed with empty review, auth claims unconfirmed, frontdoor +pending/unresolvable and evidence not executed. Independent platform owner +verification remains separately attributed in the receipt. + +Source implementation commits: ops-warden `dfe436e4e05610cae96085dadd582e5a63525580`; +railiance-platform `f5b7ff5118326f66be8ecd8330d4cda9e4d94520`. +Evidence: `docs/evidence/2026-10-04-catalog-scaffold.json`. +`warden plan` now names the supported offline command for unroutable needs. +The workplan finishes its local draft scaffold contract; CCR approval, binding +confirmation, attended values, deployment and actual capability receipts +remain separate lane-activation work, never implied by fixture acceptance. +No unfinished in-scope implementation or residual is parked by this closure. diff --git a/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0042-openbao-structure-survey-route.md b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0042-openbao-structure-survey-route.md new file mode 100644 index 00000000..097d6479 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-backup/workplans/WARDEN-WP-0042-openbao-structure-survey-route.md @@ -0,0 +1,55 @@ +--- +id: WARDEN-WP-0042 +type: workplan +title: "Route the OpenBao existing-structure survey to ops-mason" +domain: infotech +repo: ops-warden +status: finished +flavor: implementation +owner: claude +topic_slug: netkingdom +created: "2026-10-05" +updated: "2026-10-05" +depends_on: [] +state_hub_workstream_id: "bd5edebd-2988-5685-881e-13931464f92f" +--- + +ops-mason construction plans need an existing-structure survey (section 2) +built from live OpenBao metadata. Founder decision: ops-warden routes, +ops-mason surveys. ops-mason implements `scripts/plan-survey.py` under its +own `ops-mason-build` grant (`ops-mason/MASON-WP-0008`). ops-warden gets no +survey code and no token, per the no-double-source rule +(`WARDEN-WP-0010`, `docs/adr/ADR-0001-catalog-is-a-pointer-layer.md`). + +## Add the pointer-only catalog entry + +```task +id: WARDEN-WP-0042-T01 +status: done +priority: medium +state_hub_task_id: "ca8cd3e9-83ac-5732-8ec4-525e5ce1b113" +``` + +`registry/routing/catalog.yaml` entry `openbao-structure-survey`: owner +`ops-mason`, `warden_executes: false`, `exec_capable: false`, no `steps`, +native delegation to ops-mason, lane `ceremony` (the grant is a founder act), +`risk: high` (the grant can write policies and auth roles), `auth_method` +naming the ops-mason grant, `exec_owner`/`exec_command` pointing at the +survey script, `canon_ref` at `ops-mason/docs/construction-plan-format.md`. +Short pointer playbook `wiki/playbooks/openbao-structure-survey.md`. + +## Verify routing offline + +```task +id: WARDEN-WP-0042-T02 +status: done +priority: medium +state_hub_task_id: "05bb75bd-2de9-55d5-8bc8-41b306ddcf16" +``` + +`make test` passes, including catalog validation and layer conformance. +`warden access "openbao structure survey"`, `warden access "construction +plan section 2"` and `warden route find "existing policies auth roles +survey"` resolve to the entry; `warden plan` returns `founder_required` +with the survey command; `warden access ... --exec` refuses (not +exec_capable).