feat(api): expose harbor registry controlled recovery preflight
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled
AI 技術雷達監控 / ai-technology-watch (push) Successful in 45s

This commit is contained in:
Your Name
2026-06-30 19:57:14 +08:00
parent 90647f294d
commit f429999acf
9 changed files with 1250 additions and 0 deletions

View File

@@ -10,10 +10,14 @@ from fastapi.testclient import TestClient
from src.api.v1 import agents
from src.api.v1.agents import router
from src.services.awoooi_priority_work_order_readback import (
apply_harbor_registry_controlled_recovery_preflight,
apply_stockplatform_public_api_controlled_recovery_preflight,
apply_stockplatform_public_api_runtime_readback,
load_latest_awoooi_priority_work_order_readback,
)
from src.services.harbor_registry_controlled_recovery_preflight import (
load_latest_harbor_registry_controlled_recovery_preflight,
)
from src.services.stockplatform_public_api_controlled_recovery_preflight import (
load_latest_stockplatform_public_api_controlled_recovery_preflight,
)
@@ -71,6 +75,11 @@ def test_awoooi_priority_work_order_readback_endpoint_returns_snapshot(
"load_latest_stockplatform_public_api_runtime_readback",
_stockplatform_runtime_ready,
)
monkeypatch.setattr(
agents,
"load_latest_harbor_registry_controlled_recovery_preflight",
_harbor_registry_ready,
)
app = FastAPI()
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
@@ -88,6 +97,48 @@ def test_awoooi_priority_work_order_readback_endpoint_returns_snapshot(
assert "do not reboot" in data["next_execution_order"][0]
def test_awoooi_priority_work_order_readback_overlays_harbor_deploy_blocker(
tmp_path: Path,
):
payload = load_latest_awoooi_priority_work_order_readback()
recovery = load_latest_harbor_registry_controlled_recovery_preflight(
route_source_path=_harbor_route_source(tmp_path),
watchdog_source_path=_harbor_watchdog_source(tmp_path),
probe=_harbor_upstream_502_probe,
)
apply_harbor_registry_controlled_recovery_preflight(payload, recovery)
state = payload["mainline_execution_state"]
in_progress = payload["in_progress_or_blocked_in_priority_order"][0]
evidence = in_progress["evidence"]
assert payload["status"] == (
"p0_006_blocked_harbor_registry_controlled_recovery_preflight"
)
assert state["active_p0_state"] == (
"blocked_harbor_registry_controlled_recovery_preflight"
)
assert state["next_executable_mainline_workplan_id"] == (
"P0-006-HARBOR-REGISTRY-CONTROLLED-RECOVERY-PREFLIGHT"
)
assert evidence["harbor_registry_controlled_recovery_candidate_packaged"] is True
assert evidence["harbor_registry_upstream_502_shape"] is True
assert evidence["harbor_registry_watchdog_executor_ready"] is True
assert evidence["harbor_registry_runtime_write_gate"] == "controlled_after_preflight"
assert evidence["harbor_registry_current_apply_allowed"] is False
assert "not a manual end state" in in_progress["reason"]
assert "harbor-watchdog.sh --check" in in_progress["professional_fix"][
"action"
]
assert "Do not restart Docker daemon" in in_progress["professional_fix"]["action"]
assert payload["summary"][
"harbor_registry_controlled_recovery_candidate_packaged"
] is True
assert payload["next_execution_order"][0].startswith(
"P0-006-HARBOR-REGISTRY-CONTROLLED-RECOVERY-PREFLIGHT"
)
def test_awoooi_priority_work_order_readback_overlays_live_stockplatform_drift():
payload = load_latest_awoooi_priority_work_order_readback()
@@ -367,3 +418,69 @@ def _stockplatform_runtime_data_dependency_blocked() -> dict:
],
},
}
def _harbor_registry_ready() -> dict:
return {
"schema_version": "harbor_registry_controlled_recovery_preflight_v1",
"priority": "P0-006",
"scope": "harbor_registry_controlled_recovery_preflight",
"status": "harbor_registry_ready",
"safe_next_step": "rerun_gitea_cd_and_verify_deploy_marker",
"active_blockers": [],
"rollups": {
"registry_ready": True,
"public_registry_v2_ready": True,
"internal_110_registry_v2_ready": True,
"controlled_recovery_candidate_packaged": False,
},
}
def _harbor_route_source(tmp_path: Path) -> Path:
path = tmp_path / "188-internal-tools-https.conf.j2"
path.write_text(
"""
server {
listen 443 ssl http2;
server_name harbor.wooo.work;
location / {
proxy_pass http://192.168.0.110:5000;
}
}
server {
listen 443 ssl http2;
server_name registry.wooo.work;
location / {
proxy_pass http://192.168.0.110:5000;
}
}
""",
encoding="utf-8",
)
return path
def _harbor_watchdog_source(tmp_path: Path) -> Path:
path = tmp_path / "harbor-watchdog.sh"
path.write_text(
"""
harbor_is_healthy() {
curl -s --max-time 5 -o /dev/null -w "%{http_code}" http://127.0.0.1:5000/v2/
}
case "${1:-}" in
--check) echo AWOOOI_HARBOR_WATCHDOG_CHECK ;;
--repair-once) echo HARBOR_REPAIR_PERFORMED=1 ;;
esac
docker compose up -d harbor-log
docker compose up -d
""",
encoding="utf-8",
)
return path
def _harbor_upstream_502_probe(url: str, _timeout_seconds: float) -> dict:
if "/v2/" in url:
return {"http_status": 502}
return {"http_status": 200}

View File

@@ -0,0 +1,172 @@
from __future__ import annotations
from pathlib import Path
from fastapi import FastAPI
from fastapi.testclient import TestClient
from src.api.v1 import agents
from src.api.v1.agents import router
from src.services.harbor_registry_controlled_recovery_preflight import (
load_latest_harbor_registry_controlled_recovery_preflight,
)
def test_harbor_registry_preflight_packages_110_upstream_502(tmp_path: Path) -> None:
payload = load_latest_harbor_registry_controlled_recovery_preflight(
route_source_path=_route_source(tmp_path),
watchdog_source_path=_watchdog_source(tmp_path),
probe=_probe_for_upstream_502,
)
assert payload["schema_version"] == "harbor_registry_controlled_recovery_preflight_v1"
assert payload["priority"] == "P0-006"
assert payload["status"] == (
"controlled_recovery_preflight_packaged_harbor_registry_upstream_502"
)
assert payload["source_of_truth_diff"]["status"] == (
"route_source_present_110_harbor_registry_upstream_502"
)
assert payload["rollups"]["harbor_registry_upstream_502_shape"] is True
assert payload["rollups"]["controlled_recovery_candidate_packaged"] is True
assert payload["rollups"]["watchdog_executor_ready"] is True
assert payload["controlled_apply_policy"]["manual_end_state"] is False
assert payload["controlled_apply_policy"]["break_glass_required"] is False
assert payload["controlled_apply_policy"]["current_apply_allowed"] is False
assert payload["controlled_action_candidates"][1]["id"] == (
"harbor_watchdog_repair_once"
)
assert payload["controlled_work_items"][2]["id"] == "harbor-watchdog-repair-once"
assert "harbor_registry_upstream_502" in payload["active_blockers"]
assert "docker_daemon_restart" in payload["controlled_apply_policy"][
"forbidden_scope"
]
assert payload["operation_boundaries"]["ssh_used"] is False
assert payload["operation_boundaries"]["docker_command_performed"] is False
assert payload["operation_boundaries"]["docker_daemon_restart_performed"] is False
assert payload["operation_boundaries"]["host_reboot_performed"] is False
assert payload["operation_boundaries"]["secret_value_collection_allowed"] is False
def test_harbor_registry_preflight_ready_when_registry_v2_ready(tmp_path: Path) -> None:
payload = load_latest_harbor_registry_controlled_recovery_preflight(
route_source_path=_route_source(tmp_path),
watchdog_source_path=_watchdog_source(tmp_path),
probe=_probe_ready,
)
assert payload["status"] == "harbor_registry_ready"
assert payload["active_blockers"] == []
assert payload["rollups"]["registry_ready"] is True
assert payload["safe_next_step"] == "rerun_gitea_cd_and_verify_deploy_marker"
def test_harbor_registry_preflight_routes_gateway_drift(tmp_path: Path) -> None:
payload = load_latest_harbor_registry_controlled_recovery_preflight(
route_source_path=_route_source(tmp_path),
watchdog_source_path=_watchdog_source(tmp_path),
probe=_probe_gateway_drift,
)
assert payload["status"] == (
"controlled_recovery_preflight_packaged_public_gateway_route_drift"
)
assert payload["source_of_truth_diff"]["status"] == (
"route_source_present_public_gateway_route_drift"
)
assert payload["rollups"]["public_gateway_route_drift_shape"] is True
assert payload["controlled_action_candidates"][1]["id"] == (
"registry_public_gateway_rendered_diff"
)
def test_harbor_registry_preflight_endpoint_returns_payload(
monkeypatch,
tmp_path: Path,
) -> None:
monkeypatch.setattr(
agents,
"load_latest_harbor_registry_controlled_recovery_preflight",
lambda: load_latest_harbor_registry_controlled_recovery_preflight(
route_source_path=_route_source(tmp_path),
watchdog_source_path=_watchdog_source(tmp_path),
probe=_probe_for_upstream_502,
),
)
app = FastAPI()
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
response = client.get(
"/api/v1/agents/harbor-registry-controlled-recovery-preflight"
)
assert response.status_code == 200
data = response.json()
assert data["status"] == (
"controlled_recovery_preflight_packaged_harbor_registry_upstream_502"
)
assert data["rollups"]["controlled_recovery_candidate_packaged"] is True
def _route_source(tmp_path: Path) -> Path:
path = tmp_path / "188-internal-tools-https.conf.j2"
path.write_text(
"""
server {
listen 443 ssl http2;
server_name harbor.wooo.work;
location / {
proxy_pass http://192.168.0.110:5000;
}
}
server {
listen 443 ssl http2;
server_name registry.wooo.work;
location / {
proxy_pass http://192.168.0.110:5000;
}
}
""",
encoding="utf-8",
)
return path
def _watchdog_source(tmp_path: Path) -> Path:
path = tmp_path / "harbor-watchdog.sh"
path.write_text(
"""
harbor_is_healthy() {
curl -s --max-time 5 -o /dev/null -w "%{http_code}" http://127.0.0.1:5000/v2/
}
case "${1:-}" in
--check) echo AWOOOI_HARBOR_WATCHDOG_CHECK ;;
--repair-once) echo HARBOR_REPAIR_PERFORMED=1 ;;
esac
docker compose up -d harbor-log
docker compose up -d
""",
encoding="utf-8",
)
return path
def _probe_for_upstream_502(url: str, _timeout_seconds: float) -> dict:
if "/v2/" in url:
return {"http_status": 502}
return {"http_status": 200}
def _probe_ready(url: str, _timeout_seconds: float) -> dict:
if "/v2/" in url:
return {"http_status": 401}
return {"http_status": 200}
def _probe_gateway_drift(url: str, _timeout_seconds: float) -> dict:
if url == "https://registry.wooo.work/v2/":
return {"http_status": 502}
if url == "http://192.168.0.110:5000/v2/":
return {"http_status": 401}
return {"http_status": 200}