mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-11-14 02:08:18 +00:00
chore(p0): drop never-enabled hunter tools, test-only functions and receiver delivery
Off every active line (PATHFINDER-2026-10-13/03-unified-proposal.md, cuts). Deleted: the four hunter tools no caller enables (read_definition, entry_points, flows, obligations) with their schemas and dispatch, the dead mapping branch of find_refs; 20 functions whose only caller was one test (mapping task records, compute_ranking_metrics, build_quick_hunter_prompt, validate_evidence_transition, should_fuse, harness processors, rank_targets_with_model, model/report slice rendering, taxonomy hierarchical/related, config_value.verdict, taint.verdict, roles.load_roles, features.language_of and build_for_scan, folds.leave_one_*, features.recorded_case, search BatchExecutor and the three __main__ shims, delivery.put_input); the receiver delivery mode of the plane. push_inputs.py moved to benchmarks/push. memory.purge stays: the live-S3 test cleanup uses it. Net: 2,730 lines deleted, 207 added. 473 targeted tests passed; 3,282 tests collect. breadth.toml records the removals. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
f5a904b7f2
commit
f63703a604
@@ -15,12 +15,8 @@ from .findings import StaticFinding
|
||||
from .hunter_tools import (
|
||||
PathEscapesRepo,
|
||||
clamp_repo_path,
|
||||
entry_points,
|
||||
find_refs,
|
||||
flows,
|
||||
grep_repo,
|
||||
obligations,
|
||||
read_definition,
|
||||
read_file,
|
||||
)
|
||||
from .provider.openrouter import OpenRouterChatClient, OpenRouterError
|
||||
@@ -31,7 +27,6 @@ DEFAULT_MAX_STEPS = 4
|
||||
CLIENT_ENV = "OPENULTRASAST_HUNTER_CLIENT"
|
||||
_FINDING_ID_PREFIX = "tool-hunter:"
|
||||
DEFAULT_TOOL_NAMES = ("read_file", "grep_repo", "find_refs")
|
||||
_HUNTER_TOOL_NAMES = frozenset(DEFAULT_TOOL_NAMES) | {"read_definition", "entry_points", "flows", "obligations"}
|
||||
_SEVERITIES = frozenset({"critical", "high", "medium", "low", "info"})
|
||||
_SCRIPTED_FLAGS = frozenset({"scripted", "script"})
|
||||
_DUMP_FLAGS = frozenset({"dump", "dump-only"})
|
||||
@@ -91,50 +86,6 @@ HUNTER_TOOLS: list[dict[str, object]] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "read_definition",
|
||||
"description": "Resolve one named function to its file, line span and body. Use it instead of guessing what a callee does.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {"symbol": {"type": "string"}, "path": {"type": "string"}, "max_chars": {"type": "integer"}},
|
||||
"required": ["symbol"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "entry_points",
|
||||
"description": "List the handlers this repository exposes, with their access classification. Identifiers and line spans only.",
|
||||
"parameters": {"type": "object", "properties": {"path": {"type": "string"}}, "required": []},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "flows",
|
||||
"description": "List adjudicated source-to-sink records inside one function. Identifiers and line numbers only.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {"path": {"type": "string"}, "function": {"type": "string"}},
|
||||
"required": ["path", "function"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "obligations",
|
||||
"description": "List what one function owes and has not discharged: the operation, the missing discharger and why it is owed.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {"path": {"type": "string"}, "function": {"type": "string"}},
|
||||
"required": ["path", "function"],
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
_SYSTEM_PROMPT = (
|
||||
@@ -330,15 +281,13 @@ def run_tool_hunter(
|
||||
system_prompt: str = _SYSTEM_PROMPT,
|
||||
user_prompt: str | None = None,
|
||||
context_files: Sequence[str] = (),
|
||||
tools: Sequence[str] | None = None,
|
||||
max_chars: int = _DEFAULT_MAX_CHARS,
|
||||
tags: Sequence[str] = ("tool-hunter",),
|
||||
) -> list[StaticFinding]:
|
||||
"""One bounded hunt. Every keyword defaults to today's behaviour; a per-family detector overrides the
|
||||
prompt, the context it starts from, the tools it may call and the tags its findings carry."""
|
||||
"""One bounded hunt with a prompt, starting context and finding tags."""
|
||||
if max_steps <= 0:
|
||||
return []
|
||||
schemas = _tool_schemas(tools)
|
||||
schemas = HUNTER_TOOLS
|
||||
messages: list[dict[str, object]] = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": _user_message(root, hotspots, user_prompt, context_files, max_chars)},
|
||||
@@ -350,7 +299,7 @@ def run_tool_hunter(
|
||||
if tool_calls:
|
||||
messages.append(_assistant_tool_message(response.content, tool_calls, response.reasoning))
|
||||
for call in tool_calls:
|
||||
if call.name in _HUNTER_TOOL_NAMES:
|
||||
if call.name in DEFAULT_TOOL_NAMES:
|
||||
used_tools = True
|
||||
messages.append(_tool_result_message(root, call, max_chars))
|
||||
continue
|
||||
@@ -414,12 +363,6 @@ def _looks_like_json(content: str) -> bool:
|
||||
return stripped.startswith(("[", "{"))
|
||||
|
||||
|
||||
def _tool_schemas(names: Sequence[str] | None) -> list[dict[str, object]]:
|
||||
wanted = tuple(names) if names is not None else DEFAULT_TOOL_NAMES
|
||||
by_name = {str(schema["function"]["name"]): schema for schema in HUNTER_TOOLS} # type: ignore[index]
|
||||
return [by_name[name] for name in wanted if name in by_name]
|
||||
|
||||
|
||||
def _user_message(root: Path, hotspots: Sequence[Hotspot], user_prompt: str | None, context_files: Sequence[str], max_chars: int) -> str:
|
||||
# Context files FIRST, the question LAST. DeepSeek bills a cached prefix at 1/30 of a fresh one, and the cache
|
||||
# is by prefix: with the question first, every candidate in the same file broke the prefix at its first
|
||||
@@ -502,30 +445,13 @@ def _dispatch_tool(root: Path, name: str, arguments: Mapping[str, object], defau
|
||||
path = _require_str(arguments, "path")
|
||||
max_chars = _optional_int(arguments, "max_chars", default_max_chars)
|
||||
return {"path": path, "content": read_file(root, path, max_chars=max_chars)}
|
||||
if name == "read_definition":
|
||||
symbol = _require_str(arguments, "symbol")
|
||||
scope = arguments.get("path")
|
||||
found = read_definition(
|
||||
root,
|
||||
symbol,
|
||||
max_chars=_optional_int(arguments, "max_chars", default_max_chars),
|
||||
path=str(scope) if isinstance(scope, str) and scope else None,
|
||||
)
|
||||
return found if found is not None else {"symbol": symbol, "found": False}
|
||||
if name == "entry_points":
|
||||
scope = arguments.get("path")
|
||||
return entry_points(root, path=str(scope) if isinstance(scope, str) and scope else None)
|
||||
if name == "flows":
|
||||
return flows(root, path=_require_str(arguments, "path"), function=_require_str(arguments, "function"))
|
||||
if name == "obligations":
|
||||
return obligations(root, path=_require_str(arguments, "path"), function=_require_str(arguments, "function"))
|
||||
if name == "grep_repo":
|
||||
pattern = _require_str(arguments, "pattern")
|
||||
max_matches = _optional_int(arguments, "max_matches", _DEFAULT_MAX_MATCHES)
|
||||
return grep_repo(root, pattern, max_matches=max_matches)
|
||||
if name == "find_refs":
|
||||
symbol = _require_str(arguments, "symbol")
|
||||
return find_refs(root, symbol, None)
|
||||
return find_refs(root, symbol)
|
||||
raise ValueError(f"unknown tool: {name}")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user