121 lines
4.2 KiB
Python
121 lines
4.2 KiB
Python
"""Tests for repeated_workspace_violation throttle and signature."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from nanobot.utils.runtime import (
|
|
repeated_workspace_violation_error,
|
|
workspace_violation_signature,
|
|
)
|
|
|
|
|
|
def test_signature_for_filesystem_tools_uses_path_argument():
|
|
sig_a = workspace_violation_signature(
|
|
"read_file", {"path": "/Users/x/Downloads/01.md"}
|
|
)
|
|
sig_b = workspace_violation_signature(
|
|
"write_file", {"path": "/Users/x/Downloads/01.md"}
|
|
)
|
|
sig_c = workspace_violation_signature(
|
|
"edit_file", {"file_path": "/Users/x/Downloads/01.md"}
|
|
)
|
|
|
|
assert sig_a is not None
|
|
assert sig_a == sig_b == sig_c, (
|
|
"the throttle must collapse equivalent paths across different tools "
|
|
"so the LLM cannot bypass it by switching tool"
|
|
)
|
|
assert "/users/x/downloads/01.md" in sig_a
|
|
|
|
|
|
def test_signature_for_exec_extracts_first_absolute_path_in_command():
|
|
sig = workspace_violation_signature(
|
|
"exec",
|
|
{"command": "cat /Users/x/Downloads/01.md && echo done"},
|
|
)
|
|
assert sig is not None
|
|
assert "/users/x/downloads/01.md" in sig
|
|
|
|
|
|
def test_signature_collides_across_filesystem_and_exec_for_same_target():
|
|
"""LLM bypass loops jump tools (read_file -> exec cat). Throttle must
|
|
treat both attempts as targeting the same outside resource."""
|
|
fs_sig = workspace_violation_signature(
|
|
"read_file", {"path": "/Users/x/Downloads/01.md"}
|
|
)
|
|
exec_sig = workspace_violation_signature(
|
|
"exec", {"command": "cat /Users/x/Downloads/01.md"}
|
|
)
|
|
assert fs_sig == exec_sig
|
|
|
|
|
|
def test_signature_falls_back_to_working_dir_when_no_absolute_in_command():
|
|
sig = workspace_violation_signature(
|
|
"exec",
|
|
{"command": "ls -la", "working_dir": "/etc"},
|
|
)
|
|
assert sig is not None
|
|
assert "/etc" in sig
|
|
|
|
|
|
def test_signature_is_none_for_unknown_tool_with_no_path():
|
|
assert workspace_violation_signature("web_search", {"query": "anything"}) is None
|
|
assert workspace_violation_signature("exec", {"command": "echo hello"}) is None
|
|
|
|
|
|
def test_repeated_workspace_violation_returns_none_within_budget():
|
|
counts: dict[str, int] = {}
|
|
arguments = {"path": "/Users/x/Downloads/01.md"}
|
|
|
|
assert repeated_workspace_violation_error("read_file", arguments, counts) is None
|
|
assert repeated_workspace_violation_error("read_file", arguments, counts) is None
|
|
|
|
|
|
def test_repeated_workspace_violation_escalates_after_third_attempt():
|
|
counts: dict[str, int] = {}
|
|
arguments = {"path": "/Users/x/Downloads/01.md"}
|
|
|
|
repeated_workspace_violation_error("read_file", arguments, counts)
|
|
repeated_workspace_violation_error("read_file", arguments, counts)
|
|
third = repeated_workspace_violation_error("read_file", arguments, counts)
|
|
|
|
assert third is not None
|
|
assert "refusing repeated workspace-bypass" in third
|
|
assert "/users/x/downloads/01.md" in third
|
|
assert "ask how they want to proceed" in third
|
|
|
|
|
|
def test_repeated_workspace_violation_independent_per_target():
|
|
"""Different outside paths must each get their own retry budget."""
|
|
counts: dict[str, int] = {}
|
|
|
|
repeated_workspace_violation_error(
|
|
"read_file", {"path": "/Users/x/Downloads/01.md"}, counts,
|
|
)
|
|
repeated_workspace_violation_error(
|
|
"read_file", {"path": "/Users/x/Downloads/01.md"}, counts,
|
|
)
|
|
# Different target, fresh budget.
|
|
assert repeated_workspace_violation_error(
|
|
"read_file", {"path": "/Users/x/Documents/notes.md"}, counts,
|
|
) is None
|
|
|
|
|
|
def test_repeated_workspace_violation_collapses_tool_switching():
|
|
"""LLM switches from read_file to exec cat then to python -c open(...)
|
|
against the same path; the throttle must escalate on the third attempt."""
|
|
counts: dict[str, int] = {}
|
|
|
|
repeated_workspace_violation_error(
|
|
"read_file", {"path": "/Users/x/Downloads/01.md"}, counts,
|
|
)
|
|
repeated_workspace_violation_error(
|
|
"exec", {"command": "cat /Users/x/Downloads/01.md"}, counts,
|
|
)
|
|
third = repeated_workspace_violation_error(
|
|
"exec",
|
|
{"command": "python3 -c \"open('/Users/x/Downloads/01.md').read()\""},
|
|
counts,
|
|
)
|
|
assert third is not None
|
|
assert "refusing repeated workspace-bypass" in third
|