"""Run the real installer in a disposable root Linux filesystem fixture.""" import os from pathlib import Path import shutil import subprocess import tempfile import unittest SOURCE = Path(__file__).resolve().parents[1] MOCK = r'''#!/bin/sh printf '%s %s\n' "$(basename "$0")" "$*" >> "$FIXTURE/commands" case "$(basename "$0")" in ssh-keygen) echo '256 SHA256:341ON+FsVZMVMsduFUZjevfxjagbFG9yPeZ0edTVSOk verified (ED25519)' ;; logrotate) if [ "${FAIL_LOGROTATE:-}" = yes ]; then echo 'error: Ignoring writable configuration' fi ;; systemctl) if [ "$1" = daemon-reload ] && [ "${FAIL_RELOAD:-}" = yes ]; then exit 1; fi if [ "$1" = is-active ] && [ "${FAIL_SERVICES:-}" = yes ]; then exit 3; fi ;; esac ''' @unittest.skipUnless(os.name == 'posix' and getattr(os, 'geteuid', lambda: -1)() == 0, 'Disposable root Linux container required') class ToolingInstallerTests(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory(prefix='eusrr-installer-test-') self.addCleanup(self.temp.cleanup) self.root = Path(self.temp.name) self.source = self.root/'source' self.source.mkdir() for path in SOURCE.iterdir(): if path.is_file(): shutil.copyfile(path, self.source/path.name) shutil.copytree(SOURCE/'systemd', self.source/'systemd') # The actual deploy state machine is exercised in test_deploy_lifecycle. # Here only its installer self-test exit outcome is controlled. (self.source/'eusrr-deploy').write_text('#!/bin/sh\n[ "${FAIL_SELF_TEST:-}" != yes ]\n') script = (SOURCE/'install-deploy-hardening').read_text() for prefix in ('/srv/', '/var/', '/run/', '/etc/', '/usr/local/'): script = script.replace(prefix, str(self.root)+prefix) self.installer = self.source/'install-deploy-hardening' self.installer.write_text(script) self.bin = self.root/'bin' self.bin.mkdir() for command in ('systemctl', 'logrotate', 'visudo', 'ssh-keygen'): path = self.bin/command path.write_text(MOCK) path.chmod(0o755) for directory in ('srv/eusrr-slots', 'var/lib/eusrr-deploy', 'run/lock', 'etc/logrotate.d', 'etc/sudoers.d', 'etc/eusrr', 'etc/systemd/system', 'usr/local/sbin'): (self.root/directory).mkdir(parents=True, exist_ok=True) (self.root/'srv/eusrr-slots').chmod(0o2775) (self.root/'var/lib/eusrr-deploy/active-slot').write_text('blue\n') self.old_script = self.root/'usr/local/sbin/eusrr-deploy' self.old_script.write_text('original deploy script\n') self.old_script.chmod(0o755) self.old_unit = self.root/'etc/systemd/system/eusrr-backend@.service' self.old_unit.write_text('original backend unit\n') self.env = {**os.environ, 'FIXTURE': str(self.root), 'PATH': str(self.bin)+':'+os.environ['PATH']} def run_installer(self, **env): result = subprocess.run(['bash', str(self.installer)], capture_output=True, text=True, env={**self.env, **env}, timeout=20) self.output = result.stdout+result.stderr return result def test_success_installs_controls_without_restart_or_cleanup(self): self.assertEqual(self.run_installer().returncode, 0, self.output) self.assertEqual((self.root/'srv/eusrr-slots').stat().st_mode & 0o777, 0o755) self.assertIn('KillSignal=SIGTERM', self.old_unit.read_text()) self.assertTrue((self.root/'usr/local/libexec/eusrr-deploy-healthcheck').exists()) self.assertIn('^[0-9a-f]{40}$', (self.root/'etc/sudoers.d/eusrr-deploy').read_text()) commands = (self.root/'commands').read_text() self.assertNotIn('restart', commands) self.assertNotIn('--maintenance', commands) self.assertNotIn('--vacuum', commands) def test_failures_restore_every_changed_file_and_slot_mode(self): for flag in ('FAIL_SELF_TEST', 'FAIL_SERVICES'): with self.subTest(flag=flag): self.assertNotEqual(self.run_installer(**{flag: 'yes'}).returncode, 0) self.assertEqual(self.old_script.read_text(), 'original deploy script\n', self.output) self.assertEqual(self.old_unit.read_text(), 'original backend unit\n', self.output) self.assertFalse((self.root/'usr/local/libexec/eusrr-deploy-healthcheck').exists()) self.assertFalse((self.root/'etc/sudoers.d/eusrr-deploy').exists()) self.assertEqual((self.root/'srv/eusrr-slots').stat().st_mode & 0o7777, 0o2775) def test_logrotate_ignored_file_is_a_failure_before_mutation(self): self.assertNotEqual(self.run_installer(FAIL_LOGROTATE='yes').returncode, 0) self.assertEqual(self.old_script.read_text(), 'original deploy script\n') self.assertFalse((self.root/'usr/local/libexec/eusrr-deploy-healthcheck').exists()) def test_failed_recovery_is_not_reported_as_restored(self): self.assertNotEqual(self.run_installer(FAIL_RELOAD='yes').returncode, 0) self.assertIn('tooling recovery incomplete', self.output) self.assertNotIn('Previous tooling restored', self.output) if __name__ == '__main__': unittest.main()