From 750e269ffb7a1bb0e9a5c426b8aacc71a6a73e64 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 30 Jun 2026 01:58:08 +0800 Subject: [PATCH] fix(api): close stale backup config blocker --- .../test_backup_dr_readiness_matrix_api.py | 11 ++++- .../test_backup_dr_target_inventory_api.py | 12 ++++-- docs/LOGBOOK.md | 14 +++++++ ...backup_dr_readiness_matrix_2026-06-04.json | 42 +++++++++---------- ...backup_dr_target_inventory_2026-06-04.json | 24 +++++------ 5 files changed, 63 insertions(+), 40 deletions(-) diff --git a/apps/api/tests/test_backup_dr_readiness_matrix_api.py b/apps/api/tests/test_backup_dr_readiness_matrix_api.py index b9ec99687..01d90a93d 100644 --- a/apps/api/tests/test_backup_dr_readiness_matrix_api.py +++ b/apps/api/tests/test_backup_dr_readiness_matrix_api.py @@ -16,14 +16,21 @@ def test_backup_dr_readiness_matrix_endpoint_returns_committed_snapshot(): assert response.status_code == 200 data = response.json() assert data["schema_version"] == "backup_dr_readiness_matrix_v1" - assert data["program_status"]["overall_completion_percent"] == 91 + assert data["program_status"]["overall_completion_percent"] == 97 assert data["program_status"]["read_only_mode"] is True assert data["program_status"]["next_task_id"] == "P1-201" assert data["rollups"]["total_rows"] == len(data["readiness_rows"]) == 17 - assert data["rollups"]["by_overall_readiness"]["blocked"] == 2 + assert data["rollups"]["by_overall_readiness"]["blocked"] == 1 assert data["rollups"]["by_overall_readiness"]["action_required"] == 2 assert data["operation_boundaries"]["restore_execution_allowed"] is False assert data["operation_boundaries"]["offsite_sync_execution_allowed"] is False assert data["operation_boundaries"]["credential_marker_write_allowed"] is False + configs_capture = next( + row + for row in data["readiness_rows"] + if row["target_id"] == "configs_capture" + ) + assert configs_capture["overall_readiness"] == "ready" + assert configs_capture["gate_status"] == "restore_approval_required" assert any(row["target_id"] == "velero_k8s_resources" for row in data["readiness_rows"]) assert any(row["target_id"] == "credential_escrow_markers" for row in data["readiness_rows"]) diff --git a/apps/api/tests/test_backup_dr_target_inventory_api.py b/apps/api/tests/test_backup_dr_target_inventory_api.py index b48efa8fd..4bbd32d4a 100644 --- a/apps/api/tests/test_backup_dr_target_inventory_api.py +++ b/apps/api/tests/test_backup_dr_target_inventory_api.py @@ -16,14 +16,20 @@ def test_backup_dr_target_inventory_endpoint_returns_committed_snapshot(): assert response.status_code == 200 data = response.json() assert data["schema_version"] == "backup_dr_target_inventory_v1" - assert data["program_status"]["overall_completion_percent"] == 88 + assert data["program_status"]["overall_completion_percent"] == 94 assert data["program_status"]["read_only_mode"] is True assert data["program_status"]["next_task_id"] == "P1-102" assert data["rollups"]["total_targets"] == len(data["backup_targets"]) == 17 - assert data["rollups"]["by_status"]["blocked"] == 2 + assert data["rollups"]["by_status"]["blocked"] == 1 assert data["operation_boundaries"]["backup_execution_allowed"] is False assert data["operation_boundaries"]["restore_execution_allowed"] is False assert data["operation_boundaries"]["credential_marker_write_allowed"] is False assert data["approval_boundaries"]["destructive_operation_allowed"] is False assert any(target["target_id"] == "credential_escrow_markers" for target in data["backup_targets"]) - assert any(target["target_id"] == "configs_capture" for target in data["backup_targets"]) + configs_capture = next( + target + for target in data["backup_targets"] + if target["target_id"] == "configs_capture" + ) + assert configs_capture["status"] == "active" + assert configs_capture["automation_gate_status"] == "backup_execution_blocked" diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 84d7212aa..36bac19d1 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,17 @@ +## 2026-06-30 — 02:05 P1-102 Backup/DR config capture stale blocker closeout + +**照優先順序完成的實作**: +- P0-006 仍是 current P0,但目前只剩 fresh all-host reboot window / approved reboot drill 這個事故級邊界;未重啟主機。 +- Delivery Workbench 的 release lane 已由 controlled status cleanup package ready + blocker 0 正確映射為 100%,保留 raw `overall_completion_percent=74` 作為原始 evidence。 +- Backup/DR `configs_capture` 舊 blocker 已依 2026-06-12 post-120 recovery 與後續 backup status readback 收斂:target inventory 改為 active,readiness matrix 改為 ready;`credential_escrow_markers` 仍由 P0-005 closeout overlay 控制,不在 matrix 偽造 marker。 +- 本地 Delivery Workbench 讀回:release `100`、backup lane `97`、non-credential backup blocker `[]`、average completion `98`、current P0 仍為 `P0-006`。 + +**驗證**: +- Focused pytest:Backup/DR target inventory、Backup/DR readiness matrix、Delivery Workbench `19 passed`。 +- `py_compile`、`ruff`、`json.tool`、`git diff --check`、Gitea runner pressure guard:通過。 + +**邊界**:未執行 backup / restore / offsite sync,未讀 secret / raw session / SQLite / `.env`,未操作 host / Docker / K8s / DB / firewall,未 workflow_dispatch,未使用 GitHub / `gh` / GitHub API。 + ## 2026-06-30 — 01:26 P0-006 Delivery Workbench mainline readback shortcut **照優先順序完成的實作**: diff --git a/docs/evaluations/backup_dr_readiness_matrix_2026-06-04.json b/docs/evaluations/backup_dr_readiness_matrix_2026-06-04.json index 45d156c6f..4e6ab8e83 100644 --- a/docs/evaluations/backup_dr_readiness_matrix_2026-06-04.json +++ b/docs/evaluations/backup_dr_readiness_matrix_2026-06-04.json @@ -10,7 +10,7 @@ "scripts/reboot-recovery/post-reboot-credential-escrow-intake-scorecard.py" ], "program_status": { - "overall_completion_percent": 91, + "overall_completion_percent": 97, "current_priority": "P1", "current_task_id": "P1-102", "next_task_id": "P1-201", @@ -19,26 +19,24 @@ "rollups": { "total_rows": 17, "by_overall_readiness": { - "ready": 12, + "ready": 13, "action_required": 2, - "blocked": 2, + "blocked": 1, "deferred": 1 }, "by_restore_drill_status": { - "approval_required": 13, - "blocked": 2, - "deferred": 1, - "not_applicable": 1 - }, - "by_offsite_status": { - "verified": 13, - "needs_metric_binding": 1, + "approval_required": 14, "blocked": 1, "deferred": 1, "not_applicable": 1 }, + "by_offsite_status": { + "verified": 14, + "needs_metric_binding": 1, + "deferred": 1, + "not_applicable": 1 + }, "blocked_row_ids": [ - "configs_capture", "credential_escrow_markers" ], "action_required_row_ids": [ @@ -213,17 +211,17 @@ { "target_id": "configs_capture", "display_name": "Host / service / K8s configuration capture", - "overall_readiness": "blocked", - "freshness_status": "blocked", - "integrity_status": "blocked", - "restore_drill_status": "blocked", - "offsite_status": "blocked", + "overall_readiness": "ready", + "freshness_status": "verified", + "integrity_status": "verified", + "restore_drill_status": "approval_required", + "offsite_status": "verified", "notification_policy": "action-required 必須告警;成功不即時洗版。", - "gate_status": "blocked_by_live_evidence", - "evidence_level": "blocked_live_evidence", - "evidence_refs": ["docs/runbooks/BACKUP-STATUS.md", "scripts/backup/backup-configs.sh"], - "blocker_summary": "`120-k3s-host-configs` live evidence blocked;不得宣稱 full DR green。", - "next_action": "P1-104 顯示 config capture blocked;P1-105 才產生修復 / restore 批准包。" + "gate_status": "restore_approval_required", + "evidence_level": "runbook_live_refresh", + "evidence_refs": ["docs/runbooks/BACKUP-STATUS.md", "scripts/backup/backup-configs.sh", "docs/workplans/2026-06-04-reboot-cold-start-backup-recovery-workplan.md"], + "blocker_summary": "2026-06-12 post-120 recovery and later backup status readbacks show config capture recovered; full DR remains gated by independent restore / escrow controls.", + "next_action": "Keep config capture on normal backup cadence; restore drill still requires approval." }, { "target_id": "ai_artifacts", diff --git a/docs/evaluations/backup_dr_target_inventory_2026-06-04.json b/docs/evaluations/backup_dr_target_inventory_2026-06-04.json index 885ec3fcb..1a9150683 100644 --- a/docs/evaluations/backup_dr_target_inventory_2026-06-04.json +++ b/docs/evaluations/backup_dr_target_inventory_2026-06-04.json @@ -12,7 +12,7 @@ "scripts/backup/mark-credential-escrow-verified.sh" ], "program_status": { - "overall_completion_percent": 88, + "overall_completion_percent": 94, "current_priority": "P1", "current_task_id": "P1-101", "next_task_id": "P1-102", @@ -54,8 +54,8 @@ "rollups": { "total_targets": 17, "by_status": { - "active": 14, - "blocked": 2, + "active": 15, + "blocked": 1, "deferred": 1 }, "by_target_type": { @@ -71,14 +71,12 @@ "k8s_resource": 1 }, "by_gate_status": { - "backup_execution_blocked": 13, + "backup_execution_blocked": 14, "offsite_sync_blocked": 1, "credential_approval_required": 1, - "blocked_by_live_evidence": 1, "deferred_until_service_active": 1 }, "blocked_target_ids": [ - "configs_capture", "credential_escrow_markers" ] }, @@ -277,20 +275,20 @@ "target_id": "configs_capture", "display_name": "Host / service / K8s configuration capture", "target_type": "configuration", - "status": "blocked", + "status": "active", "risk_level": "critical", "owner_host": "110 with SSH to 188 / 120 / 121 / 125", "primary_script": "scripts/backup/backup-configs.sh", - "schedule": "納入 offsite expected repos;live status 顯示 120 target blocked", - "rpo": "24h target but currently blocked by live evidence", + "schedule": "納入 offsite expected repos;latest evidence recovered after 120 returned", + "rpo": "24h target; restore still requires approval", "storage_class": "restic_local", "storage_ref": "/backup/configs", - "offsite_policy": "rclone expected repo includes configs;config capture failure blocks full DR green。", - "automation_gate_status": "blocked_by_live_evidence", + "offsite_policy": "rclone expected repo includes configs;latest config capture evidence is recovered; full DR still requires restore approval and escrow controls.", + "automation_gate_status": "backup_execution_blocked", "restore_gate_status": "restore_approval_required", "secret_policy": "Secret / ConfigMap 只進 encrypted restic;不得在 API 顯示內容。", - "evidence_refs": ["scripts/backup/backup-configs.sh", "docs/runbooks/BACKUP-STATUS.md"], - "next_action": "P1-102 顯示 `120-k3s-host-configs` blocked status;不得自動重跑 restore。" + "evidence_refs": ["scripts/backup/backup-configs.sh", "docs/runbooks/BACKUP-STATUS.md", "docs/workplans/2026-06-04-reboot-cold-start-backup-recovery-workplan.md"], + "next_action": "Keep config capture on normal backup cadence;restore drill still requires approval." }, { "target_id": "ai_artifacts",