Files
Dorian f397661e3f Integrate accepted RC6 installer for release 2.1.23
Exact reviewed integration tree from 7bf8c8d8e9da45c533a73e59ade18df37eab9ed5.
Preserves installer branch fe383efe70 and its history.
Incorporates Gitea PR #168 with source UI approval and completed source regressions.
The canonical proposal uses one parent to avoid ngit's ten-commit submission guard; no source changes or history rewriting.
2026-11-14 06:58:59 -05:00

107 lines
5.3 KiB
Python

#!/usr/bin/env python3
"""Offline provisioning and real isolated nft policy regression checks."""
import importlib.util
import json
import os
from pathlib import Path
import re
import subprocess
import tempfile
import unittest
HERE = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location('provision', HERE / 'provision.py')
p = importlib.util.module_from_spec(spec)
spec.loader.exec_module(p)
class ProvisionTests(unittest.TestCase):
def setUp(self):
previous_umask = os.umask(0o022)
self.addCleanup(os.umask, previous_umask)
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.root = Path(self.temp.name)
for name, data in {'etc/apt/apt.conf.d/98archipelago-build-indexes': '// Archipelago image build index lock\nfixture\n',
'etc/os-release': 'ID=debian\nVERSION_CODENAME=trixie\n',
'usr/share/keyrings/debian-archive-keyring.gpg': 'fixture',
'etc/apt/sources.list.d/archipelago-build.sources': p.BUILD_MARKER.decode() + 'fixture\n'}.items():
dest = self.root / name
dest.parent.mkdir(parents=True, exist_ok=True)
dest.write_text(data)
def test_idempotent_and_runtime_authority(self):
first = p.provision(self.root, HERE)
self.assertEqual(first, p.provision(self.root, HERE))
self.assertFalse((self.root / 'etc/apt/sources.list.d/archipelago-build.sources').exists())
for name in p.MASKED:
self.assertEqual(os.readlink(self.root / 'etc/systemd/system' / name), '/dev/null')
self.assertEqual(first['review_cadence'], 'not-appointed')
self.assertFalse((self.root/'etc/apt/apt.conf.d/98archipelago-build-indexes').exists())
def test_live_root_refused(self):
with self.assertRaises(ValueError): p.provision(Path('/'), HERE)
def test_foreign_sources_preserved_before_writes(self):
source = self.root / 'etc/apt/sources.list.d/operator.list'
source.write_text('deb https://example.invalid stable main\n')
with self.assertRaises(ValueError): p.provision(self.root, HERE)
self.assertFalse((self.root / 'etc/archipelago').exists())
self.assertIn('example.invalid', source.read_text())
def test_symlink_destination_refused(self):
(self.root / 'etc/archipelago').symlink_to(self.root / 'etc')
with self.assertRaises(ValueError): p.provision(self.root, HERE)
self.assertFalse((self.root / 'etc/host-firewall.nft').exists())
def test_foreign_mask_preserved(self):
mask = self.root / 'etc/systemd/system/apt-daily.timer'
mask.parent.mkdir(parents=True)
mask.symlink_to('/operator/unit')
with self.assertRaises(ValueError): p.provision(self.root, HERE)
self.assertEqual(os.readlink(mask), '/operator/unit')
self.assertFalse((self.root / 'etc/archipelago').exists())
def test_foreign_fips_policy_preserved(self):
policy = self.root / 'etc/fips/fips.nft'
policy.parent.mkdir(parents=True)
policy.write_text('operator policy\n')
with self.assertRaisesRegex(ValueError, 'different existing image asset preserved'):
p.provision(self.root, HERE)
self.assertEqual(policy.read_text(), 'operator policy\n')
self.assertFalse((self.root / 'etc/archipelago').exists())
def test_keyring_escape_refused(self):
keyring = self.root / 'usr/share/keyrings/debian-archive-keyring.gpg'
keyring.unlink(); keyring.symlink_to('/etc/passwd')
with self.assertRaises(ValueError): p.provision(self.root, HERE)
self.assertFalse((self.root / 'etc/archipelago').exists())
def test_manifest_profiles_are_shipped(self):
repo = HERE.parents[1]
paths = subprocess.check_output(['git', '-C', str(repo), 'ls-files', 'apps/*/manifest.yml'], text=True).splitlines()
names = set()
for path in paths:
names.update(re.findall(r'^\s+apparmor_profile:\s*([a-z0-9-]+)\s*$', (repo/path).read_text(), re.M))
names.discard('default')
self.assertEqual(names, {path.name for path in (HERE/'apparmor').iterdir()})
for name in names:
self.assertIn('profile '+name+' flags=', (HERE/'apparmor'/name).read_text())
p.provision(self.root, HERE)
dependency = (self.root/'etc/systemd/system/archipelago.service.d/21-app-profiles.conf').read_text()
self.assertIn('Requires=archipelago-app-profiles.service', dependency)
self.assertIn('After=archipelago-app-profiles.service', dependency)
def test_recipe_does_not_create_mask_collisions(self):
source = (HERE.parent/'_archived/build-auto-installer-iso.sh').read_text()
copied = set(re.findall(r'^COPY \S+ /etc/systemd/system/(\S+)$', source, re.M))
enabled = set(re.findall(r'systemctl enable ([a-zA-Z0-9@_.-]+)', source))
self.assertFalse(copied & set(p.MASKED), copied & set(p.MASKED))
self.assertFalse(enabled & set(p.MASKED), enabled & set(p.MASKED))
def test_catalog_inventory(self):
source = (HERE.parents[1] / 'core/archipelago/src/fips/app_ports.rs').read_text()
ports = list(map(int, re.findall(r'^\s+(\d+),$', source, re.M)))
self.assertEqual(ports, json.loads((HERE / 'app-ports.json').read_text()))
if __name__ == '__main__': unittest.main()