diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index cd806efc0..3ac613eb3 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,18 @@ +## 2026-07-03 — 17:34 Windows99 no-secret verifier timeout 調整 + +**完成內容**: +- P0-4 往下追查時確認:110→99 SSH public-key channel 可用,manual nested SSH 回 `AWOOOI_WINDOWS99_SSH_READY`;via-110 VMX locator `rc=0`,`locator_collection_status=collected_windows99_vmx_source_locator_stdout`。 +- locator 實際輸出:`expected_vmx_path_present_count=0`、`discovery_root_present_count=2`、`candidate_source_count=0`、`source_locator_status=blocked_missing_expected_vmx_source_no_candidate_found`,且 `secret_value_read=false`、`remote_write_performed=false`、`vm_power_change_performed=false`、`raw_path_output=false`。 +- 同一條 verify collector 在 `WINDOWS99_REMOTE_VERIFY_TIMEOUT=90` 時曾 timeout;改用 `180` 後成功讀回 `VMX alias=111 present=0`、`VM_POWER alias=111 vmx_present=0 running=0`、`VMWARE_AUTOSTART_CONFIG_READY=0`、`VMWARE_AUTOSTART_VERIFY_READY=0`、`MISSING_VMX_ALIASES=111`。 +- 因此修正 `collect-windows99-vmware-verify.sh` 與 `reboot-auto-recovery-slo-exporter.sh` 的 Windows99 remote verify 預設 timeout 為 `180` 秒,避免把 99 PowerShell / VMware readback 的慢啟動誤判成 collector failure。此 timeout 仍在 10 分鐘 SLO 預算內,且不授權 Windows / VM write。 + +**仍維持**: +- 這不代表 111 VMX source 已恢復;目前真 blocker 仍是 `blocked_missing_expected_vmx_source_no_candidate_found`、guest powered off、scheduled task never ran,以及 primary `reboot_event_required_host_unreachable`。 +- 沒有讀 secret / token / `.env` / raw sessions / SQLite / auth;沒有使用 GitHub / gh;沒有啟動或關閉 VM,沒有重啟 Windows host / VMware service,沒有 Docker / Nginx / K3s / DB / firewall restart / reload,沒有 restore / prune / delete / force push。 + +**下一步**: +- 跑精準測試與 syntax guard;commit / push Gitea main;CD 後讀回 110 exporter / production scorecard,確認 collector 不再用 90 秒 timeout 製造假 blocker。P0-4 仍需取得 111 既有 VMX source / verified backup path。 + ## 2026-07-03 — 17:18 Windows99 VMX repair CLI 冷啟動修正 **完成內容**: diff --git a/docs/runbooks/FULL-STACK-COLD-START-SOP.md b/docs/runbooks/FULL-STACK-COLD-START-SOP.md index 1441546fe..20e6f007b 100644 --- a/docs/runbooks/FULL-STACK-COLD-START-SOP.md +++ b/docs/runbooks/FULL-STACK-COLD-START-SOP.md @@ -1,6 +1,6 @@ # AWOOOI 全棧冷啟動與主機重啟 SOP -> Version: v1.127 +> Version: v1.128 > Last updated: 2026-07-03 Asia/Taipei > Scope: 99 / 110 / 111 / 112 / 120 / 121 / 188 全棧重啟恢復。112 仍是 Kali / VM guest 訊號,但 2026-06-30 全主機重啟後已納入 10 分鐘 SLO 的必要 boot / power signal;此納入不代表授權任何破壞性 runtime apply。 @@ -86,6 +86,8 @@ v1.126 Windows99 bounded verifier / fallback compatibility rule:`windows99-vmw v1.127 Windows99 VMX repair CLI cold-start rule:`scripts/reboot-recovery/build-windows99-vmx-source-repair-package.py` 是 no-secret / no-DB / check-mode recovery tool,不得因工作站沒有 runtime `DATABASE_URL` 或 `.env` 就失敗;CLI 必須可用 harmless placeholder DB URL 完成 import 與 package build,但不得連 DB、不得讀 secret、不得寫 Windows、不得 power change。2026-07-03 17:18 production scorecard package readback:`work_order_id=windows99-vmx-source-repair-111`、`missing_vmx_aliases=["111"]`、`apply_allowed_by_this_package=false`、`rollback_required=true`、`vm_power_change_allowed=false`。同輪 via-110 locator 若回 `blocked_ssh_publickey_auth_missing` / `ssh_auth_probe_exit_status=124`,只能當 management-channel blocker;不得把 repair package ready 誤報成 111 VMX 已恢復。 +v1.128 Windows99 no-secret verifier timeout budget rule:110→99 SSH channel ready 不等於 full VMware Verify 會在 90 秒內穩定完成。2026-07-03 17:34 live 對照:locator 經 via-110 成功收集,`expected_vmx_path_present_count=0`、`candidate_source_count=0`;同一條 verify collector 90 秒曾 timeout,但 180 秒成功回 `MISSING_VMX_ALIASES=111`、`VMWARE_AUTOSTART_CONFIG_READY=0`、`VMWARE_AUTOSTART_VERIFY_READY=0`。因此 `collect-windows99-vmware-verify.sh` 與 SLO exporter 的 Windows99 remote verify 預設 timeout 必須是 `180` 秒;timeout 超過仍 fail-closed,但不得用 90 秒假 timeout 改變 P0 方向。此規則不授權 VM power change、Windows write、host reboot、service restart 或 secret 讀取。 + 2026-07-02 110 control-path / Harbor recovery receipt rule:若 Gitea Harbor repair queue 仍保留 `harbor_110_remote_ssh_publickey_auth_stalled`、remote-control unavailable、jobs stale 或 historical failure,但同一輪本地證據同時證明 `wooo` command path ready、110 local Harbor `/v2/` ready、public/internal registry `/v2/` 回 `401`,則該 Gitea Harbor repair 失敗只能列為 historical queue metadata,不得再當成 current SSH blocker。必須用 `/api/v1/agents/harbor-registry-controlled-recovery-receipt` 或同等 validator 合併 `diagnose-110-ssh-publickey-auth.sh`、`recover-110-control-path-and-harbor-local.sh --check`、public Gitea queue readback 與 registry `/v2/` verifier,並把機器可讀結果寫入 `docs/operations/harbor-110-control-path-recovery-readback-2026-07-02.snapshot.json` 類型的 snapshot。2026-07-02 live receipt 顯示:public/internal registry `/v2/` 均為 `401`、latest visible CD `#4335` 為 `Success`、Gitea Harbor repair failure 已是 `historical_after_latest_cd_success=true`;active blockers 收斂為 110 controlled CD lane config / binary / registration / service guardrail、active action container pressure,以及 Gitea CD jobs head-SHA / stale readback mismatch。若 local-console output 只有 `AWOOOI_110_CONTROLLED_CD_LANE_READY` marker,non110 runner parser 不得從 110 `BLOCKER` 行推導 non110 blocker;non110 只有看到 `AWOOOI_NON110_RUNNER_READY` marker 才能列入 active blocker。 2026-07-02 110 controlled CD lane fail-closed enforcer staging rule:110 runner 壓力事故後,legacy / generic runner 仍必須 fail-closed;但 `awoooi-cd-lane-drain.service` 的非 secret staging artifact 不得再被 enforcer 無差別封回 stub。`scripts/reboot-recovery/enforce-110-runner-failclosed.sh` 只有在 `config.yaml` 符合 `capacity <= 1`、只含 `awoooi-host:host` 與 `awoooi-ubuntu:docker://192.168.0.110:5000/awoooi/ci-runner:act-22.04`、binary 是 executable ELF、systemd unit 具備 `ConditionPathExists=/home/wooo/awoooi-cd-lane-drain/data/.runner`、`CPUAccounting` / `MemoryAccounting` / `TasksAccounting` / `NoNewPrivileges` 等 guardrail,且 service `inactive`、`MainPID=0`、未 enabled / 未 masked 時,才可保留 drain config / binary / unit,並輸出 `CONTROLLED_DRAIN_STAGING_ALLOWED=1` 與 textfile metric。此 staging 規則不得讀 token、不得讀 `.runner` 內容、不得註冊 runner、不得啟動 service;若 registration 缺失,readiness verifier 仍必須只留下 `controlled_cd_lane_registration_missing` / `controlled_cd_lane_service_not_active` 類 blocker。若 `CONTROLLED_DRAIN_STAGING_ALLOWED=0` 且 config / binary 又被搬走,優先修 source enforcer / unit guardrail,不要手工反覆補同一組 artifact。 diff --git a/docs/runbooks/REBOOT-RECOVERY-SOP.md b/docs/runbooks/REBOOT-RECOVERY-SOP.md index 3ee1ec347..957881358 100644 --- a/docs/runbooks/REBOOT-RECOVERY-SOP.md +++ b/docs/runbooks/REBOOT-RECOVERY-SOP.md @@ -1,9 +1,9 @@ # AWOOOI 重開機恢復 SOP -> **版本**: v5.18 +> **版本**: v5.19 > **最後更新**: 2026-07-03 (台北時間) > **更新者**: Codex -> **觸發事件**: 2026-07-03 17:18 Windows99 VMX source repair package CLI 冷啟動修正,111 VMX missing 轉入 check-mode repair lane +> **觸發事件**: 2026-07-03 17:34 Windows99 no-secret verifier timeout 預算修正,避免 90 秒假 timeout 遮蔽 111 VMX source blocker --- @@ -21,6 +21,12 @@ ## 架構概覽與依賴圖 +### 2026-07-03 17:34 P0-4 Verify Timeout 覆蓋 + +110→99 SSH public-key channel 可用,via-110 locator 已成功收集且未讀 secret / 未寫 Windows / 未改 VM power:`expected_vmx_path_present_count=0`、`discovery_root_present_count=2`、`candidate_source_count=0`、`source_locator_status=blocked_missing_expected_vmx_source_no_candidate_found`。同輪 full VMware Verify 在 90 秒曾 timeout,但 180 秒成功讀回 `MISSING_VMX_ALIASES=111`、`VMWARE_AUTOSTART_CONFIG_READY=0`、`VMWARE_AUTOSTART_VERIFY_READY=0`。 + +SOP v5.19 起,Windows99 remote verify 預設 timeout 使用 `180` 秒;仍屬 bounded no-secret verifier,超過 180 秒 fail-closed。不得把 90 秒 timeout 當成 SSH channel 故障,不得因此偏離到 VM power / Windows service restart / host reboot;P0-4 下一步仍是取得 111 既有 VMX source / verified backup path。 + ### 2026-07-03 17:18 P0-4 VMX Repair CLI 覆蓋 Gitea CD `#4617` 已完成 source `40713b2f8` 投產,deploy marker `b85d574`,production deploy readback matched=true,job succeeded。production reboot SLO scorecard 已讀回 Windows99 default target `111 / 188 / 120 / 121 / 112`,其中 `missing_vmx_aliases=["111"]`、`powered_off_aliases=["112","120","121","188","111"]`,舊 `110` 不得再當 Windows99 guest alias。 diff --git a/docs/workplans/2026-06-04-reboot-cold-start-backup-recovery-workplan.md b/docs/workplans/2026-06-04-reboot-cold-start-backup-recovery-workplan.md index e856fac21..0f91f32c9 100644 --- a/docs/workplans/2026-06-04-reboot-cold-start-backup-recovery-workplan.md +++ b/docs/workplans/2026-06-04-reboot-cold-start-backup-recovery-workplan.md @@ -22,7 +22,7 @@ | P0-1 | BLOCKED_REBOOT_EVENT_AND_HOST_REACHABILITY | 全主機 reboot auto-detection / auto-trigger / 10 分鐘恢復 SLO | 2026-07-03 15:49 verify-only artifact `/tmp/awoooi-reboot-event-verify-20260703-154907`:`reboot_detected=false`、`all_required_hosts_observed=false`、`all_required_hosts_in_reboot_window=false`、`recovery_deadline_status=target_window_elapsed`、`unreachable_hosts=["111"]`、99 reachable 但 `uptime_seconds=unknown`、188 reachable 但 `systemd_state=degraded` / `startup_active=failed`。production SLO 仍為 `blocked_reboot_auto_recovery_slo_not_ready`,不能宣稱 10 分鐘自動恢復。 | 固定先 rerun host probe + reboot-event detector verify-only,並收斂 111 reachability、99 uptime / VMware readback、188 degraded/startup failed;不得 reboot、不得 VM power change、不得讀 Windows 密碼,不得用 ping-only 或舊 boot evidence 當完成證據。 | | P0-2 | DEPLOYED_RUNTIME_EDGE_DRIFT_BLOCKED | Deploy / reboot 期間 public 502 維護頁與外部 fallback | 2026-07-03 15:35 source fix 已部署讀回:production `/api/v1/agents/reboot-auto-recovery-slo-scorecard` 保留 `edge_public_maintenance_live_config_drift`,`runtime_metric_active_blocker_count=8`,且 route fallback ready 不再清掉 edge Nginx drift。110 SLO artifact `/home/wooo/reboot-recovery/reboot-auto-recovery-slo-20260703-151219` 與 textfile 證明 edge 未 ready:`awoooi_public_maintenance_edge_fallback_ready{scope="public_routes"} 0`、active blocker `edge_public_maintenance_live_config_drift`。 | 後續才進 privileged edge apply 或 L1 cloud/CDN fallback decision;完成條件是 edge fallback live config / maintenance file / `nginx -t` / reload / public header verifier 或外部 L1 fallback 全綠。不得讀密碼、不得用 app / Docker / host restart 掩蓋 edge fallback drift。 | | P0-3 | PARTIAL_GREEN_DEPLOYED_SOURCE | 所有產品 / 網站版本與資料最新性 | Gitea `main=bc8d3af3f chore(cd): deploy dacdd90 [skip ci]`;CD `#4558` log 顯示 API/Web build/push wrapper 全部 `rc=0`、deploy marker `dacdd90`、production deploy readback matched。Production SLO route 已讀回最新 API 行為:`runtime_metric_runtime_readback_added_blockers=["windows99_vmware_autostart_config_not_ready","windows99_update_no_auto_reboot_policy_not_ready"]`、`windows99_update_no_auto_reboot_ready=false`。Stock freshness 仍為 `status=ok`、`latest_trading_date=2026-07-02`、blockers `[]`。 | 版本層已補到 AWOOOI production;完成整體 P0 仍需收斂 Windows99 VMX / service / policy / power 與 host reboot-event blockers。後續每個 public product 仍要維持 source SHA、deploy marker、runtime endpoint、public route watch、freshness 四層一致。 | -| P0-4 | BLOCKED_WINDOWS99_VMX_SOURCE_AND_TASK_NOT_TRIGGERED | 192.168.0.99 VMware 自動啟動與 VM guest 111 / 188 / 120 / 121 / 112 | 2026-07-03 17:18 CD `#4617` 已完成 source `40713b2f8` 投產,deploy marker `b85d574`,production deploy readback matched=true,job succeeded。production scorecard 已讀回 `required_vm_aliases=["111","188","120","121","112"]`、`missing_vmx_aliases=["111"]`、`powered_off_aliases=["112","120","121","188","111"]`,舊 `110` 不再出現在 Windows99 VM alias。`build-windows99-vmx-source-repair-package.py` 已修正可在無 `DATABASE_URL` 冷啟動環境產生 `windows99-vmx-source-repair-111` package;via-110 locator 本輪仍回 `blocked_ssh_publickey_auth_missing` / `ssh_auth_probe_exit_status=124`。 | 下一步固定為取得 111 既有 VMX source / verified backup / 授權 console candidate identity,產生 scoped relink dry-run + rollback + post-verifier,再 rerun no-secret collector + SLO scorecard。仍不得從 scorecard 直接 power on VM、重啟 Windows host / VMware service、改 scheduled task / registry、猜 generic Ubuntu candidate、restore 到 production 或讀 Windows 密碼。 | +| P0-4 | BLOCKED_WINDOWS99_VMX_SOURCE_AND_TASK_NOT_TRIGGERED | 192.168.0.99 VMware 自動啟動與 VM guest 111 / 188 / 120 / 121 / 112 | 2026-07-03 17:34 已確認 110→99 SSH channel 可用,via-110 locator `rc=0`,`expected_vmx_path_present_count=0`、`candidate_source_count=0`、`source_locator_status=blocked_missing_expected_vmx_source_no_candidate_found`。full verify 在 90 秒曾 timeout,但 180 秒成功讀回 `VMX alias=111 present=0`、`MISSING_VMX_ALIASES=111`、`VMWARE_AUTOSTART_CONFIG_READY=0`;因此 source 已調整 Windows99 remote verify 預設 timeout 為 `180` 秒。前一輪 CD `#4618` 已將 `36536adcf` 投產,deploy marker `acbf96c`,production package endpoint live。 | 下一步固定為取得 111 既有 VMX source / verified backup / 授權 console candidate identity,產生 scoped relink dry-run + rollback + post-verifier,再 rerun no-secret collector + SLO scorecard。仍不得從 scorecard 直接 power on VM、重啟 Windows host / VMware service、改 scheduled task / registry、猜 generic Ubuntu candidate、restore 到 production 或讀 Windows 密碼;也不得把 90 秒 timeout 當成 SSH channel 故障。 | | P0-5 | RUNTIME_READY_BACKUP_RECEIPT_GAP | Gitea / 主機 / DB / 網站 / 服務 / 套件 / 工具 / log 備份監控告警 | Gitea repo bundle readback ready:expected `12`、rows `12`、missing `0`、failed `0`、sample restore dry-run ok;backup core green。2026-07-03 source / runtime 已部署 `awoooi_backup_alert_receipt_*` 指標與 Prometheus rules;110 exporter 讀回 88 個 stage requirement、188 讀回 12 個 stage requirement,`BackupAlertReceiptMetricMissing*` inactive,`BackupAlertReceiptStageMissing` 已修成每 `host / receipt_channel` 聚合 pending:110 一條、188 一條。 | 補 `/backup/alert-receipts/*.last_success` 脫敏 marker;下一層仍要補 Gitea full dump、DB/settings/issues/packages/LFS、所有工具與 log 全量備份監控。 | | P0-6 | RUNTIME_READY_ALERT_RECEIPT_GAP | 主機關機 / 重啟 / SLO miss / backup failure Telegram 告警 | Reboot per-blocker alert 與 backup receipt alert rules 已 deploy/readback;backup receipt 缺段不再產生 100 條 stage 噪音,現在聚合成 110 / 188 兩條 host-level pending。scorecard 目前有 10 個 reboot active blockers,其中 Windows99 config / policy blocker 已可供 per-blocker alert routing 使用;尚未完成 shutdown / reboot / backup alert 的 production 脫敏 delivery receipt 全矩陣。 | 補 alert receipt readback:host down、host up、SLO miss、Windows99 blocker、backup stale/failed、deploy 502、freshness stale;完成條件是每類告警都有 sent / received / dedup / escalation evidence。 | | P0-7 | SOURCE_READY_SLA_AUTOMATION | 固定排查順序、ETA / wait reason、自動化判斷與修復 | Scorecard 已固定 `current_phase`、`eta_or_wait_reason`、`primary_blocker`、fixed triage order 與 action matrix;2026-07-03 新增 `windows99_vmware_autostart_task_never_ran`,其 next action 固定為 `run_windows99_vmware_autostart_check_mode_package_for_powered_off_aliases_then_rerun_no_secret_collector_no_vm_power_change`,不再退回泛用「再收一次 verify」。 | 把每個 blocker 的 next_safe_action、post_verifier、forbidden_actions 接到自動 work item / Telegram / scorecard;完成條件是重啟後自動判斷、主動告警、主動 rerun verifier,不再人工臨場猜流程。 | diff --git a/scripts/reboot-recovery/collect-windows99-vmware-verify.sh b/scripts/reboot-recovery/collect-windows99-vmware-verify.sh index 6fadb9e0c..ef5c90912 100755 --- a/scripts/reboot-recovery/collect-windows99-vmware-verify.sh +++ b/scripts/reboot-recovery/collect-windows99-vmware-verify.sh @@ -7,7 +7,7 @@ TARGET_HOST="${WINDOWS99_HOST:-192.168.0.99}" VIA_HOST="${WINDOWS99_VIA_HOST:-}" CONNECT_TIMEOUT="${WINDOWS99_CONNECT_TIMEOUT:-3}" SSH_TIMEOUT="${WINDOWS99_SSH_TIMEOUT:-3}" -REMOTE_VERIFY_TIMEOUT="${WINDOWS99_REMOTE_VERIFY_TIMEOUT:-45}" +REMOTE_VERIFY_TIMEOUT="${WINDOWS99_REMOTE_VERIFY_TIMEOUT:-180}" SSH_PORT="${WINDOWS99_SSH_PORT:-22}" MAX_AUTH_USERS="${WINDOWS99_MAX_AUTH_USERS:-}" MAX_AUTH_USERS_EXPLICIT=0 @@ -37,7 +37,7 @@ if ! is_positive_int "${SSH_TIMEOUT}"; then SSH_TIMEOUT=3 fi if ! is_positive_int "${REMOTE_VERIFY_TIMEOUT}"; then - REMOTE_VERIFY_TIMEOUT=45 + REMOTE_VERIFY_TIMEOUT=180 fi if ! is_positive_int "${MAX_AUTH_USERS}"; then MAX_AUTH_USERS="${#SSH_USERS[@]}" @@ -99,7 +99,7 @@ if ! is_positive_int "${SSH_TIMEOUT}"; then SSH_TIMEOUT=3 fi if ! is_positive_int "${REMOTE_VERIFY_TIMEOUT}"; then - REMOTE_VERIFY_TIMEOUT=45 + REMOTE_VERIFY_TIMEOUT=180 fi if ! is_positive_int "${MAX_AUTH_USERS}"; then MAX_AUTH_USERS="${#SSH_USERS[@]}" diff --git a/scripts/reboot-recovery/reboot-auto-recovery-slo-exporter.sh b/scripts/reboot-recovery/reboot-auto-recovery-slo-exporter.sh index c0b4a5b35..31eed664b 100755 --- a/scripts/reboot-recovery/reboot-auto-recovery-slo-exporter.sh +++ b/scripts/reboot-recovery/reboot-auto-recovery-slo-exporter.sh @@ -324,7 +324,7 @@ if [ -f "$ROOT_DIR/scripts/reboot-recovery/windows99-management-channel-probe.py fi if [ -x "$ROOT_DIR/scripts/reboot-recovery/collect-windows99-vmware-verify.sh" ]; then WINDOWS99_MAX_AUTH_USERS="${WINDOWS99_MAX_AUTH_USERS:-5}" \ - WINDOWS99_REMOTE_VERIFY_TIMEOUT="${WINDOWS99_REMOTE_VERIFY_TIMEOUT:-90}" \ + WINDOWS99_REMOTE_VERIFY_TIMEOUT="${WINDOWS99_REMOTE_VERIFY_TIMEOUT:-180}" \ bash "$ROOT_DIR/scripts/reboot-recovery/collect-windows99-vmware-verify.sh" --collect \ >"$windows99_vmware_file" 2>"$artifact_dir/windows99-vmware-verify.err" \ || true diff --git a/scripts/reboot-recovery/tests/test_reboot_auto_recovery_slo_installer.py b/scripts/reboot-recovery/tests/test_reboot_auto_recovery_slo_installer.py index dc9101775..2e067f63a 100644 --- a/scripts/reboot-recovery/tests/test_reboot_auto_recovery_slo_installer.py +++ b/scripts/reboot-recovery/tests/test_reboot_auto_recovery_slo_installer.py @@ -109,7 +109,7 @@ def test_exporter_projects_each_scorecard_blocker_to_textfile_metric() -> None: assert "windows99-vmware-verify.txt" in text assert "collect-windows99-vmware-verify.sh\" --collect" in text assert "WINDOWS99_MAX_AUTH_USERS=\"${WINDOWS99_MAX_AUTH_USERS:-5}\"" in text - assert "WINDOWS99_REMOTE_VERIFY_TIMEOUT=\"${WINDOWS99_REMOTE_VERIFY_TIMEOUT:-90}\"" in text + assert "WINDOWS99_REMOTE_VERIFY_TIMEOUT=\"${WINDOWS99_REMOTE_VERIFY_TIMEOUT:-180}\"" in text assert "WINDOWS99_REQUIRED_VM_ALIASES=\"${WINDOWS99_REQUIRED_VM_ALIASES:-111 188 120 121 112}\"" in text assert "windows99_vmware_verify_alias_set_matches_current" in text assert "AWOOOI_WINDOWS99_VMWARE_AUTOSTART=1" in text