user-engine/workplans/USER-WP-0024-security-layer-conformance.md
repo-manager c7b6148a70
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
chore(registrar): assign State Hub identifiers
Assistant: grok
Assistant-Session: 01a04cea-f0d6-7ab3-9ffd-881eb6bea6cb
2026-08-29 12:10:32 +02:00

5.5 KiB

id type title domain repo status owner topic_slug created updated depends_on state_hub_workstream_id
USER-WP-0024 workplan Security layer model conformance for Engine/PIP communication user-engine active grok netkingdom 2026-08-29 2026-08-29
USER-WP-0023
dee4ec0e-c451-50be-9363-e9cbc8ff68de

USER-WP-0024 — security layer model conformance

Adopt the accepted NetKingdom Security Layer Model (net-kingdom/canon/standards/security-layer-model_v0.7.md, companion net-kingdom/SECURITY-COMPANION.md) as this repository's own declaration and close the implementation gaps that leave a PEP-shaped Engine short of the standard.

Assessment: history/2026-08-29-security-layer-scope-intent-assessment.md.

Working references: ops-warden/layer.yaml and kings-guard/layer.yaml (no Tooling contacts). Credential and lane questions go to ops-warden, not this workplan.

T01 — Declare Engine/PIP in own voice

id: USER-WP-0024-T01
status: done
priority: high
state_hub_task_id: "ee4c6a3c-a48c-5508-85c1-a02c6a0b1d11"

Replace the gate-house review note in INTENT.md with this repository's own declaration: frontmatter layer: Engine, role: PIP, plus prose that subject context is a claim, never a decision, and that protected mutations are PEP-shaped without changing layer. Restate SCOPE.md from that INTENT. Record the scope-vs-intent-vs-implementation assessment under history/.

Done 2026-08-29. Closes the declaration half of USER-IN-0001. Does not by itself make the runtime conforming.

T02 — Machine-readable layer declaration and check

id: USER-WP-0024-T02
status: todo
priority: high
state_hub_task_id: "2874fd05-5b54-5812-9e89-2832408e488b"

Add layer.yaml (or equivalent) naming Engine/PIP, empty catalogued Tooling contacts, non-Tooling / own-store clients (PostgreSQL modeled concept, State Hub, env-injected secrets, flex-auth Engine API, OIDC claim input), and the path of the PEP stance map. Adapt kings-guard/scripts/check_layer_conformance.py and a unit test so an undeclared OpenBao, Vault, LDAP, or cluster client fails the commit that introduces it.

Do not add a Tooling client to have something to declare.

Done when: layer.yaml is the machine-readable declaration, the checker exits 0 on the current tree, and a test covers the empty Tooling-contact claim.

T03 — PEP obligations on the production path

id: USER-WP-0024-T03
status: todo
priority: high
state_hub_task_id: "caf7ef66-d221-5548-947b-17b5ff1865ee"

Ship the four §6.4 obligations for this PEP-shaped Engine:

  1. Publish pep-stance.yaml (total, no implicit default). Production remains fail-closed, including unknown. A test asserts the file equals FlexAuthHTTPAdapter behaviour.
  2. On engine-unavailable DENY, record stance application (scope, failure mode, outcome). decision_id is present only when flex-auth rendered a decision. Stop minting a local id via AuthorizationDecision's default factory on that path.
  3. Give AuthorizationDecision an explicit lifetime (TTL or session/obligation binding). Do not add a verdict cache.
  4. Confine LocalAuthorizationCheckPort to tests and standalone fixtures. Production create_application() must be unable to construct a default-allow adapter.

Done when: the published map matches shipped fail-closed behaviour, unavailable DENY audits carry no engine decision id, allows carry a lifetime, and the local port cannot enter the production runtime assembly.

T04 — Evidence bound and cadence

id: USER-WP-0024-T04
status: todo
priority: medium
state_hub_task_id: "b4cebd66-21d0-5a6d-b718-971af70bebb6"

Classify local audit and outbox events as load-bearing or attributive. Keep mutation+audit+outbox atomic in the store transaction (already true). For denials and membership/account revocations — low-volume load-bearing classes — declare a heartbeat or reconciliation, not a rate. Update docs/evidence-gap-examples.md and operability copy so the trail is never described as complete, and so absence of a record is not read as non-occurrence.

Done when: the classification is in-repo, the heartbeat or reconciliation form is named, and docs use the sound evidence sentences.

T05 — Access-control facts remain claims

id: USER-WP-0024-T05
status: todo
priority: medium
state_hub_task_id: "f1ac9244-0639-5e97-8981-babdbe8991e5"

Prove under statute §6.1 that hats, access profiles, and AccessControlFact exports cannot be mistaken for an authorization decision. Add a test that selection and export never return allow/deny. Document the consumer contract: compiling those facts into a local decision is an early decision and is forbidden.

Done when: a test and the hats/boundary docs state the claim contract, and no user-engine API on that path exposes an effect.

T06 — Close the intake and request the stance-map row

id: USER-WP-0024-T06
status: done
priority: medium
state_hub_task_id: "81ecfc55-2b23-53cd-9269-c7211bad8bd9"

Mark USER-IN-0001 answered: Engine/PIP, not contested. Message gate-house with the declaration path, the PEP-shaped finding for statute §13.1 (user-engine is a third PEP-shaped consumer; the register currently has one published row), and a pointer at this workplan for the runtime follow-through.

Done 2026-08-29. Intake marked answered in intakes/intakes.md. Message c014d12a-fe7a-4a90-ba73-03a5ac3e7f73 to gate-house carries the declaration, the non-contest, and the §13.1 request (row to be added when pep-stance.yaml ships in T03).