Review the stance register's second row; record why T04 cannot proceed
TWO FINDINGS, BOTH FROM READING OTHER REPOSITORIES RATHER THAN OURS. The §13.1 stance register has a second row. secrets-engine published pep-stance.yaml -- total over catalog stage plus unknown, runtime-read and pinned to SHIPPED_STANCE by test. SCOPE.md claimed ops-warden's was the estate's only published map and that the register's single row was itself the finding; that is no longer true and is corrected. docs/stance-register-review.md is the first exercise of the aggregate-divergence capability flex-auth claimed on 2026-08-29 and then recorded as unexercised because one row cannot diverge from anything. Three findings: The two maps take opposite stances on unknown -- ops-warden fail_open by versioned build profile under ADR-0009, secrets-engine fail_closed. Both conformant, neither a defect, and they disagree about the one case nobody planned for. Reported as an observation for gate-house's register, not as a request that either repository change: a PDP does not set a consumer's stance, and §9.3's two-owner split is our own finding. The rows are not comparable. ops-warden scopes by security-zone, secrets-engine by catalog-stage. §6.4 permits both, but the register cannot then answer what the estate's stance is for a z2 workload. Worth recording before a third row arrives. secrets-engine's map defines fail_closed in terms of a durable ActionAuthorization record, which GH-DEC-2026-005 shelved. The stance is unaffected -- only the artifact name is stale -- but the file is read at runtime and pinned by test, so the stale name outlives a comment. SEPARATELY, T04 IS BLOCKED AND THE REASON IS STRUCTURAL. The task assumed the ops-warden/tenant-engine/user-engine pattern, where the pin's default-deny NetworkPolicy admits one approved consumer workload. secrets-engine has no Kubernetes deployment at all -- it is a CLI. There is no pod selector to write, and inventing one would repeat the error corrected in T02. Three possible shapes recorded in the workplan and raised with them; callerAuth, not the NetworkPolicy, becomes the real boundary if an operator CLI is the caller, so the FLEX-WP-0016 precedent does not transfer unexamined. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JTbVXpEiXA7mNJVpDnEPcB Assistant: claude-code Assistant-Model: opus Assistant-Process: 412054@bnt-lap001 Assistant-Session: 3968fae1-8d59-4209-9bd6-c22594b8ab19
This commit is contained in:
parent
591df344fb
commit
c3ede0b494
3 changed files with 133 additions and 2 deletions
11
SCOPE.md
11
SCOPE.md
|
|
@ -135,8 +135,15 @@ call itself. `ADR-0009` retires `policy.enabled` and the global `policy.fail_clo
|
|||
outright and replaces them with a total per-zone stance map in the consumer PEP
|
||||
(`ops-warden/pep-stance.yaml`): open for `z0`-`z2` and `unknown`, closed for
|
||||
`z3-critical`. That map is the reference shape for `security-layer-model_v0.7`
|
||||
§6.4 obligation 3, and it is the estate's only published one — §13.1's register
|
||||
has one row, which the standard records as itself the finding.
|
||||
§6.4 obligation 3. It is no longer the only published one: `secrets-engine`
|
||||
published `pep-stance.yaml` (total over catalog stage plus `unknown`, runtime-read
|
||||
and test-pinned), so §13.1's register now has **two rows** rather than the one the
|
||||
standard recorded as itself the finding. flex-auth reviewed the pair in
|
||||
`docs/stance-register-review.md` — the first exercise of the aggregate-divergence
|
||||
capability it claimed on 2026-08-29 — and found that the two maps take opposite
|
||||
stances on `unknown` (`fail_open` vs `fail_closed`) and scope on different axes
|
||||
(security-zone vs catalog-stage), which makes the rows conformant but not
|
||||
comparable.
|
||||
|
||||
flex-auth reviewed the zone model as the PDP on 2026-08-19 and holds one
|
||||
boundary: zone **membership** compiles into
|
||||
|
|
|
|||
101
docs/stance-register-review.md
Normal file
101
docs/stance-register-review.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# Stance-register review — the register has a second row
|
||||
|
||||
Status: published
|
||||
Date: 2026-09-06
|
||||
Standard: `security-layer-model_v0.7` §6.4 obligation 3, §13.1
|
||||
Reviewer: flex-auth (Engine / PDP)
|
||||
|
||||
## Why flex-auth is writing this
|
||||
|
||||
In the 2026-08-29 alignment review flex-auth told gate-house it is "the
|
||||
repository positioned to notice when the aggregate of consumer stances diverges
|
||||
from what the policy packages say," and then recorded that the claim was sound
|
||||
but unexercised: §13.1's register existed with **one row**, and one row cannot
|
||||
diverge from anything.
|
||||
|
||||
It now has two. This is that claim being exercised for the first time, and
|
||||
flex-auth is reporting a divergence it found rather than waiting to be asked.
|
||||
|
||||
## The two published maps
|
||||
|
||||
| | `ops-warden` | `secrets-engine` |
|
||||
| --- | --- | --- |
|
||||
| File | `pep-stance.yaml` | `pep-stance.yaml` |
|
||||
| Rule of record | `ADR-0009` | `INTENT.md` / `layer.yaml` |
|
||||
| Protected action | SSH certificate issuance | OpenBao metadata/KV lifecycle and delivery |
|
||||
| Scope axis | `security-zone` | `catalog-stage` |
|
||||
| Pinned to code by test | yes (`PolicyConfig.failure_modes`) | yes (`SHIPPED_STANCE`) |
|
||||
|
||||
Both are §6.4-conformant. Both are total over their axis, both publish rather
|
||||
than bury the map, both carry no implicit default, and both are asserted equal
|
||||
to the shipped value by a test — which is the property that makes a published
|
||||
map worth relying on at all.
|
||||
|
||||
## Finding 1 — the two maps take opposite stances on `unknown`
|
||||
|
||||
| | `unknown` |
|
||||
| --- | --- |
|
||||
| `ops-warden` | `fail_open` — explicit, versioned build profile, `ADR-0009` |
|
||||
| `secrets-engine` | `fail_closed` |
|
||||
|
||||
Both are defensible and neither is a defect. `ops-warden`'s `unknown` is a
|
||||
build-profile artifact on a path whose z3 rows are closed; `secrets-engine`
|
||||
treats an unmapped stage as production-shaped. But the estate's only two
|
||||
published maps disagree about the case that, by construction, is the one nobody
|
||||
planned for.
|
||||
|
||||
That is the aggregate divergence flex-auth said it would notice. It is reported
|
||||
as an observation for gate-house's register, **not** as a request that either
|
||||
repository change. A PDP does not get to set a consumer's stance — §9.3's
|
||||
two-owner split is flex-auth's own finding and it cuts this way too.
|
||||
|
||||
What is worth deciding, and it is gate-house's to decide, is whether §6.4 should
|
||||
say anything about `unknown` specifically. Today it requires only that the map
|
||||
be total; totality is satisfied by either answer.
|
||||
|
||||
## Finding 2 — the rows are not comparable, and the register cannot say so
|
||||
|
||||
`ops-warden` scopes by `security-zone`; `secrets-engine` scopes by
|
||||
`catalog-stage`, explicitly "the equivalent scope until security-zone
|
||||
membership arrives as a claim on the decision." §6.4's "per zone or equivalent"
|
||||
permits both.
|
||||
|
||||
The consequence is that the register cannot answer the question an inventory
|
||||
exists to answer. "What is the estate's stance for a `z2-protected` workload?"
|
||||
has no answer for `secrets-engine`, because that repository has no zone axis —
|
||||
and the mapping between a catalog stage and a zone is not published anywhere.
|
||||
|
||||
This is a property of the register rather than a fault in either map. It is
|
||||
worth recording before a third row arrives, because the cost of two
|
||||
incommensurable axes is small and the cost of five is not.
|
||||
|
||||
flex-auth holds a relevant boundary here, unchanged from 2026-08-19: zone
|
||||
**membership** compiles into the registry snapshot flex-auth already consumes,
|
||||
while per-zone **stance** belongs to the consumer. If zone membership becomes a
|
||||
claim on the decision, `secrets-engine`'s axis can converge onto zones without
|
||||
either side inventing a mapping.
|
||||
|
||||
## Finding 3 — `secrets-engine`'s map cites a shelved artifact
|
||||
|
||||
`pep-stance.yaml` defines `fail_closed` as "no protected side effect without a
|
||||
durable access-engine / `ActionAuthorization` record."
|
||||
|
||||
`ActionAuthorization` was shelved on the PEP consumption path by
|
||||
`GH-DEC-2026-005`, which flex-auth accepted in `FLEX-DEC-2026-006` — arguing
|
||||
against its own proposal. The step-1 artifact is `approval-engine`'s
|
||||
approval-claim; the step-2 artifact is flex-auth's `DecisionEnvelope`.
|
||||
|
||||
The stance itself is unaffected: `fail_closed` still means no protected side
|
||||
effect without a durable record, and the records exist. Only the name of the
|
||||
artifact is stale. Because this file is read at runtime and pinned by test, the
|
||||
stale name is more durable than a comment would be, which is why it is worth a
|
||||
line rather than being left.
|
||||
|
||||
## What flex-auth is not claiming
|
||||
|
||||
- No stance is wrong. flex-auth cannot express fail-open at all, and does not
|
||||
get to grade a consumer's residue.
|
||||
- No change is requested of `ops-warden`. Its `unknown: fail_open` is
|
||||
documented, versioned, and reasoned.
|
||||
- This is not a §13.1 register. gate-house owns the register; this is one
|
||||
reviewer's reading of the two rows now in it.
|
||||
|
|
@ -178,6 +178,29 @@ Owner: `flex-auth`; deployment approval required.
|
|||
Gate: the pin answers `POST /v1/check` for the secrets-engine workload and
|
||||
default-denies every other source; the other two pins are unchanged.
|
||||
|
||||
**Blocked 2026-09-06 — the consumer is not a workload.** This task was written
|
||||
from the `ops-warden` / `tenant-engine` / `user-engine` pattern, where the pin's
|
||||
default-deny `NetworkPolicy` admits ingress from exactly one approved consumer
|
||||
*workload*. `secrets-engine` has no Kubernetes deployment at all: it is a CLI
|
||||
(`src/`, `cli.py`, `pyproject.toml`) with no manifests, no namespace, and no pod
|
||||
labels. There is no selector to write, and inventing one would be the same error
|
||||
corrected in `FLEX-WP-0021-T02` — authoring against a shape that does not exist.
|
||||
|
||||
Three shapes are possible and the choice is not flex-auth's alone:
|
||||
|
||||
1. **Operator-run CLI reaching an in-cluster pin.** Needs a decided ingress
|
||||
path (tunnel or port-forward), and `callerAuth` becomes the real boundary
|
||||
rather than the `NetworkPolicy`, because the source address is an operator's
|
||||
machine rather than a pod.
|
||||
2. **A `secrets-engine` workload that does not exist yet.** Then this task is
|
||||
correct as written but waits on `secrets-engine` to have one.
|
||||
3. **No pin at all**, if the gate is only ever consulted from an operator
|
||||
context that already holds a decision.
|
||||
|
||||
Raised with `secrets-engine`; T04 does not proceed until the shape is decided.
|
||||
Note this also changes what `callerAuth.mode: warn` is warning about, so the
|
||||
`FLEX-WP-0016` precedent does not transfer unexamined.
|
||||
|
||||
## 5. Hand the pin coordinates back and close
|
||||
|
||||
```task
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue