Declare Engine/PIP and open TEN-WP-0011 for v0.7 conformance
The security layer model is accepted at v0.7. INTENT.md now declares Engine / PIP in this repository's own voice (TEN-DEC-2026-001), SCOPE.md is brought current with shipped APIs, and the intent/scope/implementation review is history/2026-08-29-security-layer-intent-scope-review.md. TEN-IN-0003 is absorbed by the declaration. Approvals stay with approval-engine. TEN-IN-0001 and TEN-IN-0002 promote into TEN-WP-0011. Assistant: grok Assistant-Session: 01a04cea-e5e8-7081-a0fc-808ebbc35fa9
This commit is contained in:
parent
d9bacfa953
commit
76677bffc5
7 changed files with 780 additions and 86 deletions
224
workplans/TEN-WP-0011-security-layer-conformance.md
Normal file
224
workplans/TEN-WP-0011-security-layer-conformance.md
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
---
|
||||
id: TEN-WP-0011
|
||||
type: workplan
|
||||
title: "Align tenant-engine with the accepted security layer model"
|
||||
domain: infotech
|
||||
repo: tenant-engine
|
||||
status: ready
|
||||
owner: grok
|
||||
topic_slug: netkingdom
|
||||
created: "2026-08-29"
|
||||
updated: "2026-08-29"
|
||||
depends_on:
|
||||
- TEN-WP-0003
|
||||
- TEN-WP-0006
|
||||
- TEN-WP-0009
|
||||
unblocks: []
|
||||
origin: residual
|
||||
origin_ref: TEN-IN-0003
|
||||
---
|
||||
|
||||
# TEN-WP-0011 — Align tenant-engine with the accepted security layer model
|
||||
|
||||
The NetKingdom Security Layer Model is accepted at v0.7. This repository is
|
||||
catalogued Engine / PIP for tenant-as-an-entity facts. `INTENT.md` now
|
||||
declares that in its own voice (`TEN-DEC-2026-001`). The remaining work is
|
||||
to make the shipped engine match the obligations that declaration takes on.
|
||||
|
||||
Review of record:
|
||||
`history/2026-08-29-security-layer-intent-scope-review.md`.
|
||||
|
||||
Start here: `net-kingdom/SECURITY-COMPANION.md` v0.2. Statute:
|
||||
`net-kingdom/canon/standards/security-layer-model_v0.7.md`. On disagreement
|
||||
the statute governs.
|
||||
|
||||
## Why this is a workplan
|
||||
|
||||
Declaration is documentation. Conformance is mechanical. Companion §2
|
||||
offers `layer.yaml` plus a check as the working reference. Companion §5
|
||||
and statute §6.4 bind the write path as PEP-shaped. Statute §9.6 and the
|
||||
already-open intakes `TEN-IN-0001` / `TEN-IN-0002` bind evidence. Statute
|
||||
§9.7 requires a published lifetime on PIP input classes.
|
||||
|
||||
This is not a layer change (statute §10). We are declaring the layer we
|
||||
already occupy and closing the gaps between that layer's rules and the
|
||||
code.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Not a second PDP. Guardrail resolution stays a ceiling, never an allow.
|
||||
- Not an approval engine. `TEN-DEC-2026-001` contested that placement.
|
||||
- Not containment or production observation (companion §10).
|
||||
- Not staged promotion — that remains `TEN-WP-0008`.
|
||||
- Not forking the boundary contract. T06 requests an amendment in
|
||||
`net-kingdom`; it does not copy the contract into this repo.
|
||||
|
||||
## T01 — Machine-readable layer declaration and conformance check
|
||||
|
||||
```task
|
||||
id: TEN-WP-0011-T01
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Add `layer.yaml` modelled on `ops-warden`'s reference and `kings-guard`'s
|
||||
no-Tooling adaptation: `layer: engine`, `role: pip`, `standard_version:
|
||||
"0.7"`, empty `tooling_contacts`, and a complete `non_tooling_clients`
|
||||
inventory (PostgreSQL / SQLite store, `flex-auth` `/v1/check`, State Hub
|
||||
work records).
|
||||
|
||||
Add a check script and a test so a new catalogued Tooling client
|
||||
(`key-cape`, OpenBao) fails on the commit that introduces it. Record
|
||||
non-Tooling clients so the check is total (companion §4).
|
||||
|
||||
Done when: `INTENT.md` frontmatter and `layer.yaml` agree on layer and
|
||||
role; `make test` covers the check; no OpenBao / `key-cape` client exists
|
||||
in `src/`.
|
||||
|
||||
## T02 — PEP write-path: decision records and published fail-closed stance
|
||||
|
||||
```task
|
||||
id: TEN-WP-0011-T02
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
`FlexAuthCheckClient.is_allowed()` currently returns a bool and drops the
|
||||
decision envelope. The boundary contract's Audit Correlation Contract
|
||||
already required `authorization_decision_id` on every mutation; the code
|
||||
never stored it.
|
||||
|
||||
- Keep the decision record (id, effect, request digest) on the authorizer
|
||||
seam and persist it on every mutation event.
|
||||
- Where `access-engine` is unset or unreachable, record the **application
|
||||
of the stance** in place of a decision (companion §5.1). Do not proceed
|
||||
silently.
|
||||
- Publish the unreachable-engine stance as a file named from `layer.yaml`
|
||||
(fail-closed for every scope this engine serves — this is not
|
||||
ops-warden's per-zone fail-open map). Assert with a test that the
|
||||
published map equals shipped behaviour (`DefaultDenyWriteAuthorizer` and
|
||||
transport-failure deny).
|
||||
- Lock obligation 2: no verdict cache. Re-check every write. Add a test
|
||||
that a previous allow cannot authorize a later, different request.
|
||||
- Offer the map to gate-house for the statute §13.1 register. Do not edit
|
||||
the statute from this repo.
|
||||
|
||||
Done when: a granted role, a denied grant, and an unreachable-engine
|
||||
attempt each leave a reconstructable record; `make test` proves stance
|
||||
file == code; no write path can succeed without one of those two records.
|
||||
|
||||
## T03 — PIP claim freshness, and prove live-lookup is not cyclic
|
||||
|
||||
```task
|
||||
id: TEN-WP-0011-T03
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Statute §9.7: every allow has a lifetime, and a PDP states a deadline per
|
||||
input class. This engine owes the input-class description.
|
||||
|
||||
- Publish, next to the stance map, the freshness contract for
|
||||
`tenant_roles` / grouping / plan / guardrail claims: cache-read is
|
||||
bounded by the IAM Profile token lifetime; live-lookup results MUST NOT
|
||||
be cached across requests; request-scoped memoization inside one
|
||||
`access-engine` decision remains allowed (boundary contract).
|
||||
- Name the consumer-visible failure: store unavailability is `503`, never
|
||||
empty roles. That is already shipped; make it part of the published
|
||||
contract so `access-engine` can treat it as input degradation (§9.3).
|
||||
- **Prove** that `GET /tenants/{id}/roles/live` → `POST /v1/check`
|
||||
(`tenant.role.read.live`) does not re-enter tenant-engine for the claims
|
||||
that check needs. If it does, the live path is cyclic and must be
|
||||
unwound (static service-identity rule, or an authorizer bypass that is
|
||||
itself a declared exception — prefer the former). Record the proof in
|
||||
`docs/flex-auth-integration.md`.
|
||||
|
||||
Done when: the freshness contract is published; a test fails if live-lookup
|
||||
cross-request caching is introduced; the re-entry question is answered with
|
||||
evidence, not a comment.
|
||||
|
||||
## T04 — Externalize mutation evidence to audit-core
|
||||
|
||||
```task
|
||||
id: TEN-WP-0011-T04
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Promoted from `TEN-IN-0001` (origin: residual of `TEN-WP-0009`).
|
||||
|
||||
The local `events` table shares a database and runtime credential with the
|
||||
facts it attests to. Statute §9.6: that trail cannot be described as
|
||||
independent custody. Classify current classes as **attributive** unless a
|
||||
named control branches on their presence.
|
||||
|
||||
Design and implement a governed tenant-engine → `audit-core` emission path:
|
||||
|
||||
1. Agree envelope, sender registration, and credential custody with
|
||||
`audit-core` without putting a secret in Git or a work record. Route
|
||||
credentials through `warden route`, never through a State Hub message.
|
||||
2. Preserve mutation atomicity (local outbox against crash) while defining
|
||||
retry, duplicate, and audit-core-unavailable semantics. Unavailable
|
||||
evidence MUST NOT fail-open a mutation, and SHOULD NOT fail-closed a
|
||||
mutation either unless a class is later reclassified load-bearing —
|
||||
declare the trade if emission stays attributive and non-blocking.
|
||||
3. Prove the external copy cannot be rewritten through tenant-engine's
|
||||
runtime database credential.
|
||||
4. Decide whether pre-cutover event classes need a bounded backfill, and
|
||||
record the decision.
|
||||
5. Do not claim the archive proves events happened, or that absence proves
|
||||
they did not.
|
||||
|
||||
Done when: production mutations emit to `audit-core` under the bound above;
|
||||
the trade (atomic vs non-blocking) is declared; `TEN-IN-0001` can close as
|
||||
promoted and completed.
|
||||
|
||||
## T05 — Remove or authorize the unfiltered event-read interface
|
||||
|
||||
```task
|
||||
id: TEN-WP-0011-T05
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Promoted from `TEN-IN-0002` (origin: RISK-F-0004).
|
||||
|
||||
`TenantStore.events()` returns every tenant's event and payload. There is
|
||||
no HTTP event-read route today, but the production protocol still offers
|
||||
the dump.
|
||||
|
||||
- Remove `events()` from the production protocol, **or** replace it with
|
||||
an authorized, deliberately scoped export/query that cannot return
|
||||
another tenant's payload.
|
||||
- Add cross-tenant negative tests.
|
||||
- Hand risk-nexus the accessibility and payload reading.
|
||||
|
||||
Done when: a production caller cannot list another tenant's events through
|
||||
this repo's store protocol; tests say so; `TEN-IN-0002` can close.
|
||||
|
||||
## T06 — Request the boundary-contract amendment
|
||||
|
||||
```task
|
||||
id: TEN-WP-0011-T06
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
`net-kingdom/canon/standards/tenant-engine-boundary-contract_v0.1.md` still
|
||||
says guardrail/quota policy is "reserved, not yet implemented" and that
|
||||
`tenant-engine` is "not a policy enforcement point". Both sentences now
|
||||
mislead: guardrails shipped in `TEN-WP-0006`, and writes are PEP-shaped
|
||||
even though this repo is not a PDP.
|
||||
|
||||
File an intake on `net-kingdom` (do not edit the canon from here) asking
|
||||
to:
|
||||
|
||||
- mark guardrail/quota policy as owned and implemented, pointing at
|
||||
`docs/tenant-guardrail-policy.md`;
|
||||
- restate the authorization contract: data source / PIP for decisions;
|
||||
PEP-shaped for its own protected writes; never a second PDP;
|
||||
- mention Engine / PIP and the v0.7 statute next to the existing IAM
|
||||
Profile / ADR-0013 / ADR-0014 references.
|
||||
|
||||
Done when: the intake exists on the canon side with a named id, and this
|
||||
task records it.
|
||||
Loading…
Add table
Add a link
Reference in a new issue