import asyncio import sys from pathlib import Path import pytest from codexpi.commands import SAFE_BRANCH, SAFE_NAME, run_command def test_user_argument_is_not_interpreted_by_shell(tmp_path: Path): marker = tmp_path / "owned" hostile = f"; touch {marker}" result = asyncio.run(run_command([sys.executable, "-c", "import sys; print(sys.argv[1])", hostile])) assert result.stdout.strip() == hostile assert not marker.exists() def test_docker_and_branch_names_are_strict(): assert SAFE_NAME.fullmatch("jellyfin-1") assert not SAFE_NAME.fullmatch("jellyfin;id") assert SAFE_BRANCH.fullmatch("feature/codexpi-ui") assert not SAFE_BRANCH.fullmatch("../escape") def test_backend_never_uses_shell_true(): backend = Path(__file__).resolve().parents[1] / "backend" / "codexpi" source = "\n".join(p.read_text(encoding="utf-8") for p in backend.glob("*.py")) assert "shell=True" not in source