fix(test): restore pruned live boot entries and verify mounted ESP
This commit is contained in:
+148
-1
@@ -42,6 +42,13 @@ class BootConsole:
|
||||
|
||||
|
||||
SCRIPT = Path(__file__).resolve().parents[1] / 'dev/laptop-smoke.py'
|
||||
EFI_GUID = '8be4df61-93ca-11d2-aa0d-00e098032b8c'
|
||||
# Captured efivarfs bytes from the actual OVMF SATA0 DVD boot option.
|
||||
DVD_VARIABLE = bytes.fromhex(
|
||||
'0700000001000000200055004500460049002000510045004d005500200044005600'
|
||||
'44002d0052004f004d00200051004d00300030003000300031002000000002010c00'
|
||||
'd041030a0000000001010600021f03120a000000ffff00007fff04004eac0881119f'
|
||||
'594d850ee21a522c59b2')
|
||||
|
||||
|
||||
class LaptopSmokeTests(unittest.TestCase):
|
||||
@@ -67,6 +74,105 @@ class LaptopSmokeTests(unittest.TestCase):
|
||||
with self.subTest(key=key), self.assertRaises(self.mod.SmokeError):
|
||||
self.mod.verify_preserved(original, changed)
|
||||
|
||||
def test_cross_firmware_comparison_excludes_only_bootorder(self):
|
||||
original = {'gpt': 'partition table', 'foreign_sha256': 'data',
|
||||
'foreign_efi': {'fallback': 'bytes'}, 'boot_order': '0000,0001,0002'}
|
||||
after = dict(original, boot_order='0000,0002')
|
||||
self.mod.verify_preserved(original, after, firmware_reboot=True)
|
||||
for name in ('gpt', 'foreign_sha256', 'foreign_efi'):
|
||||
with self.subTest(name=name), self.assertRaises(self.mod.SmokeError):
|
||||
self.mod.verify_preserved(original, dict(after, **{name: 'changed'}), firmware_reboot=True)
|
||||
|
||||
def dvd_namespace(self):
|
||||
namespace = {}
|
||||
exec(self.mod.GUEST_COMMON, namespace)
|
||||
return namespace
|
||||
|
||||
def test_capture_requires_actual_current_unique_validated_dvd_option(self):
|
||||
namespace = self.dvd_namespace()
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
variables = Path(directory)
|
||||
(variables / ('BootCurrent-' + EFI_GUID)).write_bytes(bytes.fromhex('060000000100'))
|
||||
(variables / ('Boot0001-' + EFI_GUID)).write_bytes(DVD_VARIABLE)
|
||||
saved = namespace['capture_dvd_variable'](variables)
|
||||
self.assertEqual(saved['raw_hex'], DVD_VARIABLE.hex())
|
||||
self.assertEqual(saved['entry'], '0001')
|
||||
(variables / ('BootCurrent-' + EFI_GUID)).write_bytes(bytes.fromhex('060000000200'))
|
||||
with self.assertRaises(RuntimeError):
|
||||
namespace['capture_dvd_variable'](variables)
|
||||
(variables / ('BootCurrent-' + EFI_GUID)).write_bytes(bytes.fromhex('060000000100'))
|
||||
(variables / ('Boot0002-' + EFI_GUID)).write_bytes(DVD_VARIABLE)
|
||||
with self.assertRaises(RuntimeError):
|
||||
namespace['capture_dvd_variable'](variables)
|
||||
|
||||
def test_restore_saved_dvd_uses_free_variable_without_overwriting_or_reordering(self):
|
||||
namespace = self.dvd_namespace()
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
variables = Path(directory)
|
||||
original = {'Boot0000-' + EFI_GUID: b'unrelated boot entry',
|
||||
'Boot0001-' + EFI_GUID: b'HydraOS reused original DVD number',
|
||||
'BootOrder-' + EFI_GUID: bytes.fromhex('0700000000000300'),
|
||||
'unrelated-vendor-variable': b'foreign variable'}
|
||||
for name, data in original.items():
|
||||
(variables / name).write_bytes(data)
|
||||
restored = namespace['restore_dvd_variable'](variables, DVD_VARIABLE)
|
||||
self.assertEqual(restored['entry'], '0002')
|
||||
self.assertTrue(restored['created'])
|
||||
self.assertEqual((variables / ('Boot0002-' + EFI_GUID)).read_bytes(), DVD_VARIABLE)
|
||||
for name, data in original.items():
|
||||
self.assertEqual((variables / name).read_bytes(), data)
|
||||
restored_again = namespace['restore_dvd_variable'](variables, DVD_VARIABLE)
|
||||
self.assertFalse(restored_again['created'])
|
||||
self.assertEqual(restored_again['entry'], '0002')
|
||||
|
||||
def test_restore_rejects_wrong_attributes_label_device_path_or_extra_payload(self):
|
||||
namespace = self.dvd_namespace()
|
||||
changes = [bytes.fromhex('06000000') + DVD_VARIABLE[4:],
|
||||
DVD_VARIABLE[:4] + bytes.fromhex('00000000') + DVD_VARIABLE[8:],
|
||||
DVD_VARIABLE.replace('QM00001'.encode('utf-16-le'), 'QM00003'.encode('utf-16-le')),
|
||||
DVD_VARIABLE.replace(bytes.fromhex('03120a000000ffff0000'), bytes.fromhex('03120a000200ffff0000')),
|
||||
DVD_VARIABLE + b'foreign optional loader data']
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
variables = Path(directory)
|
||||
(variables / ('BootOrder-' + EFI_GUID)).write_bytes(bytes.fromhex('070000000000'))
|
||||
for data in changes:
|
||||
with self.subTest(data=data.hex()), self.assertRaises(RuntimeError):
|
||||
namespace['restore_dvd_variable'](variables, data)
|
||||
self.assertEqual(len(list(variables.iterdir())), 1)
|
||||
|
||||
def test_restore_refuses_ambiguous_or_altered_existing_dvd_option(self):
|
||||
namespace = self.dvd_namespace()
|
||||
for altered in (False, True):
|
||||
with self.subTest(altered=altered), tempfile.TemporaryDirectory() as directory:
|
||||
variables = Path(directory)
|
||||
(variables / ('BootOrder-' + EFI_GUID)).write_bytes(bytes.fromhex('070000000000'))
|
||||
(variables / ('Boot0001-' + EFI_GUID)).write_bytes(DVD_VARIABLE)
|
||||
(variables / ('Boot0002-' + EFI_GUID)).write_bytes(DVD_VARIABLE if not altered else
|
||||
DVD_VARIABLE.replace(bytes.fromhex('03120a000000ffff0000'), bytes.fromhex('03120a000200ffff0000')))
|
||||
with self.assertRaises(RuntimeError):
|
||||
namespace['restore_dvd_variable'](variables, DVD_VARIABLE)
|
||||
self.assertEqual(len(list(variables.iterdir())), 3)
|
||||
|
||||
def test_restore_never_overwrites_a_concurrently_created_boot_variable(self):
|
||||
import os
|
||||
from unittest.mock import patch
|
||||
namespace = self.dvd_namespace()
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
variables = Path(directory)
|
||||
order = variables / ('BootOrder-' + EFI_GUID)
|
||||
order.write_bytes(bytes.fromhex('070000000100'))
|
||||
original_order = order.read_bytes()
|
||||
destination = variables / ('Boot0000-' + EFI_GUID)
|
||||
real_open = os.open
|
||||
def race(path, flags, mode):
|
||||
self.assertEqual(path, destination)
|
||||
destination.write_bytes(b'concurrent foreign boot entry')
|
||||
return real_open(path, flags, mode)
|
||||
with patch.object(namespace['os'], 'open', side_effect=race), self.assertRaises(FileExistsError):
|
||||
namespace['restore_dvd_variable'](variables, DVD_VARIABLE)
|
||||
self.assertEqual(destination.read_bytes(), b'concurrent foreign boot entry')
|
||||
self.assertEqual(order.read_bytes(), original_order)
|
||||
|
||||
def test_http_serves_only_explicit_bytes_with_no_filesystem_or_traversal(self):
|
||||
server = self.mod.artifact_server({'/public.pem': b'TEST public', '/one/manifest.json': b'{}'})
|
||||
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
||||
@@ -94,10 +200,11 @@ class LaptopSmokeTests(unittest.TestCase):
|
||||
self.assertFalse((Path(directory) / 'TEST-private.pem').exists())
|
||||
|
||||
def test_every_guest_probe_compiles(self):
|
||||
for mode in ('seed', 'preserved', 'baseline', 'upgrade', 'base-state', 'damage', 'restored', 'runtime', 'restore-interrupt'):
|
||||
for mode in self.mod.GUEST_BODIES:
|
||||
with self.subTest(mode=mode):
|
||||
compile(self.mod.guest_script(mode, {'sentinel': 'fixture', 'port': 1234,
|
||||
'checkpoint': '00000000-0000-0000-0000-000000000001',
|
||||
'dvd_variable': DVD_VARIABLE.hex(),
|
||||
'root_uuid': '00000000-0000-0000-0000-000000000002'}), mode, 'exec')
|
||||
|
||||
def test_installer_only_formats_selected_root_and_registration_is_opt_in(self):
|
||||
@@ -215,6 +322,46 @@ class LaptopSmokeTests(unittest.TestCase):
|
||||
self.assertEqual(calls[-1], ('mount', '-t', filesystem, '-o', options, device, str(directory)))
|
||||
self.assertEqual(calls[-1], ('umount', str(directory)))
|
||||
|
||||
def test_installed_esp_is_read_from_verified_existing_mount_without_remount(self):
|
||||
namespace = self.dvd_namespace()
|
||||
calls = []
|
||||
def query(*args):
|
||||
calls.append(args)
|
||||
if args[0] == 'findmnt':
|
||||
return json.dumps({'filesystems': [{'source': '/dev/vda1', 'target': '/boot/efi',
|
||||
'fstype': 'vfat', 'uuid': '1234-ABCD', 'maj:min': '253:1'}]})
|
||||
if args[0] == 'lsblk':
|
||||
return json.dumps({'blockdevices': [{'name': 'vda1', 'fstype': 'vfat',
|
||||
'uuid': '1234-ABCD', 'maj:min': '253:1'}]})
|
||||
raise AssertionError('ESP verification attempted a mutation: ' + repr(args))
|
||||
namespace['run'] = query
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
marker = Path(directory) / 'marker.json'
|
||||
marker.write_text(json.dumps({'esp_uuid': '1234-ABCD'}))
|
||||
def guest_path(path):
|
||||
if path == '/etc/hydra/storage.json': return marker
|
||||
if path == '/etc/hydra/live-mode/active': return Path(directory) / 'absent-live-mode'
|
||||
return Path(path)
|
||||
namespace['Path'] = guest_path
|
||||
with namespace['readonly_esp']() as esp:
|
||||
self.assertEqual(esp, Path('/boot/efi'))
|
||||
self.assertEqual(calls, [
|
||||
('findmnt', '--json', '--mountpoint', '/boot/efi', '--output', 'SOURCE,TARGET,FSTYPE,UUID,MAJ:MIN'),
|
||||
('lsblk', '--json', '--nodeps', '--output', 'NAME,MAJ:MIN,FSTYPE,UUID', '/dev/vda1')])
|
||||
|
||||
def test_installed_esp_rejects_wrong_device_uuid_mountpoint_or_filesystem(self):
|
||||
namespace = self.dvd_namespace()
|
||||
mount = {'source': '/dev/vda1', 'target': '/boot/efi', 'fstype': 'vfat',
|
||||
'uuid': '1234-ABCD', 'maj:min': '253:1'}
|
||||
device = {'name': 'vda1', 'fstype': 'vfat', 'uuid': '1234-ABCD', 'maj:min': '253:1'}
|
||||
for key, wrong in [('source', '/dev/vdb1'), ('target', '/boot'), ('fstype', 'ext4'),
|
||||
('uuid', 'FFFF-ABCD'), ('maj:min', '253:2')]:
|
||||
altered = dict(mount, **{key: wrong})
|
||||
namespace['run'] = lambda *args: json.dumps(
|
||||
{'filesystems': [altered]} if args[0] == 'findmnt' else {'blockdevices': [device]})
|
||||
with self.subTest(key=key), self.assertRaises(RuntimeError):
|
||||
namespace['installed_esp']({'esp_uuid': '1234-ABCD'})
|
||||
|
||||
def test_every_guest_mount_call_names_the_partition_filesystem(self):
|
||||
import ast
|
||||
expected = {'/dev/vda1': 'vfat', '/dev/vda2': 'ext4', '/dev/vda3': 'btrfs'}
|
||||
|
||||
Reference in New Issue
Block a user