#!/usr/bin/env python3 """ IwoooS 高價值配置 owner request 草稿包產生器。 本工具讀取 owner packet intake preflight snapshot,產生可人工送件前核對 的 request draft 與 handoff envelope。它不送件、不確認收件人、不建立 audit event、不寫 reviewer queue、不開 runtime gate。 """ from __future__ import annotations import argparse import json import subprocess import sys from datetime import datetime, timedelta, timezone from pathlib import Path from typing import Any TAIPEI = timezone(timedelta(hours=8)) HANDOFF_ENVELOPE_FIELDS = [ "request_id", "stage_id", "packet_id", "recipient_role_or_team", "sender_role_or_team", "requested_response_window", "allowed_response_format", "redacted_evidence_refs", "forbidden_payloads", "followup_owner", "not_approval", ] FORBIDDEN_PAYLOADS = [ "token", "secret", "private_key", "cookie", "session", "authorization_header", "runner_token", "webhook_secret", "db_dump", "repo_archive", "git_object_pack", "raw_sensitive_live_config", ] NOT_APPROVAL_STATEMENT = ( "本草稿不是 request sent、不是 owner response received、不是 reviewer accepted、" "不是 Nginx reload、DNS / TLS change、workflow 修改、host write、active scan、" "production write 或 runtime gate 授權。" ) def git_short_sha(root: Path) -> str: try: result = subprocess.run( ["git", "rev-parse", "--short", "HEAD"], cwd=root, check=True, capture_output=True, text=True, ) return result.stdout.strip() except Exception: return "unknown" def load_json(path: Path) -> dict[str, Any]: return json.loads(path.read_text(encoding="utf-8")) def request_id_for(packet: dict[str, Any]) -> str: return packet["packet_id"].replace("high_value_config_owner_packet:", "high_value_config_owner_request:") def request_draft(packet: dict[str, Any], intake_report: dict[str, Any]) -> dict[str, Any]: request_id = request_id_for(packet) return { "request_id": request_id, "status": "draft_not_dispatched", "stage_id": "P0-14", "packet_id": packet["packet_id"], "category_id": packet["category_id"], "label": packet["label"], "priority": packet["priority"], "control_tier": packet["control_tier"], "required_gate": packet["required_gate"], "recipient_role_or_team": "pending_owner_role_or_team", "sender_role_or_team": "iwooos_security_reviewer", "requested_response_window": "not_scheduled", "allowed_response_format": { "fields": packet["required_owner_fields"], "allowed_decisions": intake_report.get("allowed_decisions", []), "redacted_evidence_refs_only": True, }, "redacted_evidence_refs": [ "docs/security/high-value-config-owner-packet.snapshot.json", "docs/security/high-value-config-owner-packet-intake-preflight.snapshot.json", ], "affected_files": packet.get("affected_files", []), "required_validation": packet.get("required_validation", []), "forbidden_payloads": FORBIDDEN_PAYLOADS, "blocked_requests": intake_report.get("blocked_requests", []), "handoff_envelope_fields": HANDOFF_ENVELOPE_FIELDS, "followup_owner": "pending_followup_owner", "not_approval": True, "not_approval_statement": NOT_APPROVAL_STATEMENT, "request_sent": False, "recipient_confirmed": False, "audit_event_emitted": False, "received_response": False, "accepted_response": False, "rejected_response": False, "reviewer_queue_write": False, "runtime_gate": False, "action_buttons_allowed": False, "secret_value_collection_allowed": False, "production_write_authorized": False, } def build_report(root: Path, intake_report: dict[str, Any], generated_at: str | None) -> dict[str, Any]: report_time = generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds") intake_packets = intake_report.get("intake_packets", []) drafts = [request_draft(packet, intake_report) for packet in intake_packets] c0_drafts = [draft for draft in drafts if draft.get("control_tier") == "C0"] c1_drafts = [draft for draft in drafts if draft.get("control_tier") == "C1"] required_owner_field_total = sum(len(draft["allowed_response_format"]["fields"]) for draft in drafts) return { "schema_version": "high_value_config_owner_request_draft_v1", "generated_at": report_time, "git_commit": git_short_sha(root), "source_intake_preflight_schema_version": intake_report.get("schema_version"), "source_intake_preflight_status": intake_report.get("status"), "status": "owner_request_draft_ready_not_dispatched", "summary": { "request_draft_count": len(drafts), "c0_request_draft_count": len(c0_drafts), "c1_request_draft_count": len(c1_drafts), "dispatch_preflight_check_count": intake_report.get("summary", {}).get( "dispatch_preflight_check_count", 0 ), "reviewer_intake_lane_count": intake_report.get("summary", {}).get("reviewer_intake_lane_count", 0), "handoff_envelope_field_count": len(HANDOFF_ENVELOPE_FIELDS), "required_owner_field_total": required_owner_field_total, "forbidden_payload_count": len(FORBIDDEN_PAYLOADS), "blocked_request_count": len(intake_report.get("blocked_requests", [])), "request_sent_count": 0, "recipient_confirmed_count": 0, "audit_event_emitted_count": 0, "received_response_count": 0, "accepted_response_count": 0, "rejected_response_count": 0, "reviewer_queue_write_count": 0, "runtime_gate_count": 0, "action_button_count": 0, }, "execution_boundaries": { "dispatch_authorized": False, "request_sent": False, "recipient_confirmed": False, "audit_event_emitted": False, "reviewer_queue_write": False, "runtime_execution_authorized": False, "secret_value_collection_allowed": False, "production_write_authorized": False, "host_write_authorized": False, "nginx_reload_authorized": False, "dns_tls_change_authorized": False, "workflow_modification_authorized": False, "active_scan_authorized": False, "action_buttons_allowed": False, "not_authorization": True, }, "handoff_envelope_fields": HANDOFF_ENVELOPE_FIELDS, "forbidden_payloads": FORBIDDEN_PAYLOADS, "not_approval_statement": NOT_APPROVAL_STATEMENT, "request_drafts": drafts, "send_after_conditions": [ "必須先重新確認 gitea/main、P0 總帳與另一個 AwoooP Session 基線。", "只能送出脫敏欄位與禁止條款,不得附 secret value、raw payload 或執行命令。", "只有真實人工送件 metadata 存在時,才能另行記錄 request_sent_count。", "送件後不得同步拉高 received / accepted / rejected / reviewer queue / runtime gate。", ], } def main() -> int: parser = argparse.ArgumentParser(description="IwoooS 高價值配置 owner request 草稿包產生器") parser.add_argument("--root", default=".", help="repo root") parser.add_argument( "--intake-preflight-report", default="docs/security/high-value-config-owner-packet-intake-preflight.snapshot.json", help="high-value-config-owner-packet-intake-preflight.py 輸出的 JSON", ) parser.add_argument("--output", help="寫出 JSON 報告") parser.add_argument("--generated-at", help="固定報告時間,供 committed snapshot 使用") args = parser.parse_args() root = Path(args.root).resolve() intake_report = load_json(root / args.intake_preflight_report) report = build_report(root, intake_report, args.generated_at) payload = json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) if args.output: output = Path(args.output) output.parent.mkdir(parents=True, exist_ok=True) output.write_text(payload + "\n", encoding="utf-8") else: print(payload) summary = report["summary"] print( "HIGH_VALUE_CONFIG_OWNER_REQUEST_DRAFT_OK " f"drafts={summary['request_draft_count']} " f"c0={summary['c0_request_draft_count']} " f"fields={summary['required_owner_field_total']} " f"sent={summary['request_sent_count']} " f"runtime_gate={summary['runtime_gate_count']}", file=sys.stderr, ) return 0 if __name__ == "__main__": sys.exit(main())