diff --git a/apps/api/src/api/v1/webhooks.py b/apps/api/src/api/v1/webhooks.py index 2ff6dd1f..2febfd71 100644 --- a/apps/api/src/api/v1/webhooks.py +++ b/apps/api/src/api/v1/webhooks.py @@ -767,9 +767,9 @@ class HMACVerificationError(Exception): async def verify_webhook_signature( request: Request, - x_signature_256: str | None = Header(None, alias="X-Signature-256"), - x_webhook_timestamp: str | None = Header(None, alias="X-Webhook-Timestamp"), - x_webhook_nonce: str | None = Header(None, alias="X-Webhook-Nonce"), + x_signature_256: str | None = None, + x_webhook_timestamp: str | None = None, + x_webhook_nonce: str | None = None, ) -> bool: """ 驗證 Webhook 請求的 HMAC-SHA256 簽章 @@ -1033,6 +1033,8 @@ async def receive_signal( request: Request, signal: SignalPayload, x_signature_256: str | None = Header(None, alias="X-Signature-256"), + x_webhook_timestamp: str | None = Header(None, alias="X-Webhook-Timestamp"), + x_webhook_nonce: str | None = Header(None, alias="X-Webhook-Nonce"), ) -> SignalResponse: """ Phase 6.1: Event Bus Producer @@ -1047,7 +1049,12 @@ async def receive_signal( """ # HMAC 驗證 (與 /alerts 相同邏輯) try: - await verify_webhook_signature(request, x_signature_256) + await verify_webhook_signature( + request, + x_signature_256, + x_webhook_timestamp, + x_webhook_nonce, + ) except HMACVerificationError as e: logger.warning("signal_hmac_rejected", error=str(e)) raise HTTPException( @@ -1091,6 +1098,8 @@ async def receive_alert( alert: AlertPayload, background_tasks: BackgroundTasks, x_signature_256: str | None = Header(None, alias="X-Signature-256"), + x_webhook_timestamp: str | None = Header(None, alias="X-Webhook-Timestamp"), + x_webhook_nonce: str | None = Header(None, alias="X-Webhook-Nonce"), ) -> AlertResponse: """ 接收外部告警並觸發 OpenClaw AI 大腦分析 @@ -1107,7 +1116,12 @@ async def receive_alert( # Phase 5 Step 0: HMAC 簽章驗證 (CISO 要求) # ========================================================================== try: - await verify_webhook_signature(request, x_signature_256) + await verify_webhook_signature( + request, + x_signature_256, + x_webhook_timestamp, + x_webhook_nonce, + ) except HMACVerificationError as e: logger.warning("webhook_hmac_rejected", error=str(e)) raise HTTPException( diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 20655a2d..7478b0c3 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -14,6 +14,28 @@ **邊界**:未讀 token / `.runner` 內容 / cookie / session / secret / auth / `.env`;未使用 GitHub;未操作 host / Docker / K8s;未修改 workflow;未 force push。 +## 2026-06-29 — 12:06 P0 priority work order readback / cold-start truth + +**完成內容**: +- 依全域 scorecard 與 live readback 重排目前工作順序,不再以單一 CD run 當主線:P0-001 full-host runtime / cold-start truth → P0-005 product data / backup DR evidence → P0-004 CI/CD baseline source readiness → P0-003 Gitea private inventory → P0-006 source-to-runtime drift。 +- P0-001 live full-stack cold-start:`scripts/reboot-recovery/full-stack-cold-start-check.sh --monitor-read-only --no-color` 讀回 110 / 120 / 121 / 188 ping + SSH 全通,188 PostgreSQL / Redis / MOMO / SigNoz 通,110 legacy runner fail-closed,K3s 120 / 121 Ready,public routes / TLS 通;summary `PASS=91 WARN=2 BLOCKED=0`,結果為 warning-only `DEGRADED`,不是 hard block。 +- P0-001 machine-readable summary artifact `/tmp/awoooi-post-reboot-readiness-20260629-115730/summary.txt`:`SERVICE_GREEN=1`、`PRODUCT_DATA_GREEN=1`、`STOCK_FRESHNESS_STATUS=ok`、`STOCK_LATEST_TRADING_DATE=2026-06-26`、`BACKUP_CORE_GREEN=1`、`HOST_188_HYGIENE_BLOCKED=0`、`WAZUH_MANAGER_REGISTRY_ACCEPTED=6`、`RUNTIME_ACTION_AUTHORIZED=0`、`OVERALL_DECLARATION=FULL_STACK_GREEN_DR_ESCROW_BLOCKED`、`NEXT_REQUIRED_GATES=credential_escrow_evidence`。 +- P0-005 no-secret credential escrow chain 已刷新:owner packet / placeholder response / preflight / offsite report / marker status / scorecard 皆產出;`status=blocked_waiting_non_secret_credential_escrow_evidence`、`effective_escrow_missing_count=5`、`owner_response_received_count=0`、`owner_response_accepted_count=0`、`runtime_gate_count=0`、`secret_value_collection_allowed=0`、`credential_marker_write_authorized_count=0`。五項 missing:`restic_repository_password`、`offsite_provider_credentials`、`break_glass_admin_credentials`、`dns_registrar_recovery`、`oauth_ai_provider_recovery`。 +- P0-004 CI/CD production closure:Gitea public queue 讀回 `cd.yaml #3868` / commit `2a50505ee3c55ae99d37eaa52f6c96072f7ca715` / `Success`,deploy marker `96d1f1403 chore(cd): deploy 2a50505 [skip ci]`;production Delivery Workbench 讀回 `production_deploy_status=closure_verified`、`production_deploy_image_tag_matches_main=true`、`production_deploy_governance_fields_present=true`。 +- P0-004 source-readiness 只讀投影已進 Gitea main `f06bc0b49 feat(delivery): expose p0 cicd baseline readiness`:`p0_cicd_baseline_source_readiness_v1` 目前 `blocked_required_sources_missing`、required `11`、present `3`、missing `8`、readiness `27%`;下一步是補回 warning-step / onboarding source files 與測試,不得直接啟用 workflow。 +- `cd.yaml #3869` 對 `f06bc0b49` 讀回 `Failure`,但 public queue 顯示 `no_matching_runner_visible=false`;本輪補上 P0-004 priority snapshot / HMAC focused test 的 controlled-runtime profile,並修正 `verify_webhook_signature()` 在手動 helper 呼叫時把 FastAPI `Header(...)` default 當成 timestamp/nonce 的 CI baseline bug。 +- 新增 `docs/operations/awoooi-priority-work-order-readback.snapshot.json`,固定目前完成 / blocked / stopped / 下一步順序,避免後續被舊 scorecard 或單點 CD 狀態帶偏。 + +**驗證結果**: +- `PYTHONPATH=apps/api python3.11 -m pytest apps/api/tests/test_p0_cicd_baseline_source_readiness_api.py apps/api/tests/test_delivery_closure_workbench_api.py -q`:`4 passed`。 +- `PYTHONPATH=apps/api python3.11 -m pytest apps/api/tests/e2e_network_test.py::TestHMACVerification::test_valid_hmac_signature -q -v --tb=short -p no:cacheprovider`:`1 passed`。 +- `python3.11 -m pytest scripts/reboot-recovery/tests/test_post_reboot_credential_escrow_intake_scorecard.py scripts/reboot-recovery/tests/test_post_reboot_owner_response_template.py scripts/reboot-recovery/tests/test_post_start_smoke_process_classifier.py scripts/reboot-recovery/tests/test_momo_source_arrival_gate.py -q`:`12 passed`。 +- `python3 -m py_compile apps/api/src/services/p0_cicd_baseline_source_readiness.py apps/api/src/services/delivery_closure_workbench.py apps/api/src/api/v1/agents.py scripts/reboot-recovery/post-reboot-credential-escrow-intake-scorecard.py scripts/reboot-recovery/post-reboot-next-gate-owner-packets.py scripts/reboot-recovery/post-reboot-owner-response-template.py scripts/reboot-recovery/post-reboot-owner-response-preflight.py`:通過。 +- `python3 ops/runner/guard-gitea-runner-pressure.py --root .`:`GITEA_RUNNER_PRESSURE_GUARD_OK workflow_files=10 scheduled_workflows=3 auto_branch_events_on_110=0 generic_runner_labels=0`。 +- `jq empty docs/operations/p0-cicd-baseline-source-readiness.snapshot.json docs/operations/awoooi-priority-work-order-readback.snapshot.json`、`bash -n scripts/reboot-recovery/post-reboot-next-gate-dispatch.sh scripts/reboot-recovery/full-stack-cold-start-check.sh scripts/reboot-recovery/post-reboot-readiness-summary.sh`、`git diff --check`:通過。 + +**邊界**:未使用 GitHub / `gh` / GitHub API;未 workflow_dispatch;未讀 token / `.runner` 內容 / cookie / session / secret / auth / `.env`;未寫 credential marker;未操作 host / Docker / Nginx / firewall / K3s / DB;未重啟任何服務。 + ## 2026-06-29 — 11:35 non-110 CD closure production readback verified **完成內容**: diff --git a/docs/operations/awoooi-priority-work-order-readback.snapshot.json b/docs/operations/awoooi-priority-work-order-readback.snapshot.json new file mode 100644 index 00000000..60e78f61 --- /dev/null +++ b/docs/operations/awoooi-priority-work-order-readback.snapshot.json @@ -0,0 +1,150 @@ +{ + "schema_version": "awoooi_priority_work_order_readback_v1", + "generated_at": "2026-06-29T12:12:00+08:00", + "status": "p0_order_reestablished_ci_baseline_fix_in_progress", + "source_refs": { + "global_scorecard": "~/.codex/product-runtime-governance-completion-scorecard.snapshot.json", + "workstation_dashboard": "~/.codex/codex-workstation-sync-dashboard.snapshot.json", + "post_reboot_summary": "/tmp/awoooi-post-reboot-readiness-20260629-115730/summary.txt", + "full_stack_cold_start_check": "scripts/reboot-recovery/full-stack-cold-start-check.sh --monitor-read-only --no-color", + "delivery_closure_workbench": "https://awoooi.wooo.work/api/v1/agents/delivery-closure-workbench", + "public_gitea_queue_readback": "ops/runner/read-public-gitea-actions-queue.py --json", + "credential_escrow_scorecard": "/tmp/awoooi-credential-escrow-intake-scorecard-20260629-1200-priority.json" + }, + "current_head": { + "gitea_main_sha": "f06bc0b49149e3be4d83ae752bffcf2741f4ab63", + "latest_successful_deploy_marker": "96d1f1403 chore(cd): deploy 2a50505 [skip ci]", + "latest_successful_deployed_source_sha": "2a50505ee3c55ae99d37eaa52f6c96072f7ca715", + "latest_source_readiness_commit_sha": "f06bc0b49149e3be4d83ae752bffcf2741f4ab63", + "latest_source_readiness_cd_run_id": "3869", + "latest_source_readiness_cd_run_status": "Failure", + "source_readiness_ci_fix_required": true, + "no_matching_runner_visible": false + }, + "completed_in_priority_order": [ + { + "workplan_id": "P0-001", + "title": "建立主機 runtime inventory 權威資料", + "status": "core_green_with_warnings", + "evidence": { + "hosts_checked": [ + "192.168.0.110", + "192.168.0.120", + "192.168.0.121", + "192.168.0.188" + ], + "full_stack_pass": 91, + "full_stack_warn": 2, + "full_stack_blocked": 0, + "post_start_pass": 43, + "post_start_warn": 5, + "post_start_blocked": 0, + "service_green": true, + "host_188_hygiene_blocked": false, + "wazuh_manager_registry_accepted": 6, + "runtime_action_authorized": false + }, + "warnings_kept_visible": [ + "110 systemd failed units remain", + "188 momo daily sales stale but source preflight has no hard blocker" + ] + }, + { + "workplan_id": "P0-004", + "title": "補 dev / prod CI/CD baseline", + "status": "production_deploy_closure_verified", + "evidence": { + "non110_runner_ready": true, + "latest_cd_run_id": "3868", + "latest_cd_run_status": "Success", + "production_deploy_status": "closure_verified", + "production_image_tag_matches_main": true, + "production_governance_fields_present": true, + "runner_pressure_guard_ok": true + } + } + ], + "in_progress_or_blocked_in_priority_order": [ + { + "workplan_id": "P0-005", + "title": "產品資料與備份 contract", + "status": "blocked_waiting_non_secret_credential_escrow_evidence", + "reason": "Backup core and product freshness are green, but DR completion still requires five non-secret credential escrow evidence markers.", + "evidence": { + "product_data_green": true, + "stock_freshness_status": "ok", + "stock_latest_trading_date": "2026-06-26", + "backup_core_green": true, + "dr_escrow_blocked": true, + "summary_escrow_missing_count": 5, + "offsite_configured": true, + "rclone_configured": true, + "script_missing_count": 0, + "credential_marker_write_authorized_count": 0, + "secret_value_collection_allowed": false + }, + "missing_items": [ + "restic_repository_password", + "offsite_provider_credentials", + "break_glass_admin_credentials", + "dns_registrar_recovery", + "oauth_ai_provider_recovery" + ], + "safe_next_step": "collect_redacted_non_secret_evidence_refs_then_rerun_preflight" + }, + { + "workplan_id": "P0-004-source-readiness", + "title": "P0-004 CI/CD baseline source readiness", + "status": "blocked_required_sources_missing", + "reason": "Committed source readiness snapshot is now exposed, but warning-step/onboarding source files are still missing.", + "evidence": { + "required_source_count": 11, + "present_required_source_count": 3, + "missing_required_source_count": 8, + "source_readiness_percent": 27 + }, + "safe_next_step": "restore_or_recreate_tracked_warning_step_source_before_workflow_enablement" + }, + { + "workplan_id": "P0-003", + "title": "取得 Gitea private inventory 權限", + "status": "blocked_external_or_authenticated_inventory_required", + "reason": "Global scorecard still reports private/internal inventory incomplete; GitHub remains stopped and must not be used as a fallback." + }, + { + "workplan_id": "P0-006", + "title": "清理 source-to-runtime drift 與 stale routes", + "status": "pending_after_p0_005_and_p0_004_source_readiness", + "reason": "Do not expand into route/source drift until the active P0 escrow and CI/CD source-readiness gates are recorded." + } + ], + "stopped_or_do_not_use": [ + { + "workplan_id": "P0-003A", + "title": "GitHub 全產品備援鏡像", + "status": "removed_deleted_do_not_use", + "allowed_actions": 0 + } + ], + "operation_boundaries": { + "github_api_used": false, + "github_cli_used": false, + "workflow_dispatch_performed": false, + "runner_registration_performed": false, + "secret_or_runner_token_read": false, + "credential_secret_value_read": false, + "credential_marker_written": false, + "host_write_performed": false, + "docker_restart_performed": false, + "nginx_restart_performed": false, + "firewall_change_performed": false, + "k3s_restart_or_node_drain_performed": false, + "database_write_or_restore_performed": false + }, + "next_execution_order": [ + "P0-005: keep credential_escrow_evidence blocked until real redacted non-secret evidence refs exist; do not read or write secrets.", + "P0-004-source-readiness: restore or recreate missing warning-step/onboarding source files with tests, without enabling workflows.", + "P0-003: continue Gitea-only private/internal inventory readback when authorized source exists; do not use GitHub.", + "P0-006: source-to-runtime drift cleanup after the active P0 gates above are stable." + ] +}