security-review/cross_review.py

140 lines
4.7 KiB
Python
Raw Permalink Normal View History

feat: re-home cross-family reviewer CLI, retire Path B host artifacts (#5) * feat: add router-less cross-family reviewer CLI (cross_review.py) Re-homes the archived orchestrator repo's GPT-4.1 cross_reviewer as a direct OpenAI SDK CLI: verbatim system prompt, same model id, ported 3-attempt exponential-backoff retry. Reads OPENAI_API_KEY from the environment or the gitignored repo-root .env. Lazy openai import so --help works without the package. * feat: create machine-level suppressions dir on --global hook install install-hooks.sh --global now mkdir -p's ${SH_SECURITY_SUPPRESSIONS_DIR:-~/.config/sea-haven/security-review} and states the convention: machine-level <dir>/<repo-basename>/suppressions.json is preferred over repo-local .security-review/suppressions.json, with review.sh merging both when run without --suppressions. * docs: describe sh-build-review as cross-family GPT-4.1 pass via cross_review.py * chore: retire Path B VM host artifacts, repoint xmodel hook to cross_review.py - delete systemd/ units and DEPLOY-R720.md (VM destroyed; recoverable from git history) - nightly_sweep.sh: retained for reference — header notes the VM-based Path B sweep is retired; ENABLE_XMODEL_HOOK now calls this repo's cross_review.py instead of the archived orchestrator's run.py - sweep-targets.txt: drop the stale ~/orchestrator warning block - README: document the Claude Code web cloud routines (repo-scanner-nightly-sweep 08:00 ET, repo-checkers-plane1 07:30 ET, ALARM-only to #repo-scanner) and add the cross_review.py section * docs(iam): repoint cross-family review invocations to cross_review.py * fix(ci): exclude canary corpus from ruff, add import smoke test CI has been red repo-wide: the latest ruff wants to reformat the intentionally-vulnerable canary fixtures (whose line numbers are keyed in canary-meta/KEY.md), and pytest --collect-only exits 5 with zero tests. Exclude canary/ via ruff.toml and add a root-level import smoke test so collection is non-empty and imports cross_review.py.
2026-07-14 19:24:01 -04:00
#!/usr/bin/env python3
"""cross_review.py — Sea Haven cross-family (GPT-4.1) review CLI.
Re-homed from the archived Sea-Haven-Industries/orchestrator repo's
`cross_reviewer` agent. Router-less: one direct OpenAI SDK call, no langchain,
no routing logic. This is the mandatory cross-family reviewer for IAM/policy
and Lambda-handler-signature changes, and the reasoning backend for the
sh-plan-review / sh-security-audit / sh-build-review gates.
Usage:
python3 cross_review.py "Review this diff for breaking changes: <diff>"
Auth: reads OPENAI_API_KEY from the environment, falling back to the
gitignored .env at the repo root. Never prints the key.
"""
import argparse
import os
import random
import sys
import time
# Model ID — single source of truth (ported from orchestrator/models.py).
DEFAULT_MODEL = "gpt-4.1"
TEMPERATURE = 0.2
MAX_ATTEMPTS = 3
# System prompt ported verbatim from the orchestrator's cross_reviewer agent
# (orchestrator/agents.py, CROSS_REVIEWER_PROMPT).
CROSS_REVIEWER_PROMPT = """You are a cross-family code review agent. You provide an independent review perspective.
Review the provided code for bugs, security issues, and improvements.
Categorize findings as BLOCK, FIX, or NIT. Be concise.
Focus on issues that might be missed by the primary development team."""
def load_api_key() -> str:
"""OPENAI_API_KEY from the environment, else hand-parsed from repo-root .env."""
key = os.environ.get("OPENAI_API_KEY")
if key:
return key
env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env")
try:
with open(env_path, encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
name, _, value = line.partition("=")
if name.strip() == "OPENAI_API_KEY":
return value.strip().strip("'\"")
except OSError:
pass
return ""
def run_review(task: str, model: str, api_key: str) -> str:
"""One review call with retries on transient API errors (3 attempts,
exponential backoff with jitter — ported from orchestrator/models.py
with_retries)."""
# Lazy import so --help works without the openai package installed.
import openai
retriable = (
openai.APIConnectionError,
openai.RateLimitError,
openai.InternalServerError,
)
client = openai.OpenAI(api_key=api_key)
for attempt in range(1, MAX_ATTEMPTS + 1):
try:
response = client.chat.completions.create(
model=model,
temperature=TEMPERATURE,
messages=[
{"role": "system", "content": CROSS_REVIEWER_PROMPT},
{"role": "user", "content": task},
],
)
content = response.choices[0].message.content
if not content:
raise RuntimeError("model returned an empty review")
return content
except retriable as exc:
if attempt == MAX_ATTEMPTS:
raise
delay = (2 ** (attempt - 1)) + random.uniform(0, 1)
print(
f"cross_review: transient API error ({type(exc).__name__}), "
f"retrying in {delay:.1f}s (attempt {attempt}/{MAX_ATTEMPTS})",
file=sys.stderr,
)
time.sleep(delay)
raise RuntimeError("unreachable")
def main() -> int:
parser = argparse.ArgumentParser(
description=(
"Cross-family GPT-4.1 review (direct OpenAI SDK, no router). "
"Mandatory for IAM/policy and Lambda-handler-signature changes."
)
)
parser.add_argument("task", help="review task: a diff, change description, or plan")
parser.add_argument(
"--model",
default=DEFAULT_MODEL,
help=f"OpenAI model id (default: {DEFAULT_MODEL})",
)
args = parser.parse_args()
api_key = load_api_key()
if not api_key:
print(
"cross_review: OPENAI_API_KEY not set and not found in repo-root .env",
file=sys.stderr,
)
return 2
try:
review = run_review(args.task, args.model, api_key)
except ImportError:
print(
"cross_review: the 'openai' package is not installed "
"(pip install -r requirements.txt)",
file=sys.stderr,
)
return 2
except Exception as exc: # noqa: BLE001 — CLI boundary: report and exit nonzero
print(
f"cross_review: review failed: {type(exc).__name__}: {exc}", file=sys.stderr
)
return 1
print(review)
return 0
if __name__ == "__main__":
sys.exit(main())