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.
87 lines
3.0 KiB
Python
87 lines
3.0 KiB
Python
"""Append one subagent_run row per agent after the fan-out completes.
|
|
|
|
The orchestrator calls this once after all subagents return. It scans
|
|
<output-dir>/findings-<agent>.json for each agent listed in the
|
|
--usage-json payload, counts findings, and writes a subagent_run row to
|
|
runs.jsonl using token / duration metadata supplied by the orchestrator.
|
|
|
|
Usage:
|
|
|
|
python scripts/log-run.py \\
|
|
--output-dir <OUTPUT> --run-id <hex> --repo <path> --mode <local|ref> \\
|
|
--usage-json - <<JSON
|
|
{
|
|
"walkthrough-reviewer": {"model":"sonnet","input_tokens":1234,"output_tokens":567,"duration_ms":4500},
|
|
"aws-bp-reviewer": {"model":"sonnet","input_tokens":2345,"output_tokens":678,"duration_ms":5200}
|
|
}
|
|
JSON
|
|
|
|
`--log-path` defaults to ~/.claude/cache/audit-terraform/runs.jsonl.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
|
|
from scripts.telemetry import append_subagent_run
|
|
|
|
_DEFAULT_LOG = Path.home() / ".claude/cache/audit-terraform/runs.jsonl"
|
|
|
|
|
|
def _count_findings(path: Path) -> int:
|
|
if not path.exists():
|
|
return 0
|
|
try:
|
|
data = json.loads(path.read_text(encoding="utf-8"))
|
|
except json.JSONDecodeError:
|
|
return 0
|
|
if isinstance(data, dict):
|
|
findings = data.get("findings")
|
|
if isinstance(findings, list):
|
|
return len(findings)
|
|
elif isinstance(data, list):
|
|
return len(data)
|
|
return 0
|
|
|
|
|
|
def main(argv: list[str]) -> int:
|
|
p = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
p.add_argument("--output-dir", required=True, type=Path)
|
|
p.add_argument("--run-id", required=True)
|
|
p.add_argument("--repo", required=True)
|
|
p.add_argument("--mode", required=True, choices=["local", "ref"])
|
|
p.add_argument("--log-path", type=Path, default=_DEFAULT_LOG)
|
|
p.add_argument("--usage-json", required=True,
|
|
help="Path to JSON file, or '-' for stdin.")
|
|
args = p.parse_args(argv)
|
|
|
|
raw = sys.stdin.read() if args.usage_json == "-" else Path(args.usage_json).read_text(encoding="utf-8")
|
|
usage = json.loads(raw)
|
|
if not isinstance(usage, dict):
|
|
print("usage-json must be a JSON object keyed by agent name", file=sys.stderr)
|
|
return 2
|
|
|
|
for agent, meta in usage.items():
|
|
if not isinstance(meta, dict):
|
|
print(f"skipping {agent}: usage entry not an object", file=sys.stderr)
|
|
continue
|
|
findings_path = args.output_dir / f"findings-{agent}.json"
|
|
append_subagent_run(
|
|
args.log_path,
|
|
run_id=args.run_id, repo=args.repo, mode=args.mode, agent=agent,
|
|
model=str(meta.get("model", "?")),
|
|
input_tokens=int(meta.get("input_tokens", 0)),
|
|
output_tokens=int(meta.get("output_tokens", 0)),
|
|
duration_ms=int(meta.get("duration_ms", 0)),
|
|
finding_count=_count_findings(findings_path),
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main(sys.argv[1:]))
|