NK48-R2-F1: revoke session and broker grant independently in mint-secret
A raising parent-session revocation no longer skips broker-grant revocation, and the reverse; the first failure is re-raised after both are attempted, so the attempt is refused rather than reported as success. Regression tests cover each direction and both failing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 903097@bnt-lap001 Assistant-Session: aa320c8f-c3fa-46e7-8541-0b58e1e45d23
This commit is contained in:
parent
68f4bbb8ca
commit
eeed8e118e
3 changed files with 47 additions and 1 deletions
|
|
@ -15,6 +15,8 @@ modelled on the T13 registration adapter.
|
|||
authenticate is destroyed, by exact version; otherwise rollback is refused.
|
||||
- **Revocation.** Descriptor effect `mint` with scopes `parent-session` and
|
||||
`broker-grant`; both are revoked after every attempt, including failures.
|
||||
Each revocation is attempted independently: if one raises, the other is still
|
||||
called, and the attempt is refused rather than reported as success.
|
||||
- Confidential clients only; case, descriptor, acceptance and attempt pins bound
|
||||
as in T13. Not retry-safe.
|
||||
|
||||
|
|
|
|||
|
|
@ -113,8 +113,21 @@ def build(*, admitted: Invocation, case_source: bytes, case_acceptance: str,
|
|||
receipt = destroy(path, version)
|
||||
check(receipt, 'destroy', version)
|
||||
finally:
|
||||
# Each revocation is attempted independently: a failing session
|
||||
# revocation must not leave the broker grant alive, or the reverse.
|
||||
# The first failure is re-raised only after both were attempted.
|
||||
with contained_output():
|
||||
session, grant = revoke_session(inv), revoke_grant(inv)
|
||||
session = grant = failure = None
|
||||
try:
|
||||
session = revoke_session(inv)
|
||||
except BaseException as exc:
|
||||
failure = exc
|
||||
try:
|
||||
grant = revoke_grant(inv)
|
||||
except BaseException as exc:
|
||||
failure = failure or exc
|
||||
if failure is not None:
|
||||
raise failure
|
||||
for ref in (session, grant):
|
||||
if not isinstance(ref, str) or not IDENTIFIER.fullmatch(ref):
|
||||
raise Refused('revocation evidence missing')
|
||||
|
|
|
|||
|
|
@ -90,6 +90,37 @@ class MintSecretTests(unittest.TestCase):
|
|||
self.assertEqual([c[0] for c in self.calls], [])
|
||||
self.assertEqual(self.revoked, [('session', 'rollback'), ('grant', 'rollback')])
|
||||
|
||||
def _failing(self, kind):
|
||||
def revoke(inv):
|
||||
self.revoked.append((kind, inv.operation))
|
||||
raise RuntimeError(kind + ' revocation unavailable')
|
||||
return revoke
|
||||
|
||||
def test_failing_session_revocation_still_revokes_grant(self):
|
||||
self.kw['revoke_session'] = self._failing('session')
|
||||
adapter = a.build(**self.kw)
|
||||
with self.assertRaises(Exception):
|
||||
adapter.invoke(self.run)
|
||||
self.assertEqual(self.revoked, [('session', 'run'), ('grant', 'run')])
|
||||
self.assertEqual(self.evidence, {}) # never published as success
|
||||
|
||||
def test_failing_grant_revocation_still_revokes_session(self):
|
||||
self.kw['revoke_grant'] = self._failing('grant')
|
||||
adapter = a.build(**self.kw)
|
||||
with self.assertRaises(Exception):
|
||||
adapter.invoke(self.run)
|
||||
self.assertEqual(self.revoked, [('session', 'run'), ('grant', 'run')])
|
||||
self.assertEqual(self.evidence, {})
|
||||
|
||||
def test_both_revocations_failing_attempts_both_and_refuses(self):
|
||||
self.kw['revoke_session'] = self._failing('session')
|
||||
self.kw['revoke_grant'] = self._failing('grant')
|
||||
adapter = a.build(**self.kw)
|
||||
with self.assertRaises(Exception):
|
||||
adapter.rollback(self.back, a.CREATED)
|
||||
self.assertEqual(self.revoked, [('session', 'rollback'), ('grant', 'rollback')])
|
||||
self.assertEqual(self.evidence, {})
|
||||
|
||||
def test_receipt_with_value_or_extra_field_refused(self):
|
||||
for bad in (receipt('mint', value='x'), receipt('mint', values_emitted=True),
|
||||
receipt('mint', path='platform/workloads/keycape/other'),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue