From f234d0175af81f648922022b6c326fc1cc5a962a Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 5 Oct 2026 01:01:29 +0200 Subject: [PATCH] Admit named-recipient discovery for lifecycle reviews Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a10780-6d41-7952-9718-dfbc1f41236f --- .../pin.json | 4 +- .../policy.md | 56 +++++++++++++++++-- ...0034-informed-decision-review-discovery.md | 47 ++++++++++++++++ 3 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 workplans/FLEX-WP-0034-informed-decision-review-discovery.md diff --git a/examples/informed-decision-lifecycle-review/pin.json b/examples/informed-decision-lifecycle-review/pin.json index 4d7df37..6d503e5 100644 --- a/examples/informed-decision-lifecycle-review/pin.json +++ b/examples/informed-decision-lifecycle-review/pin.json @@ -1,5 +1,5 @@ { "package": "informed-decision.compact-sitting", - "version": "v12", - "package_digest": "sha256:c5387f7d198dc39ab5967e0c218ce05cc779693565c8875e3035e45ec002a2db" + "package_digest": "sha256:31be5985c0c1e6b0c3a039ed7310d1e94daf523a94f6d926e6e8d759d3711873", + "version": "v13" } diff --git a/examples/informed-decision-lifecycle-review/policy.md b/examples/informed-decision-lifecycle-review/policy.md index 9487256..9e5e170 100644 --- a/examples/informed-decision-lifecycle-review/policy.md +++ b/examples/informed-decision-lifecycle-review/policy.md @@ -2,7 +2,7 @@ id: informed-decision.compact-sitting name: Compact sitting exact-record human review namespace: informed-decision:decision-memo -version: v12 +version: v13 status: ready package: flexauth.informed_decision.compact_sitting allow_ttl: 30s @@ -129,6 +129,13 @@ route; it does not assert directory membership in tenant:platform. Only a real human uses accept. This package neither issues nor consumes approval. Native pins: `docs/evidence/2026-09-15-sitting-approval-creates.json`. +v13 adds attribute-based `list` for the retained named recipient. The consumer +supplies `review_recipient` from the immutable memo and verifies the live native +approval requester, human-control flag and binding digest before asking the PDP. +Listing has the existing twelve-hour MFA window; read and all acts retain 900 +seconds. Existing exact-record branches retain precedence. A list allow exposes +only overview metadata and cannot stand in for a read or act decision. + ```rego import rego.v1 @@ -265,7 +272,7 @@ exact_id if { attribute_attempt if { not exact_id - input.action in {"read", "acknowledge", "accept", "return", "discuss", "decline"} + input.action in {"read", "acknowledge", "accept", "return", "discuss", "decline", "list"} ctx := object.get(input, "context", {}) some key in {"review_group", "memo_class", "intake_submitter", "approval_requester", "approval_human_control"} object.get(ctx, key, null) != null @@ -288,17 +295,26 @@ identity_core if { assurance.at > 0 } +mfa_window := 43200 if input.action == "list" else := 900 + mfa_fresh if { identity_core age := time.now_ns() / 1000000000 - input.subject.attributes.assurance.at age >= -30 - age <= 900 + age <= mfa_window } stale_mfa if { identity_core age := time.now_ns() / 1000000000 - input.subject.attributes.assurance.at - age > 900 + age > mfa_window +} + +recipient_ok if input.action != "list" + +recipient_ok if { + input.action == "list" + input.context.review_recipient == input.subject.id } resource_ok if { @@ -433,6 +449,7 @@ decision := {"effect": "allow", "reason": "operator_admitted_compact_sitting"} i } else := {"effect": "allow", "reason": "attribute_eligible"} if { attribute_attempt mfa_fresh + recipient_ok resource_ok review_group_ok class_ok @@ -451,6 +468,9 @@ decision := {"effect": "allow", "reason": "operator_admitted_compact_sitting"} i } else := {"effect": "deny", "reason": "identity_refused"} if { attribute_attempt not mfa_fresh +} else := {"effect": "deny", "reason": "recipient_refused"} if { + attribute_attempt + not recipient_ok } else := {"effect": "deny", "reason": "resource_refused"} if { attribute_attempt not resource_ok @@ -671,10 +691,34 @@ test_bad_memo_id_refused if { eligible(object.union(attribute_input, {"resource": object.union(attribute_input.resource, {"id": "memo:NO"})})).reason == "resource_refused" } -test_list_does_not_use_attribute_admission if { +test_list_requires_explicit_recipient if { got := eligible(object.union(attribute_input, {"action": "list"})) got.effect == "deny" - got.reason == "compact_sitting_scope_or_identity_refused" + got.reason == "recipient_refused" +} + +list_input := patched_context(object.union(attribute_input, {"action": "list"}), {"review_recipient": "test-human"}) + +test_list_admits_recipient_with_twelve_hour_mfa if { + eligible(with_at(list_input, time.now_ns() / 1000000000 - 3600)).effect == "allow" + eligible(with_at(list_input, time.now_ns() / 1000000000 - 43201)).reason == "stale_mfa" +} + +test_list_refuses_other_recipient if { + eligible(patched_context(list_input, {"review_recipient": "other-human"})).reason == "recipient_refused" +} + +test_list_does_not_relax_read_or_accept if { + every action in {"read", "accept"} { + eligible(with_at(object.union(list_input, {"action": action}), time.now_ns() / 1000000000 - 3600)).reason == "stale_mfa" + } +} + +test_list_retains_approval_and_group_guards if { + eligible(patched_context(list_input, {"approval_human_control": false})).reason == "human_control_false" + eligible(patched_context(list_input, {"approval_requester": "other"})).reason == "requester_mismatch" + eligible(patched_context(list_input, {"review_group": "other"})).reason == "review_group_not_verified" + eligible(patched_context(list_input, {"memo_class": "other"})).reason == "unknown_class" } test_exact_record_ignores_attribute_context if { diff --git a/workplans/FLEX-WP-0034-informed-decision-review-discovery.md b/workplans/FLEX-WP-0034-informed-decision-review-discovery.md new file mode 100644 index 0000000..e3fc40c --- /dev/null +++ b/workplans/FLEX-WP-0034-informed-decision-review-discovery.md @@ -0,0 +1,47 @@ +--- +id: FLEX-WP-0034 +type: workplan +title: "Named-recipient discovery for lifecycle reviews" +domain: infotech +repo: access-engine +status: active +owner: codex +topic_slug: netkingdom +created: "2026-10-05" +updated: "2026-10-05" +origin: demand +origin_ref: INFD-WP-0007-T05 +--- + +## Implement and verify recipient-scoped list admission + +```task +id: FLEX-WP-0034-T01 +status: done +priority: high +``` + +Compact-sitting v13 extends the admitted lifecycle attribute branch to list. +It requires the carried immutable review recipient to equal the authenticated +human subject, existing class/submitter/group admission and live native approval +checks in the consumer. Existing exact records retain precedence. Listing uses +the existing twelve-hour assurance window; read/acts retain fifteen minutes. +32 embedded policy tests and owner InformedDecision regressions pass. Consumer +integration covers list/read separation, another recipient and engine outage. +Attribution remains unsigned; no new control claim is made. + +## Release through the owning Helm workflow + +```task +id: FLEX-WP-0034-T02 +status: progress +priority: high +``` + +Founder requested deploying the authoring increment and implementing the rest of +INFD-WP-0007. Authority for its continuation: ADMINISTER @ +realm:kubernetes/railiance01, activation=APPROVED. Build immutable owner artifact, +scan, dry-run/diff, then update the existing review Helm release. The consumer's +pinned version/digest must match. Retain the previous artifact/config as rollback. +No anonymous publication, additional workload identity or non-approval bind is +admitted by this change.