flex-auth/examples/secrets-engine/README.md
tegwick d98323b2bb
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
fix(secrets-engine): v2 adds the tenant rule v1 never had
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
2026-09-06 20:38:45 +02:00

54 lines
2.3 KiB
Markdown

# secrets-engine example
Policy package, manifests, and fixtures for `secrets-engine`'s gated
catalog-lane operations. Opened by `FLEX-DEC-2026-005`, carried by
`FLEX-WP-0021`.
| File | What it is |
| --- | --- |
| `policy_package.md` | `secrets-engine.catalog-lane.lifecycle` v2, `allow_ttl: 15m` |
| `protected_system_manifest.yaml` | the `secret-catalog-lane` resource type and twelve actions |
| `subject_manifest.yaml` | the single `secrets-engine` service identity |
| `registry_snapshot.json` | loadable snapshot combining both manifests |
| `policy_fixtures.yaml` | 32 fixtures — 11 allows, dual control both ways, and every denial branch |
| `check_request_*.json` | standalone requests for `POST /v1/check` |
The action vocabulary is **secrets-engine's**, delivered under
`FLEX-WP-0021-T01` and recorded in
[`../../docs/secrets-engine-action-vocabulary.md`](../../docs/secrets-engine-action-vocabulary.md).
Read that before changing any action string here.
## Verify
```bash
go run ./cmd/flex-auth validate -kind policy -file examples/secrets-engine/policy_package.md
go run ./cmd/flex-auth load-registry -file examples/secrets-engine/registry_snapshot.json
```
28 Rego tests and 32 fixtures.
## Deployed, and the version to pin
`FLEX-WP-0021-T04` deployed the `flex-auth-secrets-engine` pin on 2026-09-06:
```text
Service: http://flex-auth-secrets-engine.flex-auth.svc.cluster.local:8080
Package: secrets-engine.catalog-lane.lifecycle
Version: v2
callerAuth.mode: warn (not enforced caller authentication)
```
Ingress admits namespace `secrets-engine` with pod label
`app.kubernetes.io/name=secrets-engine` and default-denies everything else. A
workstation CLI process is not that, and Service DNS is not workstation
connectivity — an operator-run consumer needs a decided access path before it
can call this pin at all (`FLEX-WP-0021-T04`'s three shapes).
**Pin `_VERSION` to `v2`, never `v1`.** `v1` is deployed and superseded: it had
no tenant rule and allowed a foreign tenant. See the correction section in
`policy_package.md`. The pin still serves `v1` until the redeploy lands, which
is why the version is stated here rather than left to be read off the running
service.
`SECRETS_ENGINE_AUTHORIZATION_POLICY_PACKAGE` / `_VERSION` remain fallback-free
and fail-closed by design; nothing here changes that.