from __future__ import annotations from pathlib import Path import pytest from minisweagent.exceptions import Submitted from lai_automation.security import SafeLocalEnvironment, redact def test_environment_does_not_inherit_worker_secrets( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: monkeypatch.setenv("GITEA_TOKEN", "gitea-secret") monkeypatch.setenv("MISTRAL_API_KEY", "model-secret") environment = SafeLocalEnvironment( cwd=str(tmp_path), env={"APP_ENV": "testing"}, username=None, ) result = environment.execute( {"command": "printf '%s|%s|%s' \"$GITEA_TOKEN\" \"$MISTRAL_API_KEY\" \"$APP_ENV\""} ) assert result["output"] == "||testing" assert "GITEA_TOKEN" not in environment.get_template_vars() assert "MISTRAL_API_KEY" not in environment.get_template_vars() assert "gitea-secret" not in str(environment.serialize()) def test_environment_rejects_cwd_outside_repository(tmp_path: Path) -> None: repository = tmp_path / "repo" repository.mkdir() environment = SafeLocalEnvironment(cwd=str(repository), username=None) with pytest.raises(ValueError, match="inside the repository"): environment.execute({"command": "pwd"}, cwd=str(tmp_path)) @pytest.mark.parametrize( "command", [ "git status", "cat /proc/self/environ", "cat .env", "touch /tmp/agent-file", "cd .. && pwd", "php -S 127.0.0.1:8000", "php artisan serve &", "cp config/app.php config/app.php.bak", "printf debug > test_debug.php", "touch scratch.py", ], ) def test_environment_rejects_unsafe_commands(tmp_path: Path, command: str) -> None: environment = SafeLocalEnvironment(cwd=str(tmp_path), username=None) result = environment.execute({"command": command}) assert result["returncode"] == -1 assert "safety policy" in result["exception_info"] assert not (tmp_path / "agent-file").exists() def test_environment_allows_commands_within_repository(tmp_path: Path) -> None: nested = tmp_path / "tests" nested.mkdir() environment = SafeLocalEnvironment(cwd=str(tmp_path), username=None) result = environment.execute( {"command": f"cd {nested} && printf focused-test"} ) assert result["returncode"] == 0 assert result["output"] == "focused-test" def test_environment_allows_standard_error_redirection(tmp_path: Path) -> None: environment = SafeLocalEnvironment(cwd=str(tmp_path), username=None) result = environment.execute({"command": "printf redirected 2>&1"}) assert result["returncode"] == 0 assert result["output"] == "redirected" def test_environment_recognizes_submission_marker(tmp_path: Path) -> None: environment = SafeLocalEnvironment(cwd=str(tmp_path), username=None) with pytest.raises(Submitted) as submission: environment.execute( {"command": "printf 'COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT\\ndone\\n'"} ) assert submission.value.messages[0]["extra"]["submission"] == "done\n" @pytest.mark.parametrize( "value", [ "Authorization: Bearer abcdefghijklmnop", "api_key=abcdefghijklmnop", "password: supersecret", "https://bot:supersecret@gitea.example.test/repo.git", "sk-abcdefghijklmnop", ], ) def test_redact_removes_common_secret_forms(value: str) -> None: result = redact(value) assert "supersecret" not in result assert "abcdefghijklmnop" not in result assert "[REDACTED]" in result