flex-auth/examples/informed-decision-sitting/policy.md
tegwick ad7b7f536a
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 1m14s
Admit list for the informed-decision overview as compact-sitting v3 (FLEX-DEC-2026-017).
list is a separate rule with exact-record scope over the union of the eight
sitting records and the three T03 records, each pinned by approval id, digest and
its own memo version, with a 12-hour MFA window. read and the five acts keep the
v2 rule unchanged — same eight records, same 900-second window — so a list allow
satisfies nothing else.

The operator chose exact-record scope over the consumer's preferred type-wide
scope: the PDP checks no recipient, so type-wide scope with a relaxed window would
have left the consumer's structural match — which the consumer itself says is
not an entitlement — as the only scope. The 12-hour bound replaces the requested
"no bound" so the PDP still states one. The KeyCape stale-timestamp defect is not
worked around; read stays strict.

417 evaluator checks: 168 v2 unchanged, 231 list, 18 proving no act widens to the
T03 records. Also fixes tools/exercise_t03_review_policy.py, which had been
failing since f85479c moved the T03 records to memo version 2 and it still sent
version 1. Test-only.

Not deployed: the pin serving the live review surface changes only with operator
confirmation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 28468@bnt-lap001
Assistant-Session: c76569b2-6056-4dad-aea4-49cd7a018f5d
2026-09-21 23:06:40 +02:00

8 KiB

id name namespace version status package allow_ttl actions owner fixtures caring activation
informed-decision.compact-sitting Compact sitting exact-record human review informed-decision:decision-memo v3 ready flexauth.informed_decision.compact_sitting 30s
read
acknowledge
accept
return
discuss
decline
list
flex-auth
fixtures.json
profile enforce
caring-0.4.0-rc2 false
mode
local

Compact sitting review mandate

This is a new exact-record package for seven 2026-09-14 sitting memos. v2 (2026-09-21) adds exactly one record, memo:infd-20260921-b01 (the SECRETS-WP-0009-T03 spend envelope), with native pins from informed-decision docs/evidence/2026-09-21-budget-approval-create.json. The seven v1 records and the identity bar are unchanged. It is not an expansion of examples/informed-decision-t03 / FLEX-WP-0027. memo:infd-20260914-c01 is omitted (create-client still undecided).

v3 (2026-09-21, FLEX-WP-0032, FLEX-DEC-2026-017) adds one action, list, for informed-decision's decision overview (INFD-IN-0008). It is a separate rule, not an extra member of the act set, and it changes nothing else:

  • read and the five acts keep the v2 rule unchanged — the same eight records, the same 900-second MFA window. A list allow satisfies no other action.
  • list covers the union of this package's eight records and the three SECRETS-WP-0010-T03-* records from informed-decision.t03-review, each pinned by approval id, binding digest and its own memo version (T03 at 2). Scope stays exact-record: a memo is listable only once someone admitted it. The operator declined resource-type-wide scope because the PDP checks no recipient, and a type-wide rule would have left consumer code — which the consumer itself says is not an entitlement — as the only scope.
  • list carries the same identity bar with a 12-hour MFA window instead of 900 seconds. Looking back at your own outcomes is not binding a new one. The bar is lighter, not absent: the PDP still states a bound.
  • The KeyCape stale-timestamp defect (INFD-IN-0005) is not worked around here. read stays strict; that defect is key-cape's to fix.

The identity bar matches T03: authenticated informed-decision caller, net-kingdom-admins, fresh KeyCape AAL2 MFA. No permission follows from memo content or presentation state. TokenReview must admit system:serviceaccount:informed-decision:review before this package is served. Membership tenant provenance may follow the accepted registration 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.

import rego.v1

records := {
  "memo:infd-20260914-c02": {
    "approval_id": "ccfd8007-2061-48fd-9356-99b16279dac1",
    "binding_digest": "sha256:942cf7d5e6805987df2077a0cc6cde75b148e1729a96dd0692153287820b6a0a"
  },
  "memo:infd-20260914-c03": {
    "approval_id": "a0611d0d-b9ef-4b9a-aa79-e94a9e3fcd5f",
    "binding_digest": "sha256:95cae135b994acea6dad9da978dd3df1aa3354de900a1f43c2e5a03a20e8e844"
  },
  "memo:infd-20260914-c04": {
    "approval_id": "22ac6df3-e6a9-472b-a68e-c8caca4289a7",
    "binding_digest": "sha256:dec960b30efaf654abbdcd8a2cdd20d4ff6bf52e170744f817dc55845d9cb192"
  },
  "memo:infd-20260914-d01": {
    "approval_id": "9f7c3506-68de-4826-86ff-e301f428408d",
    "binding_digest": "sha256:8cb7cc93f38db9d19b49e201e0554b50af1891fec853fef333a06ea078541d15"
  },
  "memo:infd-20260914-d02": {
    "approval_id": "b3ce2c01-0a3b-401e-b4ed-c1954af169c9",
    "binding_digest": "sha256:be0c7de123216740d2c2eeaed80384e03e6b6d1668104f94bb8f9cbae7dfe30f"
  },
  "memo:infd-20260914-d03": {
    "approval_id": "3b483e6b-0b92-45ff-83b6-bc5057c0a496",
    "binding_digest": "sha256:3c562278e86bb5e7f747452cf2e99d3a136853ab748676e8359262b835cd1425"
  },
  "memo:infd-20260914-d04": {
    "approval_id": "356e67a3-5539-46a1-922a-f5591fd38ee5",
    "binding_digest": "sha256:3c2d7759679d871cb7c5cac8999542a365e64c918d59d0c4ce864ffb837453e4"
  },
  "memo:infd-20260921-b01": {
    "approval_id": "ba5ce2d8-8b6d-40be-af89-2e8c147029a3",
    "binding_digest": "sha256:e9eaf454e94871ec2060855fcfbd327bcaec873d2c61cae031bec9f95a34bcae"
  }
}

list_only_records := {
  "memo:SECRETS-WP-0010-T03-apply": {
    "approval_id": "9935335c-8e9a-566e-a48e-6a5b5f4882eb",
    "binding_digest": "sha256:03cc5b37437f14e86b686ce4054f976556334eff3fa260b03e8014ed3d9217e5",
    "memo_version": 2
  },
  "memo:SECRETS-WP-0010-T03-verify": {
    "approval_id": "273d6882-6253-5dc9-ac54-544f92ef5e56",
    "binding_digest": "sha256:72d9267d038c17107c880ffc9009793ce9c70defbddfe2219628854b811a04b2",
    "memo_version": 2
  },
  "memo:SECRETS-WP-0010-T03-exec": {
    "approval_id": "7ba0c13b-68cd-5b3e-9481-42ba9e385e68",
    "binding_digest": "sha256:f2cf0fb53b740900756ccde5587c3578fcff44beef2f1edab17b9a198a4033d8",
    "memo_version": 2
  }
}

# listable is the union list may range over. Sitting records are memo version 1,
# as the act rule pins; T03 records carry their own version (2).
listable := object.union(
  {id: object.union(r, {"memo_version": 1}) | some id, r in records},
  list_only_records,
)

decision := {"effect": "allow", "reason": "operator_admitted_compact_sitting"} if {
  input.tenant == "tenant:platform"
  input.subject.tenant == "tenant:platform"
  input.subject.type == "human"
  is_string(input.subject.id)
  input.subject.id != ""
  input.subject.attributes.principal_type_source == "authentication-derived"
  input.subject.attributes.tenant_source in {"registration-supplied", "directory-asserted"}
  "net-kingdom-admins" in input.subject.attributes.groups
  assurance := input.subject.attributes.assurance
  assurance.level == "aal2"
  assurance.mfa == true
  assurance.source == "key-cape"
  assurance.methods == ["pwd", "otp"]
  is_number(assurance.at)
  assurance.at > 0
  age := time.now_ns() / 1000000000 - assurance.at
  age >= -30
  age <= 900
  input.resource.tenant == "tenant:platform"
  input.resource.system == "informed-decision"
  input.resource.type == "decision-memo"
  record := records[input.resource.id]
  input.context.memo_version == 1
  input.context.approval_id == record.approval_id
  input.context.approval_binding_digest == record.binding_digest
  input.action in {"read", "acknowledge", "accept", "return", "discuss", "decline"}
} else := {"effect": "allow", "reason": "operator_admitted_overview_list"} if {
  input.action == "list"
  input.tenant == "tenant:platform"
  input.subject.tenant == "tenant:platform"
  input.subject.type == "human"
  is_string(input.subject.id)
  input.subject.id != ""
  input.subject.attributes.principal_type_source == "authentication-derived"
  input.subject.attributes.tenant_source in {"registration-supplied", "directory-asserted"}
  "net-kingdom-admins" in input.subject.attributes.groups
  assurance := input.subject.attributes.assurance
  assurance.level == "aal2"
  assurance.mfa == true
  assurance.source == "key-cape"
  assurance.methods == ["pwd", "otp"]
  is_number(assurance.at)
  assurance.at > 0
  age := time.now_ns() / 1000000000 - assurance.at
  age >= -30
  age <= 43200
  input.resource.tenant == "tenant:platform"
  input.resource.system == "informed-decision"
  input.resource.type == "decision-memo"
  record := listable[input.resource.id]
  input.context.memo_version == record.memo_version
  input.context.approval_id == record.approval_id
  input.context.approval_binding_digest == record.binding_digest
} else := {"effect": "deny", "reason": "compact_sitting_scope_or_identity_refused"} if {
  true
}
package flexauth.informed_decision.compact_sitting_test
import rego.v1
import data.flexauth.informed_decision.compact_sitting

test_unknown_request_denied if {
  compact_sitting.decision.effect == "deny" with input as {}
}

test_listable_is_exact_union if {
  count(compact_sitting.listable) == count(compact_sitting.records) + count(compact_sitting.list_only_records)
}

test_t03_records_not_in_act_scope if {
  every id, _ in compact_sitting.list_only_records {
    not compact_sitting.records[id]
  }
}