From 550ba95a6746e8cae80c1b4f53d7151e8c1566c3 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 21 Sep 2026 02:36:31 +0200 Subject: [PATCH] Answer the exec-path question: the front door reads the ungoverned duplicate. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ops-warden and railiance-platform asked, independently, which OpenBao location `secrets-engine exec --catalog whynot-design-npm-publish` reads. Answered from this repository's own code and catalog with no OpenBao read and no value. It reads `secret/coulomb/whynot-design/npm/publish` — the legacy, ungoverned duplicate. `_fetch_value` concatenates the catalog's `mount` and `path` with no override or fallback, so the proven pilot published from the duplicate and the lowercase `npm_token` field is the field there. ops-warden's front door names this repository as exec_owner, so it currently routes callers at a path no CCR covers. Recorded in SECRETS-WP-0006 with what a move to the governed lane requires, and flagged that the duplicate must not be destroyed until the lane moves. Whether the two locations hold the same value is a value comparison and is not answered here. Also records GH-DEC-2026-017 against SECRETS-WP-0008: INTENT.md governs, the sidecar is derived, the vocabulary is case-insensitive so nothing is re-spelled, and standard_version comes out of layer.yaml once ops-warden updates the reference form this repository copied. Co-Authored-By: Claude Opus 5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 63291@bnt-lap001 Assistant-Session: 8bd77868-ca68-4f49-bb1e-d539ecc0d703 --- docs/whynot-design-real-publish-closeout.md | 15 +++- .../SECRETS-WP-0006-catalog-lane-adoption.md | 86 +++++++++++++++++++ ...-0008-layer-model-lifecycle-conformance.md | 62 +++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) diff --git a/docs/whynot-design-real-publish-closeout.md b/docs/whynot-design-real-publish-closeout.md index ab0749a..034a83e 100644 --- a/docs/whynot-design-real-publish-closeout.md +++ b/docs/whynot-design-real-publish-closeout.md @@ -17,10 +17,23 @@ prompts, workplans, or normal logs. | Org/repo | `coulomb/whynot-design` | | npm package | `@whynot/design` | | npm registry | `https://forgejo.coulomb.social/api/packages/coulomb/npm/` | -| Catalog mount/path | `secret/coulomb/whynot-design/npm/publish` | +| Catalog mount/path | `secret/coulomb/whynot-design/npm/publish` **(ungoverned legacy — see below)** | | Catalog field | `npm_token` | | Injected env var | `NPM_AUTH_TOKEN` | +> **Governance status, 2026-09-21.** The catalog mount/path above is the +> location `secrets-engine exec` actually reads — confirmed from +> `exec_delivery._fetch_value`, which concatenates `entry.mount` and +> `entry.path` with no override — and it is the **ungoverned duplicate**. The +> governed lane is `platform/workloads/coulomb/whynot-design/npm-publish` under +> CCR-2026-0001, field `NPM_AUTH_TOKEN`. The lowercase `npm_token` in the table +> above is the field at the legacy path, which is why the two records disagreed +> without either being wrong. Moving to the governed path is a reviewed lane +> change with its own approval; the steps are recorded in +> `workplans/SECRETS-WP-0006-catalog-lane-adoption.md` (2026-09-21). Until that +> move completes and re-verifies, the legacy path must not be destroyed or +> wrapped — it is the live publish path. + The decision UUID above is resolved from State Hub in normal operation. A UUID-named local fixture exists only as an offline fallback for throwaway demos. diff --git a/workplans/SECRETS-WP-0006-catalog-lane-adoption.md b/workplans/SECRETS-WP-0006-catalog-lane-adoption.md index 5d5b9f1..3e27a1d 100644 --- a/workplans/SECRETS-WP-0006-catalog-lane-adoption.md +++ b/workplans/SECRETS-WP-0006-catalog-lane-adoption.md @@ -328,3 +328,89 @@ routing/proxy retirement; SECRETS-WP-0007-T04/T07 retain general native readines Do not reuse the consumed approvals or treat the temporary key-check overlay as approval for a radar trial recipient. IR-WP-0005 owns radar delivery acceptance; IR-WP-0006 owns the outstanding USD 0.023712 billing reservation. + + +### 2026-09-21 answered: the exec front door reads the ungoverned legacy path + +ops-warden (`abf27efc`) and railiance-platform (RPF-WP-0035-T07, `09b719fe`) +asked the same location-only question. Answered from this repository's own code +and catalog, with no OpenBao read and no value of any kind. + +**`secrets-engine exec --catalog whynot-design-npm-publish` reads +`secret/coulomb/whynot-design/npm/publish`.** That is the legacy, ungoverned +duplicate, not the governed lane. + +Derivation, which is short because there is no indirection to hide in: + +- `catalog/whynot-design-npm-publish.yaml` declares `mount: secret` and + `path: coulomb/whynot-design/npm/publish`. +- `exec_with_secret` delegates the read to `_fetch_value` in + `src/secrets_engine/exec_delivery.py`, which issues + `kv get -format=json {entry.mount}/{entry.path}` inside the lane's AppRole + session. The path is the catalog pointer, concatenated, with no override, + fallback, alias, or environment substitution anywhere on the exec path. +- `publication_policy.resolve` and `delivery_config.npm` decide the injected + env-var name and the npm registry. Neither touches the KV location. Nothing + in `routing.py`, `safe_paths.py`, or the policy layer rewrites mount or path. + +So railiance-platform's straightforward reading was the right one. The proven +2026-07-03 `@whynot/design` pilot published by reading the legacy duplicate, and +the lowercase `npm_token` field this repository has consistently reported is the +field **there** — which is why it never appeared at the governed path and why +nobody's record was wrong. ops-warden's `NPM_AUTH_TOKEN` and this repository's +`npm_token` were each correct about the location each side was describing. + +The consequence is the one ops-warden named and it should be stated plainly +rather than softened: ops-warden's routing catalog lists secrets-engine as +`exec_owner` and routes callers here as the primary front door, so that front +door currently points at a path no CCR covers, and CCR-2026-0001's acceptance +evidence describes a path its consumer does not use. That is a real governance +gap, not a bookkeeping mismatch. + +**Not answerable here, and not attempted:** whether the two locations hold the +same value. That is a value comparison. This repository will not read, fetch, +fingerprint, or compare either value, and has not. It is custody's question and +needs no answer from us to proceed with the path move. + +#### What it would take to move to the governed path + +The move is a reviewed production lane change, not an edit. In order: + +1. **Custody confirms the governed lane is consumable by this lane's identity.** + `platform/workloads/coulomb/whynot-design/npm-publish` under CCR-2026-0001 + grants read to the workload policy; the AppRole this engine's delivery + session assumes must be admitted on `platform/data/...` and + `platform/metadata/...` of exactly that path. Without that, the edit produces + a lane that denies on read. +2. **Reconcile the field name in the same change.** The catalog declares + `npm_token`; the governed path was enumerated by railiance-platform on + 2026-09-10 as holding exactly one field, `NPM_AUTH_TOKEN`. Moving the path + without moving `fields:` produces `field 'npm_token' absent in lane` from + `_fetch_value`. The injected env var is separately resolved and stays + `NPM_AUTH_TOKEN` while netkingdom is `maturity-build`; after the move the KV + field name and the injected env-var name coincide, which is a coincidence and + must be annotated as one so the category error corrected on 2026-09-09 is not + reintroduced. +3. **Carry an approval.** The lane's `approval.model` is `decision`; this is a + production lane pointer change and takes its own approved decision, not the + existing `e6381a56` pilot decision. +4. **Re-verify positive and negative.** The lane's declared expectations — the + approved consumer reads the field, an unrelated identity is denied — must be + re-run against the governed path before the old pointer is abandoned. +5. **Update the derived records:** `docs/whynot-design-real-publish-closeout.md` + pointer table, `docs/hardening-backlog.md` (which already names both + locations), and `docs/cli.md`. +6. **Only then is destruction of the duplicate safe.** RPF-WP-0035-T07 holds + destruction pending this confirmation, correctly. The confirmation it was + waiting for is now given, and it is the unwelcome one: the duplicate is the + live consumer path, so it must not be destroyed or wrapped until this lane + has moved and re-verified. Destroying it today breaks production publish. + +Note also `scripts/demo-e2e.sh:66`, which grants a policy on +`secret/data/prod/coulomb/whynot-design/npm` — a third, demo-only spelling under +a `prod/` prefix. It is a throwaway demo fixture and not a consumer lane, but it +should be renamed away from `prod` when the lane moves so it cannot be mistaken +for a fourth location. + +`SECRETS-WP-0006-T06` stays `wait`: this answer unblocks the question, not the +lane change, which needs custody's step 1 and its own approval. diff --git a/workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md b/workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md index a975009..f0c30e6 100644 --- a/workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md +++ b/workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md @@ -354,6 +354,68 @@ Acceptance: - No fallback from JWT/service-auth failure into bootstrap or AppRole. - Issued delivery sessions continue to self-revoke as in WP-0007-T05. +### 2026-09-21 GH-DEC-2026-017 — section 11 layer declaration ruled + +Read from `gate-house/decisions/decisions.md`, not from message text. +`secrets-engine` is a named affected repository and carries both permitted +forms, so all four parts apply here. State Hub decision id +`82dd0fea-fabb-4940-92d5-d6e2ea9985f5`. + +What the ruling settles for this repository: + +1. **`INTENT.md` governs.** Our declaration is the `layer: Engine` key in + `INTENT.md` frontmatter. `layer.yaml` is a **derived artifact**: it must be + marked as derived, must name `INTENT.md` as what it derives from, and must + agree with it. Our `layer.yaml` already carries `declared_by: INTENT.md` and + a `Voice: INTENT.md (this repository's own declaration, §11)` header comment, + so we are among the repositories already treating the sidecar as derived in + substance. What is missing is the explicit derived marking the ruling now + requires as a field rather than a comment. +2. **The §3 vocabulary is case-insensitive and comparison must ASCII case-fold.** + Our `INTENT.md` says `Engine` and our `layer.yaml` says `engine`. Under §2 of + the ruling that is **conforming**, it was never a disagreement about a layer, + and **nothing here is re-spelled**. flex-auth withdrew the casing finding + itself (message `962bf395`) and its validator is the thing that changes. We + do not touch either file's spelling, and we do not "align" them. +3. **The vocabulary is closed with four tokens** — `Taxonomy`, `Tooling`, + `Engine`, `Staff`. `Engine` is in it; no action. +4. **`standard_version` comes out of the declaration.** Our `layer.yaml` carries + `standard_version: "0.7"`. A declaration asserts a standing property and must + not carry a standard version; version-scoped state belongs in the derived + conformance record, which must name what it derives from and the version or + commit it was derived at. + +**Deliberately not done in this session.** The ruling states that +`standard_version` is not one repository's habit but **ops-warden's reference +form**, which this repository copied along with seven others, and that ops-warden +is asked to make the change there rather than each adopter deciding independently. +ops-warden is updating that reference form in a parallel session. Inventing our +own sidecar shape ahead of it would produce exactly the divergence the ruling +exists to close, so we record the requirement and wait for the reference form. + +What `secrets-engine` will need, once the reference form lands: + +- Adopt the reference form's derived-artifact marking in `layer.yaml`, keeping + `declared_by: INTENT.md` or whatever field the reference form names for it. +- Remove `standard_version: "0.7"` from `layer.yaml`. +- Move the version the conformance run was derived at into our derived + conformance record, per the reference form's field for it. Our conformance + checker is `scripts/check_layer_conformance.py`; it reads `layer.yaml` today + and will need to read `INTENT.md` as the governing form, read the sidecar as + well, and **report a disagreement between them as a finding** rather than + resolve it by precedence. A casing-only difference is not such a disagreement. +- Keep `framework:`, `layer:`, `role:` and the substantive §3/§5/§6/§9.6 + content unchanged. `role:` is explicitly not ruled and stays as it is. +- The `Framework:` header comment in `layer.yaml` cites + `security-layer-model_v0.7.md` while the ruling is issued against `v0.8`. + That is a citation in a comment, not a declaration version, so it is out of + scope for part 4 — but it should be refreshed in the same commit so the two + are not confused for each other. + +No task is opened here by hand. This is a note against the workplan that already +owns `layer.yaml` / `pep-stance.yaml` / INTENT frontmatter staying in one voice; +the work lands under that exit criterion when ops-warden's form is published. + ## Exit criteria - The published PEP stance is the shipped default and stance application is