fix(execution): retain scoped cleanup after uncertain outcomes
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
parent
3b6e647aa0
commit
59d1441cf8
7 changed files with 462 additions and 4 deletions
72
scripts/task_execution_cleanup.py
Normal file
72
scripts/task_execution_cleanup.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
"""Fixed cleanup driver for a trusted owner mediator; no native transport exists here.
|
||||
|
||||
Call from the mediator's finally block while its original Journal.locked context
|
||||
is still live. The owner adapter retains credential/handle custody and reconstructs
|
||||
and compares the native call with the expected digest before effect. Its three
|
||||
methods take no caller-selected path, body, shell command or token. This source
|
||||
component neither validates consume nor creates a native execution entitlement.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import hashlib
|
||||
import re
|
||||
from typing import Protocol
|
||||
|
||||
from task_execution_journal import Binding, Cleanup, Journal, Refused
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CleanupResult:
|
||||
confirmed: bool
|
||||
evidence_digest: str
|
||||
|
||||
def validate(self):
|
||||
if type(self.confirmed) is not bool or type(self.evidence_digest) is not str or not re.fullmatch(r"[0-9a-f]{64}", self.evidence_digest):
|
||||
raise Refused("invalid owner cleanup evidence")
|
||||
|
||||
|
||||
class OwnerCleanup(Protocol):
|
||||
# Confirm requires actual native revoke/absence evidence; a timeout is never
|
||||
# proof of absence. Implementations must use bounded calls and discard raw
|
||||
# backend failure output. Protected handles never leave the owner adapter.
|
||||
def revoke_task_token(self, expected_call_digest: str) -> CleanupResult: ...
|
||||
def revoke_identity_token(self, expected_call_digest: str) -> CleanupResult: ...
|
||||
def delete_grant_policy(self, expected_call_digest: str) -> CleanupResult: ...
|
||||
|
||||
|
||||
def run_cleanup(journal: Journal, binding: Binding, owner: OwnerCleanup):
|
||||
"""Attempt each fixed obligation once, preserving business/unknown outcomes.
|
||||
|
||||
Ordinary adapter failures record unconfirmed evidence and do not suppress the
|
||||
remaining independent cleanup. BaseException/process death leaves durable
|
||||
pending intent; neither this driver nor a reopened journal retries it.
|
||||
Journal failures propagate and prohibit dispatch without durable intent.
|
||||
"""
|
||||
obligations = journal.cleanup_status(binding)['obligations']
|
||||
if not obligations:
|
||||
raise Refused("explicit owner cleanup obligations required")
|
||||
if any(item['outcome'] != 'owed' for item in obligations):
|
||||
raise Refused("cleanup already attempted; owner reconciliation required")
|
||||
for item in obligations:
|
||||
obligation = Cleanup(item['kind'], item['call_digest'])
|
||||
journal.before_cleanup(binding, item['ordinal'], obligation)
|
||||
try:
|
||||
if obligation.kind == 'task-token-revoke':
|
||||
result = owner.revoke_task_token(obligation.call_digest)
|
||||
elif obligation.kind == 'identity-token-revoke':
|
||||
result = owner.revoke_identity_token(obligation.call_digest)
|
||||
elif obligation.kind == 'grant-policy-delete':
|
||||
result = owner.delete_grant_policy(obligation.call_digest)
|
||||
else:
|
||||
raise Refused("unsupported cleanup obligation")
|
||||
if type(result) is not CleanupResult:
|
||||
raise Refused("typed owner cleanup evidence required")
|
||||
result.validate()
|
||||
except Exception:
|
||||
# Closed metadata only. Never hash/log a backend exception, response,
|
||||
# token, accessor or secret-bearing stdout/stderr.
|
||||
result = CleanupResult(False, hashlib.sha256(b'owner-cleanup-unconfirmed/v1').hexdigest())
|
||||
journal.after_cleanup(binding, item['ordinal'], obligation,
|
||||
confirmed=result.confirmed, evidence_digest=result.evidence_digest)
|
||||
return journal.cleanup_status(binding)
|
||||
Loading…
Add table
Add a link
Reference in a new issue