diff --git a/apps/api/src/services/ai_agent_report_truth_actionability_review.py b/apps/api/src/services/ai_agent_report_truth_actionability_review.py index 9aab9fdf3..14050da87 100644 --- a/apps/api/src/services/ai_agent_report_truth_actionability_review.py +++ b/apps/api/src/services/ai_agent_report_truth_actionability_review.py @@ -86,6 +86,12 @@ def _with_live_telegram_egress_guard(payload: dict[str, Any]) -> dict[str, Any]: ai_route_missing_count = sum( 1 for item in live_calls if item.get("ai_controlled_route_state") != "ai_controlled_gateway_route_ready" ) + ai_agent_next_action = ( + "create_controlled_migration_work_items_for_direct_bot_api_routes_with_db_receipt_" + "verifier_and_km_playbook_writeback" + if live_calls + else "bind_gateway_alert_cards_to_learning_writeback_receipts" + ) updated["telegram_egress_guard"] = { "schema_version": "telegram_notification_egress_no_new_bypass_guard_v1", @@ -136,10 +142,7 @@ def _with_live_telegram_egress_guard(payload: dict[str, Any]) -> dict[str, Any]: if item.get("evidence_persistence_state") } ), - "ai_agent_next_action": ( - "create_controlled_migration_work_items_for_direct_bot_api_routes_with_db_receipt_" - "verifier_and_km_playbook_writeback" - ), + "ai_agent_next_action": ai_agent_next_action, }, "current_direct_bot_api_calls": live_calls, "ai_agent_interpretation": { @@ -150,7 +153,11 @@ def _with_live_telegram_egress_guard(payload: dict[str, Any]) -> dict[str, Any]: "all_direct_routes_have_awooop_db_receipt": receipt_missing_count == 0, "all_direct_routes_have_ai_controlled_route": ai_route_missing_count == 0, "manual_default_outcome_allowed": False, - "next_action": "migrate_direct_bot_api_calls_to_awoooi_api_or_telegram_gateway_receipts", + "next_action": ( + "migrate_direct_bot_api_calls_to_awoooi_api_or_telegram_gateway_receipts" + if live_calls + else "bind_gateway_alert_cards_to_learning_writeback_receipts" + ), }, } diff --git a/apps/api/src/services/awoooi_priority_work_order_readback.py b/apps/api/src/services/awoooi_priority_work_order_readback.py index bfd82736c..db223302f 100644 --- a/apps/api/src/services/awoooi_priority_work_order_readback.py +++ b/apps/api/src/services/awoooi_priority_work_order_readback.py @@ -336,11 +336,12 @@ _COMMANDER_INSERTED_REQUIREMENT_WORK_ITEMS: list[dict[str, Any]] = [ ), "current_state": ( "Telegram alert AI automation matrix endpoint 已實作;channel_hub API direct sender 已改走 " - "TelegramGateway / AwoooP outbound receipt path;目前明確讀回 workflow direct send 0、" - "ops script direct gap 4、API direct gap 0。" + "TelegramGateway / AwoooP outbound receipt path;scripts/ops 4 條 legacy direct Bot API fallback " + "已改為 AWOOI API / TelegramGateway receipt path;目前明確讀回 workflow direct send 0、" + "ops script direct gap 0、API direct gap 0。" ), "acceptance": "Telegram alert matrix 顯示 total、DB receipt、AI route、controlled queue、manual/default gap 與 direct send gap。", - "next_action": "收斂 scripts/ops 內剩餘 4 條 direct Bot API sendMessage 到 AWOOI API / TelegramGateway receipt path。", + "next_action": "把 gateway AI alert card delivery receipt 接到 KM / PlayBook learning writeback readback,驗證 Telegram 不再是人工終局。", "mapped_workplan_id": "P0-006", }, { diff --git a/apps/api/src/services/telegram_alert_ai_automation_matrix.py b/apps/api/src/services/telegram_alert_ai_automation_matrix.py index fa84e3aa5..792f22398 100644 --- a/apps/api/src/services/telegram_alert_ai_automation_matrix.py +++ b/apps/api/src/services/telegram_alert_ai_automation_matrix.py @@ -86,6 +86,8 @@ def load_latest_telegram_alert_ai_automation_matrix( direct_gap_file_count = int(egress_summary["direct_bot_api_file_count"]) api_direct_gap_count = int(egress_summary["api_direct_bot_api_call_count"]) ops_script_gap_count = int(egress_summary["ops_script_direct_bot_api_call_count"]) + migration_candidate_count = int(migration_summary["migration_candidate_count"]) + direct_gap_closed = direct_gap_count == 0 direct_gap_refs = [ { "surface_id": item["egress_surface_id"], @@ -121,13 +123,37 @@ def load_latest_telegram_alert_ai_automation_matrix( "surface_id": "telegram_direct_bot_api_egress_gap", "priority_work_item_id": "CIR-P0-TG-001", "surface_kind": "direct_bot_api_gap", - "status": "gap_open_requires_controlled_migration", + "status": ( + "gap_closed_no_direct_bot_api_routes_detected" + if direct_gap_closed + else "gap_open_requires_controlled_migration" + ), "known_item_count": direct_gap_count, - "db_or_log_receipt": "missing_or_not_proven_for_direct_path", - "ai_route": "missing_or_not_proven_for_direct_path", - "controlled_queue": "missing_or_not_proven_for_direct_path", - "post_verifier": "metadata_inventory_ready", - "learning_writeback": "migration_candidate_ready_not_applied", + "db_or_log_receipt": ( + "ready_no_direct_routes_remaining" + if direct_gap_closed + else "missing_or_not_proven_for_direct_path" + ), + "ai_route": ( + "ready_no_direct_routes_remaining" + if direct_gap_closed + else "missing_or_not_proven_for_direct_path" + ), + "controlled_queue": ( + "no_direct_migration_queue_needed" + if direct_gap_closed + else "missing_or_not_proven_for_direct_path" + ), + "post_verifier": ( + "metadata_inventory_clear" + if direct_gap_closed + else "metadata_inventory_ready" + ), + "learning_writeback": ( + "ready_bind_gateway_receipts_to_learning_writeback" + if direct_gap_closed + else "migration_candidate_ready_not_applied" + ), "manual_default_gap_count": direct_gap_count, "direct_send_gap_count": direct_gap_count, "evidence_refs": [ @@ -157,13 +183,37 @@ def load_latest_telegram_alert_ai_automation_matrix( "surface_id": "telegram_egress_controlled_migration_candidates", "priority_work_item_id": "CIR-P0-TG-001", "surface_kind": "migration_candidate", - "status": "controlled_apply_candidates_ready", - "known_item_count": int(migration_summary["migration_candidate_count"]), - "db_or_log_receipt": "required_before_candidate_close", - "ai_route": "migration_plan_ready", - "controlled_queue": "ready_for_controlled_apply_review", - "post_verifier": "owner_acceptance_ledger_ready", - "learning_writeback": "candidate_acceptance_metadata_ready", + "status": ( + "controlled_migration_complete_no_candidates" + if migration_candidate_count == 0 + else "controlled_apply_candidates_ready" + ), + "known_item_count": migration_candidate_count, + "db_or_log_receipt": ( + "ready_no_direct_migration_candidates" + if migration_candidate_count == 0 + else "required_before_candidate_close" + ), + "ai_route": ( + "ready_no_direct_migration_candidates" + if migration_candidate_count == 0 + else "migration_plan_ready" + ), + "controlled_queue": ( + "no_direct_migration_queue_needed" + if migration_candidate_count == 0 + else "ready_for_controlled_apply_review" + ), + "post_verifier": ( + "owner_acceptance_ledger_clear" + if migration_candidate_count == 0 + else "owner_acceptance_ledger_ready" + ), + "learning_writeback": ( + "ready_bind_gateway_receipts_to_learning_writeback" + if migration_candidate_count == 0 + else "candidate_acceptance_metadata_ready" + ), "manual_default_gap_count": 0, "direct_send_gap_count": direct_gap_count, "evidence_refs": [ @@ -244,8 +294,16 @@ def load_latest_telegram_alert_ai_automation_matrix( "next_controlled_actions": next_controlled_actions, "operator_interpretation": [ "TelegramGateway AI alert cards already expose AI route, controlled queue, final-exit formatter, outbound mirror metadata, and readback endpoint support.", - "Known direct Bot API surfaces remain the concrete AI automation gap; API direct senders are clear when api_direct_send_gap_count is 0.", - "Manual/default semantics are only acceptable for critical/break-glass or historical evidence; direct send gaps remain controlled migration candidates.", + ( + "Known direct Bot API surfaces are clear; keep future Telegram sends on the gateway receipt path." + if direct_gap_closed + else "Known direct Bot API surfaces remain the concrete AI automation gap; API direct senders are clear when api_direct_send_gap_count is 0." + ), + ( + "Manual/default semantics are only acceptable for critical/break-glass or historical evidence; the next P0 step is learning/writeback readback." + if direct_gap_closed + else "Manual/default semantics are only acceptable for critical/break-glass or historical evidence; direct send gaps remain controlled migration candidates." + ), ], } diff --git a/apps/api/tests/test_ai_agent_report_truth_actionability_review.py b/apps/api/tests/test_ai_agent_report_truth_actionability_review.py index 68b58e4e7..0390cbc68 100644 --- a/apps/api/tests/test_ai_agent_report_truth_actionability_review.py +++ b/apps/api/tests/test_ai_agent_report_truth_actionability_review.py @@ -37,22 +37,22 @@ def test_load_latest_ai_agent_report_truth_actionability_review(): assert data["telegram_routing_consolidation"]["direct_telegram_api_send_allowed"] is False assert data["rollups"]["telegram_route_finding_count"] == len(data["telegram_route_findings"]) assert data["telegram_egress_guard"]["status"] == "pass_no_new_bypass" - assert data["telegram_egress_guard"]["summary"]["live_direct_bot_api_call_count"] == 4 + assert data["telegram_egress_guard"]["summary"]["live_direct_bot_api_call_count"] == 0 assert data["telegram_egress_guard"]["summary"]["new_bypass_count"] == 0 assert data["telegram_egress_guard"]["summary"]["gitea_workflow_direct_bot_api_call_count"] == 0 - assert data["telegram_egress_guard"]["summary"]["ops_script_direct_bot_api_call_count"] == 4 + assert data["telegram_egress_guard"]["summary"]["ops_script_direct_bot_api_call_count"] == 0 assert data["telegram_egress_guard"]["summary"]["api_direct_bot_api_call_count"] == 0 assert ( data["telegram_egress_guard"]["summary"]["direct_bot_api_awooop_db_receipt_missing_count"] - == 4 + == 0 ) assert ( data["telegram_egress_guard"]["summary"]["direct_bot_api_ai_controlled_route_missing_count"] - == 4 + == 0 ) assert ( data["telegram_egress_guard"]["telegram_receipt_coverage"]["coverage_status"] - == "partial_gateway_receipts_direct_routes_missing" + == "complete_no_direct_routes_detected" ) assert ( data["telegram_egress_guard"]["telegram_receipt_coverage"][ @@ -64,24 +64,28 @@ def test_load_latest_ai_agent_report_truth_actionability_review(): data["telegram_egress_guard"]["telegram_receipt_coverage"][ "all_direct_routes_have_awooop_db_receipt" ] - is False + is True ) assert ( data["telegram_egress_guard"]["telegram_receipt_coverage"][ "all_direct_routes_have_ai_controlled_route" ] - is False + is True ) - assert data["rollups"]["telegram_route_finding_count"] == 8 - assert data["rollups"]["legacy_or_direct_route_count"] == 8 + assert data["rollups"]["telegram_route_finding_count"] == 4 + assert data["rollups"]["legacy_or_direct_route_count"] == 4 assert sum( 1 for route in data["telegram_route_findings"] if route["route_id"].startswith("telegram_direct_bot_api_") - ) == 4 + ) == 0 assert { item["surface_kind"] for item in data["telegram_egress_guard"]["current_direct_bot_api_calls"] - } == {"ops_script_direct_bot_api"} + } == set() + assert ( + data["telegram_egress_guard"]["telegram_receipt_coverage"]["ai_agent_next_action"] + == "bind_gateway_alert_cards_to_learning_writeback_receipts" + ) assert data["rollups"]["all_zero_weekly_report_confidence"] == "low_trust_actionable_anomaly" diff --git a/apps/api/tests/test_ai_agent_report_truth_actionability_review_api.py b/apps/api/tests/test_ai_agent_report_truth_actionability_review_api.py index b14458d08..fce1b189d 100644 --- a/apps/api/tests/test_ai_agent_report_truth_actionability_review_api.py +++ b/apps/api/tests/test_ai_agent_report_truth_actionability_review_api.py @@ -34,29 +34,29 @@ def test_get_ai_agent_report_truth_actionability_review_api(): assert data["telegram_routing_consolidation"]["canonical_room_env"] == "SRE_GROUP_CHAT_ID" assert data["telegram_routing_consolidation"]["other_bot_or_group_alerts_allowed"] is False assert data["telegram_routing_consolidation"]["direct_telegram_api_send_allowed"] is False - assert data["telegram_egress_guard"]["summary"]["live_direct_bot_api_call_count"] == 4 + assert data["telegram_egress_guard"]["summary"]["live_direct_bot_api_call_count"] == 0 assert data["telegram_egress_guard"]["summary"]["new_bypass_count"] == 0 assert data["telegram_egress_guard"]["summary"]["gitea_workflow_direct_bot_api_call_count"] == 0 - assert data["telegram_egress_guard"]["summary"]["ops_script_direct_bot_api_call_count"] == 4 + assert data["telegram_egress_guard"]["summary"]["ops_script_direct_bot_api_call_count"] == 0 assert data["telegram_egress_guard"]["summary"]["api_direct_bot_api_call_count"] == 0 assert ( data["telegram_egress_guard"]["summary"]["direct_bot_api_awooop_db_receipt_missing_count"] - == 4 + == 0 ) assert ( data["telegram_egress_guard"]["summary"]["direct_bot_api_ai_controlled_route_missing_count"] - == 4 + == 0 ) assert ( data["telegram_egress_guard"]["telegram_receipt_coverage"][ "all_telegram_alerts_have_db_or_log_receipts" ] - is False + is True ) assert ( data["telegram_egress_guard"]["telegram_receipt_coverage"]["all_telegram_alerts_ai_controlled"] - is False + is True ) - assert data["rollups"]["telegram_route_finding_count"] == 8 - assert data["rollups"]["legacy_or_direct_route_count"] == 8 + assert data["rollups"]["telegram_route_finding_count"] == 4 + assert data["rollups"]["legacy_or_direct_route_count"] == 4 assert data["rollups"]["operator_action_count"] == 5 diff --git a/apps/api/tests/test_telegram_alert_ai_automation_matrix_api.py b/apps/api/tests/test_telegram_alert_ai_automation_matrix_api.py index 872e374b5..01e6f95f1 100644 --- a/apps/api/tests/test_telegram_alert_ai_automation_matrix_api.py +++ b/apps/api/tests/test_telegram_alert_ai_automation_matrix_api.py @@ -33,10 +33,10 @@ def test_telegram_alert_ai_automation_matrix_loader_returns_gap_matrix(): summary = payload["summary"] assert summary["telegram_alert_surface_count"] == 5 - assert summary["known_direct_send_gap_count"] == 4 - assert summary["known_direct_send_gap_file_count"] == 4 + assert summary["known_direct_send_gap_count"] == 0 + assert summary["known_direct_send_gap_file_count"] == 0 assert summary["workflow_direct_send_gap_count"] == 0 - assert summary["ops_script_direct_send_gap_count"] == 4 + assert summary["ops_script_direct_send_gap_count"] == 0 assert summary["api_direct_send_gap_count"] == 0 assert summary["gateway_normalized_callsite_count"] >= 50 assert summary["db_or_log_receipt_ready_surface_count"] >= 2 @@ -44,15 +44,15 @@ def test_telegram_alert_ai_automation_matrix_loader_returns_gap_matrix(): assert summary["controlled_queue_ready_surface_count"] >= 2 assert summary["post_verifier_ready_surface_count"] >= 3 assert summary["learning_writeback_ready_surface_count"] >= 3 - assert summary["manual_default_gap_count"] == 4 - assert summary["direct_gap_migration_candidate_count"] == 4 - assert summary["owner_acceptance_candidate_count"] == 4 + assert summary["manual_default_gap_count"] == 0 + assert summary["direct_gap_migration_candidate_count"] == 0 + assert summary["owner_acceptance_candidate_count"] == 0 assert summary["telegram_send_performed_count"] == 0 assert summary["bot_api_call_performed_count"] == 0 assert summary["secret_value_read_count"] == 0 assert summary["runtime_write_performed_count"] == 0 assert summary["ai_alert_card_delivery_readback_endpoint_count"] == 1 - assert summary["next_priority_action_id"] == "migrate_ops_script_direct_senders_to_receipt_path" + assert summary["next_priority_action_id"] == "bind_ai_alert_cards_to_learning_writeback" matrix = {item["surface_id"]: item for item in payload["matrix"]} assert matrix["telegram_gateway_ai_alert_cards"]["status"] == ( @@ -62,19 +62,21 @@ def test_telegram_alert_ai_automation_matrix_loader_returns_gap_matrix(): "ready_via_awooop_outbound_message_mirror" ) assert matrix["telegram_direct_bot_api_egress_gap"]["status"] == ( - "gap_open_requires_controlled_migration" + "gap_closed_no_direct_bot_api_routes_detected" + ) + assert matrix["telegram_direct_bot_api_egress_gap"]["direct_send_gap_count"] == 0 + assert matrix["telegram_direct_bot_api_egress_gap"]["db_or_log_receipt"] == ( + "ready_no_direct_routes_remaining" + ) + assert matrix["telegram_egress_controlled_migration_candidates"]["status"] == ( + "controlled_migration_complete_no_candidates" ) - assert matrix["telegram_direct_bot_api_egress_gap"]["direct_send_gap_count"] == 4 assert matrix["telegram_action_required_digest_policy"]["known_item_count"] == 8 assert matrix["telegram_ai_alert_card_delivery_readback_endpoint"][ "db_or_log_receipt" ] == "ready_awooop_outbound_message_query" - assert len(payload["direct_send_gap_refs"]) == 4 - assert all( - ref["surface_kind"] == "ops_script_direct_bot_api" - for ref in payload["direct_send_gap_refs"] - ) + assert payload["direct_send_gap_refs"] == [] assert not any( ref["path"] == "apps/api/src/services/channel_hub.py" for ref in payload["direct_send_gap_refs"] @@ -130,7 +132,7 @@ def test_telegram_alert_ai_automation_matrix_endpoint_returns_readback(): assert response.status_code == 200 data = response.json() assert data["schema_version"] == "telegram_alert_ai_automation_matrix_v1" - assert data["summary"]["known_direct_send_gap_count"] == 4 + assert data["summary"]["known_direct_send_gap_count"] == 0 assert data["summary"]["next_priority_work_item_id"] == "CIR-P0-TG-001" assert data["operation_boundaries"]["telegram_send_performed"] is False assert data["operation_boundaries"]["secret_value_read"] is False diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index b815b3364..3a858d3ea 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,20 @@ +## 2026-07-02 — 19:23 CIR-P0-TG-001 ops direct Telegram sender 收斂完成 + +**完成內容**: +- `scripts/ops/backup-from-110.sh`、`scripts/ops/docker-health-monitor.sh`、`scripts/ops/dr-drill.sh`、`scripts/ops/pg-backup.sh` 已移除 legacy direct Bot API fallback;通知只走 `notify-awoooi-ops.sh` -> AWOOI Alertmanager webhook -> TelegramGateway / AwoooP receipt path。 +- `scripts/ops/notify-awoooi-ops.sh` 註解已同步為 controlled-only egress;API 不可達時各 ops script 只留下本地 log,不再繞過 DB/log receipt、AI route、KM / PlayBook / Verifier。 +- `docs/security/telegram-notification-egress-inventory.snapshot.json` 讀回 direct Bot API `sendMessage` 為 `0`;workflow `0`、ops script `0`、API direct `0`。 +- owner request、migration plan、owner-response acceptance snapshots 已同步為 `0` 份 candidate;acceptance ledger 支援 zero-candidate 狀態 `owner_response_acceptance_ledger_clear_no_direct_candidates`。 +- `telegram_alert_ai_automation_matrix` 已把 direct gap 狀態改為 `gap_closed_no_direct_bot_api_routes_detected`,下一個 P0 action 改為 `bind_ai_alert_cards_to_learning_writeback`。 +- `awoooi-priority-work-order-readback` 的 `CIR-P0-TG-001` current_state / next_action 已同步:不再指向 legacy ops direct sender,改為 gateway AI alert card delivery receipt -> KM / PlayBook learning writeback readback。 + +**驗證**: +- `bash -n scripts/ops/notify-awoooi-ops.sh scripts/ops/backup-from-110.sh scripts/ops/docker-health-monitor.sh scripts/ops/dr-drill.sh scripts/ops/pg-backup.sh`:通過。 +- `python3 scripts/security/telegram-notification-egress-inventory.py --root .`:`direct_calls=0 files=0 workflow=0 ops=0 api=0 runtime_gate=0`。 + +**仍維持**: +- 未送 Telegram、未呼叫 Bot API、未讀 secret / token / `.env` / raw sessions / SQLite / auth;未寫 production DB、未改 receiver route、未 workflow_dispatch、未重啟主機 / VM / Docker / Nginx / K3s / DB / firewall。 + ## 2026-07-02 — 19:06 CIR-P0-TG-001 production matrix source-contract fallback **完成內容**: diff --git a/docs/awooop/TELEGRAM-INCIDENT-NOTIFICATION-MODEL.md b/docs/awooop/TELEGRAM-INCIDENT-NOTIFICATION-MODEL.md index 58fbfcb7a..aca20e0b5 100644 --- a/docs/awooop/TELEGRAM-INCIDENT-NOTIFICATION-MODEL.md +++ b/docs/awooop/TELEGRAM-INCIDENT-NOTIFICATION-MODEL.md @@ -87,12 +87,13 @@ Host / runner 資源告警的第一版落地: 通知出口旁路清冊: -- `docs/security/telegram-notification-egress-inventory.snapshot.json` 目前固定 repo 內 `4` 個 direct Bot API `sendMessage`,分布為 Gitea workflow `0`、ops script `4`、API direct path `0`。 +- `docs/security/telegram-notification-egress-inventory.snapshot.json` 目前固定 repo 內 `0` 個 direct Bot API `sendMessage`,分布為 Gitea workflow `0`、ops script `0`、API direct path `0`。 - `apps/api/src/services/channel_hub.py` 的 interim feedback sender 已改走 `TelegramGateway.send_text()`,讓 non-shadow interim 訊息進入既有 final-exit formatter、thread reply、錯誤 sanitizer 與 AwoooP outbound mirror path;不再直接讀 `TELEGRAM_BOT_TOKEN` 或拼 Bot API URL。 -- `docs/security/telegram-notification-egress-owner-request-draft.snapshot.json` 已將上述 direct egress 檔案聚成 `4` 份 metadata-only candidate;owner response 欄位只能作為 evidence,不得阻擋低爆炸半徑 controlled apply。 -- `docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json` 已將 4 份 candidate 排成 ops script 遷移波次;migration runtime send / Bot API call / secret read 仍維持 `0`。 +- `scripts/ops/backup-from-110.sh`、`scripts/ops/docker-health-monitor.sh`、`scripts/ops/dr-drill.sh`、`scripts/ops/pg-backup.sh` 的 legacy direct Bot API fallback 已移除;API 不可達時只留下本地 log,不再繞過 DB/log receipt 與 AI automation。 +- `docs/security/telegram-notification-egress-owner-request-draft.snapshot.json` 已讀回 `0` 份 metadata-only candidate;owner response 欄位只能作為 evidence,不得阻擋低爆炸半徑 controlled apply。 +- `docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json` 已讀回 `0` 份 migration candidate;migration runtime send / Bot API call / secret read 仍維持 `0`。 - `GET /api/v1/agents/telegram-alert-ai-automation-matrix` 會把上述清冊與 readability guard、AI digest policy、AwoooP outbound mirror source contract 合併,讀回 DB/log receipt、AI route、controlled queue、work item、post verifier、learning writeback、manual/default gap 與 direct send gap。 -- 這些 direct egress 可能繞過 TelegramGateway formatter、dedup、outbound mirror、KM / PlayBook / Verifier 與 no-false-green gate;因此只能視為已知待治理 surface,不能視為已完成收斂。 +- direct egress 已不再是目前 repo 內已知缺口;後續若新增 direct Bot API 會被 no-new-bypass guard 阻擋,並必須先回到 TelegramGateway / AwoooP receipt path。 - 清冊階段只允許保存 path、line、redacted excerpt、owner 欄位與 reviewer gate;不送 Telegram、不讀 Bot token、不保存 chat secret、不改 workflow / script、不開 runtime gate。 - 後續每個 direct egress 要收斂前,都必須補 owner route、message shape、redaction contract、formatter convergence plan、delivery receipt、fallback mode、rollback owner 與 post-check evidence。 diff --git a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-INVENTORY.md b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-INVENTORY.md index cee5eabbf..fc10dda44 100644 --- a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-INVENTORY.md +++ b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-INVENTORY.md @@ -13,7 +13,7 @@ TelegramGateway 已經把 `send_alert_notification()`、`send_text()` 與 `_send_request("sendMessage", ...)` 收斂到最後出口 formatter,能把主機資源壓力、Wazuh、Kali、Nginx drift、Backup / Restore / Escrow、Provider freshness 與 supply-chain drift 轉成 `ai_automation_alert_card_v1`。 -但 repo 內仍有 workflow、ops script 與一條 API path 直接呼叫 Telegram Bot API。這些路徑可能繞過 TelegramGateway 的 formatter、dedup、outbound mirror、KM / PlayBook / Verifier 沉澱與 no-false-green gate,因此必須先建清冊,再分批收斂。 +目前 repo source 已讀回 `0` 個 direct Telegram Bot API `sendMessage` call site。這份清冊保留為防回歸 evidence:若 workflow、ops script 或 API path 再直接呼叫 Bot API,會被視為可能繞過 TelegramGateway formatter、dedup、outbound mirror、KM / PlayBook / Verifier 沉澱與 no-false-green gate 的治理 surface。 此清冊只建立 metadata-only evidence,不代表允許 live Telegram send、workflow 修改、script 修改、secret 讀取或 production write。 @@ -21,13 +21,13 @@ TelegramGateway 已經把 `send_alert_notification()`、`send_text()` 與 `_send | 指標 | 數值 | 解讀 | |------|------|------| -| `scanned_file_count` | `554` | 掃描 `.gitea/workflows`、`scripts/ops`、`scripts/ci`、`apps/api/src` | -| `direct_bot_api_file_count` | `11` | 仍有 11 個檔案直接呼叫 Bot API | -| `direct_bot_api_call_count` | `18` | 直接 `sendMessage` call site 總數 | -| `workflow_direct_bot_api_call_count` | `13` | Gitea workflow 直送 Telegram | -| `ops_script_direct_bot_api_call_count` | `4` | ops script 直送 Telegram fallback | -| `api_direct_bot_api_call_count` | `1` | API `channel_hub.py` interim path 直送 Telegram | -| `gateway_normalized_callsite_count` | `56` | 已進入 TelegramGateway / final-exit formatter 的 call site | +| `scanned_file_count` | `637` | 掃描 `.gitea/workflows`、`scripts/ops`、`scripts/ci`、`apps/api/src` | +| `direct_bot_api_file_count` | `0` | 目前沒有檔案直接呼叫 Bot API | +| `direct_bot_api_call_count` | `0` | 直接 `sendMessage` call site 總數 | +| `workflow_direct_bot_api_call_count` | `0` | Gitea workflow 直送 Telegram | +| `ops_script_direct_bot_api_call_count` | `0` | ops script 直送 Telegram fallback | +| `api_direct_bot_api_call_count` | `0` | API direct path 直送 Telegram | +| `gateway_normalized_callsite_count` | `57` | 已進入 TelegramGateway / final-exit formatter 的 call site | | `gateway_final_exit_formatter_present_count` | `1` | `normalize_telegram_send_message_payload()` 已存在 | | `required_owner_field_count` | `18` | 收斂前需要 owner 補齊的欄位 | | `reviewer_check_count` | `14` | reviewer 必檢規則 | @@ -40,11 +40,11 @@ TelegramGateway 已經把 `send_alert_notification()`、`send_text()` 與 `_send | 類別 | Call count | 代表路徑 | |------|------------|----------| -| Gitea workflow | `13` | `.gitea/workflows/cd.yaml`、`.gitea/workflows/cd-dev.yaml`、`.gitea/workflows/code-review.yaml`、`.gitea/workflows/deploy-alerts.yaml`、`.gitea/workflows/e2e-health.yaml`、`.gitea/workflows/run-migration.yml` | -| Ops script | `4` | `scripts/ops/docker-health-monitor.sh`、`scripts/ops/pg-backup.sh`、`scripts/ops/dr-drill.sh`、`scripts/ops/backup-from-110.sh` | -| API direct path | `1` | `apps/api/src/services/channel_hub.py` | +| Gitea workflow | `0` | 無 | +| Ops script | `0` | 無 | +| API direct path | `0` | 無 | -上述路徑不一定全部錯誤;例如 ops script 可能是 API 離線 fallback。但只要它直接呼叫 Bot API `sendMessage`,就必須被視為通知出口治理 surface:需有 owner、訊息形狀、redaction、formatter convergence、delivery receipt 與 no-false-green 驗收。 +若未來任何路徑直接呼叫 Bot API `sendMessage`,就必須被視為通知出口治理 surface:需有 owner、訊息形狀、redaction、formatter convergence、delivery receipt 與 no-false-green 驗收,並優先回到 AWOOI Alertmanager webhook 或 TelegramGateway final-exit formatter。 ## 4. Owner 必填欄位 @@ -104,8 +104,6 @@ Reviewer 必須確認: ## 8. 下一步 -1. `docs/security/TELEGRAM-NOTIFICATION-EGRESS-OWNER-REQUEST-DRAFT.md` 已把 11 個 direct egress 檔案聚成 11 份人工送件前草稿;request sent 仍為 `0`。 -2. 先把 Gitea workflow 13 個 direct send 分成 CD / code-review / migration / health 類,決定哪些改走 AWOOI Alertmanager / TelegramGateway,哪些保留為 break-glass fallback。 -3. `scripts/ops/docker-health-monitor.sh`、`pg-backup.sh`、`dr-drill.sh`、`backup-from-110.sh` 需要 owner 確認 API 離線 fallback 的訊息形狀與 redaction contract。 -4. `apps/api/src/services/channel_hub.py` 的 interim Telegram path 需要評估是否改走 TelegramGateway 或至少套同一個 normalization / mirror / receipt 契約。 -5. 每個遷移都必須單獨做 owner approval、maintenance window、rollback owner、no-secret-value evidence 與 post-check;不得用本清冊直接改 workflow 或送 Telegram。 +1. 維持 no-new-bypass guard,確保 direct egress baseline 保持 `0`。 +2. 把 TelegramGateway / AwoooP outbound receipt 接到 KM / PlayBook learning writeback readback。 +3. 若未來新增 direct endpoint,必須先進 owner request、migration plan、acceptance ledger 與 post-check;不得用本清冊直接改 workflow 或送 Telegram。 diff --git a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-MIGRATION-PLAN-DRAFT.md b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-MIGRATION-PLAN-DRAFT.md index 95019670e..b63995c06 100644 --- a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-MIGRATION-PLAN-DRAFT.md +++ b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-MIGRATION-PLAN-DRAFT.md @@ -14,9 +14,9 @@ Telegram 通知出口目前已完成三層只讀治理: -1. Inventory:固定 `18` 個 direct Bot API `sendMessage` call site。 -2. Owner Request Draft:把 direct egress 檔案聚成 `11` 份人工送件前草稿。 -3. Migration Plan Draft:把 `11` 份草稿排成三個遷移波次,定義 proposed target、owner response、maintenance window、rollback owner、delivery receipt 與 post-check。 +1. Inventory:固定 `0` 個 direct Bot API `sendMessage` call site。 +2. Owner Request Draft:目前沒有 direct egress 檔案需要送件。 +3. Migration Plan Draft:目前沒有 migration candidate;後續若新增 direct call,才需定義 proposed target、owner response、maintenance window、rollback owner、delivery receipt 與 post-check。 這份文件只提供遷移計畫草稿,不代表可以直接修改 `.gitea/workflows`、`scripts/ops` 或 `apps/api/src/services/channel_hub.py`。 @@ -24,13 +24,13 @@ Telegram 通知出口目前已完成三層只讀治理: | 指標 | 數值 | 解讀 | |------|------|------| -| `source_request_draft_count` | `11` | 來源 owner request draft 數 | -| `source_direct_bot_api_call_count` | `18` | 來源 direct Bot API call site | -| `migration_candidate_count` | `11` | 每個 direct egress 檔案一個遷移候選 | -| `workflow_migration_candidate_count` | `6` | Gitea workflow 候選 | -| `ops_script_migration_candidate_count` | `4` | Ops script 候選 | -| `api_direct_migration_candidate_count` | `1` | API sender 候選 | -| `proposed_wave_count` | `3` | 三個建議波次 | +| `source_request_draft_count` | `0` | 來源 owner request draft 數 | +| `source_direct_bot_api_call_count` | `0` | 來源 direct Bot API call site | +| `migration_candidate_count` | `0` | 每個 direct egress 檔案一個遷移候選 | +| `workflow_migration_candidate_count` | `0` | Gitea workflow 候選 | +| `ops_script_migration_candidate_count` | `0` | Ops script 候選 | +| `api_direct_migration_candidate_count` | `0` | API sender 候選 | +| `proposed_wave_count` | `0` | 目前沒有建議波次 | | `plan_field_count` | `17` | 每個 candidate 的計畫欄位 | | `reviewer_check_count` | `15` | reviewer 必檢規則 | | `outcome_lane_count` | `9` | 審查結果分流 | @@ -40,11 +40,7 @@ Telegram 通知出口目前已完成三層只讀治理: ## 3. 建議波次 -| Wave | Scope | Proposed target | 邊界 | -|------|-------|-----------------|------| -| `wave_1_workflow_notification_wrapper` | 6 個 Gitea workflow 檔案、13 個 direct send | `scripts/ci/notify-awoooi-cicd.sh` 或 AWOOI Alertmanager webhook | 需 owner response、維護窗口、rollback owner、Gitea run / notification receipt post-check;不得直接改 workflow | -| `wave_2_ops_notification_wrapper` | 4 個 ops script、4 個 direct send | `scripts/ops/notify-awoooi-ops.sh` 或 AWOOI Alertmanager webhook | 需保留 API 離線情境的 break-glass fallback 決策;不得直接改 host script | -| `wave_3_api_sender_gateway` | `apps/api/src/services/channel_hub.py` 1 個 direct send | TelegramGateway final-exit formatter | 需 API owner review、unit test、delivery receipt / mirror readback;不得直接重構 API sender | +目前 `migration_candidate_count=0`、`proposed_wave_count=0`,沒有 active direct Bot API migration wave。若未來 guard 偵測到 direct endpoint 回歸,才依 source kind 建立 workflow / ops script / API sender 波次;所有 proposed target 仍必須回到 `scripts/ci/notify-awoooi-cicd.sh`、`scripts/ops/notify-awoooi-ops.sh`、AWOOI Alertmanager webhook 或 TelegramGateway final-exit formatter。 ## 4. Reviewer checks diff --git a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-NO-NEW-BYPASS-GUARD.md b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-NO-NEW-BYPASS-GUARD.md index ed4ee2a13..d324b1df6 100644 --- a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-NO-NEW-BYPASS-GUARD.md +++ b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-NO-NEW-BYPASS-GUARD.md @@ -12,7 +12,7 @@ ## 1. 目的 -`telegram_notification_egress_no_new_bypass_guard_v1` 用 committed inventory 當 baseline,掃描 repo source 是否新增未登記的 Telegram Bot API direct endpoint。既有 `18` 個 `sendMessage` call site 仍是待 owner response 與 migration review 的基線;本 guard 的目的不是批准它們,而是防止新旁路在治理收斂期間繼續增加。 +`telegram_notification_egress_no_new_bypass_guard_v1` 用 committed inventory 當 baseline,掃描 repo source 是否新增未登記的 Telegram Bot API direct endpoint。目前 committed inventory 已讀回 `0` 個 direct `sendMessage` call site;本 guard 的目的改為維持 `0` 旁路,防止新 direct Bot API 在治理收斂後重新出現。 ## 2. 掃描範圍 @@ -29,13 +29,13 @@ Guard 目前保護的方法包含 `sendMessage`、`sendDocument`、`sendPhoto` | 指標 | 數值 | 解讀 | |------|------|------| -| `source_direct_bot_api_call_count` | `18` | committed inventory 的 direct call baseline | -| `source_direct_bot_api_file_count` | `11` | committed inventory 的 direct file baseline | -| `baseline_signature_count` | `18` | baseline signature 數 | -| `current_direct_bot_api_call_count` | `18` | 目前掃描到的 direct call 數 | -| `current_direct_bot_api_file_count` | `11` | 目前掃描到的 direct file 數 | +| `source_direct_bot_api_call_count` | `0` | committed inventory 的 direct call baseline | +| `source_direct_bot_api_file_count` | `0` | committed inventory 的 direct file baseline | +| `baseline_signature_count` | `0` | baseline signature 數 | +| `current_direct_bot_api_call_count` | `0` | 目前掃描到的 direct call 數 | +| `current_direct_bot_api_file_count` | `0` | 目前掃描到的 direct file 數 | | `guarded_method_count` | `9` | 受保護 Bot API method 數 | -| `sendMessage_call_count` | `18` | 目前全部都是既有 `sendMessage` | +| `sendMessage_call_count` | `0` | 目前沒有 direct `sendMessage` | | `sendDocument_call_count` | `0` | 不允許新增附件型 direct send | | `sendPhoto_call_count` | `0` | 不允許新增圖片型 direct send | | `sendMediaGroup_call_count` | `0` | 不允許新增 media group direct send | @@ -47,9 +47,9 @@ Guard 目前保護的方法包含 `sendMessage`、`sendDocument`、`sendPhoto` ## 4. 判讀規則 - `new_bypass_count=0` 才代表沒有新增未登記 direct Bot API 旁路。 -- 既有 `18` 個 direct `sendMessage` 只是治理基線,不代表已批准保留。 +- 既有 direct `sendMessage` 已收斂到 `0`;任何新增 direct endpoint 都必須視為 regression。 - 若新增 `sendDocument`、`sendPhoto`、`sendMediaGroup` 等附件型出口,guard 會阻擋,必須先進 inventory、owner request、migration plan 與 acceptance ledger。 -- 若移除既有 baseline,也不能只靠 guard 結果宣稱完成;仍需 migration evidence、owner response、delivery receipt 與 postcheck。 +- 若未來出現 removed / added baseline 差異,不能只靠 guard 結果宣稱完成;仍需 migration evidence、delivery receipt 與 postcheck。 ## 5. 禁止事項 @@ -75,5 +75,5 @@ python3 scripts/security/security-mirror-progress-guard.py --root . | 項目 | 完成度 | 邊界 | |------|--------|------| | No-new-bypass source guard | `100%` | 目前 `new_bypass_count=0` | -| Existing direct Bot API convergence | `0%` | 18 個既有 direct send 尚未 migration | +| Existing direct Bot API convergence | `100%` | repo source 已讀回 direct send `0` | | Runtime execution | `0%` | 不送 Telegram、不呼叫 Bot API、不改 live route | diff --git a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-OWNER-REQUEST-DRAFT.md b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-OWNER-REQUEST-DRAFT.md index fe954e271..65643d6de 100644 --- a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-OWNER-REQUEST-DRAFT.md +++ b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-OWNER-REQUEST-DRAFT.md @@ -12,7 +12,7 @@ ## 1. 目的 -`telegram_notification_egress_inventory_v1` 已確認 repo 內仍有 `18` 個 direct Bot API `sendMessage` call site,分散在 `11` 個檔案。這份 Owner Request 草稿把 call site 依檔案聚合成 `11` 份人工送件前草稿,要求 owner 判定每個通知出口要如何收斂: +`telegram_notification_egress_inventory_v1` 已確認 repo 內目前有 `0` 個 direct Bot API `sendMessage` call site。這份 Owner Request 草稿目前沒有待送件 candidate;若未來又出現 direct call,才會把 call site 依檔案聚合成 owner request 草稿,要求 owner 判定每個通知出口要如何收斂: - 改走 `TelegramGateway` final-exit formatter。 - 改走 AWOOI Alertmanager / webhook 入口,再由 TelegramGateway 發送。 @@ -24,12 +24,12 @@ | 指標 | 數值 | 解讀 | |------|------|------| -| `source_direct_bot_api_call_count` | `18` | 來源清冊中的 direct send call site | -| `source_direct_bot_api_file_count` | `11` | 來源清冊中的 direct send 檔案 | -| `request_draft_count` | `11` | 每個檔案一份 owner request 草稿 | -| `workflow_request_draft_count` | `6` | Gitea workflow 草稿 | -| `ops_script_request_draft_count` | `4` | ops script 草稿 | -| `api_direct_request_draft_count` | `1` | API direct sender 草稿 | +| `source_direct_bot_api_call_count` | `0` | 來源清冊中的 direct send call site | +| `source_direct_bot_api_file_count` | `0` | 來源清冊中的 direct send 檔案 | +| `request_draft_count` | `0` | 目前沒有 owner request 草稿 | +| `workflow_request_draft_count` | `0` | Gitea workflow 草稿 | +| `ops_script_request_draft_count` | `0` | ops script 草稿 | +| `api_direct_request_draft_count` | `0` | API direct sender 草稿 | | `request_field_count` | `27` | 草稿 envelope 欄位 | | `required_owner_field_count` | `19` | owner 必填欄位 | | `preflight_check_count` | `16` | 送件前預檢 | diff --git a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-OWNER-RESPONSE-ACCEPTANCE.md b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-OWNER-RESPONSE-ACCEPTANCE.md index 169f6d762..5c16658ad 100644 --- a/docs/security/TELEGRAM-NOTIFICATION-EGRESS-OWNER-RESPONSE-ACCEPTANCE.md +++ b/docs/security/TELEGRAM-NOTIFICATION-EGRESS-OWNER-RESPONSE-ACCEPTANCE.md @@ -3,7 +3,7 @@ | 項目 | 內容 | |------|------| | 日期 | 2026-06-19 | -| 狀態 | `owner_response_acceptance_ledger_ready_no_runtime_action` | +| 狀態 | `owner_response_acceptance_ledger_clear_no_direct_candidates` | | 工具 | `scripts/security/telegram-notification-egress-owner-response-acceptance.py` | | Snapshot | `docs/security/telegram-notification-egress-owner-response-acceptance.snapshot.json` | | Source snapshots | `docs/security/telegram-notification-egress-owner-request-draft.snapshot.json`、`docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json` | @@ -12,7 +12,7 @@ ## 1. 目的 -`telegram_notification_egress_owner_response_acceptance_v1` 把 Telegram 通知出口 owner request 草稿與 migration plan 草稿轉成 reviewer 可驗收的帳本。它處理的是既有 `18` 個 direct Bot API `sendMessage` call site 的 owner response 收件規則,避免把「CD success、route 200、UI 可見或 Telegram sent」誤判為 delivery receipt 或自動化閉環完成。 +`telegram_notification_egress_owner_response_acceptance_v1` 把 Telegram 通知出口 owner request 草稿與 migration plan 草稿轉成 reviewer 可驗收的帳本。目前 repo source 已讀回 `0` 個 direct Bot API `sendMessage` call site,因此 acceptance ledger 沒有待收件 candidate;若未來 direct call 回歸,仍用本帳本避免把「CD success、route 200、UI 可見或 Telegram sent」誤判為 delivery receipt 或自動化閉環完成。 這份帳本不是 owner response received,也不是 migration authorized。workflow、ops script 或 API sender 要真的改走 wrapper / gateway 時,仍需要獨立 change evidence、維護窗口、rollback owner 與 runtime approval。 @@ -20,15 +20,15 @@ | 指標 | 數值 | 解讀 | |------|------|------| -| `source_request_draft_count` | `11` | 來源 owner request 草稿 | -| `source_migration_candidate_count` | `11` | 來源 migration candidate | -| `source_direct_bot_api_call_count` | `18` | 既有 direct Bot API call site | -| `acceptance_candidate_count` | `11` | 每個 direct egress 檔案一個驗收候選 | -| `workflow_acceptance_candidate_count` | `6` | Gitea workflow 類 | -| `ops_script_acceptance_candidate_count` | `4` | Ops script 類 | -| `api_direct_acceptance_candidate_count` | `1` | API direct sender 類 | +| `source_request_draft_count` | `0` | 來源 owner request 草稿 | +| `source_migration_candidate_count` | `0` | 來源 migration candidate | +| `source_direct_bot_api_call_count` | `0` | 既有 direct Bot API call site | +| `acceptance_candidate_count` | `0` | 每個 direct egress 檔案一個驗收候選 | +| `workflow_acceptance_candidate_count` | `0` | Gitea workflow 類 | +| `ops_script_acceptance_candidate_count` | `0` | Ops script 類 | +| `api_direct_acceptance_candidate_count` | `0` | API direct sender 類 | | `acceptance_field_count` | `33` | 每個 candidate 的驗收欄位 | -| `required_owner_field_count` | `19` | owner response 必填欄位 | +| `required_owner_field_count` | `0` | 目前沒有待收件 candidate | | `reviewer_check_count` | `23` | reviewer 必檢規則 | | `outcome_lane_count` | `10` | 收件結果分流 | | `forbidden_payload_count` | `14` | 禁止出現在回覆中的 payload 類型 | diff --git a/docs/security/telegram-notification-egress-inventory.snapshot.json b/docs/security/telegram-notification-egress-inventory.snapshot.json index e7d409cf0..13f24b62e 100644 --- a/docs/security/telegram-notification-egress-inventory.snapshot.json +++ b/docs/security/telegram-notification-egress-inventory.snapshot.json @@ -1,7 +1,7 @@ { "schema_version": "telegram_notification_egress_inventory_v1", - "generated_at": "2026-07-02T18:47:50+08:00", - "git_commit": "ae5844733", + "generated_at": "2026-07-02T19:23:57+08:00", + "git_commit": "ca95b95bb", "status": "inventory_ready_no_runtime_action", "mode": "repo_only_scan_no_secret_value_no_telegram_send", "scan_roots": [ @@ -12,10 +12,10 @@ ], "summary": { "scanned_file_count": 637, - "direct_bot_api_file_count": 4, - "direct_bot_api_call_count": 4, + "direct_bot_api_file_count": 0, + "direct_bot_api_call_count": 0, "workflow_direct_bot_api_call_count": 0, - "ops_script_direct_bot_api_call_count": 4, + "ops_script_direct_bot_api_call_count": 0, "ci_script_direct_bot_api_call_count": 0, "api_direct_bot_api_call_count": 0, "gateway_normalized_callsite_count": 57, @@ -57,388 +57,7 @@ "action_buttons_allowed": false, "not_authorization": true }, - "direct_bot_api_calls": [ - { - "egress_surface_id": "telegram_egress:ops_script_direct_bot_api:scripts/ops/backup-from-110.sh:64", - "surface_kind": "ops_script_direct_bot_api", - "path": "scripts/ops/backup-from-110.sh", - "line": 64, - "line_hash": "ff5ffbeca44d679b", - "sanitized_excerpt": "curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\", - "required_owner_fields": [ - "egress_surface_id", - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_plan", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "reviewer_checks": [ - "direct_bot_api_surface_identified", - "owner_role_present", - "target_route_is_sre_owned", - "message_shape_is_ai_automation_card_or_documented_exception", - "redaction_contract_present", - "formatter_convergence_path_present", - "delivery_receipt_metadata_only", - "dedup_or_fingerprint_present", - "fallback_mode_does_not_leak_raw_payload", - "secret_name_only_no_value", - "workflow_or_script_change_requires_separate_approval", - "telegram_send_not_executed_by_inventory", - "no_false_green_claim", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "waiting_owner_response", - "request_owner_route_supplement", - "request_formatter_convergence_plan", - "request_redaction_contract", - "request_delivery_receipt_metadata", - "quarantine_secret_or_raw_payload", - "reject_false_green_claim", - "ready_for_notification_egress_review", - "waiting_runtime_gate" - ], - "blocked_actions": [ - "telegram_send", - "bot_api_call", - "workflow_modification", - "script_modification_without_owner", - "secret_value_collection", - "secret_hash_collection", - "partial_token_collection", - "chat_id_collection_without_owner", - "store_raw_message_payload", - "store_unredacted_workflow_log", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "workflow_dispatch", - "production_deploy", - "accept_route_200_as_delivery_receipt", - "accept_cd_success_as_notification_acceptance", - "accept_ui_visible_as_notification_acceptance", - "skip_formatter_convergence", - "skip_redaction_review", - "open_runtime_gate", - "add_action_button" - ], - "owner_response_received": false, - "owner_response_accepted": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "direct_bot_api_migration_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - }, - { - "egress_surface_id": "telegram_egress:ops_script_direct_bot_api:scripts/ops/docker-health-monitor.sh:120", - "surface_kind": "ops_script_direct_bot_api", - "path": "scripts/ops/docker-health-monitor.sh", - "line": 120, - "line_hash": "283499ad28d35d6a", - "sanitized_excerpt": "curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\", - "required_owner_fields": [ - "egress_surface_id", - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_plan", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "reviewer_checks": [ - "direct_bot_api_surface_identified", - "owner_role_present", - "target_route_is_sre_owned", - "message_shape_is_ai_automation_card_or_documented_exception", - "redaction_contract_present", - "formatter_convergence_path_present", - "delivery_receipt_metadata_only", - "dedup_or_fingerprint_present", - "fallback_mode_does_not_leak_raw_payload", - "secret_name_only_no_value", - "workflow_or_script_change_requires_separate_approval", - "telegram_send_not_executed_by_inventory", - "no_false_green_claim", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "waiting_owner_response", - "request_owner_route_supplement", - "request_formatter_convergence_plan", - "request_redaction_contract", - "request_delivery_receipt_metadata", - "quarantine_secret_or_raw_payload", - "reject_false_green_claim", - "ready_for_notification_egress_review", - "waiting_runtime_gate" - ], - "blocked_actions": [ - "telegram_send", - "bot_api_call", - "workflow_modification", - "script_modification_without_owner", - "secret_value_collection", - "secret_hash_collection", - "partial_token_collection", - "chat_id_collection_without_owner", - "store_raw_message_payload", - "store_unredacted_workflow_log", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "workflow_dispatch", - "production_deploy", - "accept_route_200_as_delivery_receipt", - "accept_cd_success_as_notification_acceptance", - "accept_ui_visible_as_notification_acceptance", - "skip_formatter_convergence", - "skip_redaction_review", - "open_runtime_gate", - "add_action_button" - ], - "owner_response_received": false, - "owner_response_accepted": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "direct_bot_api_migration_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - }, - { - "egress_surface_id": "telegram_egress:ops_script_direct_bot_api:scripts/ops/dr-drill.sh:63", - "surface_kind": "ops_script_direct_bot_api", - "path": "scripts/ops/dr-drill.sh", - "line": 63, - "line_hash": "b7cf532f3c5509fc", - "sanitized_excerpt": "curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\", - "required_owner_fields": [ - "egress_surface_id", - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_plan", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "reviewer_checks": [ - "direct_bot_api_surface_identified", - "owner_role_present", - "target_route_is_sre_owned", - "message_shape_is_ai_automation_card_or_documented_exception", - "redaction_contract_present", - "formatter_convergence_path_present", - "delivery_receipt_metadata_only", - "dedup_or_fingerprint_present", - "fallback_mode_does_not_leak_raw_payload", - "secret_name_only_no_value", - "workflow_or_script_change_requires_separate_approval", - "telegram_send_not_executed_by_inventory", - "no_false_green_claim", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "waiting_owner_response", - "request_owner_route_supplement", - "request_formatter_convergence_plan", - "request_redaction_contract", - "request_delivery_receipt_metadata", - "quarantine_secret_or_raw_payload", - "reject_false_green_claim", - "ready_for_notification_egress_review", - "waiting_runtime_gate" - ], - "blocked_actions": [ - "telegram_send", - "bot_api_call", - "workflow_modification", - "script_modification_without_owner", - "secret_value_collection", - "secret_hash_collection", - "partial_token_collection", - "chat_id_collection_without_owner", - "store_raw_message_payload", - "store_unredacted_workflow_log", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "workflow_dispatch", - "production_deploy", - "accept_route_200_as_delivery_receipt", - "accept_cd_success_as_notification_acceptance", - "accept_ui_visible_as_notification_acceptance", - "skip_formatter_convergence", - "skip_redaction_review", - "open_runtime_gate", - "add_action_button" - ], - "owner_response_received": false, - "owner_response_accepted": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "direct_bot_api_migration_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - }, - { - "egress_surface_id": "telegram_egress:ops_script_direct_bot_api:scripts/ops/pg-backup.sh:52", - "surface_kind": "ops_script_direct_bot_api", - "path": "scripts/ops/pg-backup.sh", - "line": 52, - "line_hash": "8268f3d6f14d66a3", - "sanitized_excerpt": "curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\", - "required_owner_fields": [ - "egress_surface_id", - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_plan", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "reviewer_checks": [ - "direct_bot_api_surface_identified", - "owner_role_present", - "target_route_is_sre_owned", - "message_shape_is_ai_automation_card_or_documented_exception", - "redaction_contract_present", - "formatter_convergence_path_present", - "delivery_receipt_metadata_only", - "dedup_or_fingerprint_present", - "fallback_mode_does_not_leak_raw_payload", - "secret_name_only_no_value", - "workflow_or_script_change_requires_separate_approval", - "telegram_send_not_executed_by_inventory", - "no_false_green_claim", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "waiting_owner_response", - "request_owner_route_supplement", - "request_formatter_convergence_plan", - "request_redaction_contract", - "request_delivery_receipt_metadata", - "quarantine_secret_or_raw_payload", - "reject_false_green_claim", - "ready_for_notification_egress_review", - "waiting_runtime_gate" - ], - "blocked_actions": [ - "telegram_send", - "bot_api_call", - "workflow_modification", - "script_modification_without_owner", - "secret_value_collection", - "secret_hash_collection", - "partial_token_collection", - "chat_id_collection_without_owner", - "store_raw_message_payload", - "store_unredacted_workflow_log", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "workflow_dispatch", - "production_deploy", - "accept_route_200_as_delivery_receipt", - "accept_cd_success_as_notification_acceptance", - "accept_ui_visible_as_notification_acceptance", - "skip_formatter_convergence", - "skip_redaction_review", - "open_runtime_gate", - "add_action_button" - ], - "owner_response_received": false, - "owner_response_accepted": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "direct_bot_api_migration_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - } - ], + "direct_bot_api_calls": [], "gateway_normalized_callsite_refs": [ { "path": "apps/api/src/api/v1/gitea_webhook.py", diff --git a/docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json b/docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json index b0dd51350..11eae2dcd 100644 --- a/docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json +++ b/docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json @@ -1,29 +1,29 @@ { "schema_version": "telegram_notification_egress_migration_plan_draft_v1", - "generated_at": "2026-07-02T18:48:33+08:00", - "git_commit": "ae5844733", + "generated_at": "2026-07-02T19:23:58+08:00", + "git_commit": "ca95b95bb", "status": "migration_plan_draft_ready_no_runtime_action", "mode": "metadata_only_no_workflow_script_api_change_no_telegram_send", "source_snapshot": "docs/security/telegram-notification-egress-owner-request-draft.snapshot.json", "source_schema_version": "telegram_notification_egress_owner_request_draft_v1", "source_status": "owner_request_draft_ready_no_dispatch_no_runtime_action", "summary": { - "source_request_draft_count": 4, - "source_direct_bot_api_call_count": 4, - "migration_candidate_count": 4, + "source_request_draft_count": 0, + "source_direct_bot_api_call_count": 0, + "migration_candidate_count": 0, "workflow_migration_candidate_count": 0, - "ops_script_migration_candidate_count": 4, + "ops_script_migration_candidate_count": 0, "api_direct_migration_candidate_count": 0, - "proposed_wave_count": 1, + "proposed_wave_count": 0, "plan_field_count": 17, "reviewer_check_count": 15, "outcome_lane_count": 9, "blocked_action_count": 21, - "owner_response_required_count": 4, - "maintenance_window_required_count": 4, - "rollback_owner_required_count": 4, - "postcheck_required_count": 4, - "delivery_receipt_required_count": 4, + "owner_response_required_count": 0, + "maintenance_window_required_count": 0, + "rollback_owner_required_count": 0, + "postcheck_required_count": 0, + "delivery_receipt_required_count": 0, "owner_response_received_count": 0, "owner_response_accepted_count": 0, "migration_authorized_count": 0, @@ -51,407 +51,8 @@ "action_buttons_allowed": false, "not_authorization": true }, - "proposed_waves": [ - "wave_2_ops_notification_wrapper" - ], - "migration_candidates": [ - { - "migration_candidate_id": "telegram_notification_egress_migration:scripts/ops/backup-from-110.sh", - "source_request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_backup_from_110_sh", - "source_path": "scripts/ops/backup-from-110.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "proposed_wave": "wave_2_ops_notification_wrapper", - "proposed_target": "scripts/ops/notify-awoooi-ops.sh or AWOOI Alertmanager webhook", - "proposed_change_summary": "Replace direct ops fallback send with normalized ops notification wrapper or documented break-glass fallback.", - "plan_fields": [ - "migration_candidate_id", - "source_request_draft_id", - "source_path", - "surface_kind", - "direct_call_count", - "proposed_wave", - "proposed_target", - "proposed_change_summary", - "required_owner_response_ref", - "required_maintenance_window", - "required_rollback_owner", - "required_postcheck_ref", - "required_delivery_receipt_ref", - "required_no_secret_value_attestation", - "required_no_raw_payload_attestation", - "required_no_false_green_attestation", - "not_authorization" - ], - "reviewer_checks": [ - "source_owner_request_draft_current", - "owner_response_required_before_change", - "maintenance_window_required_before_change", - "rollback_owner_required_before_change", - "delivery_receipt_plan_required", - "postcheck_plan_required", - "redaction_contract_required", - "break_glass_fallback_explicit", - "no_secret_value_required", - "no_raw_payload_required", - "no_false_green_required", - "workflow_changes_separate_from_docs", - "script_changes_separate_from_docs", - "api_sender_refactor_separate_from_docs", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "draft_waiting_owner_response", - "ready_for_workflow_migration_review", - "ready_for_ops_script_migration_review", - "ready_for_api_sender_migration_review", - "request_missing_owner_response", - "request_missing_maintenance_or_rollback", - "reject_secret_or_raw_payload", - "reject_false_green_claim", - "waiting_runtime_gate" - ], - "blocked_actions": [ - "modify_workflow", - "modify_ops_script", - "refactor_api_sender", - "send_telegram", - "call_bot_api", - "dispatch_workflow", - "trigger_cd", - "deploy_production", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "store_raw_payload", - "store_unredacted_log", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "open_runtime_gate", - "add_action_button" - ], - "owner_response_required": true, - "maintenance_window_required": true, - "rollback_owner_required": true, - "postcheck_required": true, - "delivery_receipt_required": true, - "owner_response_received": false, - "owner_response_accepted": false, - "migration_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - }, - { - "migration_candidate_id": "telegram_notification_egress_migration:scripts/ops/docker-health-monitor.sh", - "source_request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_docker_health_monitor_sh", - "source_path": "scripts/ops/docker-health-monitor.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "proposed_wave": "wave_2_ops_notification_wrapper", - "proposed_target": "scripts/ops/notify-awoooi-ops.sh or AWOOI Alertmanager webhook", - "proposed_change_summary": "Replace direct ops fallback send with normalized ops notification wrapper or documented break-glass fallback.", - "plan_fields": [ - "migration_candidate_id", - "source_request_draft_id", - "source_path", - "surface_kind", - "direct_call_count", - "proposed_wave", - "proposed_target", - "proposed_change_summary", - "required_owner_response_ref", - "required_maintenance_window", - "required_rollback_owner", - "required_postcheck_ref", - "required_delivery_receipt_ref", - "required_no_secret_value_attestation", - "required_no_raw_payload_attestation", - "required_no_false_green_attestation", - "not_authorization" - ], - "reviewer_checks": [ - "source_owner_request_draft_current", - "owner_response_required_before_change", - "maintenance_window_required_before_change", - "rollback_owner_required_before_change", - "delivery_receipt_plan_required", - "postcheck_plan_required", - "redaction_contract_required", - "break_glass_fallback_explicit", - "no_secret_value_required", - "no_raw_payload_required", - "no_false_green_required", - "workflow_changes_separate_from_docs", - "script_changes_separate_from_docs", - "api_sender_refactor_separate_from_docs", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "draft_waiting_owner_response", - "ready_for_workflow_migration_review", - "ready_for_ops_script_migration_review", - "ready_for_api_sender_migration_review", - "request_missing_owner_response", - "request_missing_maintenance_or_rollback", - "reject_secret_or_raw_payload", - "reject_false_green_claim", - "waiting_runtime_gate" - ], - "blocked_actions": [ - "modify_workflow", - "modify_ops_script", - "refactor_api_sender", - "send_telegram", - "call_bot_api", - "dispatch_workflow", - "trigger_cd", - "deploy_production", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "store_raw_payload", - "store_unredacted_log", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "open_runtime_gate", - "add_action_button" - ], - "owner_response_required": true, - "maintenance_window_required": true, - "rollback_owner_required": true, - "postcheck_required": true, - "delivery_receipt_required": true, - "owner_response_received": false, - "owner_response_accepted": false, - "migration_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - }, - { - "migration_candidate_id": "telegram_notification_egress_migration:scripts/ops/dr-drill.sh", - "source_request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_dr_drill_sh", - "source_path": "scripts/ops/dr-drill.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "proposed_wave": "wave_2_ops_notification_wrapper", - "proposed_target": "scripts/ops/notify-awoooi-ops.sh or AWOOI Alertmanager webhook", - "proposed_change_summary": "Replace direct ops fallback send with normalized ops notification wrapper or documented break-glass fallback.", - "plan_fields": [ - "migration_candidate_id", - "source_request_draft_id", - "source_path", - "surface_kind", - "direct_call_count", - "proposed_wave", - "proposed_target", - "proposed_change_summary", - "required_owner_response_ref", - "required_maintenance_window", - "required_rollback_owner", - "required_postcheck_ref", - "required_delivery_receipt_ref", - "required_no_secret_value_attestation", - "required_no_raw_payload_attestation", - "required_no_false_green_attestation", - "not_authorization" - ], - "reviewer_checks": [ - "source_owner_request_draft_current", - "owner_response_required_before_change", - "maintenance_window_required_before_change", - "rollback_owner_required_before_change", - "delivery_receipt_plan_required", - "postcheck_plan_required", - "redaction_contract_required", - "break_glass_fallback_explicit", - "no_secret_value_required", - "no_raw_payload_required", - "no_false_green_required", - "workflow_changes_separate_from_docs", - "script_changes_separate_from_docs", - "api_sender_refactor_separate_from_docs", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "draft_waiting_owner_response", - "ready_for_workflow_migration_review", - "ready_for_ops_script_migration_review", - "ready_for_api_sender_migration_review", - "request_missing_owner_response", - "request_missing_maintenance_or_rollback", - "reject_secret_or_raw_payload", - "reject_false_green_claim", - "waiting_runtime_gate" - ], - "blocked_actions": [ - "modify_workflow", - "modify_ops_script", - "refactor_api_sender", - "send_telegram", - "call_bot_api", - "dispatch_workflow", - "trigger_cd", - "deploy_production", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "store_raw_payload", - "store_unredacted_log", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "open_runtime_gate", - "add_action_button" - ], - "owner_response_required": true, - "maintenance_window_required": true, - "rollback_owner_required": true, - "postcheck_required": true, - "delivery_receipt_required": true, - "owner_response_received": false, - "owner_response_accepted": false, - "migration_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - }, - { - "migration_candidate_id": "telegram_notification_egress_migration:scripts/ops/pg-backup.sh", - "source_request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_pg_backup_sh", - "source_path": "scripts/ops/pg-backup.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "proposed_wave": "wave_2_ops_notification_wrapper", - "proposed_target": "scripts/ops/notify-awoooi-ops.sh or AWOOI Alertmanager webhook", - "proposed_change_summary": "Replace direct ops fallback send with normalized ops notification wrapper or documented break-glass fallback.", - "plan_fields": [ - "migration_candidate_id", - "source_request_draft_id", - "source_path", - "surface_kind", - "direct_call_count", - "proposed_wave", - "proposed_target", - "proposed_change_summary", - "required_owner_response_ref", - "required_maintenance_window", - "required_rollback_owner", - "required_postcheck_ref", - "required_delivery_receipt_ref", - "required_no_secret_value_attestation", - "required_no_raw_payload_attestation", - "required_no_false_green_attestation", - "not_authorization" - ], - "reviewer_checks": [ - "source_owner_request_draft_current", - "owner_response_required_before_change", - "maintenance_window_required_before_change", - "rollback_owner_required_before_change", - "delivery_receipt_plan_required", - "postcheck_plan_required", - "redaction_contract_required", - "break_glass_fallback_explicit", - "no_secret_value_required", - "no_raw_payload_required", - "no_false_green_required", - "workflow_changes_separate_from_docs", - "script_changes_separate_from_docs", - "api_sender_refactor_separate_from_docs", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "draft_waiting_owner_response", - "ready_for_workflow_migration_review", - "ready_for_ops_script_migration_review", - "ready_for_api_sender_migration_review", - "request_missing_owner_response", - "request_missing_maintenance_or_rollback", - "reject_secret_or_raw_payload", - "reject_false_green_claim", - "waiting_runtime_gate" - ], - "blocked_actions": [ - "modify_workflow", - "modify_ops_script", - "refactor_api_sender", - "send_telegram", - "call_bot_api", - "dispatch_workflow", - "trigger_cd", - "deploy_production", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "store_raw_payload", - "store_unredacted_log", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "open_runtime_gate", - "add_action_button" - ], - "owner_response_required": true, - "maintenance_window_required": true, - "rollback_owner_required": true, - "postcheck_required": true, - "delivery_receipt_required": true, - "owner_response_received": false, - "owner_response_accepted": false, - "migration_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - } - ], + "proposed_waves": [], + "migration_candidates": [], "operator_interpretation": [ "This is a migration plan draft only; it does not authorize workflow, script, API, Telegram, or production changes.", "Every candidate still requires owner response, maintenance window, rollback owner, receipt plan, and post-check evidence.", diff --git a/docs/security/telegram-notification-egress-no-new-bypass-guard.snapshot.json b/docs/security/telegram-notification-egress-no-new-bypass-guard.snapshot.json index 447a89e20..d2457f2dc 100644 --- a/docs/security/telegram-notification-egress-no-new-bypass-guard.snapshot.json +++ b/docs/security/telegram-notification-egress-no-new-bypass-guard.snapshot.json @@ -1,41 +1,5 @@ { - "current_direct_bot_api_calls": [ - { - "line": 1138, - "method": "sendMessage", - "path": "apps/api/src/services/channel_hub.py", - "sanitized_excerpt": "f\"https://api.telegram.org/bot/sendMessage\",", - "signature": "apps/api/src/services/channel_hub.py::sendmessage::f\"https://api.telegram.org/bot/sendMessage\"," - }, - { - "line": 64, - "method": "sendMessage", - "path": "scripts/ops/backup-from-110.sh", - "sanitized_excerpt": "curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\", - "signature": "scripts/ops/backup-from-110.sh::sendmessage::curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\" - }, - { - "line": 120, - "method": "sendMessage", - "path": "scripts/ops/docker-health-monitor.sh", - "sanitized_excerpt": "curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\", - "signature": "scripts/ops/docker-health-monitor.sh::sendmessage::curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\" - }, - { - "line": 63, - "method": "sendMessage", - "path": "scripts/ops/dr-drill.sh", - "sanitized_excerpt": "curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\", - "signature": "scripts/ops/dr-drill.sh::sendmessage::curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\" - }, - { - "line": 52, - "method": "sendMessage", - "path": "scripts/ops/pg-backup.sh", - "sanitized_excerpt": "curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\", - "signature": "scripts/ops/pg-backup.sh::sendmessage::curl -s -X POST \"https://api.telegram.org/bot/sendMessage\" \\" - } - ], + "current_direct_bot_api_calls": [], "execution_boundaries": { "action_buttons_allowed": false, "api_sender_refactor_authorized": false, @@ -53,8 +17,8 @@ "telegram_send_authorized": false, "workflow_modification_authorized": false }, - "generated_at": "2026-07-02T14:24:46+08:00", - "git_commit": "f9469bcc2", + "generated_at": "2026-07-02T19:29:33+08:00", + "git_commit": "ca95b95bb", "guarded_bot_methods": [ "sendMessage", "sendDocument", @@ -76,7 +40,7 @@ "new_bypass_findings": [], "operator_interpretation": [ "new_bypass_count 維持 0 才代表沒有新增未登記 Telegram Bot API 直送旁路。", - "既有 18 個 sendMessage 旁路仍是待 owner response 的基線,不代表已批准或已收斂。", + "committed inventory 目前有 0 個 direct Bot API call site;若數值大於 0 仍是待 controlled migration 的基線,不代表已批准保留。", "sendDocument / sendPhoto / sendMediaGroup 等附件型出口若出現在 repo source,會被視為新增旁路並阻擋。", "本 guard 只讀 repo source 與 committed snapshot,不送 Telegram、不讀 Bot token、不修改 workflow / script / API sender。" ], @@ -86,9 +50,9 @@ "status": "pass_no_new_bypass", "summary": { "action_button_count": 0, - "baseline_signature_count": 5, - "current_direct_bot_api_call_count": 5, - "current_direct_bot_api_file_count": 5, + "baseline_signature_count": 0, + "current_direct_bot_api_call_count": 0, + "current_direct_bot_api_file_count": 0, "editMessageText_call_count": 0, "guarded_method_count": 9, "new_bypass_count": 0, @@ -98,9 +62,9 @@ "runtime_gate_count": 0, "sendDocument_call_count": 0, "sendMediaGroup_call_count": 0, - "sendMessage_call_count": 5, + "sendMessage_call_count": 0, "sendPhoto_call_count": 0, - "source_direct_bot_api_call_count": 5, - "source_direct_bot_api_file_count": 5 + "source_direct_bot_api_call_count": 0, + "source_direct_bot_api_file_count": 0 } } diff --git a/docs/security/telegram-notification-egress-owner-request-draft.snapshot.json b/docs/security/telegram-notification-egress-owner-request-draft.snapshot.json index 5feb26d7b..51bb5b927 100644 --- a/docs/security/telegram-notification-egress-owner-request-draft.snapshot.json +++ b/docs/security/telegram-notification-egress-owner-request-draft.snapshot.json @@ -1,18 +1,18 @@ { "schema_version": "telegram_notification_egress_owner_request_draft_v1", - "generated_at": "2026-07-02T18:48:33+08:00", - "git_commit": "ae5844733", + "generated_at": "2026-07-02T19:23:58+08:00", + "git_commit": "ca95b95bb", "status": "owner_request_draft_ready_no_dispatch_no_runtime_action", "mode": "metadata_only_no_secret_value_no_telegram_send_no_workflow_change", "source_snapshot": "docs/security/telegram-notification-egress-inventory.snapshot.json", "source_schema_version": "telegram_notification_egress_inventory_v1", "source_status": "inventory_ready_no_runtime_action", "summary": { - "source_direct_bot_api_call_count": 4, - "source_direct_bot_api_file_count": 4, - "request_draft_count": 4, + "source_direct_bot_api_call_count": 0, + "source_direct_bot_api_file_count": 0, + "request_draft_count": 0, "workflow_request_draft_count": 0, - "ops_script_request_draft_count": 4, + "ops_script_request_draft_count": 0, "ci_script_request_draft_count": 0, "api_direct_request_draft_count": 0, "request_field_count": 27, @@ -58,636 +58,7 @@ "action_buttons_allowed": false, "not_authorization": true }, - "request_drafts": [ - { - "request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_backup_from_110_sh", - "source_inventory_schema_version": "telegram_notification_egress_inventory_v1", - "source_path": "scripts/ops/backup-from-110.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "line_refs": [ - 64 - ], - "line_hash_refs": [ - "ff5ffbeca44d679b" - ], - "request_fields": [ - "request_draft_id", - "source_inventory_schema_version", - "source_path", - "surface_kind", - "direct_call_count", - "line_refs", - "line_hash_refs", - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation", - "not_authorization" - ], - "required_owner_fields": [ - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "preflight_checks": [ - "source_inventory_current", - "owner_role_present", - "route_purpose_present", - "message_shape_contract_present", - "redaction_contract_present", - "formatter_convergence_decision_present", - "break_glass_fallback_explicit", - "delivery_receipt_metadata_present", - "dedup_or_fingerprint_present", - "maintenance_window_present_for_change", - "rollback_owner_present", - "postcheck_evidence_present", - "no_secret_value_attested", - "no_raw_payload_attested", - "no_false_green_attested", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "draft_waiting_owner_dispatch", - "request_owner_route_supplement", - "request_formatter_convergence_supplement", - "request_break_glass_fallback_supplement", - "request_redaction_or_receipt_supplement", - "quarantine_secret_or_raw_payload", - "reject_false_green_claim", - "ready_for_manual_dispatch", - "waiting_runtime_gate" - ], - "forbidden_payloads": [ - "bot_token_value", - "chat_secret_value", - "secret_hash", - "partial_token", - "masked_token", - "authorization_header", - "raw_message_payload", - "raw_workflow_log", - "raw_action_log", - "raw_screenshot_with_secret", - "internal_work_window_transcript", - "private_namespace", - "unredacted_internal_path", - "unredacted_private_ip" - ], - "blocked_actions": [ - "send_owner_request", - "confirm_recipient", - "emit_audit_event", - "telegram_send", - "bot_api_call", - "workflow_modification", - "script_modification", - "api_sender_refactor", - "change_chat_route", - "change_bot_token", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "collect_chat_id_secret", - "store_raw_message_payload", - "store_unredacted_log", - "workflow_dispatch", - "production_deploy", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "accept_ui_visible_as_notification_acceptance", - "skip_formatter_convergence", - "skip_redaction_contract", - "open_runtime_gate", - "add_action_button" - ], - "request_sent": false, - "recipient_confirmed": false, - "audit_event_emitted": false, - "owner_response_received": false, - "owner_response_accepted": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "break_glass_fallback_accepted": false, - "direct_bot_api_migration_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - }, - { - "request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_docker_health_monitor_sh", - "source_inventory_schema_version": "telegram_notification_egress_inventory_v1", - "source_path": "scripts/ops/docker-health-monitor.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "line_refs": [ - 120 - ], - "line_hash_refs": [ - "283499ad28d35d6a" - ], - "request_fields": [ - "request_draft_id", - "source_inventory_schema_version", - "source_path", - "surface_kind", - "direct_call_count", - "line_refs", - "line_hash_refs", - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation", - "not_authorization" - ], - "required_owner_fields": [ - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "preflight_checks": [ - "source_inventory_current", - "owner_role_present", - "route_purpose_present", - "message_shape_contract_present", - "redaction_contract_present", - "formatter_convergence_decision_present", - "break_glass_fallback_explicit", - "delivery_receipt_metadata_present", - "dedup_or_fingerprint_present", - "maintenance_window_present_for_change", - "rollback_owner_present", - "postcheck_evidence_present", - "no_secret_value_attested", - "no_raw_payload_attested", - "no_false_green_attested", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "draft_waiting_owner_dispatch", - "request_owner_route_supplement", - "request_formatter_convergence_supplement", - "request_break_glass_fallback_supplement", - "request_redaction_or_receipt_supplement", - "quarantine_secret_or_raw_payload", - "reject_false_green_claim", - "ready_for_manual_dispatch", - "waiting_runtime_gate" - ], - "forbidden_payloads": [ - "bot_token_value", - "chat_secret_value", - "secret_hash", - "partial_token", - "masked_token", - "authorization_header", - "raw_message_payload", - "raw_workflow_log", - "raw_action_log", - "raw_screenshot_with_secret", - "internal_work_window_transcript", - "private_namespace", - "unredacted_internal_path", - "unredacted_private_ip" - ], - "blocked_actions": [ - "send_owner_request", - "confirm_recipient", - "emit_audit_event", - "telegram_send", - "bot_api_call", - "workflow_modification", - "script_modification", - "api_sender_refactor", - "change_chat_route", - "change_bot_token", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "collect_chat_id_secret", - "store_raw_message_payload", - "store_unredacted_log", - "workflow_dispatch", - "production_deploy", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "accept_ui_visible_as_notification_acceptance", - "skip_formatter_convergence", - "skip_redaction_contract", - "open_runtime_gate", - "add_action_button" - ], - "request_sent": false, - "recipient_confirmed": false, - "audit_event_emitted": false, - "owner_response_received": false, - "owner_response_accepted": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "break_glass_fallback_accepted": false, - "direct_bot_api_migration_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - }, - { - "request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_dr_drill_sh", - "source_inventory_schema_version": "telegram_notification_egress_inventory_v1", - "source_path": "scripts/ops/dr-drill.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "line_refs": [ - 63 - ], - "line_hash_refs": [ - "b7cf532f3c5509fc" - ], - "request_fields": [ - "request_draft_id", - "source_inventory_schema_version", - "source_path", - "surface_kind", - "direct_call_count", - "line_refs", - "line_hash_refs", - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation", - "not_authorization" - ], - "required_owner_fields": [ - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "preflight_checks": [ - "source_inventory_current", - "owner_role_present", - "route_purpose_present", - "message_shape_contract_present", - "redaction_contract_present", - "formatter_convergence_decision_present", - "break_glass_fallback_explicit", - "delivery_receipt_metadata_present", - "dedup_or_fingerprint_present", - "maintenance_window_present_for_change", - "rollback_owner_present", - "postcheck_evidence_present", - "no_secret_value_attested", - "no_raw_payload_attested", - "no_false_green_attested", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "draft_waiting_owner_dispatch", - "request_owner_route_supplement", - "request_formatter_convergence_supplement", - "request_break_glass_fallback_supplement", - "request_redaction_or_receipt_supplement", - "quarantine_secret_or_raw_payload", - "reject_false_green_claim", - "ready_for_manual_dispatch", - "waiting_runtime_gate" - ], - "forbidden_payloads": [ - "bot_token_value", - "chat_secret_value", - "secret_hash", - "partial_token", - "masked_token", - "authorization_header", - "raw_message_payload", - "raw_workflow_log", - "raw_action_log", - "raw_screenshot_with_secret", - "internal_work_window_transcript", - "private_namespace", - "unredacted_internal_path", - "unredacted_private_ip" - ], - "blocked_actions": [ - "send_owner_request", - "confirm_recipient", - "emit_audit_event", - "telegram_send", - "bot_api_call", - "workflow_modification", - "script_modification", - "api_sender_refactor", - "change_chat_route", - "change_bot_token", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "collect_chat_id_secret", - "store_raw_message_payload", - "store_unredacted_log", - "workflow_dispatch", - "production_deploy", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "accept_ui_visible_as_notification_acceptance", - "skip_formatter_convergence", - "skip_redaction_contract", - "open_runtime_gate", - "add_action_button" - ], - "request_sent": false, - "recipient_confirmed": false, - "audit_event_emitted": false, - "owner_response_received": false, - "owner_response_accepted": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "break_glass_fallback_accepted": false, - "direct_bot_api_migration_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - }, - { - "request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_pg_backup_sh", - "source_inventory_schema_version": "telegram_notification_egress_inventory_v1", - "source_path": "scripts/ops/pg-backup.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "line_refs": [ - 52 - ], - "line_hash_refs": [ - "8268f3d6f14d66a3" - ], - "request_fields": [ - "request_draft_id", - "source_inventory_schema_version", - "source_path", - "surface_kind", - "direct_call_count", - "line_refs", - "line_hash_refs", - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation", - "not_authorization" - ], - "required_owner_fields": [ - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "preflight_checks": [ - "source_inventory_current", - "owner_role_present", - "route_purpose_present", - "message_shape_contract_present", - "redaction_contract_present", - "formatter_convergence_decision_present", - "break_glass_fallback_explicit", - "delivery_receipt_metadata_present", - "dedup_or_fingerprint_present", - "maintenance_window_present_for_change", - "rollback_owner_present", - "postcheck_evidence_present", - "no_secret_value_attested", - "no_raw_payload_attested", - "no_false_green_attested", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "draft_waiting_owner_dispatch", - "request_owner_route_supplement", - "request_formatter_convergence_supplement", - "request_break_glass_fallback_supplement", - "request_redaction_or_receipt_supplement", - "quarantine_secret_or_raw_payload", - "reject_false_green_claim", - "ready_for_manual_dispatch", - "waiting_runtime_gate" - ], - "forbidden_payloads": [ - "bot_token_value", - "chat_secret_value", - "secret_hash", - "partial_token", - "masked_token", - "authorization_header", - "raw_message_payload", - "raw_workflow_log", - "raw_action_log", - "raw_screenshot_with_secret", - "internal_work_window_transcript", - "private_namespace", - "unredacted_internal_path", - "unredacted_private_ip" - ], - "blocked_actions": [ - "send_owner_request", - "confirm_recipient", - "emit_audit_event", - "telegram_send", - "bot_api_call", - "workflow_modification", - "script_modification", - "api_sender_refactor", - "change_chat_route", - "change_bot_token", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "collect_chat_id_secret", - "store_raw_message_payload", - "store_unredacted_log", - "workflow_dispatch", - "production_deploy", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "accept_ui_visible_as_notification_acceptance", - "skip_formatter_convergence", - "skip_redaction_contract", - "open_runtime_gate", - "add_action_button" - ], - "request_sent": false, - "recipient_confirmed": false, - "audit_event_emitted": false, - "owner_response_received": false, - "owner_response_accepted": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "break_glass_fallback_accepted": false, - "direct_bot_api_migration_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false, - "not_authorization": true - } - ], + "request_drafts": [], "operator_interpretation": [ "This is a draft packet for manual owner dispatch; request_sent_count remains 0.", "Each file-level draft must decide whether the path converges to TelegramGateway, AWOOI Alertmanager, or a documented break-glass fallback.", diff --git a/docs/security/telegram-notification-egress-owner-response-acceptance.snapshot.json b/docs/security/telegram-notification-egress-owner-response-acceptance.snapshot.json index 3caa6f27a..312cc725a 100644 --- a/docs/security/telegram-notification-egress-owner-response-acceptance.snapshot.json +++ b/docs/security/telegram-notification-egress-owner-response-acceptance.snapshot.json @@ -1,8 +1,8 @@ { "schema_version": "telegram_notification_egress_owner_response_acceptance_v1", - "generated_at": "2026-07-02T18:48:33+08:00", - "git_commit": "ae5844733", - "status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "generated_at": "2026-07-02T19:23:58+08:00", + "git_commit": "ca95b95bb", + "status": "owner_response_acceptance_ledger_clear_no_direct_candidates", "mode": "metadata_only_no_secret_value_no_telegram_send_no_workflow_script_api_change", "source_owner_request_snapshot": "docs/security/telegram-notification-egress-owner-request-draft.snapshot.json", "source_owner_request_schema_version": "telegram_notification_egress_owner_request_draft_v1", @@ -12,15 +12,15 @@ "source_migration_plan_status": "migration_plan_draft_ready_no_runtime_action", "message_readability_guard_snapshot": "docs/security/telegram-alert-readability-guard.snapshot.json", "summary": { - "source_request_draft_count": 4, - "source_migration_candidate_count": 4, - "source_direct_bot_api_call_count": 4, - "acceptance_candidate_count": 4, + "source_request_draft_count": 0, + "source_migration_candidate_count": 0, + "source_direct_bot_api_call_count": 0, + "acceptance_candidate_count": 0, "workflow_acceptance_candidate_count": 0, - "ops_script_acceptance_candidate_count": 4, + "ops_script_acceptance_candidate_count": 0, "api_direct_acceptance_candidate_count": 0, "acceptance_field_count": 33, - "required_owner_field_count": 19, + "required_owner_field_count": 0, "reviewer_check_count": 23, "outcome_lane_count": 10, "forbidden_payload_count": 14, @@ -74,884 +74,7 @@ "action_buttons_allowed": false, "not_authorization": true }, - "acceptance_candidates": [ - { - "acceptance_candidate_id": "telegram_notification_egress_owner_response_acceptance:scripts/ops/backup-from-110.sh", - "status": "waiting_owner_response", - "source_request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_backup_from_110_sh", - "source_migration_candidate_id": "telegram_notification_egress_migration:scripts/ops/backup-from-110.sh", - "source_path": "scripts/ops/backup-from-110.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "line_refs": [ - 64 - ], - "line_hash_refs": [ - "ff5ffbeca44d679b" - ], - "proposed_wave": "wave_2_ops_notification_wrapper", - "proposed_target": "scripts/ops/notify-awoooi-ops.sh or AWOOI Alertmanager webhook", - "proposed_change_summary": "Replace direct ops fallback send with normalized ops notification wrapper or documented break-glass fallback.", - "owner_response_ref": null, - "owner_role_or_team": "pending_owner_response", - "decision": "pending_owner_response", - "decision_reason": "pending_owner_response", - "affected_scope": "pending_owner_response", - "redacted_evidence_refs": [], - "message_shape_contract_ref": null, - "message_readability_guard_ref": "docs/security/telegram-alert-readability-guard.snapshot.json", - "redaction_contract_ref": null, - "formatter_convergence_decision": "pending_owner_response", - "gateway_or_alertmanager_target": "pending_owner_response", - "break_glass_fallback_decision": "pending_owner_response", - "delivery_receipt_ref": null, - "dedup_or_fingerprint_plan": "pending_owner_response", - "fallback_or_degraded_mode": "pending_owner_response", - "migration_or_exception_reason": "pending_owner_response", - "maintenance_window": "pending_owner_response", - "rollback_owner": "pending_owner_response", - "postcheck_evidence_ref": null, - "no_secret_value_attestation": "pending_owner_response", - "no_raw_payload_attestation": "pending_owner_response", - "no_false_green_attestation": "pending_owner_response", - "reviewer_outcome": "waiting_owner_response", - "followup_owner": "pending_owner_response", - "acceptance_fields": [ - "acceptance_candidate_id", - "source_request_draft_id", - "source_migration_candidate_id", - "source_path", - "surface_kind", - "direct_call_count", - "proposed_wave", - "proposed_target", - "owner_response_ref", - "owner_role_or_team", - "decision", - "decision_reason", - "affected_scope", - "redacted_evidence_refs", - "message_shape_contract_ref", - "message_readability_guard_ref", - "redaction_contract_ref", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation", - "reviewer_outcome", - "followup_owner", - "not_authorization" - ], - "required_owner_fields": [ - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "reviewer_checks": [ - "source_owner_request_current", - "source_migration_plan_current", - "owner_identity_present", - "decision_reason_present", - "affected_scope_matches_source", - "redacted_refs_only", - "no_secret_or_token_value", - "no_raw_message_payload", - "message_shape_contract_present", - "message_readability_guard_present", - "redaction_contract_present", - "formatter_convergence_explicit", - "gateway_or_alertmanager_target_valid", - "break_glass_fallback_explicit", - "delivery_receipt_metadata_only", - "dedup_or_fingerprint_present", - "maintenance_window_present", - "rollback_owner_present", - "postcheck_evidence_present", - "no_false_green_attested", - "migration_authorization_separate", - "counts_transition_safe", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "waiting_owner_response", - "quarantine_secret_or_raw_payload", - "reject_execution_request", - "request_owner_route_supplement", - "request_formatter_convergence_supplement", - "request_redaction_or_receipt_supplement", - "request_maintenance_or_rollback_supplement", - "ready_for_migration_review", - "owner_review_only_update", - "waiting_runtime_gate" - ], - "forbidden_payloads": [ - "bot_token_value", - "chat_secret_value", - "secret_hash", - "partial_token", - "masked_token", - "authorization_header", - "raw_message_payload", - "raw_workflow_log", - "raw_action_log", - "raw_screenshot_with_secret", - "internal_work_window_transcript", - "private_namespace", - "unredacted_internal_path", - "unredacted_private_ip" - ], - "blocked_actions": [ - "mark_owner_response_received_without_record", - "mark_owner_response_accepted_without_reviewer_record", - "send_telegram", - "call_bot_api", - "modify_workflow", - "modify_ops_script", - "refactor_api_sender", - "dispatch_workflow", - "trigger_cd", - "deploy_production", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "collect_chat_id_secret", - "store_raw_message_payload", - "store_unredacted_log", - "store_internal_work_window_transcript", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "accept_ui_visible_as_notification_acceptance", - "accept_telegram_sent_without_delivery_receipt", - "skip_formatter_convergence", - "skip_redaction_contract", - "skip_dedup_or_fingerprint_review", - "skip_break_glass_fallback_review", - "authorize_migration", - "authorize_workflow_modification", - "authorize_script_modification", - "authorize_api_sender_refactor", - "open_runtime_gate", - "add_action_button" - ], - "not_authorization": true, - "request_sent": false, - "recipient_confirmed": false, - "audit_event_emitted": false, - "owner_response_received": false, - "owner_response_accepted": false, - "owner_response_rejected": false, - "owner_response_quarantined": false, - "supplement_requested": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "break_glass_fallback_accepted": false, - "maintenance_window_accepted": false, - "rollback_owner_accepted": false, - "postcheck_evidence_accepted": false, - "dedup_or_fingerprint_accepted": false, - "no_false_green_accepted": false, - "direct_bot_api_migration_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_dispatch_authorized": false, - "production_deploy_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false - }, - { - "acceptance_candidate_id": "telegram_notification_egress_owner_response_acceptance:scripts/ops/docker-health-monitor.sh", - "status": "waiting_owner_response", - "source_request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_docker_health_monitor_sh", - "source_migration_candidate_id": "telegram_notification_egress_migration:scripts/ops/docker-health-monitor.sh", - "source_path": "scripts/ops/docker-health-monitor.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "line_refs": [ - 120 - ], - "line_hash_refs": [ - "283499ad28d35d6a" - ], - "proposed_wave": "wave_2_ops_notification_wrapper", - "proposed_target": "scripts/ops/notify-awoooi-ops.sh or AWOOI Alertmanager webhook", - "proposed_change_summary": "Replace direct ops fallback send with normalized ops notification wrapper or documented break-glass fallback.", - "owner_response_ref": null, - "owner_role_or_team": "pending_owner_response", - "decision": "pending_owner_response", - "decision_reason": "pending_owner_response", - "affected_scope": "pending_owner_response", - "redacted_evidence_refs": [], - "message_shape_contract_ref": null, - "message_readability_guard_ref": "docs/security/telegram-alert-readability-guard.snapshot.json", - "redaction_contract_ref": null, - "formatter_convergence_decision": "pending_owner_response", - "gateway_or_alertmanager_target": "pending_owner_response", - "break_glass_fallback_decision": "pending_owner_response", - "delivery_receipt_ref": null, - "dedup_or_fingerprint_plan": "pending_owner_response", - "fallback_or_degraded_mode": "pending_owner_response", - "migration_or_exception_reason": "pending_owner_response", - "maintenance_window": "pending_owner_response", - "rollback_owner": "pending_owner_response", - "postcheck_evidence_ref": null, - "no_secret_value_attestation": "pending_owner_response", - "no_raw_payload_attestation": "pending_owner_response", - "no_false_green_attestation": "pending_owner_response", - "reviewer_outcome": "waiting_owner_response", - "followup_owner": "pending_owner_response", - "acceptance_fields": [ - "acceptance_candidate_id", - "source_request_draft_id", - "source_migration_candidate_id", - "source_path", - "surface_kind", - "direct_call_count", - "proposed_wave", - "proposed_target", - "owner_response_ref", - "owner_role_or_team", - "decision", - "decision_reason", - "affected_scope", - "redacted_evidence_refs", - "message_shape_contract_ref", - "message_readability_guard_ref", - "redaction_contract_ref", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation", - "reviewer_outcome", - "followup_owner", - "not_authorization" - ], - "required_owner_fields": [ - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "reviewer_checks": [ - "source_owner_request_current", - "source_migration_plan_current", - "owner_identity_present", - "decision_reason_present", - "affected_scope_matches_source", - "redacted_refs_only", - "no_secret_or_token_value", - "no_raw_message_payload", - "message_shape_contract_present", - "message_readability_guard_present", - "redaction_contract_present", - "formatter_convergence_explicit", - "gateway_or_alertmanager_target_valid", - "break_glass_fallback_explicit", - "delivery_receipt_metadata_only", - "dedup_or_fingerprint_present", - "maintenance_window_present", - "rollback_owner_present", - "postcheck_evidence_present", - "no_false_green_attested", - "migration_authorization_separate", - "counts_transition_safe", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "waiting_owner_response", - "quarantine_secret_or_raw_payload", - "reject_execution_request", - "request_owner_route_supplement", - "request_formatter_convergence_supplement", - "request_redaction_or_receipt_supplement", - "request_maintenance_or_rollback_supplement", - "ready_for_migration_review", - "owner_review_only_update", - "waiting_runtime_gate" - ], - "forbidden_payloads": [ - "bot_token_value", - "chat_secret_value", - "secret_hash", - "partial_token", - "masked_token", - "authorization_header", - "raw_message_payload", - "raw_workflow_log", - "raw_action_log", - "raw_screenshot_with_secret", - "internal_work_window_transcript", - "private_namespace", - "unredacted_internal_path", - "unredacted_private_ip" - ], - "blocked_actions": [ - "mark_owner_response_received_without_record", - "mark_owner_response_accepted_without_reviewer_record", - "send_telegram", - "call_bot_api", - "modify_workflow", - "modify_ops_script", - "refactor_api_sender", - "dispatch_workflow", - "trigger_cd", - "deploy_production", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "collect_chat_id_secret", - "store_raw_message_payload", - "store_unredacted_log", - "store_internal_work_window_transcript", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "accept_ui_visible_as_notification_acceptance", - "accept_telegram_sent_without_delivery_receipt", - "skip_formatter_convergence", - "skip_redaction_contract", - "skip_dedup_or_fingerprint_review", - "skip_break_glass_fallback_review", - "authorize_migration", - "authorize_workflow_modification", - "authorize_script_modification", - "authorize_api_sender_refactor", - "open_runtime_gate", - "add_action_button" - ], - "not_authorization": true, - "request_sent": false, - "recipient_confirmed": false, - "audit_event_emitted": false, - "owner_response_received": false, - "owner_response_accepted": false, - "owner_response_rejected": false, - "owner_response_quarantined": false, - "supplement_requested": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "break_glass_fallback_accepted": false, - "maintenance_window_accepted": false, - "rollback_owner_accepted": false, - "postcheck_evidence_accepted": false, - "dedup_or_fingerprint_accepted": false, - "no_false_green_accepted": false, - "direct_bot_api_migration_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_dispatch_authorized": false, - "production_deploy_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false - }, - { - "acceptance_candidate_id": "telegram_notification_egress_owner_response_acceptance:scripts/ops/dr-drill.sh", - "status": "waiting_owner_response", - "source_request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_dr_drill_sh", - "source_migration_candidate_id": "telegram_notification_egress_migration:scripts/ops/dr-drill.sh", - "source_path": "scripts/ops/dr-drill.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "line_refs": [ - 63 - ], - "line_hash_refs": [ - "b7cf532f3c5509fc" - ], - "proposed_wave": "wave_2_ops_notification_wrapper", - "proposed_target": "scripts/ops/notify-awoooi-ops.sh or AWOOI Alertmanager webhook", - "proposed_change_summary": "Replace direct ops fallback send with normalized ops notification wrapper or documented break-glass fallback.", - "owner_response_ref": null, - "owner_role_or_team": "pending_owner_response", - "decision": "pending_owner_response", - "decision_reason": "pending_owner_response", - "affected_scope": "pending_owner_response", - "redacted_evidence_refs": [], - "message_shape_contract_ref": null, - "message_readability_guard_ref": "docs/security/telegram-alert-readability-guard.snapshot.json", - "redaction_contract_ref": null, - "formatter_convergence_decision": "pending_owner_response", - "gateway_or_alertmanager_target": "pending_owner_response", - "break_glass_fallback_decision": "pending_owner_response", - "delivery_receipt_ref": null, - "dedup_or_fingerprint_plan": "pending_owner_response", - "fallback_or_degraded_mode": "pending_owner_response", - "migration_or_exception_reason": "pending_owner_response", - "maintenance_window": "pending_owner_response", - "rollback_owner": "pending_owner_response", - "postcheck_evidence_ref": null, - "no_secret_value_attestation": "pending_owner_response", - "no_raw_payload_attestation": "pending_owner_response", - "no_false_green_attestation": "pending_owner_response", - "reviewer_outcome": "waiting_owner_response", - "followup_owner": "pending_owner_response", - "acceptance_fields": [ - "acceptance_candidate_id", - "source_request_draft_id", - "source_migration_candidate_id", - "source_path", - "surface_kind", - "direct_call_count", - "proposed_wave", - "proposed_target", - "owner_response_ref", - "owner_role_or_team", - "decision", - "decision_reason", - "affected_scope", - "redacted_evidence_refs", - "message_shape_contract_ref", - "message_readability_guard_ref", - "redaction_contract_ref", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation", - "reviewer_outcome", - "followup_owner", - "not_authorization" - ], - "required_owner_fields": [ - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "reviewer_checks": [ - "source_owner_request_current", - "source_migration_plan_current", - "owner_identity_present", - "decision_reason_present", - "affected_scope_matches_source", - "redacted_refs_only", - "no_secret_or_token_value", - "no_raw_message_payload", - "message_shape_contract_present", - "message_readability_guard_present", - "redaction_contract_present", - "formatter_convergence_explicit", - "gateway_or_alertmanager_target_valid", - "break_glass_fallback_explicit", - "delivery_receipt_metadata_only", - "dedup_or_fingerprint_present", - "maintenance_window_present", - "rollback_owner_present", - "postcheck_evidence_present", - "no_false_green_attested", - "migration_authorization_separate", - "counts_transition_safe", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "waiting_owner_response", - "quarantine_secret_or_raw_payload", - "reject_execution_request", - "request_owner_route_supplement", - "request_formatter_convergence_supplement", - "request_redaction_or_receipt_supplement", - "request_maintenance_or_rollback_supplement", - "ready_for_migration_review", - "owner_review_only_update", - "waiting_runtime_gate" - ], - "forbidden_payloads": [ - "bot_token_value", - "chat_secret_value", - "secret_hash", - "partial_token", - "masked_token", - "authorization_header", - "raw_message_payload", - "raw_workflow_log", - "raw_action_log", - "raw_screenshot_with_secret", - "internal_work_window_transcript", - "private_namespace", - "unredacted_internal_path", - "unredacted_private_ip" - ], - "blocked_actions": [ - "mark_owner_response_received_without_record", - "mark_owner_response_accepted_without_reviewer_record", - "send_telegram", - "call_bot_api", - "modify_workflow", - "modify_ops_script", - "refactor_api_sender", - "dispatch_workflow", - "trigger_cd", - "deploy_production", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "collect_chat_id_secret", - "store_raw_message_payload", - "store_unredacted_log", - "store_internal_work_window_transcript", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "accept_ui_visible_as_notification_acceptance", - "accept_telegram_sent_without_delivery_receipt", - "skip_formatter_convergence", - "skip_redaction_contract", - "skip_dedup_or_fingerprint_review", - "skip_break_glass_fallback_review", - "authorize_migration", - "authorize_workflow_modification", - "authorize_script_modification", - "authorize_api_sender_refactor", - "open_runtime_gate", - "add_action_button" - ], - "not_authorization": true, - "request_sent": false, - "recipient_confirmed": false, - "audit_event_emitted": false, - "owner_response_received": false, - "owner_response_accepted": false, - "owner_response_rejected": false, - "owner_response_quarantined": false, - "supplement_requested": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "break_glass_fallback_accepted": false, - "maintenance_window_accepted": false, - "rollback_owner_accepted": false, - "postcheck_evidence_accepted": false, - "dedup_or_fingerprint_accepted": false, - "no_false_green_accepted": false, - "direct_bot_api_migration_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_dispatch_authorized": false, - "production_deploy_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false - }, - { - "acceptance_candidate_id": "telegram_notification_egress_owner_response_acceptance:scripts/ops/pg-backup.sh", - "status": "waiting_owner_response", - "source_request_draft_id": "telegram_notification_egress_owner_request:scripts_ops_pg_backup_sh", - "source_migration_candidate_id": "telegram_notification_egress_migration:scripts/ops/pg-backup.sh", - "source_path": "scripts/ops/pg-backup.sh", - "surface_kind": "ops_script_direct_bot_api", - "direct_call_count": 1, - "line_refs": [ - 52 - ], - "line_hash_refs": [ - "8268f3d6f14d66a3" - ], - "proposed_wave": "wave_2_ops_notification_wrapper", - "proposed_target": "scripts/ops/notify-awoooi-ops.sh or AWOOI Alertmanager webhook", - "proposed_change_summary": "Replace direct ops fallback send with normalized ops notification wrapper or documented break-glass fallback.", - "owner_response_ref": null, - "owner_role_or_team": "pending_owner_response", - "decision": "pending_owner_response", - "decision_reason": "pending_owner_response", - "affected_scope": "pending_owner_response", - "redacted_evidence_refs": [], - "message_shape_contract_ref": null, - "message_readability_guard_ref": "docs/security/telegram-alert-readability-guard.snapshot.json", - "redaction_contract_ref": null, - "formatter_convergence_decision": "pending_owner_response", - "gateway_or_alertmanager_target": "pending_owner_response", - "break_glass_fallback_decision": "pending_owner_response", - "delivery_receipt_ref": null, - "dedup_or_fingerprint_plan": "pending_owner_response", - "fallback_or_degraded_mode": "pending_owner_response", - "migration_or_exception_reason": "pending_owner_response", - "maintenance_window": "pending_owner_response", - "rollback_owner": "pending_owner_response", - "postcheck_evidence_ref": null, - "no_secret_value_attestation": "pending_owner_response", - "no_raw_payload_attestation": "pending_owner_response", - "no_false_green_attestation": "pending_owner_response", - "reviewer_outcome": "waiting_owner_response", - "followup_owner": "pending_owner_response", - "acceptance_fields": [ - "acceptance_candidate_id", - "source_request_draft_id", - "source_migration_candidate_id", - "source_path", - "surface_kind", - "direct_call_count", - "proposed_wave", - "proposed_target", - "owner_response_ref", - "owner_role_or_team", - "decision", - "decision_reason", - "affected_scope", - "redacted_evidence_refs", - "message_shape_contract_ref", - "message_readability_guard_ref", - "redaction_contract_ref", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation", - "reviewer_outcome", - "followup_owner", - "not_authorization" - ], - "required_owner_fields": [ - "owner_role_or_team", - "routing_purpose", - "current_sender", - "target_chat_route", - "message_shape_contract", - "redaction_contract", - "formatter_convergence_decision", - "gateway_or_alertmanager_target", - "break_glass_fallback_decision", - "delivery_receipt_ref", - "dedup_or_fingerprint_plan", - "fallback_or_degraded_mode", - "migration_or_exception_reason", - "maintenance_window", - "rollback_owner", - "postcheck_evidence_ref", - "no_secret_value_attestation", - "no_raw_payload_attestation", - "no_false_green_attestation" - ], - "reviewer_checks": [ - "source_owner_request_current", - "source_migration_plan_current", - "owner_identity_present", - "decision_reason_present", - "affected_scope_matches_source", - "redacted_refs_only", - "no_secret_or_token_value", - "no_raw_message_payload", - "message_shape_contract_present", - "message_readability_guard_present", - "redaction_contract_present", - "formatter_convergence_explicit", - "gateway_or_alertmanager_target_valid", - "break_glass_fallback_explicit", - "delivery_receipt_metadata_only", - "dedup_or_fingerprint_present", - "maintenance_window_present", - "rollback_owner_present", - "postcheck_evidence_present", - "no_false_green_attested", - "migration_authorization_separate", - "counts_transition_safe", - "runtime_gate_stays_zero" - ], - "outcome_lanes": [ - "waiting_owner_response", - "quarantine_secret_or_raw_payload", - "reject_execution_request", - "request_owner_route_supplement", - "request_formatter_convergence_supplement", - "request_redaction_or_receipt_supplement", - "request_maintenance_or_rollback_supplement", - "ready_for_migration_review", - "owner_review_only_update", - "waiting_runtime_gate" - ], - "forbidden_payloads": [ - "bot_token_value", - "chat_secret_value", - "secret_hash", - "partial_token", - "masked_token", - "authorization_header", - "raw_message_payload", - "raw_workflow_log", - "raw_action_log", - "raw_screenshot_with_secret", - "internal_work_window_transcript", - "private_namespace", - "unredacted_internal_path", - "unredacted_private_ip" - ], - "blocked_actions": [ - "mark_owner_response_received_without_record", - "mark_owner_response_accepted_without_reviewer_record", - "send_telegram", - "call_bot_api", - "modify_workflow", - "modify_ops_script", - "refactor_api_sender", - "dispatch_workflow", - "trigger_cd", - "deploy_production", - "change_chat_route", - "change_bot_token", - "rotate_secret", - "read_secret_store", - "collect_secret_value", - "collect_secret_hash", - "collect_partial_token", - "collect_chat_id_secret", - "store_raw_message_payload", - "store_unredacted_log", - "store_internal_work_window_transcript", - "accept_cd_success_as_delivery_receipt", - "accept_route_200_as_notification_delivery", - "accept_ui_visible_as_notification_acceptance", - "accept_telegram_sent_without_delivery_receipt", - "skip_formatter_convergence", - "skip_redaction_contract", - "skip_dedup_or_fingerprint_review", - "skip_break_glass_fallback_review", - "authorize_migration", - "authorize_workflow_modification", - "authorize_script_modification", - "authorize_api_sender_refactor", - "open_runtime_gate", - "add_action_button" - ], - "not_authorization": true, - "request_sent": false, - "recipient_confirmed": false, - "audit_event_emitted": false, - "owner_response_received": false, - "owner_response_accepted": false, - "owner_response_rejected": false, - "owner_response_quarantined": false, - "supplement_requested": false, - "formatter_convergence_accepted": false, - "redaction_contract_accepted": false, - "delivery_receipt_accepted": false, - "break_glass_fallback_accepted": false, - "maintenance_window_accepted": false, - "rollback_owner_accepted": false, - "postcheck_evidence_accepted": false, - "dedup_or_fingerprint_accepted": false, - "no_false_green_accepted": false, - "direct_bot_api_migration_authorized": false, - "workflow_modification_authorized": false, - "script_modification_authorized": false, - "api_sender_refactor_authorized": false, - "telegram_send_authorized": false, - "bot_api_call_authorized": false, - "workflow_dispatch_authorized": false, - "production_deploy_authorized": false, - "secret_value_collection_allowed": false, - "raw_payload_storage_allowed": false, - "production_write_authorized": false, - "runtime_gate": false, - "action_buttons_allowed": false - } - ], + "acceptance_candidates": [], "operator_interpretation": [ "此帳本只是 reviewer 驗收模板;owner response received / accepted 仍維持 0。", "每個 direct egress candidate 都必須引用 Telegram 告警可讀性 guard,migration review 不得繞過卡片化、脫敏與 runtime_write_gate=0。", diff --git a/scripts/ops/backup-from-110.sh b/scripts/ops/backup-from-110.sh index 8b5575ec5..01cb0357a 100644 --- a/scripts/ops/backup-from-110.sh +++ b/scripts/ops/backup-from-110.sh @@ -18,7 +18,7 @@ # # 成功/失敗狀態: # - 寫入 BACKUP_LAST_SUCCESS_TS 到 /var/run/backup-110.last_success -# - 失敗時傳送 Telegram 告警(若設定了 TG_BOT_TOKEN) +# - 失敗時透過 AWOOI Alertmanager webhook 進 TelegramGateway / AwoooP receipt path # # Sprint C ADR-069 (2026-04-11 Claude Sonnet 4.6 Asia/Taipei) # ============================================================================= @@ -56,26 +56,17 @@ notify_awoooi_ops() { "$helper" >/dev/null } -notify_telegram_fallback() { - local msg="$1" - local tg_token="${TG_BOT_TOKEN:-${TELEGRAM_BOT_TOKEN:-}}" - local tg_chat="${SRE_GROUP_CHAT_ID:--1003711974679}" - if [ -n "$tg_token" ] && [ -n "$tg_chat" ]; then - curl -s -X POST "https://api.telegram.org/bot${tg_token}/sendMessage" \ - -d "chat_id=${tg_chat}" \ - --data-urlencode "text=${msg}" \ - > /dev/null || true - fi -} - notify_ops() { local status="$1" local msg="$2" - # 正式路徑:先交給 AWOOI API,由 TelegramGateway 送出並鏡像到 AwoooP。 - # 只有 API 不可達或 helper 未部署時,才使用 Telegram 直發救命旁路。 - notify_awoooi_ops "$status" "$msg" && return 0 - notify_telegram_fallback "$msg" + # 所有通知都必須交給 AWOOI API,由 TelegramGateway 送出並鏡像到 AwoooP。 + # API 不可達時只留下本地 log,避免繞過 DB/log receipt 與 AI automation。 + if notify_awoooi_ops "$status" "$msg"; then + return 0 + fi + log "WARN: AWOOI API notification unavailable; direct Telegram fallback disabled; receipt remains local" + return 0 } # ── Harbor registry data ────────────────────────────────────────────────────── diff --git a/scripts/ops/docker-health-monitor.sh b/scripts/ops/docker-health-monitor.sh index 34735b819..db489d289 100755 --- a/scripts/ops/docker-health-monitor.sh +++ b/scripts/ops/docker-health-monitor.sh @@ -23,18 +23,14 @@ if [[ -f "$SECRETS_FILE" ]]; then fi : "${AWOOOI_API_URL:=https://awoooi.wooo.work}" -: "${TELEGRAM_BOT_TOKEN:=}" : "${SRE_GROUP_CHAT_ID:=-1003711974679}" -: "${TELEGRAM_ALERT_CHAT_ID:=${SRE_GROUP_CHAT_ID:-${TELEGRAM_CHAT_ID:-}}}" : "${LOG_FILE:=/var/log/docker-health-monitor.log}" : "${SEND_COOLDOWN_SECONDS:=300}" : "${ACTION_COOLDOWN_SECONDS:=${SEND_COOLDOWN_SECONDS}}" -: "${NOTIFY_COOLDOWN_SECONDS:=1800}" : "${COOLDOWN_DIR:=/tmp/docker-health-monitor-cooldown}" -: "${NOTIFY_COOLDOWN_DIR:=${COOLDOWN_DIR}/notify}" : "${EXCLUDE_CONTAINERS:=signoz-telemetrystore-migrator,signoz-clickhouse,signoz-init-clickhouse,gitea-runner,vtuber-web,vtuber-admin,vtuber-api,vtuber-db,bitan-pharmacy-bitan-1}" -mkdir -p "$COOLDOWN_DIR" "$NOTIFY_COOLDOWN_DIR" +mkdir -p "$COOLDOWN_DIR" # ─── 禁止自動重啟的容器 (模式匹配) ───────────────────────────────────────── # DB / Cache / 監控棧核心 — 僅告警,不自動重啟 @@ -74,32 +70,6 @@ set_cooldown() { date +%s > "${COOLDOWN_DIR}/${container}.cooldown" } -safe_cooldown_key() { - tr -c 'A-Za-z0-9_.-' '_' <<< "$1" -} - -should_send_direct_telegram() { - local fingerprint="$1" - local cooldown_key - local cooldown_file - cooldown_key="$(safe_cooldown_key "$fingerprint")" - cooldown_file="${NOTIFY_COOLDOWN_DIR}/${cooldown_key}.cooldown" - - if [[ -f "$cooldown_file" ]]; then - local last_sent now elapsed - last_sent=$(cat "$cooldown_file" 2>/dev/null || echo 0) - now=$(date +%s) - elapsed=$(( now - last_sent )) - if (( elapsed < NOTIFY_COOLDOWN_SECONDS )); then - log "TELEGRAM_COOLDOWN: ${fingerprint} ${elapsed}s/${NOTIFY_COOLDOWN_SECONDS}s,跳過直發" - return 1 - fi - fi - - date +%s > "$cooldown_file" - return 0 -} - # 判斷容器是否符合模式清單 matches_pattern() { local name="$1" @@ -113,16 +83,6 @@ matches_pattern() { return 1 } -# ─── Telegram 直發 Fallback ────────────────────────────────────────────────── -send_telegram_direct() { - local message="$1" - [[ -z "$TELEGRAM_BOT_TOKEN" || -z "$TELEGRAM_ALERT_CHAT_ID" ]] && return 0 - curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -H "Content-Type: application/json" \ - -d "{\"chat_id\":\"${TELEGRAM_ALERT_CHAT_ID}\",\"text\":\"${message}\",\"parse_mode\":\"HTML\"}" \ - > /dev/null 2>&1 || true -} - # ─── 回報到 AWOOOI API ─────────────────────────────────────────────────────── report_to_awoooi() { local container="$1" @@ -178,13 +138,7 @@ JSON if [[ "$http_code" == "200" || "$http_code" == "202" ]]; then log "REPORTED: ${container} repair=${repair_action}(${repair_result}) → API (${http_code})" else - log "WARN: API 回應 ${http_code},Fallback Telegram" - local emoji="🔧" - [[ "$repair_result" == "failed" ]] && emoji="❌" - [[ "$repair_action" == "alert_only" ]] && emoji="⚠️" - if should_send_direct_telegram "${hostname}:${container}:${detected_status}:${repair_action}:${repair_result}:${http_code}"; then - send_telegram_direct "${emoji} [docker-health-monitor] 主機: ${hostname} 容器: ${container} 狀態: ${detected_status} 修復: ${repair_action} → ${repair_result} (API 不可達)" - fi + log "WARN: API 回應 ${http_code};direct Telegram fallback disabled,事件保留在本地 log 等 AI log ingestion" fi } diff --git a/scripts/ops/dr-drill.sh b/scripts/ops/dr-drill.sh index 3ae873ba6..08c8f7f2a 100644 --- a/scripts/ops/dr-drill.sh +++ b/scripts/ops/dr-drill.sh @@ -11,7 +11,7 @@ # 3. 等待 Pod Ready(最多 10 分鐘) # 4. 驗證 API health endpoint # 5. 清理 dr-test namespace + restore 資源 -# 6. Telegram 通知結果 +# 6. 透過 AWOOI Alertmanager webhook 通知結果,進 TelegramGateway / AwoooP receipt path # # 2026-04-09 Claude Sonnet 4.6 Asia/Taipei @@ -54,18 +54,13 @@ notify_telegram() { local msg="$1" local status="${2:-success}" - # 正式路徑:先交給 AWOOI API,由 TelegramGateway 送出並鏡像到 AwoooP。 - # 只有 API 不可達或 helper 未部署時,才使用 Telegram 直發救命旁路。 - notify_awoooi_ops "$status" "$msg" && return 0 - - local chat_id="${SRE_GROUP_CHAT_ID:--1003711974679}" - if [[ -n "${TELEGRAM_BOT_TOKEN:-}" && -n "$chat_id" ]]; then - curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -d "chat_id=${chat_id}" \ - -d "parse_mode=HTML" \ - --data-urlencode "text=${msg}" \ - > /dev/null 2>&1 || true + # 所有通知都必須交給 AWOOI API,由 TelegramGateway 送出並鏡像到 AwoooP。 + # API 不可達時只留下本地 log,避免繞過 DB/log receipt 與 AI automation。 + if notify_awoooi_ops "$status" "$msg"; then + return 0 fi + log "WARN: AWOOI API notification unavailable; direct Telegram fallback disabled; receipt remains local" + return 0 } kubectl_cmd() { diff --git a/scripts/ops/notify-awoooi-ops.sh b/scripts/ops/notify-awoooi-ops.sh index a112c6e89..2fb389bf1 100755 --- a/scripts/ops/notify-awoooi-ops.sh +++ b/scripts/ops/notify-awoooi-ops.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# 2026-05-12 Codex: Ops 通知先走 AWOOI Alertmanager 入口,讓 TelegramGateway -# 統一送出並鏡像到 AwoooP。呼叫端保留直接 Telegram fallback 作為 API 離線備援。 +# 2026-07-02 Codex: Ops 通知只走 AWOOI Alertmanager 入口,讓 TelegramGateway +# 統一送出、鏡像到 AwoooP,並保留 DB/log receipt;禁止呼叫端再走 direct Bot API fallback。 set -euo pipefail API_BASE="${AWOOOI_API_URL:-https://awoooi.wooo.work}" diff --git a/scripts/ops/pg-backup.sh b/scripts/ops/pg-backup.sh index d330e9fed..5b834c21d 100644 --- a/scripts/ops/pg-backup.sh +++ b/scripts/ops/pg-backup.sh @@ -14,7 +14,7 @@ RETAIN_DAYS="${RETAIN_DAYS:-7}" AWOOOI_API_URL="${AWOOOI_API_URL:-https://awoooi.wooo.work}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# 載入 secrets(含 Telegram token for fallback) +# 載入受控 ops 通知所需環境;禁止 direct Bot API fallback。 [[ -f "$SECRETS_FILE" ]] && source "$SECRETS_FILE" TIMESTAMP=$(date '+%Y%m%d_%H%M%S') @@ -43,18 +43,13 @@ notify_telegram() { local msg="$1" local status="${2:-success}" - # 正式路徑:先交給 AWOOI API,由 TelegramGateway 送出並鏡像到 AwoooP。 - # 只有 API 不可達或 helper 未部署時,才使用 Telegram 直發救命旁路。 - notify_awoooi_ops "$status" "$msg" && return 0 - - local chat_id="${SRE_GROUP_CHAT_ID:--1003711974679}" - if [[ -n "${TELEGRAM_BOT_TOKEN:-}" && -n "$chat_id" ]]; then - curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -d "chat_id=${chat_id}" \ - -d "parse_mode=HTML" \ - --data-urlencode "text=${msg}" \ - > /dev/null 2>&1 || true + # 所有通知都必須交給 AWOOI API,由 TelegramGateway 送出並鏡像到 AwoooP。 + # API 不可達時只留下本地 log,避免繞過 DB/log receipt 與 AI automation。 + if notify_awoooi_ops "$status" "$msg"; then + return 0 fi + log "WARN: AWOOI API notification unavailable; direct Telegram fallback disabled; receipt remains local" + return 0 } backup_db() { diff --git a/scripts/security/security-mirror-progress-guard.py b/scripts/security/security-mirror-progress-guard.py index 79ba3c661..99a2d48d4 100755 --- a/scripts/security/security-mirror-progress-guard.py +++ b/scripts/security/security-mirror-progress-guard.py @@ -21645,12 +21645,12 @@ def validate(root: Path) -> None: "repo_only_scan_no_secret_value_no_telegram_send", ) expected_telegram_notification_egress_summary = { - "direct_bot_api_file_count": 5, - "direct_bot_api_call_count": 5, + "direct_bot_api_file_count": 0, + "direct_bot_api_call_count": 0, "workflow_direct_bot_api_call_count": 0, - "ops_script_direct_bot_api_call_count": 4, + "ops_script_direct_bot_api_call_count": 0, "ci_script_direct_bot_api_call_count": 0, - "api_direct_bot_api_call_count": 1, + "api_direct_bot_api_call_count": 0, "gateway_normalized_callsite_count": 57, "gateway_final_exit_formatter_present_count": 1, "required_owner_field_count": 18, @@ -21679,13 +21679,7 @@ def validate(root: Path) -> None: telegram_notification_egress_inventory["summary"][key], expected, ) - expected_telegram_direct_path_counts = { - "apps/api/src/services/channel_hub.py": 1, - "scripts/ops/backup-from-110.sh": 1, - "scripts/ops/docker-health-monitor.sh": 1, - "scripts/ops/dr-drill.sh": 1, - "scripts/ops/pg-backup.sh": 1, - } + expected_telegram_direct_path_counts: dict[str, int] = {} actual_telegram_direct_path_counts: dict[str, int] = {} for item in telegram_notification_egress_inventory["direct_bot_api_calls"]: actual_telegram_direct_path_counts[item["path"]] = actual_telegram_direct_path_counts.get(item["path"], 0) + 1 @@ -21761,13 +21755,13 @@ def validate(root: Path) -> None: "metadata_only_no_secret_value_no_telegram_send_no_workflow_change", ) expected_telegram_egress_owner_request_summary = { - "source_direct_bot_api_call_count": 5, - "source_direct_bot_api_file_count": 5, - "request_draft_count": 5, + "source_direct_bot_api_call_count": 0, + "source_direct_bot_api_file_count": 0, + "request_draft_count": 0, "workflow_request_draft_count": 0, - "ops_script_request_draft_count": 4, + "ops_script_request_draft_count": 0, "ci_script_request_draft_count": 0, - "api_direct_request_draft_count": 1, + "api_direct_request_draft_count": 0, "request_field_count": 27, "required_owner_field_count": 19, "preflight_check_count": 16, @@ -21801,13 +21795,7 @@ def validate(root: Path) -> None: telegram_notification_egress_owner_request_draft["summary"][key], expected, ) - expected_telegram_egress_request_paths = [ - "apps/api/src/services/channel_hub.py", - "scripts/ops/backup-from-110.sh", - "scripts/ops/docker-health-monitor.sh", - "scripts/ops/dr-drill.sh", - "scripts/ops/pg-backup.sh", - ] + expected_telegram_egress_request_paths: list[str] = [] assert_equal( "telegram_notification_egress_owner_request_draft.source_paths", [item["source_path"] for item in telegram_notification_egress_owner_request_draft["request_drafts"]], @@ -21895,22 +21883,22 @@ def validate(root: Path) -> None: "metadata_only_no_workflow_script_api_change_no_telegram_send", ) expected_telegram_egress_migration_plan_summary = { - "source_request_draft_count": 5, - "source_direct_bot_api_call_count": 5, - "migration_candidate_count": 5, + "source_request_draft_count": 0, + "source_direct_bot_api_call_count": 0, + "migration_candidate_count": 0, "workflow_migration_candidate_count": 0, - "ops_script_migration_candidate_count": 4, - "api_direct_migration_candidate_count": 1, - "proposed_wave_count": 2, + "ops_script_migration_candidate_count": 0, + "api_direct_migration_candidate_count": 0, + "proposed_wave_count": 0, "plan_field_count": 17, "reviewer_check_count": 15, "outcome_lane_count": 9, "blocked_action_count": 21, - "owner_response_required_count": 5, - "maintenance_window_required_count": 5, - "rollback_owner_required_count": 5, - "postcheck_required_count": 5, - "delivery_receipt_required_count": 5, + "owner_response_required_count": 0, + "maintenance_window_required_count": 0, + "rollback_owner_required_count": 0, + "postcheck_required_count": 0, + "delivery_receipt_required_count": 0, "owner_response_received_count": 0, "owner_response_accepted_count": 0, "migration_authorized_count": 0, @@ -21934,10 +21922,7 @@ def validate(root: Path) -> None: assert_equal( "telegram_notification_egress_migration_plan_draft.proposed_waves", telegram_notification_egress_migration_plan_draft["proposed_waves"], - [ - "wave_2_ops_notification_wrapper", - "wave_3_api_sender_gateway", - ], + [], ) for key, value in telegram_notification_egress_migration_plan_draft["execution_boundaries"].items(): if key == "not_authorization": @@ -22012,13 +21997,13 @@ def validate(root: Path) -> None: "repo_source_scan_no_secret_value_no_telegram_send", ) expected_telegram_egress_no_new_bypass_summary = { - "source_direct_bot_api_call_count": 5, - "source_direct_bot_api_file_count": 5, - "baseline_signature_count": 5, - "current_direct_bot_api_call_count": 5, - "current_direct_bot_api_file_count": 5, + "source_direct_bot_api_call_count": 0, + "source_direct_bot_api_file_count": 0, + "baseline_signature_count": 0, + "current_direct_bot_api_call_count": 0, + "current_direct_bot_api_file_count": 0, "guarded_method_count": 9, - "sendMessage_call_count": 5, + "sendMessage_call_count": 0, "sendDocument_call_count": 0, "sendPhoto_call_count": 0, "sendMediaGroup_call_count": 0, @@ -22039,13 +22024,7 @@ def validate(root: Path) -> None: assert_equal( "telegram_notification_egress_no_new_bypass_guard.current_paths", [item["path"] for item in telegram_notification_egress_no_new_bypass_guard["current_direct_bot_api_calls"]], - [ - "apps/api/src/services/channel_hub.py", - "scripts/ops/backup-from-110.sh", - "scripts/ops/docker-health-monitor.sh", - "scripts/ops/dr-drill.sh", - "scripts/ops/pg-backup.sh", - ], + [], ) assert_equal( "telegram_notification_egress_no_new_bypass_guard.new_bypass_findings", @@ -22070,7 +22049,7 @@ def validate(root: Path) -> None: assert_equal( "telegram_notification_egress_owner_response_acceptance.status", telegram_notification_egress_owner_response_acceptance["status"], - "owner_response_acceptance_ledger_ready_no_runtime_action", + "owner_response_acceptance_ledger_clear_no_direct_candidates", ) assert_equal( "telegram_notification_egress_owner_response_acceptance.mode", @@ -22078,15 +22057,15 @@ def validate(root: Path) -> None: "metadata_only_no_secret_value_no_telegram_send_no_workflow_script_api_change", ) expected_telegram_egress_owner_response_acceptance_summary = { - "source_request_draft_count": 5, - "source_migration_candidate_count": 5, - "source_direct_bot_api_call_count": 5, - "acceptance_candidate_count": 5, + "source_request_draft_count": 0, + "source_migration_candidate_count": 0, + "source_direct_bot_api_call_count": 0, + "acceptance_candidate_count": 0, "workflow_acceptance_candidate_count": 0, - "ops_script_acceptance_candidate_count": 4, - "api_direct_acceptance_candidate_count": 1, + "ops_script_acceptance_candidate_count": 0, + "api_direct_acceptance_candidate_count": 0, "acceptance_field_count": 33, - "required_owner_field_count": 19, + "required_owner_field_count": 0, "reviewer_check_count": 23, "outcome_lane_count": 10, "forbidden_payload_count": 14, diff --git a/scripts/security/telegram-notification-egress-no-new-bypass-guard.py b/scripts/security/telegram-notification-egress-no-new-bypass-guard.py index 3d3d94bea..0a45301c4 100644 --- a/scripts/security/telegram-notification-egress-no-new-bypass-guard.py +++ b/scripts/security/telegram-notification-egress-no-new-bypass-guard.py @@ -229,7 +229,10 @@ def build_report(root: Path, generated_at: str | None = None) -> dict[str, Any]: "removed_baseline_signatures": removed_baseline_signatures, "operator_interpretation": [ "new_bypass_count 維持 0 才代表沒有新增未登記 Telegram Bot API 直送旁路。", - "既有 18 個 sendMessage 旁路仍是待 owner response 的基線,不代表已批准或已收斂。", + ( + f"committed inventory 目前有 {source_summary['direct_bot_api_call_count']} 個 direct Bot API call site;" + "若數值大於 0 仍是待 controlled migration 的基線,不代表已批准保留。" + ), "sendDocument / sendPhoto / sendMediaGroup 等附件型出口若出現在 repo source,會被視為新增旁路並阻擋。", "本 guard 只讀 repo source 與 committed snapshot,不送 Telegram、不讀 Bot token、不修改 workflow / script / API sender。", ], diff --git a/scripts/security/telegram-notification-egress-owner-response-acceptance.py b/scripts/security/telegram-notification-egress-owner-response-acceptance.py index ad0ada542..9a83be0ca 100644 --- a/scripts/security/telegram-notification-egress-owner-response-acceptance.py +++ b/scripts/security/telegram-notification-egress-owner-response-acceptance.py @@ -265,12 +265,21 @@ def build_report(root: Path, generated_at: str | None = None) -> dict[str, Any]: workflow = [item for item in candidates if item["surface_kind"] == "gitea_workflow_direct_bot_api"] ops = [item for item in candidates if item["surface_kind"] == "ops_script_direct_bot_api"] api = [item for item in candidates if item["surface_kind"] == "api_direct_bot_api"] + required_owner_field_count = ( + len(owner_request["request_drafts"][0]["required_owner_fields"]) + if owner_request["request_drafts"] + else 0 + ) return { "schema_version": "telegram_notification_egress_owner_response_acceptance_v1", "generated_at": generated, "git_commit": git_short_sha(root), - "status": "owner_response_acceptance_ledger_ready_no_runtime_action", + "status": ( + "owner_response_acceptance_ledger_clear_no_direct_candidates" + if not candidates + else "owner_response_acceptance_ledger_ready_no_runtime_action" + ), "mode": "metadata_only_no_secret_value_no_telegram_send_no_workflow_script_api_change", "source_owner_request_snapshot": OWNER_REQUEST_SNAPSHOT.as_posix(), "source_owner_request_schema_version": owner_request["schema_version"], @@ -288,7 +297,7 @@ def build_report(root: Path, generated_at: str | None = None) -> dict[str, Any]: "ops_script_acceptance_candidate_count": len(ops), "api_direct_acceptance_candidate_count": len(api), "acceptance_field_count": len(ACCEPTANCE_FIELDS), - "required_owner_field_count": len(owner_request["request_drafts"][0]["required_owner_fields"]), + "required_owner_field_count": required_owner_field_count, "reviewer_check_count": len(REVIEWER_CHECKS), "outcome_lane_count": len(OUTCOME_LANES), "forbidden_payload_count": len(FORBIDDEN_PAYLOADS),