#!/usr/bin/python3 """Second stage after restart of the SAME disposable rootless PID1 container. This is container/PID1 restart qualification, not a physical-node reboot or native artifact/terminal acceptance. Prior authority evidence stays intact. """ import importlib.util import json import os from pathlib import Path import secrets import socket import subprocess import sys import time assert os.geteuid() == 0 and socket.gethostname() == 'd09-qualification' assert Path('/run/.containerenv').exists() and os.environ.get('D09_DISPOSABLE_SYSTEMD') == '1' PACKAGE = Path('/opt/d09-fixture') sys.path.insert(0, str(PACKAGE / 'scripts')) import d09_store as store import d09_wire as wire spec = importlib.util.spec_from_file_location('provision', PACKAGE / 'scripts/provision-d09-lifecycle.py') provision = importlib.util.module_from_spec(spec) spec.loader.exec_module(provision) owner = provision.owner def run(*args): return subprocess.run(args, check=True, capture_output=True, text=True, timeout=45) def wait(predicate): for _ in range(450): try: value = predicate() if value: return value except (OSError, ValueError, subprocess.SubprocessError): pass time.sleep(.1) raise AssertionError('reboot fixture timed out') before = store.read(owner.ROOT / 'ledger.json') value = json.loads(before) binding = value['active_binding'] assert value['receipt']['phase'] == 'COMPLETE' and value['receipt']['config_action'] == 'RESTORE' assert not (owner.RUN / 'bootstrap.json').exists() # /run is genuinely fresh. Restore only the inert requester's disposable IPC # directory; no authority, journal or permit is copied into the new boot. import pwd account = pwd.getpwnam('archipelago') control = Path('/run/d09-fixture-client') control.mkdir(mode=0o700, exist_ok=True) os.chown(control, account.pw_uid, account.pw_gid) run('systemctl', 'start', 'archipelago-d09-lifecycle.service') wait(lambda: json.loads(run('/usr/libexec/archipelago-d09ctl', 'inspect').stdout)['state'] == 'UNKNOWN') assert store.read(owner.ROOT / 'ledger.json') == before probe = owner.Owner.__new__(owner.Owner) disposition = wait(lambda: probe.drained_disposition(value)) index = {k: binding[k] for k in ('target_binding_digest', 'composition_digest', 'transaction_id')} fields = dict(index, predecessor_epoch_id=value['epoch'], head_sequence=value['sequence'], preserved_head_digest=wire.digest(wire.canonical(value['receipt'])), preserved_journal_digest=wire.digest(wire.canonical({'receipts': value['journal'], 'intents': value['intents']})), preserved_consumed_history_digest=wire.digest(wire.canonical(owner.consumption_history(value))), preserved_target_index_digest=wire.digest(wire.canonical(index)), disposition_digest=disposition, new_epoch_id=secrets.token_hex(16), new_grant_digest=secrets.token_hex(32), execution_grant_digest=secrets.token_hex(32), allowed_action='REACTIVATE_RETAINED') directory = PACKAGE / 'external-history' history_path = directory / 'pid1-restart-history.json' record_path = directory / 'pid1-restart-record.json' store.atomic(history_path, wire.canonical(dict(fields, sequence=1))) record = dict(fields, schema_version=1, external_history_sequence=1, external_history_digest=wire.digest(store.read(history_path)), observed_boot_id=owner.boot_id()) store.atomic(record_path, wire.canonical(record)) provision.readmit(record_path, history_path, activation=True) def awaiting(): latest = json.loads(store.read(owner.ROOT / 'ledger.json')) return latest if latest['receipt']['phase'] == 'AWAITING_OBSERVATION' else None latest = wait(awaiting) assert latest['journal'][:len(value['journal'])] == value['journal'] assert latest['receipt']['observed_invocation_id'] != value['receipt']['observed_invocation_id'] assert latest['receipt']['namespace_observation_digest'] is None for name, destination in owner.DESTINATIONS.items(): assert owner.object_digest(destination) == binding['objects'][name]['restore'] before_retry = store.read(owner.ROOT / 'ledger.json') provision.readmit(record_path, history_path, activation=True) assert store.read(owner.ROOT / 'ledger.json') == before_retry print('PASS fresh container PID1/run state: UNKNOWN before external authority; exact retained B activated once; journal preserved; fresh observation still required', flush=True)