Implement USER-WP-0024 security layer conformance
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 36s

Declare Engine/PIP machine-readably, publish a total fail-closed PEP
stance map, stop minting local decision ids on engine-unavailable DENY,
bind allows to a 30s request lifetime, confine the local authorization
double, classify evidence and emit a denial/revocation heartbeat, and
prove access-control facts remain claims.

Assistant: grok
Assistant-Session: 01a04cea-f0d6-7ab3-9ffd-881eb6bea6cb
This commit is contained in:
tegwick 2026-08-29 12:53:16 +02:00
parent c7b6148a70
commit 4349758608
22 changed files with 1242 additions and 89 deletions

View file

@ -4,7 +4,7 @@ type: workplan
title: "Security layer model conformance for Engine/PIP"
domain: communication
repo: user-engine
status: active
status: finished
owner: grok
topic_slug: netkingdom
created: "2026-08-29"
@ -52,7 +52,7 @@ by itself make the runtime conforming.
```task
id: USER-WP-0024-T02
status: todo
status: done
priority: high
state_hub_task_id: "2874fd05-5b54-5812-9e89-2832408e488b"
```
@ -65,46 +65,33 @@ claim input), and the path of the PEP stance map. Adapt
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.
Done 2026-08-29. `layer.yaml`, `scripts/check_layer_conformance.py`, and
`tests/test_layer_conformance.py`. Checker exits 0; a synthetic `hvac`
import fails the scan.
## T03 — PEP obligations on the production path
```task
id: USER-WP-0024-T03
status: todo
status: done
priority: high
state_hub_task_id: "caf7ef66-d221-5548-947b-17b5ff1865ee"
```
Ship the four §6.4 obligations for this PEP-shaped Engine:
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.
Done 2026-08-29. `pep-stance.yaml` is total fail-closed including unknown
and equals `user_engine.pep_stance`. Unavailable DENY sets
`stance_applied` and `decision_id=None`. Allows are request-bound with a
30s lifetime. `LocalAuthorizationCheckPort` raises when
`USER_ENGINE_FLEX_AUTH_TOKEN_FILE` is set; `runtime.py` does not import
it.
## T04 — Evidence bound and cadence
```task
id: USER-WP-0024-T04
status: todo
status: done
priority: medium
state_hub_task_id: "b4cebd66-21d0-5a6d-b718-971af70bebb6"
```
@ -113,30 +100,30 @@ 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.
rate.
**Done when:** the classification is in-repo, the heartbeat or
reconciliation form is named, and docs use the sound evidence sentences.
Done 2026-08-29. `src/user_engine/evidence.py`,
`UserEngineService.record_evidence_heartbeat()`,
`docs/evidence-classification.md`. Operability copy no longer says
audit correlation completeness.
## T05 — Access-control facts remain claims
```task
id: USER-WP-0024-T05
status: todo
status: done
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.
decision.
**Done when:** a test and the hats/boundary docs state the claim
contract, and no user-engine API on that path exposes an effect.
Done 2026-08-29. `tests/test_evidence.py` forbids effect fields on claim
shapes and asserts hat selection and export never return allow/deny.
`docs/hats-realms-services-assets-access-profiles.md` states the
consumer contract.
## T06 — Close the intake and request the stance-map row