Finish FLEX-WP-0019 layer-model v0.7 conformance
Close the remaining PDP obligations: mechanical layer declaration check, registry-snapshot digest in provenance, explicit allow TTL, per-input-class freshness deadlines, and the published decision-record contract. Document the canonical request digest as the §6.4.2 replay test. Assistant: grok Assistant-Session: 01a06256-fb71-7102-b3a9-27e6734257d0
This commit is contained in:
parent
9689894c15
commit
56940727bf
32 changed files with 1194 additions and 111 deletions
57
docs/decision-record-contract.md
Normal file
57
docs/decision-record-contract.md
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Decision-record contract
|
||||
|
||||
Status: published
|
||||
Contract: `flex-auth.decision-record.v1`
|
||||
Schema: [`../schemas/decision_envelope.schema.json`](../schemas/decision_envelope.schema.json)
|
||||
Date: 2026-09-02
|
||||
|
||||
This is flex-auth's output artifact under the NetKingdom Security Layer Model
|
||||
v0.7 §17. Taxonomy holds only the shared field vocabulary. Consumers may rely
|
||||
on this schema.
|
||||
|
||||
A decision record is a `DecisionEnvelope` returned by `POST /v1/check` and the
|
||||
CLI `check` / `batch-check` / `list-allowed` commands. Standalone evaluation
|
||||
and every delegated adapter (Topaz, relationship, rule, Keycloak) emit the
|
||||
same shape.
|
||||
|
||||
## Required fields
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `id` | Deterministic decision identifier |
|
||||
| `effect` | `allow`, `deny`, `redact`, `audit_only`, or `not_applicable` |
|
||||
| `subject` / `resource` | Normalized refs the evaluator used |
|
||||
| `provenance` | Who evaluated, over which policy and facts |
|
||||
|
||||
## Contract fields consumers may rely on
|
||||
|
||||
| Field | Meaning |
|
||||
| --- | --- |
|
||||
| `contract_version` | `flex-auth.decision-record.v1` |
|
||||
| `binding` | Structured subject, action, resource, context, and `request_digest` |
|
||||
| `lifetime` | **Required on every allow.** A TTL with `not_before` and `expires_at` |
|
||||
| `provenance.policy_package` / `policy_version` | Named package pin |
|
||||
| `provenance.policy_package_digest` | SHA-256 of package metadata plus compiled Rego |
|
||||
| `provenance.registry_snapshot_digest` | SHA-256 of the canonical registry snapshot |
|
||||
| `provenance.directory_etag` | Directory consistency token when a delegated directory was joined |
|
||||
| `provenance.input_claim_digests` | SHA-256 per request-time claim class (`context`, `caring_context`) |
|
||||
| `provenance.decision_time` | UTC timestamp used to compute `lifetime` |
|
||||
|
||||
`reason`, `diagnostics`, and CARING prose are not an authorization contract.
|
||||
|
||||
## Allow lifetime
|
||||
|
||||
Every allow carries `lifetime.kind = ttl`. The duration comes from the policy
|
||||
package `allow_ttl` field, or from the engine default of `15m` when the package
|
||||
omits it. A package that declares `allow_ttl: none` (or `0s`) produces a deny
|
||||
with reason `allow_lifetime_unstated` instead of a standing grant.
|
||||
|
||||
Replay is permitted only while `lifetime.expires_at` is still in the future.
|
||||
See [`canonical-request-digest.md`](canonical-request-digest.md) and
|
||||
[`decision-input-freshness.md`](decision-input-freshness.md).
|
||||
|
||||
## Versioning
|
||||
|
||||
This is contract version 1. Additive optional fields may appear. Removing or
|
||||
redefining a required field requires a new `contract_version` value and a new
|
||||
schema id.
|
||||
Loading…
Add table
Add a link
Reference in a new issue