"""Retirement claims are authenticated, bounded, current-scope capabilities.""" import hashlib import hmac import json import sqlite3 from pathlib import Path from types import SimpleNamespace import unittest from unittest.mock import patch class FileRetirementProof(unittest.TestCase): def setUp(self): source = Path(__file__).resolve().parents[1] / 'crates/supervisor/src/runner_files.py' self.module = {} exec(compile(source.read_text(), str(source), 'exec'), self.module) self.key = 'ab' * 32 self.current = {'computer_id': 'new', 'bot_id': 'a', 'generation': 2} self.proof = {'version': 1, 'current': self.current, 'origin': {'computer_id': 'old', 'bot_id': 'a', 'generation': 1}, 'home_key': 'home', 'operation_id': 'operation', 'proof_id': 'ack-id', 'proof_kind': 'provider_destroy_ack', 'origin_provider_ref': 'old', 'issued_at': 1000, 'expires_at': 1060} def sign(self, proof): raw = proof if isinstance(proof, str) else json.dumps(proof, separators=(',', ':')) return {'payload': raw, 'signature': hmac.new(bytes.fromhex(self.key), raw.encode(), hashlib.sha256).hexdigest()} def verify(self, envelope, **changes): with patch.object(self.module['time'], 'time', return_value=1001): return self.module['file_retirement_proof'](envelope, changes.get('identity', self.current), changes.get('home', 'home'), changes.get('key', self.key)) def test_valid_proof_and_signature_scope(self): signed = self.sign(self.proof) self.assertEqual(self.verify(signed), self.proof) for changes in [{'key': 'cd' * 32}, {'home': 'other'}, {'identity': {**self.current, 'bot_id': 'b'}}, {'identity': {**self.current, 'computer_id': 'replacement'}}, {'identity': {**self.current, 'generation': 3}}]: with self.assertRaisesRegex(ValueError, '^INVALID_FILE_RETIREMENT_PROOF$'): self.verify(signed, **changes) with self.assertRaisesRegex(ValueError, '^INVALID_FILE_RETIREMENT_PROOF$'): self.verify({**signed, 'payload': signed['payload'].replace('operation', 'tampered')}) def test_signed_invalid_claims_still_fail_closed(self): for change in [{'version': True}, {'version': 2}, {'extra': True}, {'proof_kind': 'changed_namespace'}, {'origin': {**self.proof['origin'], 'bot_id': 'b'}}, {'origin': {**self.proof['origin'], 'generation': 2}}, {'origin': {**self.proof['origin'], 'generation': True}}, {'issued_at': True}, {'issued_at': 1007}, {'issued_at': -1}, {'expires_at': 1001}, {'expires_at': 1061}, {'expires_at': 1000}, {'operation_id': '../file'}, {'proof_id': ''}, {'origin_provider_ref': ''}]: with self.subTest(change=change): with self.assertRaisesRegex(ValueError, '^INVALID_FILE_RETIREMENT_PROOF$'): self.verify(self.sign({**self.proof, **change})) def test_duplicate_fields_and_oversized_or_untrusted_envelopes_fail(self): raw = json.dumps(self.proof) invalid = [self.sign(raw[:-1] + ',"version":1}'), self.sign(' ' * 4097), self.sign('[]'), self.sign('{broken'), {'payload': raw}, {**self.sign(self.proof), 'key': self.key}, {**self.sign(self.proof), 'signature': '0' * 64}] for envelope in invalid: with self.assertRaisesRegex(ValueError, '^INVALID_FILE_RETIREMENT_PROOF$'): self.verify(envelope) def test_retirement_audit_failure_rolls_back_receipt_and_outbox(self): # Real SQLite transaction, with the already-verified filesystem # boundary replaced by a fixture to isolate late audit failure. proof = self.verify(self.sign(self.proof)) origin = proof['origin'] encoded = self.module['file_identity'](origin) key = hashlib.sha256((encoded + ':operation').encode()).hexdigest() data = b'data' digest = hashlib.sha256(data).hexdigest() observation = {'source': {'path': 'file', 'sha256': digest, 'size': 4}, 'helper_quiescent': True, 'controller_quiescent': True, 'desired_state_matches': True} self.module['file_readback'] = lambda *args, **kwargs: observation self.module['file_snapshot_store'] = lambda content, sha: sha request = {'action': 'file_status', 'identity': origin, 'input': json.dumps({'operation_id': 'operation', 'readback': True, 'resolve': True})} with sqlite3.connect(':memory:') as db: self.module['file_journal_schema'](db) db.execute('INSERT INTO file_operations VALUES (?,?,?,?,?,?,?)', (key, encoded, 'digest', 'unknown', None, json.dumps({'action': 'write', 'path': 'file'}), 0)) self.module['file_event'](db, encoded, 'operation', 'accepted') db.commit() db.execute("CREATE TRIGGER reject_audit BEFORE INSERT ON file_retirement_receipts BEGIN SELECT RAISE(ABORT,'audit unavailable'); END") with patch.object(self.module['subprocess'], 'run', return_value=SimpleNamespace(returncode=0, stdout=data)): with self.assertRaisesRegex(sqlite3.IntegrityError, 'audit unavailable'): self.module['file_journal_handle'](db, request, '', lambda *_: False, retirement=proof) self.assertEqual(db.execute('SELECT status,result FROM file_operations').fetchone(), ('unknown', None)) self.assertEqual(db.execute('SELECT count(*) FROM file_retirement_receipts').fetchone()[0], 0) self.assertEqual(db.execute('SELECT count(*) FROM file_outbox').fetchone()[0], 1) db.execute('DROP TRIGGER reject_audit') result = self.module['file_journal_handle'](db, request, '', lambda *_: False, retirement=proof) self.assertEqual(result['status'], 'succeeded') self.assertEqual(db.execute('SELECT count(*) FROM file_retirement_receipts').fetchone()[0], 1) self.assertEqual(db.execute('SELECT count(*) FROM file_outbox').fetchone()[0], 2) if __name__ == '__main__': unittest.main()