Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 2m53s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
171 lines
6.0 KiB
Python
171 lines
6.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Build the single P0-005 DR escrow evidence checklist."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
SCHEMA_VERSION = "awoooi_dr_escrow_evidence_checklist_v1"
|
|
OWNER_PACKET_SCHEMA = "awoooi_post_reboot_next_gate_owner_packets_v1"
|
|
OWNER_RESPONSE_SCHEMA = "awoooi_post_reboot_next_gate_owner_response_v1"
|
|
GATE_ID = "credential_escrow_evidence"
|
|
ITEMS = [
|
|
"restic_repository_password",
|
|
"offsite_provider_credentials",
|
|
"break_glass_admin_credentials",
|
|
"dns_registrar_recovery",
|
|
"oauth_ai_provider_recovery",
|
|
]
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(
|
|
description="Emit one no-secret checklist for the P0-005 DR escrow lane.",
|
|
)
|
|
parser.add_argument("--output", type=Path, help="Write JSON to this path.")
|
|
return parser.parse_args()
|
|
|
|
|
|
def evidence_item(item_id: str) -> dict[str, Any]:
|
|
return {
|
|
"item_id": item_id,
|
|
"required_fields": [
|
|
"non_secret_evidence_ref",
|
|
"recovery_owner",
|
|
"reviewer",
|
|
"last_reviewed_at",
|
|
"contains_secret_value=false",
|
|
],
|
|
"accepted_ref_classes": [
|
|
"password_manager_item_id",
|
|
"sealed_envelope_id",
|
|
"recovery_checklist_id",
|
|
"review_ticket_id",
|
|
],
|
|
"rejected_values": [
|
|
"passwords",
|
|
"tokens",
|
|
"private keys",
|
|
"recovery codes",
|
|
"secret URLs",
|
|
"session cookies",
|
|
],
|
|
"marker_dry_run_command": (
|
|
"/backup/scripts/mark-credential-escrow-verified.sh "
|
|
f"--item {item_id} --evidence-id <NON_SECRET_REF_FOR_{item_id}> --dry-run"
|
|
),
|
|
}
|
|
|
|
|
|
def owner_packet() -> dict[str, Any]:
|
|
return {
|
|
"schema_version": OWNER_PACKET_SCHEMA,
|
|
"source": {"next_required_gates": [GATE_ID]},
|
|
"owner_packets": [
|
|
{
|
|
"packet_id": GATE_ID,
|
|
"title": "P0-005 DR credential escrow evidence",
|
|
"priority": "P0",
|
|
"required_items": ITEMS,
|
|
}
|
|
],
|
|
}
|
|
|
|
|
|
def owner_response_skeleton() -> dict[str, Any]:
|
|
return {
|
|
"schema_version": OWNER_RESPONSE_SCHEMA,
|
|
"generated_at": datetime.now().astimezone().isoformat(timespec="seconds"),
|
|
"responses": [
|
|
{
|
|
"gate_id": GATE_ID,
|
|
"owner_role": "owner_role_here",
|
|
"owner_team": "owner_team_here",
|
|
"decision": "pending",
|
|
"decision_reason": "decision_reason_here",
|
|
"affected_scope": "P0-005 DR credential escrow evidence",
|
|
"redacted_evidence_refs": ["redacted_evidence_ref_here"],
|
|
"followup_owner": "followup_owner_here",
|
|
"runtime_action_requested": False,
|
|
"runtime_action_authorized": False,
|
|
"host_write_requested": False,
|
|
"host_write_authorized": False,
|
|
"secret_value_included": False,
|
|
"secret_value_collection_allowed": False,
|
|
"credential_marker_write_requested": False,
|
|
"credential_marker_write_authorized": False,
|
|
"escrow_items": [
|
|
{
|
|
"item_id": item_id,
|
|
"non_secret_evidence_ref": "non_secret_evidence_ref_here",
|
|
"recovery_owner": "owner_role_here",
|
|
"reviewer": "reviewer_here",
|
|
"last_reviewed_at": "pending",
|
|
"contains_secret_value": False,
|
|
}
|
|
for item_id in ITEMS
|
|
],
|
|
}
|
|
],
|
|
}
|
|
|
|
|
|
def build_payload() -> dict[str, Any]:
|
|
return {
|
|
"schema_version": SCHEMA_VERSION,
|
|
"generated_at": datetime.now().astimezone().isoformat(timespec="seconds"),
|
|
"workplan_id": "P0-005",
|
|
"status": "waiting_for_five_redacted_non_secret_evidence_refs",
|
|
"active_gate": GATE_ID,
|
|
"required_item_count": len(ITEMS),
|
|
"required_items": [evidence_item(item_id) for item_id in ITEMS],
|
|
"owner_packet": owner_packet(),
|
|
"owner_response_skeleton": owner_response_skeleton(),
|
|
"single_preflight_command": (
|
|
"python3 scripts/reboot-recovery/post-reboot-owner-response-preflight.py "
|
|
"--owner-packet-file <owner-packet.json> "
|
|
"--response-file <filled-owner-response.json> --json --no-color"
|
|
),
|
|
"scorecard_command": (
|
|
"python3 scripts/reboot-recovery/post-reboot-credential-escrow-intake-scorecard.py "
|
|
"--summary-file <summary.txt> --owner-packet-file <owner-packet.json> "
|
|
"--response-file <filled-owner-response.json> "
|
|
"--offsite-report-file <offsite-report.txt> "
|
|
"--escrow-status-file <escrow-status.txt> --json --no-color"
|
|
),
|
|
"exit_criteria": [
|
|
"preflight_status=ready_for_independent_reviewer_acceptance",
|
|
"owner_response_received_count=1",
|
|
"owner_response_accepted_count=1",
|
|
"forbidden_true_field_count=0",
|
|
"effective_escrow_missing_count=0 after marker dry-runs and accepted marker writes",
|
|
],
|
|
"execution_rules": [
|
|
"Use this as the only P0-005 intake packet.",
|
|
"Do not create per-item owner packets.",
|
|
"Do not include secret values in evidence refs.",
|
|
"Do not reopen cold-start or CI/CD while this checklist is pending.",
|
|
],
|
|
}
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
payload = build_payload()
|
|
text = json.dumps(payload, indent=2, ensure_ascii=False) + "\n"
|
|
if args.output:
|
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
args.output.write_text(text, encoding="utf-8")
|
|
else:
|
|
print(text, end="")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|