fix(secrets-engine): v2 adds the tenant rule v1 never had
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 41s

secrets-engine.catalog-lane.lifecycle v1 contained no reference to
input.tenant — not in well_formed, not in the denial ladder, not in a
test. A rotate on lane:glas-primary under tenant:coulomb returned allow
against the deployed package (decision:066e629bbf0c0924).

Found while answering glas-harness's tenant-alignment request, which had
asked for wrong-tenant denial evidence. There was none to return.

Three covers failed the same way: every one of the 29 fixtures carried
tenant:platform, so the suite could not report on the field; T02's own
gate named "wrong-tenant deny" and was recorded done unmet; and the
engine hashes tenant into request_digest but never compares it. Four
other published packages carry the branch — this one was the outlier.

v2 adds wrong_tenant above wrong_system, three Rego tests and three
fixtures (28/28, 32/32). The absent-tenant test caught a second defect
in the first draft: a bare input.tenant != comparison is undefined on a
missing key, so the branch dropped and the ladder reported the wrong
rung. request_tenant := object.get(input, "tenant", "") fixes it.

v2 supersedes rather than amends v1 because the defect failed open: a
consumer pinned to _VERSION=v1 would keep receiving allows with no
signal the rule beneath the version string had changed. The earlier
dual-control correction stayed at v1 because it denied everything.

Replay envelopes regenerated at v2; both request_digest values are
byte-identical, so secrets-engine's digest join needs no re-pinning.

The sweep this prompted found tenant-engine unscoped on tenant as well —
deployed, and verified allowing tenant:coulomb. Not the same fix: its
request tenant names the target rather than the caller, so a constant
would break it. Recorded and carried by FLEX-WP-0022 rather than patched
unilaterally.

FLEX-WP-0021 closes at T05; the pin still serves v1 until a redeploy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014aQMM1dPXaPiXVn6DwwtLd

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 715613@bnt-lap001
Assistant-Session: fabd95c1-4c9e-4080-8849-8707ae025f80
This commit is contained in:
tegwick 2026-09-06 20:38:45 +02:00
parent a81697a589
commit d98323b2bb
12 changed files with 690 additions and 28 deletions

View file

@ -4,7 +4,7 @@ type: workplan
title: "secrets-engine consumer policy package and cluster-local pin"
domain: infotech
repo: flex-auth
status: active
status: finished
owner: claude
topic_slug: netkingdom
planning_priority: P1
@ -122,6 +122,19 @@ supersession (`FLEX-DEC-2026-006`). Per the `FLEX-WP-0010-T02` precedent the
denial ladder has no `action_not_granted` branch, because one subject holding
all twelve actions could never reach it.
**Reopened and re-closed 2026-09-06 at v2 — the stated gate had not been met.**
This task's gate named "wrong-tenant deny" among the required fixtures and the
package shipped without one, because it had no tenant rule at all: a `rotate`
under `tenant: tenant:coulomb` returned `allow` against the deployed v1
(`decision:066e629bbf0c0924`). Found while answering `glas-harness`'s
tenant-alignment request, which had asked for exactly that evidence. v2 adds
`wrong_tenant` above `wrong_system`, three Rego tests and three fixtures
(28/28 and 32/32 passing), and supersedes v1 rather than amending it because
the defect failed **open** — see `FLEX-DEC-2026-008`. The `T03` replay digests
are unchanged at v2; only `policy_version` and `policy_package_digest` moved.
The sweep this prompted found the same shape in `tenant-engine`
(`FLEX-WP-0022`).
## 3. Confirm the digest join against a real decision record
```task
@ -217,7 +230,7 @@ Note this also changes what `callerAuth.mode: warn` is warning about, so the
```task
id: FLEX-WP-0021-T05
status: wait
status: done
priority: medium
state_hub_task_id: "f0828871-fd65-5d8c-adfd-28b13fedd2b0"
```
@ -233,6 +246,34 @@ Owner: `flex-auth`.
Gate: secrets-engine can set its required configuration to published values and
reach a pin; nothing about the fallback-free shape of that configuration changed.
**Done 2026-09-06, with one coordinate that is not flex-auth's to supply.**
Handed back to `secrets-engine` and `glas-harness`:
```text
Service: http://flex-auth-secrets-engine.flex-auth.svc.cluster.local:8080
Package: secrets-engine.catalog-lane.lifecycle
Version: v2 <- not v1; v1 is deployed and superseded
callerAuth.mode: warn (not enforced caller authentication)
```
`SCOPE.md` lists secrets-engine among the shipped consumers and
`examples/secrets-engine/README.md` carries the coordinates at source.
Two things are stated rather than closed, because closing them is not ours:
1. **The pin serves v1 until a redeploy lands.** The over-permissive package is
live now. Deployment approval is the user's; `FLEX-DEC-2026-008` records the
defect and does not grant it.
2. **There is still no verified access path for a workstation CLI.** Ingress
admits namespace `secrets-engine` with pod label
`app.kubernetes.io/name=secrets-engine`; a CLI on an operator's machine is
not that, and Service DNS is not workstation connectivity. `T04`'s three
shapes remain undecided, and `glas-harness` named the same gap independently.
`secrets-engine` cannot complete adoption on coordinates alone.
The fallback-free, fail-closed shape of
`SECRETS_ENGINE_AUTHORIZATION_POLICY_PACKAGE` / `_VERSION` is unchanged.
## Production deployment — 2026-09-06
User authorized production deployment in the Glas session. Installed dedicated