from __future__ import annotations import re import shlex from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] def test_promoter_archive_covers_every_required_installer_source(): from backend.app.services.controller_artifact_promoter import helper_container_spec spec = helper_container_spec(revision="a" * 40, image_id="sha256:" + "b" * 64) command = spec["Cmd"][2].replace("\\\n", " ") archive = re.search(r'archive --format=tar "\$revision"(.*?)> "\$work/controller.tar"', command, re.S) assert archive is not None packaged = shlex.split(archive.group(1)) installer = (ROOT / "scripts/upgrade_deployment_controller.sh").read_text(encoding="utf-8") required_block = re.search(r"(?m)^source_paths=\(\n(.*?)\n\)", installer, re.S) assert required_block is not None required = shlex.split(required_block.group(1)) assert required assert all(any(path == prefix or path.startswith(prefix + "/") for prefix in packaged) for path in required) def test_controller_promoter_action_is_fixed_and_registered(): registry = (ROOT / "backend/app/services/action_registry.py").read_text(encoding="utf-8") execution = (ROOT / "backend/app/services/action_execution.py").read_text(encoding="utf-8") assert "'controller.artifact.promote'" in registry assert "return 'tower/deployment-controller'" in registry assert 'action == "controller.artifact.promote"' in execution assert 'target.strip().lower() != "tower/deployment-controller"' in execution def test_controller_promoter_helper_spec_is_fixed_and_bounded(): from backend.app.services.controller_artifact_promoter import ( CONTROLLER_VERSION, HELPER_NAME, helper_container_spec, ) revision = "a" * 40 image_id = "sha256:" + "b" * 64 spec = helper_container_spec(revision=revision, image_id=image_id) assert HELPER_NAME == "itworx-controller-artifact-promoter-modern" assert CONTROLLER_VERSION == "2.1.18" assert re.fullmatch(r"2\.1\.\d+", CONTROLLER_VERSION) assert spec["Image"] == image_id assert spec["HostConfig"]["Privileged"] is False assert spec["HostConfig"]["NetworkMode"] == "host" assert spec["HostConfig"]["SecurityOpt"] == ["no-new-privileges:true"] assert spec["HostConfig"]["ReadonlyRootfs"] is True assert spec["HostConfig"]["PidsLimit"] <= 128 assert spec["HostConfig"]["Memory"] <= 1024 * 1024 * 1024 assert spec["HostConfig"]["CpuQuota"] <= spec["HostConfig"]["CpuPeriod"] assert set(spec["HostConfig"]["Tmpfs"]) == {"/tmp"} assert set(spec["HostConfig"]["Binds"]) == { "/mnt/cache:/mnt/cache", "/mnt/user:/mnt/user", "/var/lib/docker:/var/lib/docker:ro", "/srv/example/appdata/gitea/git/repositories:/gitea-repositories:ro", "/var/run/docker.sock:/var/run/docker.sock", } assert spec["Cmd"][:2] == ["/bin/bash", "-lc"] command = spec["Cmd"][2] assert "mktemp -d -p /tmp itworx-controller-artifact-promoter-" in command assert f"itworx-controller-artifact-promoter-{revision[:12]}.XXXXXX" in command assert "/mnt/cache/appdata/gitea-deploy-runners/.controller-promoter-" not in command assert "work='/mnt/cache" not in command assert "rm -rf -- \"$work\"" in command assert "scripts/upgrade_deployment_controller.sh > \"$work/controller.tar\"" in command assert "chmod 0600 \"$work/controller.tar\"" in command assert "scripts/prepare_controller_hub_release_volume.py" in command assert "scripts/run_repopulse_adoption.py" in command assert "UPGRADE_DEPLOYMENT_CONTROLLER_V2" in command assert revision in command assert "--image-id" in command assert CONTROLLER_VERSION in command assert "version='2.1.18'" in command assert "/gitea-repositories/jens/unraid-appops-gateway.git" in command archive_start = command.index('git --git-dir="$repo" archive') archive_end = command.index('> "$work/controller.tar"', archive_start) assert "scripts/vendor" in command[archive_start:archive_end] assert "scripts/upgrade_deployment_controller.sh > \"$work/controller.tar\"" in command assert '--image-id "$image_id"' in command def test_controller_promoter_bootstrap_child_spec_binds_legacy_target_identity(): from backend.app.services.controller_artifact_promoter import helper_container_spec revision = "a" * 40 image_id = "sha256:" + "b" * 64 target_id = "c" * 64 target_revision = "d" * 40 target_tree = "e" * 40 spec = helper_container_spec( revision=revision, image_id=image_id, current_controller_id=target_id, current_controller_revision=target_revision, current_controller_tree=target_tree, current_controller_version="2.1.12", ) assert spec["Image"] == image_id assert spec["Labels"] == { "itworx.controller.promoter": "true", "itworx.source.repository": "jens/unraid-appops-gateway", "itworx.source.revision": revision, "itworx.controller.version": "2.1.18", "itworx.controller.bootstrap.target.id": target_id, "itworx.controller.bootstrap.target.image": image_id, "itworx.controller.bootstrap.target.revision": target_revision, "itworx.controller.bootstrap.target.tree": target_tree, "itworx.controller.bootstrap.target.version": "2.1.12", } def test_controller_promoter_rejects_partial_or_mutable_bootstrap_binding(): from backend.app.services.controller_artifact_promoter import helper_container_spec base = {"revision": "a" * 40, "image_id": "sha256:" + "b" * 64} with pytest.raises(ValueError): helper_container_spec(**base, current_controller_id="c" * 64) with pytest.raises(ValueError): helper_container_spec( **base, current_controller_id="c" * 64, current_controller_revision="../controller", current_controller_tree="e" * 40, current_controller_version="2.1.12", ) with pytest.raises(ValueError): helper_container_spec( **base, current_controller_id="../controller", current_controller_revision="d" * 40, current_controller_tree="e" * 40, current_controller_version="2.1.12", ) @pytest.mark.parametrize( "revision,image_id", [ ("main", "sha256:" + "b" * 64), ("a" * 39, "sha256:" + "b" * 64), ("a" * 40, "ubuntu:latest"), ("a" * 40, "sha256:" + "z" * 64), ], ) def test_controller_promoter_rejects_mutable_or_invalid_identity(revision: str, image_id: str): from backend.app.services.controller_artifact_promoter import helper_container_spec with pytest.raises(ValueError): helper_container_spec(revision=revision, image_id=image_id) def test_controller_promoter_uses_only_protected_main_and_push_gate(): source = (ROOT / "backend/app/services/controller_artifact_promoter.py").read_text(encoding="utf-8") assert 'branch = "main"' in source assert 'REQUIRED_PUSH_CONTEXT = "Managed validation / full (push)"' in source assert "controller_promoter_main_not_validated" in source assert "caller_revision" not in source def test_deployment_broker_exposes_bounded_controller_health(): source = (ROOT / "backend/app/services/deployment_broker.py").read_text(encoding="utf-8") assert "def controller_health(self)" in source assert 'f"{self.base_url}/health"' in source assert "_MAX_CONTROLLER_HEALTH_BYTES" in source