58 lines
2.7 KiB
Python
58 lines
2.7 KiB
Python
|
|
"""Real SQLite subcall durability for native cleanup/verification pairs."""
|
||
|
|
import multiprocessing
|
||
|
|
import os
|
||
|
|
from pathlib import Path
|
||
|
|
import sys
|
||
|
|
import uuid
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'scripts'))
|
||
|
|
from task_execution_journal import Binding,Cleanup,Journal,Refused
|
||
|
|
|
||
|
|
|
||
|
|
def child_crash(directory,binding,obligation):
|
||
|
|
journal=Journal(Path(directory))
|
||
|
|
with journal.locked():
|
||
|
|
journal.reserve(binding,(obligation,))
|
||
|
|
journal.transition(binding,'reserved','consume-confirmed')
|
||
|
|
journal.before_cleanup(binding,0,obligation)
|
||
|
|
journal.before_cleanup_call(binding,0,obligation,0,'c'*64)
|
||
|
|
os._exit(29)
|
||
|
|
|
||
|
|
|
||
|
|
def test_subcall_crash_persists_and_never_restores_admission(tmp_path):
|
||
|
|
binding=Binding('fixture-approval','sha256:'+'a'*64,str(uuid.uuid4()),'b'*64)
|
||
|
|
obligation=Cleanup('task-token-revoke','d'*64)
|
||
|
|
os.chmod(tmp_path,0o700)
|
||
|
|
context=multiprocessing.get_context('fork')
|
||
|
|
process=context.Process(target=child_crash,args=(str(tmp_path),binding,obligation))
|
||
|
|
process.start();process.join(10)
|
||
|
|
if process.is_alive():process.terminate();process.join();pytest.fail('crash fixture exceeded bound')
|
||
|
|
assert process.exitcode==29
|
||
|
|
journal=Journal(tmp_path)
|
||
|
|
try:
|
||
|
|
assert journal.observe(binding)['external_outcome_unknown']
|
||
|
|
assert not journal.cleanup_status(binding)['confirmed']
|
||
|
|
with journal.locked():
|
||
|
|
with pytest.raises(Refused):journal.before_cleanup_call(binding,0,obligation,1,'c'*64)
|
||
|
|
finally:journal.close()
|
||
|
|
|
||
|
|
|
||
|
|
def test_pending_native_subcall_never_confirms_parent_and_survives_unconfirmed(tmp_path):
|
||
|
|
os.chmod(tmp_path,0o700);journal=Journal(tmp_path)
|
||
|
|
binding=Binding('fixture-approval','sha256:'+'a'*64,str(uuid.uuid4()),'b'*64)
|
||
|
|
obligation=Cleanup('task-token-revoke','d'*64)
|
||
|
|
try:
|
||
|
|
with journal.locked():
|
||
|
|
journal.reserve(binding,(obligation,));journal.transition(binding,'reserved','consume-confirmed')
|
||
|
|
journal.before_cleanup(binding,0,obligation)
|
||
|
|
journal.before_cleanup_call(binding,0,obligation,0,'c'*64)
|
||
|
|
with pytest.raises(Refused):journal.after_cleanup(binding,0,obligation,confirmed=True,evidence_digest='e'*64)
|
||
|
|
with pytest.raises(Refused):journal.before_cleanup_call(binding,0,obligation,1,'c'*64)
|
||
|
|
for step in [False,0.0,'0',-1,2]:
|
||
|
|
with pytest.raises(Refused):journal.after_cleanup_call(binding,0,obligation,step,'c'*64,'e'*64)
|
||
|
|
journal.after_cleanup(binding,0,obligation,confirmed=False,evidence_digest='e'*64)
|
||
|
|
assert journal.observe(binding)['external_outcome_unknown']
|
||
|
|
with pytest.raises(Refused):journal.after_cleanup_call(binding,0,obligation,0,'c'*64,'e'*64)
|
||
|
|
finally:journal.close()
|