RPF-WP-0015-T02: select the lease issued for the mounted refresh; leave predecessors

ESO refresh (15m) and role TTL (15m, max 1h) overlap, so the first window
saw two live handles and aborted before revocation.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 680842@bnt-lap001
Assistant-Session: 54eb9e8e-7d6b-4f0c-b7a6-a6db62075883
This commit is contained in:
codex 2026-10-14 18:19:38 +02:00
parent c8d45d585f
commit 044df6fe5b
4 changed files with 73 additions and 24 deletions

View file

@ -81,6 +81,24 @@ class DatabaseLeaseRecoveryTests(unittest.TestCase):
with self.assertRaises(module.ProcedureError):
module.load_approval(path, now, require_open_window=True)
def test_select_runtime_lease_ignores_older_predecessors_only(self) -> None:
refresh = datetime(2026, 10, 14, 16, 14, 7, tzinfo=UTC)
def lease(name: str, issued: datetime) -> dict:
return {"id": name, "fingerprint": name, "issue_time": issued,
"expire_time": issued + timedelta(minutes=15), "ttl": 600}
current = lease("current", refresh + timedelta(seconds=1))
older = lease("older", refresh - timedelta(minutes=15))
secret = {"refresh_time": refresh}
selected = module.select_runtime_lease([older, current], secret)
self.assertEqual("current", selected["id"])
self.assertEqual(1, selected["predecessor_handles"])
with self.assertRaises(module.ProcedureError): # nothing matches the mounted refresh
module.select_runtime_lease([older], secret)
with self.assertRaises(module.ProcedureError): # a newer unmatched handle exists
module.select_runtime_lease([current, lease("newer", refresh + timedelta(minutes=1))], secret)
with self.assertRaises(module.ProcedureError): # two handles match the refresh
module.select_runtime_lease([current, lease("twin", refresh)], secret)
def test_approval_requires_exact_owner_and_window_contract(self) -> None:
now = datetime(2026, 8, 22, 12, 0, tzinfo=UTC)
with tempfile.TemporaryDirectory() as directory: