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
This commit is contained in:
parent
1a3f2f7d78
commit
ad7b7f536a
7 changed files with 1928 additions and 8 deletions
|
|
@ -1953,3 +1953,60 @@ denies (mismatch, absent) were added. 42 fixtures, 33 embedded tests, all pass.
|
||||||
of behaviour for any caller that is not tenant-engine; per
|
of behaviour for any caller that is not tenant-engine; per
|
||||||
`FLEX-DEC-2026-008` it is a version change, not a silent edit. tenant-engine
|
`FLEX-DEC-2026-008` it is a version change, not a silent edit. tenant-engine
|
||||||
asked for no notice period.
|
asked for no notice period.
|
||||||
|
|
||||||
|
## FLEX-DEC-2026-017 — `informed-decision.compact-sitting` v3 admits `list`: exact-record scope, 12-hour MFA window, acts unchanged
|
||||||
|
|
||||||
|
**Status:** accepted — operator decision, 2026-09-21
|
||||||
|
**Requested by:** `informed-decision` (`INFD-IN-0008`, `INFD-WP-0004-T02`),
|
||||||
|
hub message `a7b9ef3b-f95c-4c50-bfc5-7628d16881f6`
|
||||||
|
**Workplan:** `FLEX-WP-0032`
|
||||||
|
**Package:** `informed-decision.compact-sitting` v3,
|
||||||
|
`sha256:dd40c80c5719851737178097cdee65afac108b54e19c07370e549b860f1a9655`
|
||||||
|
|
||||||
|
**Decision.** v3 adds one action, `list`, as a rule of its own. It is not a
|
||||||
|
seventh member of the act set, and it changes nothing that v2 decided.
|
||||||
|
|
||||||
|
1. **Acts unchanged.** `read`, `acknowledge`, `accept`, `return`, `discuss` and
|
||||||
|
`decline` keep the v2 rule unchanged: the same eight records, the same
|
||||||
|
900-second MFA window. A `list` allow satisfies no other action.
|
||||||
|
2. **Exact-record scope.** `list` ranges over 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, sitting at 1).
|
||||||
|
3. **A lighter bar, not an absent one.** `list` requires the same identity as
|
||||||
|
the acts with a **12-hour** MFA window instead of 900 seconds.
|
||||||
|
|
||||||
|
**Why exact-record over resource-type-wide.** The consumer preferred
|
||||||
|
resource-type-wide scope (option A). The v2 rule scopes a decision three ways —
|
||||||
|
exact-record pinning, group, fresh MFA — and checks no recipient. Option A,
|
||||||
|
together with a relaxed window, would have removed both PDP-side scopes for
|
||||||
|
`list` at once, leaving the consumer's structural recipient match as the only
|
||||||
|
thing between a group member and every memo's question and status. The
|
||||||
|
consumer's own request says that match "is not an entitlement." A PDP cannot
|
||||||
|
rest an allow on a check its consumer disclaims. Under exact-record scope a memo
|
||||||
|
becomes listable when someone admits it, and a package version per sitting is
|
||||||
|
the cost of that property.
|
||||||
|
|
||||||
|
**Why a bound at all.** The request asked for no freshness bound. Unbounded
|
||||||
|
would have let an MFA of any age satisfy `list` for as long as the consumer
|
||||||
|
presented a key-cape session, and the PDP would have stated nothing. Twelve
|
||||||
|
hours covers the observed production refusals (1744 s) with ample margin and
|
||||||
|
keeps the bound in the policy, where a reviewer can read it.
|
||||||
|
|
||||||
|
**What this does not do.** It does not work around the KeyCape stale-timestamp
|
||||||
|
defect (`INFD-IN-0005`), which made the overview fail in the first place. The
|
||||||
|
case for `list` stands on its own — looking back at your own outcomes is not
|
||||||
|
binding a new one — and `read` stays strict. Loosening a binding bar to absorb
|
||||||
|
an identity-layer fault would move key-cape's defect into flex-auth's policy.
|
||||||
|
|
||||||
|
**Evidence.** 417 evaluator checks
|
||||||
|
(`docs/evidence/2026-09-21-sitting-review-policy-v3.json`): the 168 v2 checks
|
||||||
|
unchanged; 231 `list` checks over the 11-record union, including the observed
|
||||||
|
1744 s case allowed, the 12-hour bound refused past it, and stale MFA still
|
||||||
|
refused for `read`; and 18 proving no act widens to the T03 records even with
|
||||||
|
fresh MFA. Rego tests assert the union is exact and that T03 records are outside
|
||||||
|
the act scope. T03's own 57 checks pass.
|
||||||
|
|
||||||
|
**Rollout.** Deploying v3 changes the pin serving a live human-review surface,
|
||||||
|
and is confirmed with the operator before it runs. informed-decision updates its
|
||||||
|
admission input to the version and digest above once the pin serves v3.
|
||||||
|
|
|
||||||
1673
docs/evidence/2026-09-21-sitting-review-policy-v3.json
Normal file
1673
docs/evidence/2026-09-21-sitting-review-policy-v3.json
Normal file
File diff suppressed because it is too large
Load diff
20
examples/informed-decision-sitting/list_only_records.json
Normal file
20
examples/informed-decision-sitting/list_only_records.json
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"memo:SECRETS-WP-0010-T03-apply": {
|
||||||
|
"approval_id": "9935335c-8e9a-566e-a48e-6a5b5f4882eb",
|
||||||
|
"binding_digest": "sha256:03cc5b37437f14e86b686ce4054f976556334eff3fa260b03e8014ed3d9217e5",
|
||||||
|
"memo_version": 2,
|
||||||
|
"label": "t03-apply"
|
||||||
|
},
|
||||||
|
"memo:SECRETS-WP-0010-T03-verify": {
|
||||||
|
"approval_id": "273d6882-6253-5dc9-ac54-544f92ef5e56",
|
||||||
|
"binding_digest": "sha256:72d9267d038c17107c880ffc9009793ce9c70defbddfe2219628854b811a04b2",
|
||||||
|
"memo_version": 2,
|
||||||
|
"label": "t03-verify"
|
||||||
|
},
|
||||||
|
"memo:SECRETS-WP-0010-T03-exec": {
|
||||||
|
"approval_id": "7ba0c13b-68cd-5b3e-9481-42ba9e385e68",
|
||||||
|
"binding_digest": "sha256:f2cf0fb53b740900756ccde5587c3578fcff44beef2f1edab17b9a198a4033d8",
|
||||||
|
"memo_version": 2,
|
||||||
|
"label": "t03-exec"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
id: informed-decision.compact-sitting
|
id: informed-decision.compact-sitting
|
||||||
name: Compact sitting exact-record human review
|
name: Compact sitting exact-record human review
|
||||||
namespace: informed-decision:decision-memo
|
namespace: informed-decision:decision-memo
|
||||||
version: v2
|
version: v3
|
||||||
status: ready
|
status: ready
|
||||||
package: flexauth.informed_decision.compact_sitting
|
package: flexauth.informed_decision.compact_sitting
|
||||||
allow_ttl: 30s
|
allow_ttl: 30s
|
||||||
actions: [read, acknowledge, accept, return, discuss, decline]
|
actions: [read, acknowledge, accept, return, discuss, decline, list]
|
||||||
owner: flex-auth
|
owner: flex-auth
|
||||||
fixtures: [fixtures.json]
|
fixtures: [fixtures.json]
|
||||||
caring:
|
caring:
|
||||||
|
|
@ -26,6 +26,25 @@ and the identity bar are unchanged.
|
||||||
It is not an expansion of `examples/informed-decision-t03` / FLEX-WP-0027.
|
It is not an expansion of `examples/informed-decision-t03` / FLEX-WP-0027.
|
||||||
`memo:infd-20260914-c01` is omitted (create-client still undecided).
|
`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,
|
The identity bar matches T03: authenticated informed-decision caller,
|
||||||
`net-kingdom-admins`, fresh KeyCape AAL2 MFA. No permission follows from
|
`net-kingdom-admins`, fresh KeyCape AAL2 MFA. No permission follows from
|
||||||
memo content or presentation state. TokenReview must admit
|
memo content or presentation state. TokenReview must admit
|
||||||
|
|
@ -73,6 +92,31 @@ records := {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
decision := {"effect": "allow", "reason": "operator_admitted_compact_sitting"} if {
|
||||||
input.tenant == "tenant:platform"
|
input.tenant == "tenant:platform"
|
||||||
input.subject.tenant == "tenant:platform"
|
input.subject.tenant == "tenant:platform"
|
||||||
|
|
@ -100,6 +144,33 @@ decision := {"effect": "allow", "reason": "operator_admitted_compact_sitting"} i
|
||||||
input.context.approval_id == record.approval_id
|
input.context.approval_id == record.approval_id
|
||||||
input.context.approval_binding_digest == record.binding_digest
|
input.context.approval_binding_digest == record.binding_digest
|
||||||
input.action in {"read", "acknowledge", "accept", "return", "discuss", "decline"}
|
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 {
|
} else := {"effect": "deny", "reason": "compact_sitting_scope_or_identity_refused"} if {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
@ -113,4 +184,14 @@ import data.flexauth.informed_decision.compact_sitting
|
||||||
test_unknown_request_denied if {
|
test_unknown_request_denied if {
|
||||||
compact_sitting.decision.effect == "deny" with input as {}
|
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]
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,77 @@ with tempfile.TemporaryDirectory() as temp:
|
||||||
target[path[-1]] = value
|
target[path[-1]] = value
|
||||||
check(label + ':' + name, candidate, 'deny')
|
check(label + ':' + name, candidate, 'deny')
|
||||||
|
|
||||||
|
# --- v3 list (FLEX-WP-0032, FLEX-DEC-2026-017) ---------------------------
|
||||||
|
# list ranges over the union of the act records and the list-only records;
|
||||||
|
# every act stays scoped to the act records, with the 900 s window.
|
||||||
|
list_only = json.loads((r / 'list_only_records.json').read_text())
|
||||||
|
listable = {k: dict(v, memo_version=1) for k, v in records.items()} | list_only
|
||||||
|
now = int(time.time())
|
||||||
|
for memo, record in listable.items():
|
||||||
|
request = {
|
||||||
|
'id': 'local-regression',
|
||||||
|
'tenant': 'tenant:platform',
|
||||||
|
'subject': {
|
||||||
|
'id': 'synthetic-reviewer', 'type': 'human', 'tenant': 'tenant:platform',
|
||||||
|
'attributes': {
|
||||||
|
'groups': ['net-kingdom-admins'], 'roles': [],
|
||||||
|
'tenant_source': 'registration-supplied',
|
||||||
|
'principal_type_source': 'authentication-derived',
|
||||||
|
'assurance': {'level': 'aal2', 'mfa': True, 'methods': ['pwd', 'otp'],
|
||||||
|
'source': 'key-cape', 'at': now},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'resource': {'id': memo, 'type': 'decision-memo',
|
||||||
|
'system': 'informed-decision', 'tenant': 'tenant:platform'},
|
||||||
|
'action': 'list',
|
||||||
|
'context': {'memo_version': record['memo_version'],
|
||||||
|
'approval_id': record['approval_id'],
|
||||||
|
'approval_binding_digest': record['binding_digest']},
|
||||||
|
}
|
||||||
|
label = 'list:' + record['label']
|
||||||
|
|
||||||
|
def variant(path, value, req=request):
|
||||||
|
c = copy.deepcopy(req)
|
||||||
|
t = c
|
||||||
|
for key in path[:-1]:
|
||||||
|
t = t[key]
|
||||||
|
t[path[-1]] = value
|
||||||
|
return c
|
||||||
|
|
||||||
|
at = ['subject', 'attributes', 'assurance', 'at']
|
||||||
|
check(label + ':fresh', request, 'allow')
|
||||||
|
# The observed production refusal: 1744 s, allowed for list...
|
||||||
|
check(label + ':observed-1744s', variant(at, now - 1744), 'allow')
|
||||||
|
check(label + ':inside-12h', variant(at, now - 43200 + 60), 'allow')
|
||||||
|
# ...but the 12 h bound is real, and read does not follow list.
|
||||||
|
check(label + ':past-12h', variant(at, now - 43200 - 60), 'deny')
|
||||||
|
is_act_record = memo in records
|
||||||
|
read_stale = variant(at, now - 1744) | {'action': 'read'}
|
||||||
|
check(label + ':read-stale-refused', read_stale, 'deny')
|
||||||
|
if not is_act_record:
|
||||||
|
# T03 records are listable only; no act widens to them, even fresh.
|
||||||
|
for action in ['read', 'acknowledge', 'accept', 'return', 'discuss', 'decline']:
|
||||||
|
check(label + ':act-' + action + '-not-widened', request | {'action': action}, 'deny')
|
||||||
|
for name, path, value in [
|
||||||
|
('wrong-group', ['subject', 'attributes', 'groups'], ['net-kingdom-users']),
|
||||||
|
('no-group', ['subject', 'attributes', 'groups'], []),
|
||||||
|
('service', ['subject', 'type'], 'service'),
|
||||||
|
('agent', ['subject', 'type'], 'agent'),
|
||||||
|
('future-mfa', at, now + 300),
|
||||||
|
('no-mfa', ['subject', 'attributes', 'assurance', 'mfa'], False),
|
||||||
|
('aal1', ['subject', 'attributes', 'assurance', 'level'], 'aal1'),
|
||||||
|
('forged-human-route', ['subject', 'attributes', 'principal_type_source'], 'registration-supplied'),
|
||||||
|
('indeterminate-route', ['subject', 'attributes', 'principal_type_source'], 'indeterminate'),
|
||||||
|
('wrong-tenant', ['subject', 'tenant'], 'tenant:other'),
|
||||||
|
('other-memo', ['resource', 'id'], 'memo:other'),
|
||||||
|
('omitted-c01', ['resource', 'id'], 'memo:infd-20260914-c01'),
|
||||||
|
('other-system', ['resource', 'system'], 'secrets-engine'),
|
||||||
|
('changed-version', ['context', 'memo_version'], record['memo_version'] + 1),
|
||||||
|
('changed-approval', ['context', 'approval_id'], 'other'),
|
||||||
|
('changed-digest', ['context', 'approval_binding_digest'], 'sha256:' + '0' * 64),
|
||||||
|
]:
|
||||||
|
check(label + ':' + name, variant(path, value), 'deny')
|
||||||
|
|
||||||
args.receipt.write_text(json.dumps({
|
args.receipt.write_text(json.dumps({
|
||||||
'scope': 'local actual evaluator with synthetic identity; no live human approvals; T03 package untouched',
|
'scope': 'local actual evaluator with synthetic identity; no live human approvals; T03 package untouched',
|
||||||
'checks': results,
|
'checks': results,
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@ with tempfile.TemporaryDirectory() as temp:
|
||||||
results.append({'check':name,'effect':d['effect']})
|
results.append({'check':name,'effect':d['effect']})
|
||||||
return d
|
return d
|
||||||
for memo,record in records.items():
|
for memo,record in records.items():
|
||||||
request={'id':'local-regression','tenant':'tenant:platform','subject':{'id':'synthetic-reviewer','type':'human','tenant':'tenant:platform','attributes':{'groups':['net-kingdom-admins'],'roles':[],'tenant_source':'registration-supplied','principal_type_source':'authentication-derived','assurance':{'level':'aal2','mfa':True,'methods':['pwd','otp'],'source':'key-cape','at':int(time.time())}}},'resource':{'id':memo,'type':'decision-memo','system':'informed-decision','tenant':'tenant:platform'},'action':'accept','context':{'memo_version':1,'approval_id':record['approval_id'],'approval_binding_digest':record['binding_digest']},'policy_version':'v1'}
|
request={'id':'local-regression','tenant':'tenant:platform','subject':{'id':'synthetic-reviewer','type':'human','tenant':'tenant:platform','attributes':{'groups':['net-kingdom-admins'],'roles':[],'tenant_source':'registration-supplied','principal_type_source':'authentication-derived','assurance':{'level':'aal2','mfa':True,'methods':['pwd','otp'],'source':'key-cape','at':int(time.time())}}},'resource':{'id':memo,'type':'decision-memo','system':'informed-decision','tenant':'tenant:platform'},'action':'accept','context':{'memo_version':record['memo_version'],'approval_id':record['approval_id'],'approval_binding_digest':record['binding_digest']},'policy_version':'v1'}
|
||||||
for action in ['read','acknowledge','accept','return','discuss','decline']:
|
for action in ['read','acknowledge','accept','return','discuss','decline']:
|
||||||
d=check(record['action']+':'+action,request|{'action':action},'allow')
|
d=check(record['action']+':'+action,request|{'action':action},'allow')
|
||||||
for name,path,value in [('wrong-group',['subject','attributes','groups'],['net-kingdom-users']),('no-group',['subject','attributes','groups'],[]),('service',['subject','type'],'service'),('stale-mfa',['subject','attributes','assurance','at'],int(time.time())-901),('future-mfa',['subject','attributes','assurance','at'],int(time.time())+300),('no-mfa',['subject','attributes','assurance','mfa'],False),('forged-human-route',['subject','attributes','principal_type_source'],'registration-supplied'),('wrong-tenant',['subject','tenant'],'tenant:other'),('other-memo',['resource','id'],'memo:other'),('changed-version',['context','memo_version'],2),('changed-approval',['context','approval_id'],'other'),('changed-digest',['context','approval_binding_digest'],'sha256:'+'0'*64),('consume',['action'],'consume')]:
|
for name,path,value in [('wrong-group',['subject','attributes','groups'],['net-kingdom-users']),('no-group',['subject','attributes','groups'],[]),('service',['subject','type'],'service'),('stale-mfa',['subject','attributes','assurance','at'],int(time.time())-901),('future-mfa',['subject','attributes','assurance','at'],int(time.time())+300),('no-mfa',['subject','attributes','assurance','mfa'],False),('forged-human-route',['subject','attributes','principal_type_source'],'registration-supplied'),('wrong-tenant',['subject','tenant'],'tenant:other'),('other-memo',['resource','id'],'memo:other'),('changed-version',['context','memo_version'],record['memo_version']+1),('changed-approval',['context','approval_id'],'other'),('changed-digest',['context','approval_binding_digest'],'sha256:'+'0'*64),('consume',['action'],'consume')]:
|
||||||
candidate=copy.deepcopy(request); target=candidate
|
candidate=copy.deepcopy(request); target=candidate
|
||||||
for key in path[:-1]:target=target[key]
|
for key in path[:-1]:target=target[key]
|
||||||
target[path[-1]]=value
|
target[path[-1]]=value
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ type: workplan
|
||||||
title: "Admit a list action for the informed-decision overview without handing the scope to the consumer"
|
title: "Admit a list action for the informed-decision overview without handing the scope to the consumer"
|
||||||
domain: infotech
|
domain: infotech
|
||||||
repo: flex-auth
|
repo: flex-auth
|
||||||
status: proposed
|
status: active
|
||||||
flavor: implementation
|
flavor: implementation
|
||||||
owner: claude
|
owner: claude
|
||||||
topic_slug: netkingdom
|
topic_slug: netkingdom
|
||||||
|
|
@ -83,18 +83,21 @@ surface was admitted by the operator (`FLEX-WP-0027-T01`, `FLEX-WP-0028`).
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: FLEX-WP-0032-T01
|
id: FLEX-WP-0032-T01
|
||||||
status: wait
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "f741d47e-50b9-5eb1-81d9-ffec847be77a"
|
state_hub_task_id: "f741d47e-50b9-5eb1-81d9-ffec847be77a"
|
||||||
```
|
```
|
||||||
|
|
||||||
Owner: operator decides; `flex-auth` records as a `FLEX-DEC`.
|
Owner: operator decides; `flex-auth` records as a `FLEX-DEC`.
|
||||||
|
|
||||||
|
2026-09-21: done. Operator chose **(B) exact-record** and a **12-hour** MFA
|
||||||
|
window for `list`. Recorded as `FLEX-DEC-2026-017`.
|
||||||
|
|
||||||
## 2. Compile compact-sitting v3
|
## 2. Compile compact-sitting v3
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: FLEX-WP-0032-T02
|
id: FLEX-WP-0032-T02
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "a24fc5cf-f663-5338-97da-169af7fb47fb"
|
state_hub_task_id: "a24fc5cf-f663-5338-97da-169af7fb47fb"
|
||||||
```
|
```
|
||||||
|
|
@ -110,11 +113,17 @@ Owner: `flex-auth`.
|
||||||
- A version bump, per `FLEX-DEC-2026-008`: a widened bar must be visible to the
|
- A version bump, per `FLEX-DEC-2026-008`: a widened bar must be visible to the
|
||||||
consumer as a version change.
|
consumer as a version change.
|
||||||
|
|
||||||
|
2026-09-21: done. v3, digest
|
||||||
|
`sha256:dd40c80c5719851737178097cdee65afac108b54e19c07370e549b860f1a9655`.
|
||||||
|
The v2 act rule is kept unchanged so its effect cannot drift; `list` is a
|
||||||
|
separate `else` branch. T03 pins in `examples/informed-decision-sitting/list_only_records.json`,
|
||||||
|
copied from the T03 package's records.
|
||||||
|
|
||||||
## 3. Fixtures and the exercise receipt
|
## 3. Fixtures and the exercise receipt
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: FLEX-WP-0032-T03
|
id: FLEX-WP-0032-T03
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "984f11f4-6ec9-5f7d-840b-4dee2e121212"
|
state_hub_task_id: "984f11f4-6ec9-5f7d-840b-4dee2e121212"
|
||||||
```
|
```
|
||||||
|
|
@ -130,6 +139,15 @@ sitting checks and T03's 57.
|
||||||
Gate: `flex-auth validate`, `test-policy`, and the exercise scripts green; a
|
Gate: `flex-auth validate`, `test-policy`, and the exercise scripts green; a
|
||||||
receipt in `docs/evidence/`.
|
receipt in `docs/evidence/`.
|
||||||
|
|
||||||
|
2026-09-21: done. 417 checks (168 v2 unchanged, 231 `list`, 18 no-act-widening),
|
||||||
|
receipt `docs/evidence/2026-09-21-sitting-review-policy-v3.json`; validate and
|
||||||
|
three Rego tests green; T03's 57 pass.
|
||||||
|
|
||||||
|
Found on the way: `tools/exercise_t03_review_policy.py` had been failing since
|
||||||
|
`f85479c` moved the T03 records to memo version 2 — it still sent version 1, so
|
||||||
|
the reproduce command `FLEX-WP-0027-T01` cites was broken. Fixed to read each
|
||||||
|
record's own version. Test-only; no policy change.
|
||||||
|
|
||||||
## 4. Publish and hand back
|
## 4. Publish and hand back
|
||||||
|
|
||||||
```task
|
```task
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue