chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from opensquilla.tools.builtin import shell
|
||||
from opensquilla.tools.types import ToolContext, ToolError, current_tool_context
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exec_command_blocks_sensitive_workdir(tmp_path: Path) -> None:
|
||||
sensitive_dir = tmp_path / ".env"
|
||||
|
||||
result = await shell.exec_command("echo ok", workdir=str(sensitive_dir))
|
||||
|
||||
payload = json.loads(result)
|
||||
assert payload["status"] == "blocked"
|
||||
assert payload["reason"] == "sensitive_path"
|
||||
assert payload["tool"] == "exec_command"
|
||||
assert ".env" in payload["command"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exec_command_blocks_sensitive_stdin_payload() -> None:
|
||||
result = await shell.exec_command(
|
||||
"cat >/tmp/opensquilla-stdin-sensitive-test",
|
||||
stdin='{"OPENROUTER_API_KEY":"sk-or-secret"}',
|
||||
)
|
||||
|
||||
payload = json.loads(result)
|
||||
assert payload["status"] == "blocked"
|
||||
assert payload["reason"] == "sensitive_payload"
|
||||
assert payload["sensitive_payload"] == "secret_json_key"
|
||||
assert "sk-or-secret" not in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exec_command_blocks_sensitive_path_in_stdin() -> None:
|
||||
result = await shell.exec_command(
|
||||
"python -",
|
||||
stdin="from pathlib import Path\nPath('/etc/passwd').read_text()\n",
|
||||
)
|
||||
|
||||
payload = json.loads(result)
|
||||
assert payload["status"] == "blocked"
|
||||
assert payload["reason"] == "sensitive_path"
|
||||
assert payload["sensitive_path"] == "/etc"
|
||||
assert "/etc/passwd" not in payload["command"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_exec_command_blocks_nested_sensitive_workdir() -> None:
|
||||
sensitive_dir = Path.home() / ".ssh" / "id_rsa"
|
||||
|
||||
result = await shell.exec_command("echo ok", workdir=str(sensitive_dir))
|
||||
|
||||
payload = json.loads(result)
|
||||
assert payload["status"] == "blocked"
|
||||
assert payload["sensitive_path"] == "~/.ssh"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skipif(os.name != "posix", reason="/dev/null redirection is POSIX-specific")
|
||||
async def test_exec_command_allows_dev_null_redirection() -> None:
|
||||
result = await shell.exec_command("printf ok 2>/dev/null")
|
||||
|
||||
assert result == "exit_code=0\nok"
|
||||
|
||||
|
||||
def test_dev_null_redirection_does_not_hide_sensitive_operand() -> None:
|
||||
payload = shell._sensitive_shell_block(
|
||||
"exec_command",
|
||||
"cat /dev/sda 2>/dev/null",
|
||||
)
|
||||
|
||||
assert payload is not None
|
||||
assert json.loads(payload)["sensitive_path"] == "/dev"
|
||||
|
||||
|
||||
def test_sensitive_shell_allows_configured_workspace_under_sensitive_prefix() -> None:
|
||||
workspace = Path("/root/.opensquilla/workspace")
|
||||
token = current_tool_context.set(ToolContext(workspace_dir=str(workspace)))
|
||||
try:
|
||||
script = (
|
||||
"python3 - <<'PY'\n"
|
||||
"from pathlib import Path\n"
|
||||
f"print(Path({str(workspace / 'notes.txt')!r}))\n"
|
||||
"PY"
|
||||
)
|
||||
payload = shell._sensitive_shell_block(
|
||||
"exec_command",
|
||||
script,
|
||||
workdir=str(workspace),
|
||||
)
|
||||
finally:
|
||||
current_tool_context.reset(token)
|
||||
|
||||
assert payload is None
|
||||
|
||||
|
||||
def test_sensitive_shell_still_blocks_sensitive_command_inside_workspace() -> None:
|
||||
workspace = Path("/root/.opensquilla/workspace")
|
||||
token = current_tool_context.set(ToolContext(workspace_dir=str(workspace)))
|
||||
try:
|
||||
payload = shell._sensitive_shell_block(
|
||||
"exec_command",
|
||||
"cat /root/.ssh/id_rsa",
|
||||
workdir=str(workspace),
|
||||
)
|
||||
finally:
|
||||
current_tool_context.reset(token)
|
||||
|
||||
assert payload is not None
|
||||
assert json.loads(payload)["sensitive_path"] == "~/.ssh"
|
||||
|
||||
|
||||
def test_sensitive_shell_workspace_exception_keeps_leaf_secret_blocks() -> None:
|
||||
workspace = Path("/root/.opensquilla/workspace")
|
||||
token = current_tool_context.set(ToolContext(workspace_dir=str(workspace)))
|
||||
try:
|
||||
payload = shell._sensitive_shell_block(
|
||||
"exec_command",
|
||||
f"cat {workspace / '.env'}",
|
||||
workdir=str(workspace),
|
||||
)
|
||||
finally:
|
||||
current_tool_context.reset(token)
|
||||
|
||||
assert payload is not None
|
||||
assert json.loads(payload)["reason"] == "sensitive_path"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_background_process_blocks_sensitive_workdir(tmp_path: Path) -> None:
|
||||
sensitive_dir = tmp_path / ".env"
|
||||
|
||||
result = await shell.background_process("echo ok", workdir=str(sensitive_dir))
|
||||
|
||||
payload = json.loads(result)
|
||||
assert payload["status"] == "blocked"
|
||||
assert payload["reason"] == "sensitive_path"
|
||||
assert payload["tool"] == "background_process"
|
||||
assert ".env" in payload["command"]
|
||||
|
||||
|
||||
def test_effective_workdir_resolves_relative_paths_against_workspace(tmp_path: Path) -> None:
|
||||
workspace = tmp_path / "workspace"
|
||||
workspace.mkdir()
|
||||
token = current_tool_context.set(ToolContext(workspace_dir=str(workspace)))
|
||||
try:
|
||||
assert shell._effective_workdir("subdir") == str((workspace / "subdir").resolve())
|
||||
finally:
|
||||
current_tool_context.reset(token)
|
||||
|
||||
|
||||
def test_effective_workdir_rejects_foreign_posix_absolute_path_on_windows(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
workspace = tmp_path / "workspace"
|
||||
workspace.mkdir()
|
||||
monkeypatch.setattr(shell.os, "name", "nt")
|
||||
token = current_tool_context.set(ToolContext(workspace_dir=str(workspace)))
|
||||
try:
|
||||
with pytest.raises(ToolError, match="foreign_host_path"):
|
||||
shell._effective_workdir("/Users/a1/Desktop")
|
||||
finally:
|
||||
current_tool_context.reset(token)
|
||||
Reference in New Issue
Block a user