114 lines
3.5 KiB
Python
114 lines
3.5 KiB
Python
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 |