#!/usr/bin/env python3 """Verify VM inputs and install small helper tools into the VM workspace only.""" import hashlib import json import os from pathlib import Path import subprocess import urllib.request import zipfile root = Path(os.environ.get('DOCVIEW_VM_WORK', 'build-ubuntu-vm')).resolve() downloads = root / 'downloads' keyring = root / 'private/gnupg' keyring.mkdir(mode=0o700, parents=True, exist_ok=True) fingerprint = 'D2EB44626FDDC30B513D5BB71A5D6C4C7DB87C81' def run(command, log): result = subprocess.run(command, capture_output=True, text=True) (root / 'logs' / log).write_text(result.stdout + result.stderr) result.check_returncode() return result.stdout + result.stderr run(['gpg', '--homedir', str(keyring), '--batch', '--import', str(downloads / 'ubuntu-cloud-key.asc')], 'ubuntu-key-import.txt') identity = run(['gpg', '--homedir', str(keyring), '--batch', '--with-colons', '--fingerprint'], 'ubuntu-key-fingerprint.txt') assert 'fpr:::::::::' + fingerprint + ':' in identity verification = run(['gpg', '--homedir', str(keyring), '--batch', '--status-fd', '1', '--verify', str(downloads / 'SHA256SUMS.gpg'), str(downloads / 'SHA256SUMS')], 'ubuntu-sha-signature.txt') assert 'VALIDSIG ' + fingerprint + ' ' in verification filename = 'noble-server-cloudimg-amd64.img' expected = next(line.split()[0] for line in (downloads / 'SHA256SUMS').read_text().splitlines() if line.split()[1].lstrip('*') == filename) with (downloads / filename).open('rb') as stream: actual = hashlib.file_digest(stream, 'sha256').hexdigest() assert actual == expected qemu = downloads / 'qemu-img-11.1.1-2-x86_64.pkg.tar.zst' with qemu.open('rb') as stream: assert hashlib.file_digest(stream, 'sha256').hexdigest() == 'a095493f3fffa82cc5db3a8409950124e67e45cb6ca30456a5851362be5c396a' # This host-only bootstrap recipe was tested on Arch. Its trusted repository # keyring is read-only; an Ubuntu guest does not use this host package. run(['gpgv', '--keyring', '/etc/pacman.d/gnupg/pubring.gpg', str(qemu) + '.sig', str(qemu)], 'qemu-package-signature.txt') subprocess.run(['bsdtar', '-xf', str(qemu), '-C', str(root / 'tools'), 'usr/bin/qemu-img'], check=True) package = json.loads((downloads / 'pycdlib.json').read_text()) wheel = next(item for item in package['urls'] if item['filename'].endswith('.whl')) target = downloads / wheel['filename'] if not target.exists(): with urllib.request.urlopen(wheel['url'], timeout=45) as response: target.write_bytes(response.read(300000)) with target.open('rb') as stream: assert hashlib.file_digest(stream, 'sha256').hexdigest() == wheel['digests']['sha256'] assert target.stat().st_size == wheel['size'] with zipfile.ZipFile(target) as archive: archive.extractall(root / 'tools/python') report = {'ubuntuImageSignatureValid': True, 'ubuntuSigningFingerprint': fingerprint, 'ubuntuImageSha256': actual, 'ubuntuImageSize': (downloads / filename).stat().st_size, 'qemuPackageSha256MatchesLocalRepositoryDatabase': True, 'qemuPackageSignatureValid': True} (root / 'metadata/verification.json').write_text(json.dumps(report, indent=2) + '\n') print('Verified Ubuntu signed checksum/image, QEMU package and local ISO helper.')