Repository: ErikBjare/gptme
File: tests/test_shell_allowlist_autoconfirm.py (Python)

Code before:
        cmd = "rm -rf /tmp/foo"
        assert is_allowlisted(cmd) is False

    def test_pipe_with_non_allowlisted_command(self):
        """Test that a pipe to a non-allowlisted command is not allowlisted."""
        cmd = "cat file | xargs rm"
        assert is_allowlisted(cmd) is False

    def test_ls_variants(self):
        """Test that ls variants are allowlisted."""
        assert is_allowlisted("ls") is True
        assert is_allowlisted("ls -la") is True
        assert is_allowlisted("ls -la /tmp") is True

    def test_pwd(self):
        """Test that pwd is allowlisted."""
        assert is_allowlisted("pwd") is True

    def test_rg_ripgrep(self):
        """Test that rg (ripgrep) is allowlisted."""
        assert is_allowlisted("rg pattern") is True
        assert is_allowlisted("rg pattern file.txt") is True

    def test_find(self):
        """Test that find is allowlisted."""
        assert is_allowlisted("find . -name '*.py'") is True

    def test_tree(self):
        """Test that tree is allowlisted."""
        assert is_allowlisted("tree -L 2") is True


class TestShellAllowlistHook:
    """Tests for the shell_allowlist_hook function."""

    def test_allowlisted_command_auto_confirms(self):
        """Test that allowlisted shell commands auto-confirm via hook."""
        tool_use = ToolUse(
            tool="shell",
            args=[],
            kwargs={},
            content="cat README.md | head -50",
        )

        result = shell_allowlist_hook(tool_use)

        assert result is not None
        assert result.action.value == "confirm"

    def test_allowlisted_pipe_command_auto_confirms(self):
        """Test that piped allowlisted commands auto-confirm via hook."""

Review comment (refactor):
What about "find -exec" examples that should NOT be allowlisted? Do we have tests for that somewhere, we should consolidate all these known positives and known negatives for easy overview, erring on the conservative side.

We don't need one test method per cmd, this PR could be a lot shorter with a helper and wrapping up all the cases up in a single or few tests.

Code after:
    # Dangerous flags within allowlisted commands - blocked by flag check
    ("find . -name '*.py' -exec rm {} \\;", False, "find -exec rm (dangerous flag)"),
    ("find . -type f -exec cat {} \\;", False, "find -exec cat (dangerous flag)"),
    (
        "find / -name passwd -exec cat {} \\;",
        False,
        "find -exec to read sensitive files",
    ),
    (
        "find . -name '*.log' -execdir rm {} \\;",
        False,
        "find -execdir (dangerous flag)",
    ),
    ("find /tmp -type f -delete", False, "find -delete (dangerous flag)"),
    ("find . -name '*.txt' -ok cat {} \\;", False, "find -ok (dangerous flag)"),
]


class TestIsAllowlisted:
    """Tests for the is_allowlisted function."""

    @pytest.mark.parametrize(("cmd", "expected", "description"), ALLOWLIST_TEST_CASES)
    def test_allowlist_cases(self, cmd: str, expected: bool, description: str):
        """Test various allowlist cases."""
        result = is_allowlisted(cmd)
        assert result == expected, f"Failed for {description}: {cmd}"


class TestShellAllowlistHook:
    """Tests for the shell_allowlist_hook function."""

    def test_allowlisted_command_auto_confirms(self):
        """Test that allowlisted shell commands auto-confirm via hook."""
        tool_use = ToolUse(
            tool="shell",
            args=[],
            kwargs={},
            content="cat README.md | head -50",
        )

        result = shell_allowlist_hook(tool_use)

        assert result is not None
        assert result.action.value == "confirm"

    def test_allowlisted_pipe_command_auto_confirms(self):
        """Test that piped allowlisted commands auto-confirm via hook."""
        tool_use = ToolUse(
            tool="shell",
            args=[],
            kwargs={},