#!/usr/bin/env python3 """Diskless/networkless kernel smoke boot. Run under release-heavy.lock. Uses an already authenticated payload receipt, never installs a host package. This proves direct kernel boot only, not ISO/EFI/GRUB or physical-node acceptance. """ import hashlib import argparse import json from pathlib import Path import re import shutil import subprocess import sys def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('receipt', type=Path) parser.add_argument('output', type=Path) parser.add_argument('--timing-collector', type=Path, help='statically linked read-only collector') parser.add_argument('--guest-suspend-seconds', type=int, choices=range(3, 31), help='explicit disposable guest-only RTC wake + mem suspend experiment') args = parser.parse_args() if args.guest_suspend_seconds and not args.timing_collector: parser.error('--guest-suspend-seconds requires --timing-collector') receipt = json.loads(args.receipt.read_text()) output = args.output output.mkdir(exist_ok=False) release = receipt['package'].removeprefix('linux-image-') image = '/boot/vmlinuz-' + release with open(image, 'rb') as stream: assert hashlib.file_digest(stream, 'sha256').hexdigest() == receipt['files'][image] shutil.copyfile(image, output / 'vmlinuz') root = output / 'initramfs' for directory in ('bin', 'dev', 'proc', 'sys'): (root / directory).mkdir(parents=True) shutil.copyfile('/usr/bin/busybox', root / 'bin/busybox') (root / 'bin/busybox').chmod(0o755) dependencies = subprocess.check_output(['ldd', '/usr/bin/busybox'], text=True) for library in re.findall(r'(/[^\s()]+)', dependencies): target = root / library.lstrip('/') target.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(library, target) for applet in ('sh', 'mount', 'uname', 'cat', 'poweroff', 'sleep'): (root / 'bin' / applet).symlink_to('busybox') timing_command = '' if args.timing_collector: shutil.copyfile(args.timing_collector, root / 'bin/timing-collector') (root / 'bin/timing-collector').chmod(0o755) timing_command = '/bin/timing-collector 201 100 && echo TIMING_COLLECTION_PASS\n' if args.guest_suspend_seconds: # This command exists only in the generated disposable initramfs. # No host rtcwake, power control, clock write, or attached host disk. rtcwake = Path('/usr/sbin/rtcwake') shutil.copy2(rtcwake, root / 'bin/rtcwake') libraries = subprocess.check_output(['ldd', str(rtcwake)], text=True) for library in re.findall(r'(/[^\s()]+)', libraries): target = root / library.lstrip('/') target.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(library, target) timing_command = ('/bin/timing-collector 201 100 &\ncollector=$!\nsleep 5\n' 'echo GUEST_SUSPEND_REQUEST\n' f'/bin/rtcwake -u -m mem -s {args.guest_suspend_seconds} && echo GUEST_SUSPEND_RETURNED\n' 'wait "$collector" && echo TIMING_COLLECTION_PASS\n') (root / 'init').write_text('#!/bin/sh\n' 'export PATH=/bin\nmount -t devtmpfs devtmpfs /dev\nexec /dev/console 2>&1\n' 'mount -t proc proc /proc\nmount -t sysfs sysfs /sys\n' 'uname -a\ncat /proc/version\n' f'[ "$(uname -r)" = "{release}" ] && echo KERNEL_ARTIFACT_BOOT_PASS\n' + timing_command + 'poweroff -f\n') (root / 'init').chmod(0o755) names = '.\n' + '\n'.join(str(p.relative_to(root)) for p in sorted(root.rglob('*'))) + '\n' with (output / 'initrd.cpio').open('wb') as stream: subprocess.run(['cpio', '-o', '-H', 'newc'], cwd=root, input=names.encode(), stdout=stream, check=True) command = ['qemu-system-x86_64', '-machine', 'pc-i440fx-10.0', '-accel', 'tcg', '-m', '256', '-smp', '1', '-nodefaults', '-no-reboot', '-display', 'none', '-serial', 'stdio', '-monitor', 'none', '-nic', 'none', '-kernel', str(output / 'vmlinuz'), '-initrd', str(output / 'initrd.cpio'), '-append', 'console=ttyS0 rdinit=/init panic=1'] try: result = subprocess.run(command, capture_output=True, timeout=120) except subprocess.TimeoutExpired as error: # subprocess.run kills/reaps its own guest; retain partial failure evidence. result = subprocess.CompletedProcess(command, 124, error.stdout or b'', error.stderr or b'') (output / 'serial.log').write_bytes(result.stdout + result.stderr) passed = result.returncode == 0 and b'KERNEL_ARTIFACT_BOOT_PASS' in result.stdout if args.timing_collector: passed = passed and b'TIMING_COLLECTION_PASS' in result.stdout if args.guest_suspend_seconds: passed = passed and b'GUEST_SUSPEND_RETURNED' in result.stdout summary = dict(command=command, exit=result.returncode, passed=passed, archive_sha256=receipt['archive_sha256'], kernel_sha256=receipt['files'][image]) summary['qualification_scope'] = 'direct boot and optional read-only samples; not elapsed-error qualification' summary['guest_suspend_seconds'] = args.guest_suspend_seconds summary['qemu_version'] = subprocess.check_output([command[0], '--version'], text=True) summary['host_kernel'] = subprocess.check_output(['uname', '-a'], text=True).strip() for name, path in [('receipt', args.receipt), ('initrd', output / 'initrd.cpio'), ('collector', args.timing_collector), ('harness', Path(__file__))]: if path: summary[name + '_sha256'] = hashlib.sha256(path.read_bytes()).hexdigest() (output / 'result.json').write_text(json.dumps(summary, indent=2) + '\n') print(json.dumps(summary)) return 0 if passed else 1 if __name__ == '__main__': sys.exit(main())