from contextlib import nullcontext import hashlib import io import json from pathlib import Path from subprocess import CompletedProcess import tempfile import unittest from unittest.mock import patch from provisioning import baseline class ManualDockerTests(unittest.TestCase): def setUp(self): tmp = tempfile.TemporaryDirectory() self.addCleanup(tmp.cleanup) self.root = Path(tmp.name).resolve() (self.root / "etc").mkdir() (self.root / "etc/os-release").write_text("ID=debian\nVERSION_ID=13\n") self.commands = [] self.arch = "arm64" self.running = False self.data_root = "/custom/data" self.missing_buildx = False self.versions = {} self.installations = [] def run_command(self, cmd, **kwargs): self.commands.append(cmd) if cmd == ["dpkg", "--print-architecture"]: return CompletedProcess(cmd, 0, self.arch + "\n", "") if cmd[-1] == "{{.DockerRootDir}}": return CompletedProcess(cmd, 0 if self.running else 1, self.data_root + "\n", "") if cmd[-2:] in (["version", "--short"], ["buildx", "version"]): if self.missing_buildx and cmd[-2:] == ["buildx", "version"]: if ["docker-buildx-plugin"] not in self.installations: return CompletedProcess(cmd, 1, "", "plugin missing") return CompletedProcess(cmd, 0, "installed\n", "") raise AssertionError(cmd) def apply(self): def target(path): path = Path(path) return path if self.root in path.parents else self.root / str(path).lstrip("/") with (patch.object(baseline, "Path", side_effect=target), patch.object(baseline, "run", side_effect=self.run_command), patch.object(baseline, "package_versions", return_value=self.versions), patch.object(baseline.shutil, "which", return_value="/usr/bin/docker" if self.running else None), patch.object(baseline, "install_missing", side_effect=self.installations.append)): return baseline.apply_docker_policy() def test_working_engine_keeps_local_data_root_without_writes(self): self.running = True self.versions = {"docker.io": "1"} self.assertEqual(self.apply()["docker_data_root"], "/custom/data") self.assertEqual(self.installations, []) self.assertFalse((self.root / "etc/docker").exists()) def test_pve_refused_before_packages_or_daemon(self): binary = self.root / "usr/bin/pveversion" binary.parent.mkdir(parents=True) binary.touch() with self.assertRaisesRegex(baseline.BaselineError, "Proxmox"): self.apply() self.assertEqual(self.commands, []) def test_unsupported_architecture_refused(self): self.arch = "i386" with self.assertRaisesRegex(baseline.BaselineError, "amd64|arm64"): self.apply() self.assertEqual(self.installations, []) def test_existing_runtime_packages_not_replaced(self): self.versions = {"containerd": "1.7"} with self.assertRaisesRegex(baseline.BaselineError, "containerd"): self.apply() self.assertEqual(self.installations, []) def test_fresh_arm64_install_verifies_the_pinned_key_and_starts_local_engine(self): key = b"test repository signing key" self.data_root = "/srv/docker" def start(service): if service == "docker": self.running = True with (patch.object(baseline, "service_start_guard", return_value=nullcontext()), patch.object(baseline.urllib.request, "urlopen", return_value=io.BytesIO(key)), patch.object(baseline, "DOCKER_KEY_SHA256", hashlib.sha256(key).hexdigest()), patch.object(baseline, "ensure_service", side_effect=start)): self.assertEqual(self.apply()["docker_data_root"], "/srv/docker") source = (self.root / "etc/apt/sources.list.d/apex-docker.sources").read_text() self.assertIn("Architectures: arm64", source) self.assertIn("Signed-By: ", source) self.assertEqual((self.root / "etc/apt/keyrings/apex-docker.asc").read_bytes(), key) self.assertEqual(json.loads((self.root / "etc/docker/daemon.json").read_text())["data-root"], "/srv/docker") self.assertIn("docker-compose-plugin", self.installations[-1]) self.assertIn("docker-buildx-plugin", self.installations[-1]) self.assertNotIn("ufw", self.installations[-1]) def test_untrusted_signing_key_cannot_publish_apt_source_or_install_docker(self): with (patch.object(baseline, "service_start_guard", return_value=nullcontext()), patch.object(baseline.urllib.request, "urlopen", return_value=io.BytesIO(b"wrong key"))): with self.assertRaisesRegex(baseline.BaselineError, "signing key"): self.apply() self.assertFalse((self.root / "etc/apt/sources.list.d/apex-docker.sources").exists()) self.assertFalse((self.root / "etc/docker/daemon.json").exists()) self.assertEqual(self.installations, [("ca-certificates",)]) def test_working_ce_engine_only_installs_the_missing_plugin(self): self.running = True self.missing_buildx = True self.versions = {"docker-ce": "1"} with patch.object(baseline, "service_start_guard", return_value=nullcontext()): self.assertEqual(self.apply()["docker_data_root"], "/custom/data") self.assertEqual(self.installations, [["docker-buildx-plugin"]]) self.assertFalse((self.root / "etc/docker").exists())