from __future__ import annotations import json import pytest from src.services.backup_dr_target_inventory import load_latest_backup_dr_target_inventory def test_load_latest_backup_dr_target_inventory_reads_newest_file(tmp_path): older = _snapshot(generated_at="2026-06-03T00:00:00+08:00", completion=84) newer = _snapshot(generated_at="2026-06-04T00:00:00+08:00", completion=88) (tmp_path / "backup_dr_target_inventory_2026-06-03.json").write_text( json.dumps(older), encoding="utf-8", ) (tmp_path / "backup_dr_target_inventory_2026-06-04.json").write_text( json.dumps(newer), encoding="utf-8", ) loaded = load_latest_backup_dr_target_inventory(tmp_path) assert loaded["generated_at"] == "2026-06-04T00:00:00+08:00" assert loaded["program_status"]["overall_completion_percent"] == 88 assert loaded["rollups"]["total_targets"] == 2 assert loaded["operation_boundaries"]["restore_execution_allowed"] is False def test_backup_dr_target_inventory_requires_read_only_mode(tmp_path): snapshot = _snapshot() snapshot["program_status"]["read_only_mode"] = False (tmp_path / "backup_dr_target_inventory_2026-06-04.json").write_text( json.dumps(snapshot), encoding="utf-8", ) with pytest.raises(ValueError, match="read_only_mode"): load_latest_backup_dr_target_inventory(tmp_path) def test_backup_dr_target_inventory_requires_blocked_operations(tmp_path): snapshot = _snapshot() snapshot["operation_boundaries"]["restore_execution_allowed"] = True (tmp_path / "backup_dr_target_inventory_2026-06-04.json").write_text( json.dumps(snapshot), encoding="utf-8", ) with pytest.raises(ValueError, match="operation boundaries"): load_latest_backup_dr_target_inventory(tmp_path) def test_backup_dr_target_inventory_requires_total_rollup_consistency(tmp_path): snapshot = _snapshot() snapshot["rollups"]["total_targets"] = 999 (tmp_path / "backup_dr_target_inventory_2026-06-04.json").write_text( json.dumps(snapshot), encoding="utf-8", ) with pytest.raises(ValueError, match="total_targets"): load_latest_backup_dr_target_inventory(tmp_path) def test_backup_dr_target_inventory_requires_blocked_rollup_consistency(tmp_path): snapshot = _snapshot() snapshot["rollups"]["blocked_target_ids"] = [] (tmp_path / "backup_dr_target_inventory_2026-06-04.json").write_text( json.dumps(snapshot), encoding="utf-8", ) with pytest.raises(ValueError, match="blocked_target_ids"): load_latest_backup_dr_target_inventory(tmp_path) def test_backup_dr_target_inventory_fails_when_missing(tmp_path): with pytest.raises(FileNotFoundError): load_latest_backup_dr_target_inventory(tmp_path) def _snapshot( *, generated_at: str = "2026-06-04T00:00:00+08:00", completion: int = 88, ) -> dict: return { "schema_version": "backup_dr_target_inventory_v1", "generated_at": generated_at, "source_refs": ["docs/runbooks/BACKUP-STATUS.md"], "program_status": { "overall_completion_percent": completion, "current_priority": "P1", "current_task_id": "P1-101", "next_task_id": "P1-102", "read_only_mode": True, }, "target_taxonomy": { "target_types": ["database", "credential_escrow"], "statuses": ["active", "blocked"], "gate_statuses": ["backup_execution_blocked", "credential_approval_required"], "storage_classes": ["restic_local", "evidence_marker"], }, "rollups": { "total_targets": 2, "by_status": {"active": 1, "blocked": 1}, "by_target_type": {"database": 1, "credential_escrow": 1}, "by_gate_status": {"backup_execution_blocked": 1, "credential_approval_required": 1}, "blocked_target_ids": ["credential_escrow_markers"], }, "backup_targets": [ { "target_id": "awoooi_postgresql_daily", "display_name": "AWOOOI PostgreSQL daily full", "target_type": "database", "status": "active", "risk_level": "critical", "owner_host": "110", "primary_script": "scripts/backup/backup-awoooi.sh", "schedule": "daily", "rpo": "24h", "storage_class": "restic_local", "storage_ref": "/backup/awoooi", "offsite_policy": "centralized", "automation_gate_status": "backup_execution_blocked", "restore_gate_status": "restore_approval_required", "secret_policy": "no secrets in API", "evidence_refs": ["scripts/backup/backup-awoooi.sh"], "next_action": "read freshness only", }, { "target_id": "credential_escrow_markers", "display_name": "Credential escrow evidence markers", "target_type": "credential_escrow", "status": "blocked", "risk_level": "critical", "owner_host": "110", "primary_script": "scripts/backup/mark-credential-escrow-verified.sh", "schedule": "manual", "rpo": "manual", "storage_class": "evidence_marker", "storage_ref": "/backup/escrow-evidence/*.last_verified", "offsite_policy": "non-secret marker only", "automation_gate_status": "credential_approval_required", "restore_gate_status": "restore_approval_required", "secret_policy": "reject secrets", "evidence_refs": ["scripts/backup/mark-credential-escrow-verified.sh"], "next_action": "human review", }, ], "readiness_surfaces": [ { "surface_id": "backup_status_daily_summary", "display_name": "每日備份心跳摘要", "script_or_metric": "scripts/backup/backup-status.sh", "mode": "read_only", "status": "active", "evidence_refs": ["scripts/backup/backup-status.sh"], "next_action": "matrix", } ], "operation_boundaries": { "read_only_api_allowed": True, "backup_execution_allowed": False, "restore_execution_allowed": False, "offsite_sync_execution_allowed": False, "credential_marker_write_allowed": False, "schedule_change_allowed": False, "destructive_prune_allowed": False, }, "approval_boundaries": { "sdk_installation_allowed": False, "paid_api_call_allowed": False, "shadow_or_canary_allowed": False, "production_routing_allowed": False, "destructive_operation_allowed": False, }, }