from __future__ import annotations import hashlib import http.client import importlib.util import json import subprocess import sys import threading import types from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] STATUS_SERVER = ROOT / "ops" / "gitea-deploy-broker" / "status_server.py" @pytest.fixture def status_module(): if "fcntl" not in sys.modules: fcntl = types.ModuleType("fcntl") fcntl.LOCK_EX = 2 fcntl.LOCK_UN = 8 fcntl.flock = lambda *_args: None sys.modules["fcntl"] = fcntl spec = importlib.util.spec_from_file_location("forge_bootstrap_status_test", STATUS_SERVER) assert spec and spec.loader module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module def _request(module, server, body: bytes, *, nonce: str, secret: bytes, signature: str | None = None): path = module.FORGE_BOOTSTRAP_PREFLIGHT_PATH timestamp = str(int(module.time.time())) signature = signature or module._request_signature( secret, method="POST", path=path, timestamp=timestamp, nonce=nonce, raw_body=body, ) connection = http.client.HTTPConnection(*server.server_address, timeout=2) connection.request( "POST", path, body=body, headers={ "Content-Type": "application/json", "Content-Length": str(len(body)), "X-ITWorx-Deployment-Timestamp": timestamp, "X-ITWorx-Deployment-Nonce": nonce, "X-ITWorx-Deployment-Signature": signature, }, ) response = connection.getresponse() status, payload = response.status, json.loads(response.read()) connection.close() return status, payload def test_forge_preflight_http_is_signed_strict_replay_safe_and_read_only( status_module, tmp_path, monkeypatch ): secret = b"forge-bootstrap-test-secret-" + b"x" * 40 secret_path = tmp_path / "bootstrap" secret_path.write_bytes(secret) secret_path.chmod(0o600) nonce_root = tmp_path / "nonces" monkeypatch.setattr(status_module, "APPOPS_ENROLLMENT_BOOTSTRAP_SECRET_FILE", secret_path) monkeypatch.setattr(status_module, "APPOPS_NONCE_ROOT", nonce_root) calls = [] response = { "apiVersion": status_module.FORGE_BOOTSTRAP_PREFLIGHT_VERSION, "status": "preflight_unknown", "revision": "a" * 40, "workspaceImageDigest": "sha256:" + "b" * 64, "frontdoorImageDigest": "sha256:" + "c" * 64, "checks": {"exact_main": {"status": "unknown"}}, "evidence": {}, } monkeypatch.setattr( status_module, "_forge_bootstrap_runtime_checks", lambda profile: calls.append(profile) or response, ) server = status_module.BoundedThreadingHTTPServer( ("127.0.0.1", 0), status_module.Handler ) serving = threading.Thread(target=server.serve_forever, daemon=True) serving.start() profile = { "api_version": status_module.FORGE_BOOTSTRAP_PREFLIGHT_VERSION, "revision": "a" * 40, "workspace_image_digest": "sha256:" + "b" * 64, "frontdoor_image_digest": "sha256:" + "c" * 64, } body = json.dumps({"profile": profile}, sort_keys=True, separators=(",", ":")).encode() try: status, payload = _request( status_module, server, body, nonce="a" * 32, secret=secret ) assert status == 200 assert payload == response assert calls == [profile] assert secret.decode() not in json.dumps(payload) assert len(list(nonce_root.iterdir())) == 1 replay_status, replay_payload = _request( status_module, server, body, nonce="a" * 32, secret=secret ) assert replay_status == 403 assert replay_payload == {"status": "authentication_rejected"} assert calls == [profile] hostile = dict(profile, host_path="/etc", endpoint="https://attacker.invalid") hostile_body = json.dumps( {"profile": hostile}, sort_keys=True, separators=(",", ":") ).encode() hostile_status, hostile_payload = _request( status_module, server, hostile_body, nonce="b" * 32, secret=secret ) assert hostile_status == 400 assert hostile_payload == {"status": "invalid_forge_preflight_contract"} assert calls == [profile] assert len(list(nonce_root.iterdir())) == 1 bad_signature_status, _ = _request( status_module, server, body, nonce="c" * 32, secret=secret, signature="0" * 64, ) assert bad_signature_status == 403 assert calls == [profile] finally: server.shutdown() server.server_close() serving.join(timeout=2) def test_forge_host_preflight_compares_exact_main_and_reports_fixed_runtime_checks( status_module, tmp_path, monkeypatch ): revision = "a" * 40 manifest = b"fixed Forge compose candidate" managed_root = tmp_path / "managed-root" postgres_dir = managed_root / "itworx-forge" / "postgres" postgres_dir.mkdir(parents=True) (managed_root / "itworx-forge").chmod(0o700) postgres_dir.chmod(0o700) app_dir = managed_root / "itworx-forge" monkeypatch.setattr(status_module, "MANAGED_APPDATA_ROOT", managed_root) monkeypatch.setattr(status_module, "_refresh_appdata_root_selection", lambda: managed_root) monkeypatch.setattr(status_module, "appdata_root_is_safe", lambda _root: True) monkeypatch.setattr( status_module, "os", types.SimpleNamespace(name="posix", geteuid=lambda: 0) ) original_lstat = Path.lstat def lstat_with_fixed_service_owners(path): info = original_lstat(path) if path == app_dir: return types.SimpleNamespace( st_mode=status_module.stat.S_IFDIR | 0o700, st_uid=0, st_gid=0 ) if path == postgres_dir: return types.SimpleNamespace( st_mode=status_module.stat.S_IFDIR | 0o700, st_uid=70, st_gid=70 ) return info monkeypatch.setattr(Path, "lstat", lstat_with_fixed_service_owners) monkeypatch.setattr(status_module, "_forge_gitea_main_revision", lambda: revision) monkeypatch.setattr(status_module, "_forge_push_validation", lambda _revision: "unknown") monkeypatch.setattr( status_module, "FORGE_COMPOSE_SHA256", hashlib.sha256(manifest).hexdigest() ) commands = [] def run(arguments, **_kwargs): commands.append(arguments) if arguments[:2] == ["git", "--git-dir"]: if "rev-parse" in arguments: return subprocess.CompletedProcess(arguments, 0, stdout=revision, stderr="") if "show" in arguments: return subprocess.CompletedProcess(arguments, 0, stdout=manifest, stderr=b"") if arguments[:3] == ["docker", "network", "ls"]: return subprocess.CompletedProcess( arguments, 0, stdout="itworx-mcp-hub-npm\n", stderr="" ) if arguments[:3] == ["docker", "network", "inspect"]: return subprocess.CompletedProcess( arguments, 0, stdout=json.dumps( {"Name": "itworx-mcp-hub-npm", "Driver": "bridge", "Scope": "local"} ), stderr="", ) if arguments[:3] == ["docker", "ps", "-a"]: return subprocess.CompletedProcess(arguments, 0, stdout="", stderr="") if arguments[:3] == ["docker", "image", "inspect"]: return subprocess.CompletedProcess( arguments, 0, stdout="sha256:" + "d" * 64, stderr="" ) raise AssertionError(f"unexpected fixed read-only command: {arguments!r}") monkeypatch.setattr(status_module.subprocess, "run", run) profile = { "revision": revision, "workspace_image_digest": "sha256:" + "b" * 64, "frontdoor_image_digest": "sha256:" + "c" * 64, } result = status_module._forge_bootstrap_runtime_checks(profile) assert result["status"] == "preflight_unknown" assert result["checks"]["exact_main"] == {"status": "passed"} assert result["checks"]["source_manifest"] == {"status": "passed"} assert result["checks"]["managed_appdata"] == {"status": "passed"} assert result["checks"]["proxy_network"] == {"status": "passed"} assert result["checks"]["resource_collisions"] == {"status": "passed"} assert result["checks"]["push_validation"] == {"status": "unknown"} assert result["evidence"]["mainRevision"] == revision assert result["evidence"]["sourceManifestSha256"] == hashlib.sha256(manifest).hexdigest() assert result["evidence"]["workspaceImagePresent"] is True assert result["evidence"]["frontdoorImagePresent"] is True assert all(isinstance(command, list) for command in commands) assert all("shell" not in " ".join(command).lower() for command in commands) commands.clear() non_head = dict(profile, revision="b" * 40) result = status_module._forge_bootstrap_runtime_checks(non_head) assert result["checks"]["exact_main"] == {"status": "blocked"} assert result["status"] == "preflight_blocked" postgres_dir.rmdir() postgres_dir.parent.rmdir() managed_root.rmdir() result = status_module._forge_bootstrap_runtime_checks(profile) assert result["checks"]["managed_appdata"] == {"status": "blocked"} assert not managed_root.exists() def test_forge_appdata_parent_requires_root_only_metadata(status_module, monkeypatch): monkeypatch.setattr(status_module, "os", types.SimpleNamespace(name="posix")) safe = types.SimpleNamespace( st_mode=status_module.stat.S_IFDIR | 0o700, st_uid=0, st_gid=0 ) group_writable = types.SimpleNamespace( st_mode=status_module.stat.S_IFDIR | 0o770, st_uid=0, st_gid=0 ) wrong_owner = types.SimpleNamespace( st_mode=status_module.stat.S_IFDIR | 0o700, st_uid=1000, st_gid=0 ) assert status_module._forge_app_dir_metadata_is_safe(safe) is True assert status_module._forge_app_dir_metadata_is_safe(group_writable) is False assert status_module._forge_app_dir_metadata_is_safe(wrong_owner) is False def test_forge_local_image_query_failure_is_unknown(status_module, monkeypatch): monkeypatch.setattr( status_module.subprocess, "run", lambda *_args, **_kwargs: subprocess.CompletedProcess( [], 1, stdout="", stderr="daemon unavailable" ), ) assert ( status_module._forge_local_image_present( "gitea.example.com/jens/itworx-forge@sha256:" + "a" * 64 ) is None )