Review NetKingdom Tenancy Posture v0.1 and declare flex-auth posture
Publishes tenancy.yaml (I1 A0 E2 P n/a R n/a, enables A3), the review answering rapp-postgres's three asks, and FLEX-WP-0015 to close the gaps. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
c84f34cf5f
commit
f2b3eeefd8
3 changed files with 485 additions and 0 deletions
270
docs/tenancy-posture-review.md
Normal file
270
docs/tenancy-posture-review.md
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
# flex-auth review — NetKingdom Tenancy Posture v0.1 (draft-5)
|
||||
|
||||
**Reviewer:** flex-auth
|
||||
**Date:** 2026-08-17
|
||||
**Subject:** `net-kingdom/canon/standards/tenancy-posture_v0.1.md`
|
||||
**Requested by:** `rapp-postgres`, message `82ec43ce`
|
||||
**Verdict:** accept the framework, with six amendments. Two of them are
|
||||
corrections of statements the document makes about flex-auth specifically.
|
||||
|
||||
The framework asked to be judged by whether it can describe the reviewing
|
||||
repos (§20.2). It describes flex-auth on three axes and cannot describe it on
|
||||
two. Both failures are informative rather than fatal, and §3.1/§3.2 below
|
||||
propose the smallest changes that fix them.
|
||||
|
||||
---
|
||||
|
||||
## 1. Posture vector
|
||||
|
||||
Declared in `tenancy.yaml` at repo root, per §5.1. Summary:
|
||||
|
||||
```
|
||||
current: I1 A0 E2 P n/a R n/a enables A3 for consumers
|
||||
target: I1 A2 E2 P n/a R n/a
|
||||
```
|
||||
|
||||
Three of these need defending.
|
||||
|
||||
**I1 is correct and is not a defect.** Subject and tenant arrive in the
|
||||
`CheckRequest` body, asserted by the calling PEP; flex-auth verifies no token.
|
||||
§4.1 says a service reading the tenant from the request is at I1 "however
|
||||
canonical the string", and that rule catches flex-auth exactly. It should. A
|
||||
policy decision point evaluates claims it is handed — it cannot also be the
|
||||
verifier of its own inputs without becoming the identity provider that SCOPE.md
|
||||
explicitly refuses to be. flex-auth is at I1 permanently and by design, and the
|
||||
framework should be able to say that a permanent low rung is a decision rather
|
||||
than a stalled trajectory.
|
||||
|
||||
**A0 is the finding this review actually produced.** `POST /v1/check` and
|
||||
`POST /v1/batch_check` authenticate no caller (`cmd/flex-auth/main.go:349`).
|
||||
Any workload with network reach to the ClusterIP Service can assert any
|
||||
subject and any tenant and receive an authoritative allow. flex-auth is the
|
||||
estate's authorization oracle and it currently trusts its own callers
|
||||
completely. That is A0 — "no authorization" — on its own inbound surface, and
|
||||
it is not something we knew we were carrying before this exercise. The
|
||||
framework earned its keep here. Target A2 under `FLEX-WP-0015-T02`.
|
||||
|
||||
**E2 is asserted, not evidenced.** Tenant scoping runs through one choke
|
||||
point (`internal/decision/engine.go:188` normalisation, `:248` relationship
|
||||
tenant match). But §13.2 rules E2 evidence adversarial and explicitly says a
|
||||
passing CI run is not E2 evidence. We have unit tests, not a cross-tenant
|
||||
adversarial probe. E2 is therefore claimed with its gap stated rather than
|
||||
claimed clean, which we read as what §6 requires.
|
||||
|
||||
---
|
||||
|
||||
## 2. Ruling on A4
|
||||
|
||||
**A4 is the right shape for the top of the ladder. Accept it. flex-auth
|
||||
records it as a target, not a current level, and not an active project.**
|
||||
|
||||
Three qualifications, one of which is a correction.
|
||||
|
||||
### 2.1 Correction — AuthZEN does not remove the coupling §4.2 attributes to it
|
||||
|
||||
§4.2 justifies A4 by the action strings copied verbatim between repos, calling
|
||||
that "exactly the coupling AuthZEN removes". It is not. AuthZEN 1.0
|
||||
standardises the *envelope* — subject, action, resource, context, and the
|
||||
evaluation endpoint — and deliberately does not standardise the action
|
||||
vocabulary or the policy language. At A4, `tenant.guardrail.set` still has to
|
||||
be agreed between flex-auth and tenant-engine and still gets copied verbatim.
|
||||
The wire format becomes portable; the semantics do not.
|
||||
|
||||
This matters because the two problems have different and independently
|
||||
achievable fixes, and the cheaper one is not A4:
|
||||
|
||||
| Problem | Fix | Cost |
|
||||
|---|---|---|
|
||||
| PEP coupled to flex-auth's request shape | AuthZEN endpoint (A4) | New adapter, needs a second PEP to be worth anything |
|
||||
| Action strings re-derived by copying | Publish the vocabulary flex-auth already holds | Small — `registry.Actions` is already structured |
|
||||
|
||||
flex-auth's registry already carries `[]ActionDefinition` per system. Serving
|
||||
it read-only would end the copying without touching the wire protocol.
|
||||
Recommend §4.2 drop the vocabulary argument as its justification for A4 and
|
||||
carry the interoperability argument, which is sound on its own.
|
||||
|
||||
### 2.2 The A4 evidence artifact proves less than it appears to
|
||||
|
||||
§13 requires "a second PDP substituted without PEP change". That is
|
||||
achievable and worth having, but it demonstrates *interface* portability, not
|
||||
*decision* equivalence — the substitute PDP must be independently authored to
|
||||
the same policy semantics, and a substitution that returns different answers
|
||||
still passes the artifact as written. §13.4 sets the standard that an artifact
|
||||
must assert something achievable; by the same standard it should assert what
|
||||
it actually establishes. Recommend the artifact read: "a second PDP
|
||||
substituted without PEP change, with the decision differences between the two
|
||||
recorded" — differences expected and enumerated, not asserted absent.
|
||||
|
||||
### 2.3 Adoption stance
|
||||
|
||||
An AuthZEN `POST /access/v1/evaluation` endpoint mapping onto the existing
|
||||
engine is a small non-breaking addition — a translation layer beside
|
||||
`/v1/check`, not a replacement. flex-auth declines to build it now: it buys
|
||||
swappability for PEPs, and today every PEP in the estate is ours and there is
|
||||
no second engine to swap to. It becomes worth building when a consumer arrives
|
||||
that we do not control, or when a delegated backend under FLEX-WP-0004 needs
|
||||
to be addressed uniformly. Recorded as `FLEX-WP-0015-T04`, status `wait`, with
|
||||
that trigger written down so it is a decision rather than a backlog item.
|
||||
|
||||
The coupling is therefore carried **deliberately**, which was the question
|
||||
asked.
|
||||
|
||||
---
|
||||
|
||||
## 3. Ruling on the internal-hop question
|
||||
|
||||
**The assertion is right. Its factual premise about flex-auth is wrong today,
|
||||
and the scope needs one amendment.**
|
||||
|
||||
### 3.1 Correction — flex-auth does not call tenant-engine on the authorization path
|
||||
|
||||
§4.2 states as fact: "`flex-auth` calls `tenant-engine` synchronously on the
|
||||
authorization path." It does not, as of this commit.
|
||||
|
||||
`internal/adapters/tenantengine/` exists and is complete — an HTTP client for
|
||||
`GET /tenants/{id}/roles/live`, a `LiveRolesResult`, and `AttachToContext` to
|
||||
fold live roles into decision context. It has **no non-test caller**. The
|
||||
decision engine has no field for it and no hook that would invoke it
|
||||
(`internal/decision/engine.go:21`). The IAM Profile's live re-query capability
|
||||
is built and unwired.
|
||||
|
||||
Two consequences for the framework:
|
||||
|
||||
- The internal-hop anti-pattern it worries about is not live in flex-auth,
|
||||
because the internal hop is not live at all.
|
||||
- flex-auth's `I` cannot reach I3 today for the same reason. We had assumed
|
||||
otherwise before this review; that assumption is now corrected in
|
||||
`tenancy.yaml` and tracked as `FLEX-WP-0015-T03`, whose honest outcome is
|
||||
either wiring the adapter or deleting it. A built-and-unwired adapter is the
|
||||
worst of the three states because it reads as capability.
|
||||
|
||||
### 3.2 The assertion itself — correct, with a scoping amendment
|
||||
|
||||
"A service identity acting on behalf of a tenant must carry and revalidate
|
||||
tenant context to claim A2 or above" is right in intent and too strong as
|
||||
written. Read literally it requires revalidation on *every* internal hop, which
|
||||
in our estate means a synchronous tenant-engine call on every authorization
|
||||
decision — making tenant-engine a hard availability dependency of every
|
||||
decision the estate makes, and putting a network round trip inside a path
|
||||
`tenant-engine` itself calls latency-critical. That is a worse system, and it
|
||||
is the kind of requirement services quietly stop meeting.
|
||||
|
||||
Recommend:
|
||||
|
||||
> Tenant context MUST be carried on every internal hop and MUST NOT be
|
||||
> re-derived from a service identity. It MUST be revalidated against
|
||||
> `tenant-engine` at least once per request chain — at the service that holds
|
||||
> or mutates the tenant's data, or before a privileged, destructive,
|
||||
> credential-vending or `aal2`-class decision, whichever comes first. A hop
|
||||
> that neither holds tenant data nor makes such a decision may carry the
|
||||
> context without revalidating it.
|
||||
|
||||
This preserves the OWASP intent exactly — no hop may treat "internal" as
|
||||
grounds for skipping the check, and nothing may substitute a service identity
|
||||
for the tenant — while putting the revalidation where it can actually be
|
||||
evidenced.
|
||||
|
||||
### 3.3 The real internal-hop gap in flex-auth is on a different axis
|
||||
|
||||
Worth stating plainly because the framework would not surface it: flex-auth
|
||||
cannot today distinguish "user-engine asking on behalf of tenant X" from "any
|
||||
pod in the cluster asking on behalf of tenant X". The tenant context is
|
||||
carried; the *caller* is not authenticated at all. So the internal-hop
|
||||
weakness here is not a missing revalidation, it is a missing caller identity —
|
||||
axis A, not axis I. A framework question aimed at I surfaced an A0. Recommend
|
||||
§4.2's internal-hop paragraph note that carrying tenant context is worthless
|
||||
without an authenticated hop to carry it over.
|
||||
|
||||
---
|
||||
|
||||
## 4. Further amendments
|
||||
|
||||
### 4.1 The A ladder is written from the PEP's seat; the PDP has no seat
|
||||
|
||||
§3 names flex-auth the vocabulary owner for axis A, and then the ladder's top
|
||||
three rungs describe delegating *to* flex-auth. flex-auth cannot occupy A3 —
|
||||
"decisions delegated to flex-auth as PDP" is not a thing the PDP can do. The
|
||||
document's own worked-examples table (§5) omits flex-auth, which we read as
|
||||
this problem surfacing implicitly.
|
||||
|
||||
Recommend the A ladder state that it describes **enforcement points**, and
|
||||
that a decision point declares two numbers: its own inbound level, and the
|
||||
maximum level it enables for consumers. flex-auth then reads `A0, enables A3`
|
||||
— which is both accurate and considerably more alarming than `A3`, correctly.
|
||||
`tenancy.yaml` uses `enables_for_consumers` pending a canonical field name.
|
||||
|
||||
### 4.2 P and R have no rung for a service with no datastore
|
||||
|
||||
flex-auth holds nothing at rest. Registry snapshot and policy package are
|
||||
baked into the image and mounted read-only; production runs with no `--log`,
|
||||
so not even the decision log persists (`deploy/flex-auth-user-engine.yaml`).
|
||||
|
||||
P0 is the framework's floor and it presupposes a database — "shares a database
|
||||
with another consumer". R0 presupposes retained data — "kept indefinitely by
|
||||
default". Both would be false of flex-auth. §6 makes overclaiming the only
|
||||
violation, so a missing rung *forces* the violation it prohibits: a stateless
|
||||
service must either fabricate a level or stay outside the framework, which is
|
||||
the exact failure §1 says draft-1 was rejected for.
|
||||
|
||||
Recommend an explicit `n/a` value on P and R, admissible only with a stated
|
||||
reason, and a line in §6 that `n/a` is a conformant declaration. `tenancy.yaml`
|
||||
uses it already.
|
||||
|
||||
### 4.3 No declared location makes §12's "guard" unimplementable
|
||||
|
||||
§5.1 says the vector is declared in the repo. It does not say where, or in
|
||||
what format. §12 requires continuous verification "against the service's own
|
||||
declaration" — which needs a path a checker can read without per-repo
|
||||
archaeology. Recommend fixing `tenancy.yaml` at repo root, with the schema in
|
||||
§5. We have adopted that name speculatively; happy to move it.
|
||||
|
||||
### 4.4 §13.1 makes the most common declaration unevidenceable
|
||||
|
||||
"A level is claimed only with its evidence artifact present." The evidence
|
||||
table defines artifacts from I2, A2, E1, P1 and R2 upward. It defines none for
|
||||
I0/I1, A0/A1, E0, P0, R0/R1 — precisely the rungs of the newly absorbed repo
|
||||
that §6 was written to accommodate, and precisely the rungs flex-auth declares
|
||||
on two axes. Under a literal reading of §13.1 our `A0` is unclaimable.
|
||||
|
||||
Recommend: at or below the "no control" rung, a declaration requires a stated
|
||||
reason rather than an artifact. Evidence is what stops you overclaiming; there
|
||||
is nothing to overclaim at the bottom of a ladder.
|
||||
|
||||
### 4.5 Minor — `service_class` has no home in the vector schema
|
||||
|
||||
§8.3.2 requires a declared service class; §5's schema has no field for it.
|
||||
`tenancy.yaml` puts it beside `reviewed`. Suggest §5 add it explicitly.
|
||||
|
||||
---
|
||||
|
||||
## 5. On BOLA coverage and `whitehat-security`
|
||||
|
||||
Noted and welcomed. flex-auth's E2 claim above is exactly the kind that should
|
||||
not be self-certified, and we would rather have it tested by a facility with
|
||||
no stake in the answer than assert it from code review. When
|
||||
`WHITEHAT-WP-0001` is ready to take targets, flex-auth volunteers its
|
||||
cross-tenant decision path: the specific question is whether a
|
||||
`CheckRequest` asserting tenant A can obtain an allow against a resource
|
||||
belonging to tenant B through relationship inheritance
|
||||
(`internal/decision/engine.go:248` is the only thing preventing it).
|
||||
|
||||
We agree with the reasoning in §19.3 and note it matches our own and
|
||||
tenant-engine's August position: the fleet-level answer needed a home, not a
|
||||
volunteer.
|
||||
|
||||
---
|
||||
|
||||
## 6. What flex-auth is doing about this
|
||||
|
||||
`FLEX-WP-0015` — five tasks, one of which is the real work:
|
||||
|
||||
| Task | |
|
||||
|---|---|
|
||||
| T01 | Publish the posture vector and this review; reply to `rapp-postgres` |
|
||||
| T02 | **Close the A0**: decide and record how `/v1/check` authenticates its callers |
|
||||
| T03 | Wire or delete the tenant-engine live-roles adapter |
|
||||
| T04 | AuthZEN endpoint — `wait`, with a written trigger |
|
||||
| T05 | Guard: mechanical check that `tenancy.yaml` still matches the code |
|
||||
|
||||
Nothing in this review changes a running system, and T02 will not be applied
|
||||
to production without the usual staged-promotion path.
|
||||
62
tenancy.yaml
Normal file
62
tenancy.yaml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# flex-auth tenancy posture declaration
|
||||
# Framework: net-kingdom/canon/standards/tenancy-posture_v0.1.md (§5)
|
||||
# Conformance rule (§6): accuracy, not altitude. This file overclaims nothing.
|
||||
# Reasoning and evidence: docs/tenancy-posture-review.md
|
||||
|
||||
service: flex-auth
|
||||
role: policy-decision-point
|
||||
|
||||
tenancy:
|
||||
current:
|
||||
I: 1
|
||||
A: 0
|
||||
E: 2
|
||||
P: "n/a"
|
||||
R: "n/a"
|
||||
target:
|
||||
I: 1
|
||||
A: 2
|
||||
E: 2
|
||||
P: "n/a"
|
||||
R: "n/a"
|
||||
reviewed: "2026-08-17"
|
||||
service_class: latency-critical
|
||||
|
||||
# flex-auth is the PDP, not a PEP. The A ladder as written describes
|
||||
# enforcement points delegating outward; flex-auth is the thing delegated to.
|
||||
# Two numbers are therefore needed and only one has a slot (see review §3.1).
|
||||
enables_for_consumers: 3
|
||||
|
||||
gap:
|
||||
I: >-
|
||||
Subject and tenant arrive in the CheckRequest body, asserted by the
|
||||
calling PEP. flex-auth verifies no token and holds no session. This is
|
||||
I1 by §4.1's literal rule and is structurally correct for a PDP: the
|
||||
decision point judges asserted claims, it cannot be the verifier of its
|
||||
own inputs. Not a defect and not a target for movement.
|
||||
A: >-
|
||||
POST /v1/check and /v1/batch_check authenticate no caller. Any workload
|
||||
with network reach to the ClusterIP Service can assert any subject and
|
||||
any tenant and receive an authoritative decision. Mitigated only by
|
||||
cluster-internal exposure. Target A2 (single inbound choke point binding
|
||||
caller identity) under FLEX-WP-0015-T02.
|
||||
E: >-
|
||||
No tenant data at rest. Tenant scoping in decisions runs through one
|
||||
choke point (internal/decision/engine.go normalizeRequest and the
|
||||
relationship tenant match). E2 evidence is adversarial per §13.2 and is
|
||||
not yet produced; the claim rests on code review only, which §13
|
||||
does not accept. Treat E2 as asserted-pending-evidence.
|
||||
P: >-
|
||||
No rung applies. flex-auth holds no datastore: registry snapshot and
|
||||
policy package are baked into the image and mounted read-only, and the
|
||||
production Deployment runs with no --log flag. P0 is the framework's
|
||||
floor and presupposes a database. Declaring P0 would be a fabrication.
|
||||
R: >-
|
||||
No rung applies, same reason. No tenant data is persisted in production,
|
||||
so there is nothing to retain or erase. R0 ("kept indefinitely by
|
||||
default") would misdescribe a service that keeps nothing.
|
||||
|
||||
evidence:
|
||||
A: "None. A0 is a declared absence, not a claim; see review §3.5 on low-rung evidence."
|
||||
E2: "Pending adversarial artifact. Code choke point: internal/decision/engine.go:188,248"
|
||||
deployment: "deploy/flex-auth-user-engine.yaml, deploy/flex-auth-tenant-engine.yaml"
|
||||
153
workplans/FLEX-WP-0015-tenancy-posture-conformance.md
Normal file
153
workplans/FLEX-WP-0015-tenancy-posture-conformance.md
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
---
|
||||
id: FLEX-WP-0015
|
||||
type: workplan
|
||||
title: "Tenancy posture declaration and inbound caller authentication"
|
||||
domain: infotech
|
||||
repo: flex-auth
|
||||
status: active
|
||||
owner: claude
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
planning_order: 150
|
||||
depends_on_workplans: []
|
||||
related_workplans:
|
||||
- FLEX-WP-0004
|
||||
- FLEX-WP-0011
|
||||
created: "2026-08-17"
|
||||
updated: "2026-08-17"
|
||||
---
|
||||
|
||||
# FLEX-WP-0015 - Tenancy posture declaration and inbound caller authentication
|
||||
|
||||
Answer `rapp-postgres`'s review request on **NetKingdom Tenancy Posture v0.1**
|
||||
(message `82ec43ce`), publish flex-auth's posture vector, and close the one
|
||||
real defect the review surfaced.
|
||||
|
||||
**Review output:** `docs/tenancy-posture-review.md`
|
||||
**Declaration:** `tenancy.yaml` (repo root, per framework §5.1)
|
||||
|
||||
## Why this workplan exists
|
||||
|
||||
Three of the framework's five axes describe flex-auth cleanly. Assessing
|
||||
against them turned up two things we did not know we were carrying:
|
||||
|
||||
1. **`/v1/check` authenticates no caller.** Any workload with network reach to
|
||||
the ClusterIP Service can assert any subject and any tenant and receive an
|
||||
authoritative allow. flex-auth is the estate's authorization oracle and
|
||||
trusts its callers completely. Framework level `A0`.
|
||||
2. **The tenant-engine live-roles adapter is built and unwired.** No non-test
|
||||
caller exists. The IAM Profile live re-query reads as a capability we have
|
||||
and is not one.
|
||||
|
||||
The framework itself needs six amendments, two of them corrections of
|
||||
statements it makes about flex-auth. Those are in the review document and go
|
||||
back to `rapp-postgres` as review output, not as work here.
|
||||
|
||||
**Scope discipline:** this workplan closes flex-auth's own gaps and answers
|
||||
the review. It does not build fleet-level conformance tooling, does not adopt
|
||||
AuthZEN, and does not touch production enforcement (`policy.enabled` stays off
|
||||
per FLEX-WP-0007).
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: FLEX-WP-0015-T01
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
**Publish posture and answer the review.** Write `tenancy.yaml` and
|
||||
`docs/tenancy-posture-review.md`; reply to `rapp-postgres` with the posture
|
||||
vector, the A4 ruling, the internal-hop ruling, and the two factual
|
||||
corrections. Done 2026-08-17.
|
||||
|
||||
```task
|
||||
id: FLEX-WP-0015-T02
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
**Close the A0 — authenticate callers of `/v1/check`.** Decide first, build
|
||||
second: this is a production-facing security boundary on a service two
|
||||
consumers already depend on, and the wrong instrument is worse than the delay.
|
||||
|
||||
Record an ADR covering at minimum:
|
||||
|
||||
- What identifies a caller — Kubernetes ServiceAccount token review, mTLS via
|
||||
the cluster's own CA, or a shared secret header. Note that the Deployment
|
||||
currently sets `automountServiceAccountToken: false`, so option one changes
|
||||
the pod spec.
|
||||
- Whether caller identity only authenticates, or also constrains: may
|
||||
`user-engine` ask questions about resources owned by `tenant-engine`? A
|
||||
caller allowlist per `system` is the natural shape and flex-auth's registry
|
||||
already keys on `system`.
|
||||
- Fail-closed vs fail-open during rollout. Given `policy.enabled` is off in
|
||||
production and both consumers are ours, a warn-only phase that logs
|
||||
unauthenticated callers before rejecting them is available and probably
|
||||
right.
|
||||
- Whether NetworkPolicy is a sufficient interim control to declare `A1`
|
||||
honestly before the real fix lands.
|
||||
|
||||
Target level `A2` — a single inbound choke point binding caller identity —
|
||||
with the §13 evidence artifact: a test that an unbound request is refused.
|
||||
|
||||
Ship through the FLEX-WP-0011 staged-promotion path, not by direct apply.
|
||||
|
||||
```task
|
||||
id: FLEX-WP-0015-T03
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
**Wire or delete `internal/adapters/tenantengine`.** The adapter is complete
|
||||
and has no non-test caller; `decision.Engine` has no field for it. Both
|
||||
outcomes are conformant, silence is not.
|
||||
|
||||
Deciding factor is whether any live policy needs `tenant_roles` for a
|
||||
privileged, destructive, credential-vending or `aal2`-class decision — the
|
||||
IAM Profile's own trigger list. If yes, wire it into the decision path with a
|
||||
timeout and an explicit unavailable-path decision (`AttachToContext` already
|
||||
carries `tenant_roles_available: false` for exactly this), and note the new
|
||||
synchronous dependency on tenant-engine's availability. If no, delete it and
|
||||
say so in the review record rather than leaving it as latent capability.
|
||||
|
||||
Update `tenancy.yaml` `I` either way.
|
||||
|
||||
```task
|
||||
id: FLEX-WP-0015-T04
|
||||
status: wait
|
||||
priority: low
|
||||
```
|
||||
|
||||
**AuthZEN evaluation endpoint (framework `A4`).** Deliberately deferred, not
|
||||
backlogged. `POST /access/v1/evaluation` translating onto the existing engine
|
||||
beside `/v1/check`, non-breaking.
|
||||
|
||||
**Trigger to start:** either a PEP arrives that flex-auth's operator does not
|
||||
control, or a delegated backend under FLEX-WP-0004 needs uniform addressing.
|
||||
Until one of those, A4 buys swappability nobody can use.
|
||||
|
||||
Note when starting: AuthZEN standardises the envelope, not the action
|
||||
vocabulary — it does not end action-string copying between repos. The cheaper
|
||||
fix for that is serving `registry.Actions` read-only, which is independent of
|
||||
this task and may be worth doing first.
|
||||
|
||||
```task
|
||||
id: FLEX-WP-0015-T05
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
**Guard the declaration.** Framework §12 requires verifying the declared
|
||||
posture still holds — against our own declaration, not a universal maximum.
|
||||
|
||||
Small mechanical check, `make verify-posture`, in the shape tenant-engine used
|
||||
for `verify-pin` (bash, no dependency tree). Assert what code can actually
|
||||
prove: that the `/v1/check` handler has caller authentication iff
|
||||
`tenancy.yaml` claims `A >= 2`; that `tenantengine` has a non-test caller iff
|
||||
`I >= 3`; that the production Deployment carries no `--log` and no volume iff
|
||||
`R` is `n/a`. Exit 1 on drift.
|
||||
|
||||
Designed for invisible failure per §12: posture regression returns
|
||||
correct-looking responses, exactly like the two silent pin rollbacks the
|
||||
estate has already been bitten by.
|
||||
Loading…
Add table
Add a link
Reference in a new issue