#!/usr/bin/env python3 """Cold-boot evidence for an interrupted crypto/D09 transaction; never promote it. Observe real installed kernel/package effects and native signatures, but require reconciliation and refuse replay/postboot success after the owner's anchor loss. """ import json from pathlib import Path import platform import subprocess import sys assert 'QEMU' in Path('/sys/class/dmi/id/sys_vendor').read_text() assert subprocess.check_output(['findmnt','-n','-o','SOURCE','/'],text=True).strip()=='/dev/vda' sys.path.insert(0,'/usr/libexec') import os_update_executor as executor assert executor.ROOT==Path('/var/lib/archipelago-os-update') binding=json.loads(Path('/etc/archipelago-d09/binding.json').read_text()) instance=executor.Executor(binding['os_update']) assert instance.status['phase']=='RECONCILIATION_REQUIRED' assert platform.release()==instance.plan['boot']['expected_release'] before=instance.status_path.read_bytes() inventory=executor.inventory() instance.verify_installed() boot=instance.boot_provenance() evidence=Path('/var/log/os-ota-stage') expected=json.loads((evidence/'canaries-before.json').read_text()) assert {p.name:executor.file_hash(p) for p in Path('/var/lib/archipelago/ota-synthetic-canaries').iterdir()}==expected assert Path('/var/lib/archipelago').stat().st_uid==1000 and executor.ROOT.stat().st_uid==0 subprocess.run(['runuser','-u','archipelago','--','touch','/var/lib/archipelago/held-postboot-positive-probe'],check=True) denials=[] for args in (['touch',str(executor.ROOT/'app-write-denied')], ['python3','-c',"import os;os.rename('/var/lib/archipelago-os-update','/var/lib/app-rename-denied')"], ['python3','-c',"open('/root/os-ota-crypto-fixture/test.seed','rb').read()"]): r=subprocess.run(['runuser','-u','archipelago','--',*args],capture_output=True,text=True) assert r.returncode!=0 denials.append(dict(command=args,exit=r.returncode)) refusals=[] for phase in ('apply','postboot'): try: executor.stage(binding,'APPLY',phase) except (executor.ReconciliationRequired,ValueError) as error: refusals.append(dict(operation=phase,error=str(error))) else: raise AssertionError('uncertain transaction promoted/replayed') assert executor.inventory()==inventory and instance.status_path.read_bytes()==before public=subprocess.run(['/usr/libexec/archipelago-d09ctl','inspect'],capture_output=True,text=True) assert public.returncode==0,public.stderr status=json.loads(public.stdout) assert status['state']=='UNKNOWN' and not (status.get('os_update') or {}).get('post_boot_verified',False) result=dict(passed=True,scope='held transaction coldboot/crypto/custody/refusal proof ONLY', full_ota_passed=False,postboot_confirmed=False,production_approved=False,candidate_qualified=False, running_kernel=platform.release(),kernel_build=platform.version(),boot_id=executor.boot_id(), authenticated_archive_sha256=boot['archive_sha256'],verified_kernel_files=len(boot['files']), native_crypto_verified=True,all_planned_packages_configured=True,canaries_preserved=True, os_phase=instance.status['phase'],status_unchanged=True,package_replay=False, app_data_uid=1000,os_root=str(executor.ROOT),custody_denials=denials,refusals=refusals, authenticated_owner_inspect=status) (evidence/'crypto-held-postboot-result.json').write_text(json.dumps(result,indent=2)+'\n') print(json.dumps(result,indent=2),flush=True)