45 lines
1.6 KiB
Python
Executable file
45 lines
1.6 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Fail closed when reef admission evidence is stale or over-promoted."""
|
|
|
|
import argparse
|
|
import datetime as dt
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
def assess(record: dict, now: dt.datetime, max_age_hours: int) -> list[str]:
|
|
failures = []
|
|
checked = dt.datetime.fromisoformat(record["checked_at"].replace("Z", "+00:00"))
|
|
if now - checked > dt.timedelta(hours=max_age_hours):
|
|
failures.append("evidence is stale")
|
|
if checked > now + dt.timedelta(minutes=5):
|
|
failures.append("checked_at is in the future")
|
|
if record["readiness_state"] == "production-approved":
|
|
bad = [
|
|
name
|
|
for name, check in record["checks"].items()
|
|
if check["status"] != "pass"
|
|
]
|
|
if bad:
|
|
failures.append("production approval has non-passing checks: " + ", ".join(bad))
|
|
open_risks = [
|
|
risk["risk"] for risk in record["residual_risks"] if risk["status"] == "open"
|
|
]
|
|
if open_risks:
|
|
failures.append("production approval has open residual risks")
|
|
return failures
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("evidence", type=Path)
|
|
parser.add_argument("--max-age-hours", type=int, default=24)
|
|
args = parser.parse_args()
|
|
record = json.loads(args.evidence.read_text())
|
|
failures = assess(record, dt.datetime.now(dt.timezone.utc), args.max_age_hours)
|
|
print(json.dumps({"evidence": str(args.evidence), "pass": not failures, "failures": failures}))
|
|
return bool(failures)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|