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.
This commit is contained in:
2026-09-22 15:21:28 -05:00
parent d3258b224a
commit 37fc3fb291
30 changed files with 1045 additions and 84 deletions
@@ -4,6 +4,7 @@ from __future__ import annotations
import argparse
import concurrent.futures as cf
import json
import shutil
import subprocess
import sys
from pathlib import Path
@@ -32,6 +33,13 @@ from scripts.source_lookup import find_block
_PLAN_CONCURRENCY = 8
_INSTALL_COMMANDS = {
"trivy": "go install github.com/aquasecurity/trivy/cmd/trivy@latest",
"tflint": "go install github.com/terraform-linters/tflint@latest",
"tofu": "go install github.com/opentofu/opentofu/cmd/tofu@latest",
"terragrunt": "go install github.com/gruntwork-io/terragrunt@latest",
}
def _resolve_default_branch(repo: Path) -> str:
try:
@@ -197,6 +205,28 @@ def main(argv: list[str] | None = None) -> int:
for orphan in orphan_modules:
errors.append(f"module has no callsites; diff-only review: {orphan}")
plan_tools = sorted({detect_tool(repo / pd) for pd in plan_units_map})
tools_unavailable = {
t: _INSTALL_COMMANDS[t] for t in ("trivy", "tflint", *plan_tools)
if shutil.which(t) is None
}
missing_plan_tools = [t for t in plan_tools if t in tools_unavailable]
if missing_plan_tools:
manifest = Manifest(
base_ref=base, head_ref=args.head, mode=args.mode,
default_branch=default_branch,
changed_source_dirs=sorted(dirs), plan_units=[], catalog=[],
trivy_findings=[], module_graph=module_graph,
errors=[
f"{t} is not installed, so the changed units cannot be planned. "
f"Install it with `{tools_unavailable[t]}` and re-run."
for t in missing_plan_tools
],
tools_unavailable=tools_unavailable,
)
(out_dir / "manifest.json").write_text(manifest.to_json())
return 1
plan_hits: dict[str, list[PlanHit]] = {}
plan_unit_records: list[PlanUnit] = []
@@ -250,7 +280,9 @@ def main(argv: list[str] | None = None) -> int:
f"terragrunt change has no planned unit context: {terragrunt_file}"
)
trivy_payload, trivy_findings, trivy_error = _run_trivy_config(repo, files)
trivy_payload, trivy_findings, trivy_error = (
({}, [], None) if "trivy" in tools_unavailable else _run_trivy_config(repo, files)
)
(out_dir / "trivy-findings.json").write_text(json.dumps(trivy_payload, indent=2))
if trivy_error:
errors.append(trivy_error)
@@ -293,6 +325,7 @@ def main(argv: list[str] | None = None) -> int:
tflint_findings=tflint_findings,
module_graph=module_graph,
errors=errors,
tools_unavailable=tools_unavailable,
)
(out_dir / "manifest.json").write_text(manifest.to_json())
manifest_dict = manifest.to_dict()