teleo-infrastructure/scripts/collect_working_leo_production_preflight.py
twentyOne2x 0d70c09f6f
Some checks are pending
CI / lint-and-test (push) Waiting to run
Support VPS local preflight collection
2026-07-10 03:41:29 +02:00

281 lines
10 KiB
Python

#!/usr/bin/env python3
"""Collect live read-only production preflight output for the Working Leo packet.
This tool runs only the preflight SQL files from the authorized apply runbook.
It does not run apply, postflight, or rollback SQL. Before any SQL is sent to a
database, each file is statically checked for mutating SQL and then wrapped in a
Postgres read-only transaction. The intended use is to attach fresh row-level
preflight evidence to an operator receipt without crossing the production apply
authorization boundary.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import re
import subprocess
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
import build_working_leo_authorized_apply_runbook as runbook
REPO_REPORT_DIR = Path("docs/reports/leo-working-state-20260709")
DEFAULT_OUT = REPO_REPORT_DIR / "working-leo-production-preflight-current.json"
DEFAULT_MARKDOWN_OUT = REPO_REPORT_DIR / "working-leo-production-preflight-current.md"
DEFAULT_SSH_TARGET = "root@77.42.65.182"
DEFAULT_SSH_KEY = Path.home() / ".ssh/livingip_hetzner_20260604_ed25519"
FORBIDDEN_SQL_TOKENS = {
"alter",
"analyze",
"begin",
"call",
"cluster",
"commit",
"copy",
"create",
"delete",
"drop",
"execute",
"grant",
"insert",
"merge",
"refresh",
"reindex",
"revoke",
"rollback",
"truncate",
"update",
"vacuum",
}
def _sha256_text(text: str) -> str:
return hashlib.sha256(text.encode("utf-8")).hexdigest()
def _strip_sql_for_token_scan(sql: str) -> str:
without_block_comments = re.sub(r"/\*.*?\*/", " ", sql, flags=re.S)
without_line_comments = re.sub(r"--.*?$", " ", without_block_comments, flags=re.M)
without_strings = re.sub(r"'(?:''|[^'])*'", "''", without_line_comments)
without_meta = "\n".join(
line for line in without_strings.splitlines() if not line.lstrip().startswith("\\")
)
return without_meta
def forbidden_tokens(sql: str) -> list[str]:
scan = _strip_sql_for_token_scan(sql)
tokens = {match.group(0).lower() for match in re.finditer(r"\b[a-z_]+\b", scan, flags=re.I)}
return sorted(tokens & FORBIDDEN_SQL_TOKENS)
def readonly_sql(sql: str) -> str:
body_lines = [
line for line in sql.splitlines() if line.strip().lower() != r"\set on_error_stop on"
]
body = "\n".join(body_lines).strip()
return f"\\set ON_ERROR_STOP on\nbegin transaction read only;\n{body}\ncommit;\n"
def preflight_entries(report_dir: Path = REPO_REPORT_DIR) -> list[dict[str, Any]]:
generated = runbook.build_runbook(report_dir)
return generated["phases"]["preflight_order"]
def build_command(args: argparse.Namespace) -> list[str]:
docker_psql = f"docker exec -i {args.container} psql -U {args.db_user} -d {args.db} -v ON_ERROR_STOP=1 -P pager=off"
if args.transport == "local-docker":
return docker_psql.split()
return [
"ssh",
"-i",
str(args.ssh_key),
"-o",
"BatchMode=yes",
"-o",
"StrictHostKeyChecking=accept-new",
"-o",
f"ConnectTimeout={args.connect_timeout}",
args.ssh_target,
docker_psql,
]
def command_for_report(args: argparse.Namespace) -> str:
if args.transport == "local-docker":
return (
f"docker exec -i {args.container} psql -U {args.db_user} -d {args.db} "
"-v ON_ERROR_STOP=1 -P pager=off"
)
return (
"ssh -i [SSH_KEY] -o BatchMode=yes -o StrictHostKeyChecking=accept-new "
f"-o ConnectTimeout={args.connect_timeout} {args.ssh_target} "
f"'docker exec -i {args.container} psql -U {args.db_user} -d {args.db} "
"-v ON_ERROR_STOP=1 -P pager=off'"
)
def collect_preflight(args: argparse.Namespace) -> dict[str, Any]:
entries = preflight_entries(args.report_dir)
results: list[dict[str, Any]] = []
mode = "live_vps_readonly_preflight" if args.execute else "validated_not_executed"
command = build_command(args)
for index, entry in enumerate(entries, start=1):
path = args.report_dir / entry["file"]
sql = path.read_text(encoding="utf-8")
forbidden = forbidden_tokens(sql)
wrapped = readonly_sql(sql)
result: dict[str, Any] = {
"index": index,
"packet_id": entry["packet_id"],
"preflight_file": entry["file"],
"path": str(path),
"sql_sha256": _sha256_text(sql),
"readonly_sql_sha256": _sha256_text(wrapped),
"forbidden_tokens": forbidden,
"static_readonly_ok": not forbidden,
"executed": False,
"ok": False,
}
if forbidden:
result["error"] = "preflight SQL contains forbidden mutating or transaction token(s)"
results.append(result)
continue
if args.execute:
proc = subprocess.run(
command,
input=wrapped,
text=True,
capture_output=True,
timeout=args.timeout,
check=False,
)
result.update(
{
"executed": True,
"returncode": proc.returncode,
"stdout": proc.stdout,
"stderr": proc.stderr,
"ok": proc.returncode == 0,
}
)
else:
result.update({"ok": True, "stdout": "", "stderr": ""})
results.append(result)
status = "pass" if all(item["ok"] for item in results) else "fail"
return {
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
"mode": mode,
"status": status,
"execute_requested": args.execute,
"mutates_production_db": False,
"applies_production_packet": False,
"production_apply_executed": False,
"readonly_transaction_wrapper": True,
"ssh_target": args.ssh_target if args.execute else None,
"transport": args.transport,
"command_redacted": command_for_report(args) if args.execute else None,
"preflight_count": len(results),
"passes": sum(1 for item in results if item["ok"]),
"failures": [item for item in results if not item["ok"]],
"results": results,
"claim_ceiling": (
"This is read-only production preflight evidence. It can prove current row-level readiness or drift before "
"an apply window. It does not authorize production apply and does not prove canonical rows were changed."
),
}
def write_report(path: Path, report: dict[str, Any]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8")
def write_markdown(path: Path, report: dict[str, Any]) -> None:
lines = [
"# Working Leo Production Preflight",
"",
f"Generated UTC: `{report['generated_at_utc']}`",
f"Mode: `{report['mode']}`",
f"Status: `{report['status']}`",
f"Executed: `{report['execute_requested']}`",
f"Mutates production DB: `{report['mutates_production_db']}`",
f"Applies production packet: `{report['applies_production_packet']}`",
f"Production apply executed: `{report['production_apply_executed']}`",
f"Read-only transaction wrapper: `{report['readonly_transaction_wrapper']}`",
"",
"## Results",
"",
]
for item in report["results"]:
lines.append(
f"- `{item['packet_id']}` / `{item['preflight_file']}`: "
f"`ok={item['ok']}`, `executed={item['executed']}`, "
f"`forbidden_tokens={item['forbidden_tokens']}`"
)
if item.get("returncode") is not None:
lines.append(f" - returncode: `{item['returncode']}`")
stdout = (item.get("stdout") or "").strip()
stderr = (item.get("stderr") or "").strip()
if stdout:
lines.extend([" - stdout:", "", "```text", stdout, "```", ""])
if stderr:
lines.extend([" - stderr:", "", "```text", stderr, "```", ""])
lines.extend(["", "## Claim Ceiling", "", report["claim_ceiling"], ""])
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("\n".join(lines), encoding="utf-8")
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--report-dir", type=Path, default=REPO_REPORT_DIR)
parser.add_argument("--out", type=Path, default=DEFAULT_OUT)
parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MARKDOWN_OUT)
parser.add_argument("--execute", action="store_true", help="run the preflight SQL against the VPS")
parser.add_argument(
"--transport",
choices=["ssh", "local-docker"],
default="ssh",
help="Use ssh from an operator machine, or local-docker when already running on the VPS.",
)
parser.add_argument("--ssh-target", default=DEFAULT_SSH_TARGET)
parser.add_argument("--ssh-key", type=Path, default=DEFAULT_SSH_KEY)
parser.add_argument("--connect-timeout", type=int, default=15)
parser.add_argument("--timeout", type=int, default=120)
parser.add_argument("--container", default="teleo-pg")
parser.add_argument("--db-user", default="postgres")
parser.add_argument("--db", default="teleo")
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
report = collect_preflight(args)
write_report(args.out, report)
write_markdown(args.markdown_out, report)
print(
json.dumps(
{
"out": str(args.out),
"markdown_out": str(args.markdown_out),
"status": report["status"],
"execute_requested": report["execute_requested"],
"passes": report["passes"],
"preflight_count": report["preflight_count"],
},
indent=2,
sort_keys=True,
)
)
return 0 if report["status"] == "pass" else 1
if __name__ == "__main__":
raise SystemExit(main())