Files
claude-plugin/plugins/reviews/skills/audit-code/tests/test_slicing.py
T
mroberts 37fc3fb291 Fix audit tool bootstrap and add per-run preflight
audit-code install-tools.sh:
- Buffer the opengrep release JSON before grep -m1; curl died with (23)
  under pipefail when grep quit early.
- Use ${m}: in the PowerShell block; $m: parsed as a scope-qualified var.
- On Arch, skip paru/yay when pacman -Q shows every package installed,
  since --needed still invokes sudo.
- Add --check-only (fast, installs nothing, non-zero naming missing tools)
  and --user-only (no system package managers, no sudo).

log-run.py (both skills): put the skill dir on sys.path so running it as
a script from any cwd no longer raises ModuleNotFoundError.

audit-terraform: move deps from requirements.txt into pyproject
dependency groups and add scripts/install-tools.sh (uv sync --group tools,
then check trivy, tflint, tofu, terragrunt, gh).

Both SKILL.md files gain a 0.5 Preflight step and call scripts through
uv run --project ${SKILL_DIR}. tools_unavailable is now a map of tool to
exact install command; audit-terraform skips trivy when absent and stops
with an install hint instead of crashing when tofu/terragrunt is missing.
2026-09-22 15:21:28 -05:00

190 lines
8.4 KiB
Python

from scripts.slicing import slice_for_agent
def _manifest_dict():
return {
"mode": "local",
"base_ref": "origin/main",
"head_ref": "HEAD",
"default_branch": "main",
"language_breakdown": {"python": 1, "javascript": 0, "typescript": 0, "csharp": 0, "skipped_files": []},
"changed_files": [{"path": "src/api.py", "language": "python", "added_lines": [[10, 15]]}],
"findings": [
{"tool": "bandit", "rule_id": "B608", "severity": "high", "file": "src/api.py", "line": 12, "end_line": 12, "message": "sqlinj"},
{"tool": "mypy", "rule_id": "arg-type", "severity": "medium", "file": "src/api.py", "line": 14, "end_line": 14, "message": "type"},
{"tool": "gitleaks", "rule_id": "aws-token", "severity": "critical", "file": "src/api.py", "line": 11, "end_line": 11, "message": "leak"},
{"tool": "pip-audit", "rule_id": "GHSA-x", "severity": "high", "file": "requirements.txt", "line": 1, "end_line": 1, "message": "vuln"},
{"tool": "opengrep", "rule_id": "py.dangerous","severity": "high", "file": "src/api.py", "line": 13, "end_line": 13, "message": "dangerous"},
{"tool": "ruff", "rule_id": "S102", "severity": "high", "file": "src/api.py", "line": 10, "end_line": 10, "message": "issue"},
{"tool": "ruff-idiom", "rule_id": "SIM102", "severity": "low", "file": "src/api.py", "line": 20, "end_line": 20, "message": "collapsible-if"},
],
"package_diffs": {"python": {"added": [], "removed": [], "upgraded": []}},
"tool_stats": {},
"tools_unavailable": {},
"errors": [],
}
def test_security_slice_only_security_tools():
sliced = slice_for_agent(_manifest_dict(), "security-triage")
tools = {f["tool"] for f in sliced["findings"]}
assert tools == {"bandit", "opengrep", "ruff"}
def test_type_safety_slice_only_type_tools():
sliced = slice_for_agent(_manifest_dict(), "type-safety")
tools = {f["tool"] for f in sliced["findings"]}
assert tools == {"mypy"}
def test_dependency_slice_includes_dep_tools_and_diffs():
sliced = slice_for_agent(_manifest_dict(), "dependency")
tools = {f["tool"] for f in sliced["findings"]}
assert tools == {"pip-audit"}
assert "package_diffs" in sliced
def test_secrets_slice_only_gitleaks():
sliced = slice_for_agent(_manifest_dict(), "secrets")
tools = {f["tool"] for f in sliced["findings"]}
assert tools == {"gitleaks"}
def test_consistency_slice_excludes_non_idiom_tools():
sliced = slice_for_agent(_manifest_dict(), "consistency")
tools = {f["tool"] for f in sliced["findings"]}
non_idiom = {"bandit", "mypy", "gitleaks", "pip-audit", "opengrep", "ruff"}
assert tools & non_idiom == set()
assert "changed_files" in sliced
def test_consistency_slice_includes_ruff_idiom():
sliced = slice_for_agent(_manifest_dict(), "consistency")
tools = {f["tool"] for f in sliced["findings"]}
assert tools == {"ruff-idiom"}
rule_ids = {f["rule_id"] for f in sliced["findings"]}
assert "SIM102" in rule_ids
def test_security_slice_excludes_ruff_idiom():
sliced = slice_for_agent(_manifest_dict(), "security-triage")
tools = {f["tool"] for f in sliced["findings"]}
assert "ruff-idiom" not in tools
assert tools == {"bandit", "opengrep", "ruff"}
def _manifest_with_lua_gha():
"""Manifest with selene, luac, actionlint, and zizmor findings."""
return {
"mode": "local",
"base_ref": "origin/main",
"head_ref": "HEAD",
"default_branch": "main",
"language_breakdown": {
"python": 0, "javascript": 0, "typescript": 0, "csharp": 0,
"lua": 1, "github_actions": 1, "skipped_files": [],
},
"changed_files": [
{"path": "src/game.lua", "language": "lua", "added_lines": [[5, 10]]},
{"path": ".github/workflows/ci.yml", "language": "github-actions", "added_lines": [[12, 12]]},
],
"findings": [
{"tool": "selene", "rule_id": "undefined_variable", "severity": "high", "file": "src/game.lua", "line": 5, "end_line": 5, "message": "undefined var"},
{"tool": "luac", "rule_id": "syntax-error", "severity": "critical","file": "src/game.lua", "line": 8, "end_line": 8, "message": "syntax error"},
{"tool": "actionlint", "rule_id": "expression", "severity": "high", "file": ".github/workflows/ci.yml", "line": 12, "end_line": 12, "message": "bad expr"},
{"tool": "zizmor", "rule_id": "unpinned-uses", "severity": "medium", "file": ".github/workflows/ci.yml", "line": 15, "end_line": 15, "message": "unpin"},
],
"package_diffs": {},
"tool_stats": {},
"tools_unavailable": {},
"errors": [],
}
def test_gha_reviewer_slice_only_gha_tools():
sliced = slice_for_agent(_manifest_with_lua_gha(), "gha-reviewer")
tools = {f["tool"] for f in sliced["findings"]}
assert tools == {"actionlint", "zizmor"}
def test_gha_reviewer_slice_excludes_lua_tools():
sliced = slice_for_agent(_manifest_with_lua_gha(), "gha-reviewer")
tools = {f["tool"] for f in sliced["findings"]}
assert "selene" not in tools
assert "luac" not in tools
def test_selene_routes_to_maintainability():
sliced = slice_for_agent(_manifest_with_lua_gha(), "maintainability")
tools = {f["tool"] for f in sliced["findings"]}
assert "selene" in tools
def test_luac_routes_to_security_triage():
sliced = slice_for_agent(_manifest_with_lua_gha(), "security-triage")
tools = {f["tool"] for f in sliced["findings"]}
assert "luac" in tools
def test_luac_routes_to_maintainability():
sliced = slice_for_agent(_manifest_with_lua_gha(), "maintainability")
tools = {f["tool"] for f in sliced["findings"]}
assert "luac" in tools
def test_security_triage_excludes_gha_tools():
sliced = slice_for_agent(_manifest_with_lua_gha(), "security-triage")
tools = {f["tool"] for f in sliced["findings"]}
assert "actionlint" not in tools
assert "zizmor" not in tools
def _manifest_with_powershell():
"""Manifest with psscriptanalyzer (security + style rules) and injectionhunter."""
return {
"mode": "local",
"base_ref": "origin/main",
"head_ref": "HEAD",
"default_branch": "main",
"language_breakdown": {
"python": 0, "javascript": 0, "typescript": 0, "csharp": 0,
"lua": 0, "powershell": 1, "github_actions": 0, "skipped_files": [],
},
"changed_files": [
{"path": "scripts/Deploy.ps1", "language": "powershell", "added_lines": [[10, 40]]},
],
"findings": [
{"tool": "psscriptanalyzer", "rule_id": "PSAvoidUsingInvokeExpression", "severity": "medium", "file": "scripts/Deploy.ps1", "line": 12, "end_line": 12, "message": "iex"},
{"tool": "psscriptanalyzer", "rule_id": "PSAvoidUsingWriteHost", "severity": "medium", "file": "scripts/Deploy.ps1", "line": 5, "end_line": 5, "message": "write-host"},
{"tool": "injectionhunter", "rule_id": "InjectionRisk.InvokeExpression","severity": "high", "file": "scripts/Deploy.ps1", "line": 12, "end_line": 12, "message": "injection"},
],
"package_diffs": {},
"tool_stats": {},
"tools_unavailable": {},
"errors": [],
}
def test_injectionhunter_routes_to_security_triage():
sliced = slice_for_agent(_manifest_with_powershell(), "security-triage")
tools = {f["tool"] for f in sliced["findings"]}
assert "injectionhunter" in tools
def test_psscriptanalyzer_security_rules_route_to_security_triage():
sliced = slice_for_agent(_manifest_with_powershell(), "security-triage")
rules = {f["rule_id"] for f in sliced["findings"] if f["tool"] == "psscriptanalyzer"}
assert rules == {"PSAvoidUsingInvokeExpression"}
def test_psscriptanalyzer_style_rules_route_to_maintainability():
sliced = slice_for_agent(_manifest_with_powershell(), "maintainability")
rules = {f["rule_id"] for f in sliced["findings"] if f["tool"] == "psscriptanalyzer"}
assert rules == {"PSAvoidUsingWriteHost"}
def test_maintainability_excludes_injectionhunter():
sliced = slice_for_agent(_manifest_with_powershell(), "maintainability")
tools = {f["tool"] for f in sliced["findings"]}
assert "injectionhunter" not in tools