emergent-security/tools/probe_pilot.py
tegwick 4c6fda3829 Gate knowledge probes on current sources and qualify blocked dependencies
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1046e-4817-7f02-b732-e219136e037a
2026-10-04 11:32:30 +02:00

89 lines
4.9 KiB
Python

#!/usr/bin/env python3
"""Read-only Claude probe from an actual pilot checkout; no production effects."""
from pathlib import Path
import argparse
from datetime import datetime, timezone
import json
import os
import subprocess
import sys
import tempfile
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from emergent_security.knowledge import Knowledge
from probe_provider import extract_json, unwrap_response, source_preflight, write_report
SCENARIOS = {
"net-kingdom": ("compatibility", "The old generic canon calls Gate House a broker. Explain the current owner mapping and how the reference evaluator relates to live authorization."),
"ops-warden": ("access", "A coding agent needs a scoped credential. Explain discovery, when warden plan is required before founder steps, and why a readable broader token is insufficient."),
"tenant-engine": ("tenant", "A tenant admin wants to approve beyond the platform envelope. Explain the next recipient and what this engine can decide."),
"railiance-master": ("deployment", "A local test passed in build mode. Explain whether a live production change can proceed and who must decide."),
}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("repo", choices=SCENARIOS)
parser.add_argument("--root", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()
package = Knowledge(ROOT / "knowledge")
card, question = SCENARIOS[args.repo]
preflight = source_preflight(package, args.root, "claude", ("start", card))
report = {"schema": "emergent.repository-pilot.v1", "repository": args.repo,
"provider": "claude", "timestamp": datetime.now(timezone.utc).isoformat(),
"package_version": package.catalog["version"], "package_digest": package.package_digest,
"source_status": preflight["cards"][card], "source_preflight": preflight,
"scope": "read-only scenario in actual repository", "status": "unverified"}
if not preflight["ok"]:
report["status"] = "source-withheld"
write_report(args.output, report)
return 2
repo = args.root / args.repo
schema = {"type": "object", "additionalProperties": False,
"properties": {"package_version": {"type": "string"},
"answers": {"type": "array", "items": {"type": "object", "additionalProperties": False,
"properties": {key: {"type": "string"} for key in ("card", "source_path", "route", "reason")},
"required": ["card", "source_path", "route", "reason"]}}},
"required": ["package_version", "answers"]}
prompt = (
"This is a read-only situational knowledge pilot. Do not perform operational work, "
"write records, contact services or read credentials. Follow the new orientation "
"pilot pointer in the repository instructions; read the shared start and relevant "
"task card and knowledge/catalog.yaml and knowledge/release.yaml from the sibling "
"emergent-security checkout (sources are indexed in knowledge/sources.yaml). "
"The supervising runner verified the relevant source digests. Answer this scenario: "
+ question + " Return only JSON with package_version and answers containing one "
"object with card, source_path (shared card path actually read), route (actual "
"next recipient, including a human role where appropriate), and reason."
)
command = ["claude", "-p", "--tools", "Read", "--add-dir", str(ROOT),
"--permission-mode", "default", "--no-session-persistence", "--max-budget-usd", "2",
"--output-format", "json", "--json-schema", json.dumps(schema), prompt]
try:
run = subprocess.run(command, cwd=repo, capture_output=True, text=True, timeout=180)
raw_dir = Path(tempfile.mkdtemp(prefix="emergent-pilot-"))
for name, content in [("stdout", run.stdout), ("stderr", run.stderr)]:
path = raw_dir / name
path.write_text(content)
os.chmod(path, 0o600)
report["exit_code"] = run.returncode
if run.returncode:
report["status"] = "client-failed"
else:
answer, metadata = unwrap_response(extract_json(run.stdout))
report.update(metadata)
report["answers"] = answer["answers"]
report["version_correct"] = answer.get("package_version") == package.catalog["version"]
report["status"] = "awaiting-semantic-review"
except subprocess.TimeoutExpired:
report["status"] = "timeout"
except (OSError, ValueError, TypeError):
report["status"] = "client-output-unusable"
write_report(args.output, report)
return 0 if report["status"] == "awaiting-semantic-review" else 2
if __name__ == "__main__":
raise SystemExit(main())