from __future__ import annotations import subprocess # noqa: S404 from pathlib import Path from unittest.mock import patch import pytest from control_plane.host_commands import HostCommandError from control_plane.host_commands import HostCommandResult from control_plane.host_commands import build_host_command_env from control_plane.host_commands import run_host_command def test_run_host_command_rejects_env_without_allowlist() -> None: """Environment overrides must use an explicit allowlist.""" with pytest.raises(ValueError, match="allowed_env_keys"): run_host_command(command=("true",), env_overrides={"SECRET": "value"}) def test_run_host_command_returns_captured_output() -> None: """Successful host commands should preserve stdout and stderr.""" completed = subprocess.CompletedProcess( args=("echo", "ok"), returncode=0, stdout="ok\n", stderr="", ) with patch( "control_plane.host_commands.subprocess.run", return_value=completed, ) as mock_run: result = run_host_command( command=("echo", "ok"), cwd=Path.cwd(), env_overrides={"UV_PROJECT_ENVIRONMENT": "test"}, allowed_env_keys=frozenset({"UV_PROJECT_ENVIRONMENT"}), ) assert result == HostCommandResult( args=("echo", "ok"), returncode=0, stdout="ok\n", stderr="", ) forwarded_env = mock_run.call_args.kwargs["env"] assert "DJANGO_SETTINGS_MODULE" not in forwarded_env assert forwarded_env["UV_PROJECT_ENVIRONMENT"] == "test" mock_run.assert_called_once() def test_build_host_command_env_strips_platform_django_settings( monkeypatch: pytest.MonkeyPatch, ) -> None: """Tenant child processes must not inherit platform Django settings.""" monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "config.settings") monkeypatch.setenv("PATH", "/usr/bin") environment = build_host_command_env() assert environment["PATH"] == "/usr/bin" assert "DJANGO_SETTINGS_MODULE" not in environment def test_run_host_command_wraps_called_process_errors() -> None: """Failing host commands should raise a typed exception with captured output.""" error = subprocess.CalledProcessError( returncode=17, cmd=("podman", "run"), output="", stderr="boom", ) with ( patch("control_plane.host_commands.subprocess.run", side_effect=error), pytest.raises( HostCommandError, match="Host command failed", ) as exc_info, ): run_host_command(command=("podman", "run")) assert exc_info.value.command_args == ("podman", "run") assert exc_info.value.returncode == 17 assert exc_info.value.stderr == "boom"