feat(governance): 新增全產品 Code Review 防木馬 Gate
Some checks failed
Code Review / ai-code-review (push) Successful in 13s
CD Pipeline / tests (push) Successful in 1m49s
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-19 00:26:04 +08:00
parent 9ebab2db6e
commit 4a14860c60
9 changed files with 1496 additions and 0 deletions

View File

@@ -319,6 +319,9 @@ from src.services.offsite_escrow_readiness_status import (
from src.services.package_supply_chain_inventory import (
load_latest_package_supply_chain_inventory,
)
from src.services.product_code_review_gate import (
load_latest_product_code_review_gate,
)
from src.services.runtime_surface_inventory import (
load_latest_runtime_surface_inventory,
)
@@ -3388,6 +3391,34 @@ async def get_dependency_supply_chain_drift_monitor() -> dict[str, Any]:
) from exc
@router.get(
"/product-code-review-gate",
response_model=dict[str, Any],
summary="取得 P2-111 全產品 Code Review 防木馬 Gate",
description=(
"讀取最新已提交的 P2-111 全產品推版前後 Code Review / 防木馬 Gate"
"此端點會把 AwoooP tenants 資產台帳、Gitea code-review、供應鏈漂移、Aider 事件與 AI reviewer "
"分工收斂成只讀 read model。它不啟用外部 scanner、不寫 workflow、不 auto-merge、"
"不部署、不讀 secret、不推 registry、不簽 artifact、不送 Telegram、不寫 Gateway queue、不做 host probe。"
),
)
async def get_product_code_review_gate() -> dict[str, Any]:
"""Return the latest read-only all-product code review gate."""
try:
return await asyncio.to_thread(load_latest_product_code_review_gate)
except FileNotFoundError as exc:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(exc),
) from exc
except (json.JSONDecodeError, ValueError) as exc:
logger.error("product_code_review_gate_invalid", error=str(exc))
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="P2-111 全產品 Code Review Gate 快照無效",
) from exc
@router.get(
"/dependency-upgrade-approval-package-template",
response_model=dict[str, Any],

View File

@@ -0,0 +1,193 @@
"""
Product code review gate snapshot.
Loads the latest committed, read-only all-product code-review gate and enriches
it with the existing AwoooP tenant asset inventory. The loader never enables
external scanners, writes workflows, auto-merges code, deploys, reads secrets,
pushes registry artifacts, sends Telegram messages, or opens runtime gates.
"""
from __future__ import annotations
import json
from copy import deepcopy
from pathlib import Path
from typing import Any
from src.services.platform_operator_service import build_tenant_asset_inventory
from src.services.snapshot_paths import default_evaluations_dir
_DEFAULT_EVALUATIONS_DIR = default_evaluations_dir(Path(__file__))
_SNAPSHOT_PATTERN = "product_code_review_gate_*.json"
_SCHEMA_VERSION = "product_code_review_gate_v1"
_BLOCKED_BOUNDARY_FLAGS = {
"workflow_write_allowed",
"external_scanner_activation_allowed",
"paid_ai_review_allowed",
"repo_app_install_allowed",
"auto_merge_allowed",
"production_deploy_authorized",
"aider_auto_patch_allowed",
"elephantalpha_write_allowed",
"secret_read_allowed",
"post_deploy_write_allowed",
"runtime_execution_allowed",
"telegram_send_allowed",
"gateway_queue_write_allowed",
"host_probe_allowed",
"registry_push_allowed",
"artifact_signing_allowed",
"action_buttons_allowed",
}
def load_latest_product_code_review_gate(
evaluations_dir: Path | None = None,
) -> dict[str, Any]:
"""Load the newest committed all-product code-review gate snapshot."""
directory = evaluations_dir or _DEFAULT_EVALUATIONS_DIR
candidates = sorted(directory.glob(_SNAPSHOT_PATTERN))
if not candidates:
raise FileNotFoundError(f"no product code review gate snapshots found in {directory}")
latest = candidates[-1]
with latest.open(encoding="utf-8") as handle:
payload = json.load(handle)
if not isinstance(payload, dict):
raise ValueError(f"{latest}: expected JSON object")
inventory = build_tenant_asset_inventory([])
enriched = deepcopy(payload)
enriched["tenant_asset_inventory_summary"] = inventory.get("summary") or {}
enriched["product_review_matrix"] = _build_product_review_matrix(inventory)
_require_schema(enriched, _SCHEMA_VERSION, str(latest))
_require_read_only_boundaries(enriched, str(latest))
_require_rollup_consistency(enriched, str(latest))
_require_gate_evidence(enriched, str(latest))
_require_agent_boundaries(enriched, str(latest))
return enriched
def _build_product_review_matrix(inventory: dict[str, Any]) -> list[dict[str, Any]]:
products = inventory.get("products") or []
matrix: list[dict[str, Any]] = []
for product in products:
status = product.get("coverage_status") or "read_only_candidate"
source_repo_count = int(product.get("source_repo_count") or 0)
public_route_count = int(product.get("public_route_count") or 0)
gate_state = "owner_review_required" if status == "owner_response_required" else "read_only_visible"
if source_repo_count == 0:
gate_state = "source_mapping_required"
matrix.append(
{
"product_id": product.get("product_id"),
"product_name": product.get("product_name"),
"category": product.get("category"),
"surface_kind": product.get("surface_kind"),
"owner_lane": product.get("owner_lane"),
"coverage_status": status,
"public_route_count": public_route_count,
"source_repo_count": source_repo_count,
"gate_state": gate_state,
"pre_deploy_gate": "required",
"post_deploy_gate": "required",
"owner_response_received_count": int(
product.get("owner_response_received_count") or 0
),
"owner_response_accepted_count": int(
product.get("owner_response_accepted_count") or 0
),
"runtime_gate_count": int(product.get("runtime_gate_count") or 0),
"action_button_count": int(product.get("action_button_count") or 0),
}
)
return matrix
def _require_schema(payload: dict[str, Any], expected: str, label: str) -> None:
actual = payload.get("schema_version")
if actual != expected:
raise ValueError(f"{label}: expected schema_version={expected}, got {actual!r}")
def _require_read_only_boundaries(payload: dict[str, Any], label: str) -> None:
program_status = payload.get("program_status") or {}
if program_status.get("read_only_mode") is not True:
raise ValueError(f"{label}: program_status.read_only_mode must be true")
boundaries = payload.get("gate_boundaries") or {}
if boundaries.get("read_only_api_allowed") is not True:
raise ValueError(f"{label}: read_only_api_allowed must be true")
allowed = sorted(flag for flag in _BLOCKED_BOUNDARY_FLAGS if boundaries.get(flag) is not False)
if allowed:
raise ValueError(f"{label}: gate boundaries must remain false: {allowed}")
def _require_rollup_consistency(payload: dict[str, Any], label: str) -> None:
rollups = payload.get("rollups") or {}
tenant_summary = payload.get("tenant_asset_inventory_summary") or {}
product_matrix = payload.get("product_review_matrix") or []
pre_deploy = payload.get("pre_deploy_gates") or []
post_deploy = payload.get("post_deploy_gates") or []
reviewers = payload.get("ai_reviewer_lanes") or []
tools = payload.get("mainstream_tool_lanes") or []
boundaries = payload.get("gate_boundaries") or {}
product_count = int(tenant_summary.get("product_surface_count") or 0)
route_count = int(tenant_summary.get("public_route_count") or 0)
source_count = int(tenant_summary.get("source_candidate_repo_count") or 0)
if rollups.get("product_scope_count") != product_count:
raise ValueError(f"{label}: rollups.product_scope_count must match tenant inventory")
if rollups.get("product_scope_count") != len(product_matrix):
raise ValueError(f"{label}: product_review_matrix length must match product scope count")
if route_count < int(rollups.get("public_route_count_minimum") or 0):
raise ValueError(f"{label}: tenant route count is lower than product gate minimum")
if rollups.get("source_candidate_repo_count") != source_count:
raise ValueError(f"{label}: source candidate count must match tenant inventory")
if rollups.get("pre_deploy_gate_count") != len(pre_deploy):
raise ValueError(f"{label}: pre_deploy_gate_count must match gates")
if rollups.get("post_deploy_gate_count") != len(post_deploy):
raise ValueError(f"{label}: post_deploy_gate_count must match gates")
if rollups.get("ai_reviewer_count") != len(reviewers):
raise ValueError(f"{label}: ai_reviewer_count must match reviewer lanes")
if rollups.get("mainstream_tool_count") != len(tools):
raise ValueError(f"{label}: mainstream_tool_count must match tool lanes")
false_count = sum(1 for flag in _BLOCKED_BOUNDARY_FLAGS if boundaries.get(flag) is False)
if rollups.get("blocked_operation_count") != false_count:
raise ValueError(f"{label}: blocked_operation_count must match false boundaries")
if rollups.get("active_write_gate_count") != 0:
raise ValueError(f"{label}: active_write_gate_count must remain 0")
if rollups.get("action_button_count") != 0:
raise ValueError(f"{label}: action_button_count must remain 0")
def _require_gate_evidence(payload: dict[str, Any], label: str) -> None:
for key in ("pre_deploy_gates", "post_deploy_gates"):
for gate in payload.get(key) or []:
gate_id = gate.get("gate_id") or "<missing>"
if not gate.get("evidence_refs"):
raise ValueError(f"{label}: gate {gate_id} must include evidence_refs")
if not gate.get("next_action"):
raise ValueError(f"{label}: gate {gate_id} must include next_action")
def _require_agent_boundaries(payload: dict[str, Any], label: str) -> None:
reviewers = payload.get("ai_reviewer_lanes") or []
for reviewer in reviewers:
agent_id = reviewer.get("agent_id") or "<missing>"
if reviewer.get("write_allowed") is not False:
raise ValueError(f"{label}: reviewer {agent_id} write_allowed must remain false")
matrix = payload.get("product_review_matrix") or []
active_runtime = [item for item in matrix if item.get("runtime_gate_count") != 0]
action_buttons = [item for item in matrix if item.get("action_button_count") != 0]
if active_runtime:
raise ValueError(f"{label}: product runtime gates must remain 0")
if action_buttons:
raise ValueError(f"{label}: product action buttons must remain 0")

View File

@@ -0,0 +1,199 @@
from __future__ import annotations
import json
import pytest
from src.services.product_code_review_gate import load_latest_product_code_review_gate
def test_load_latest_product_code_review_gate_enriches_tenant_inventory(tmp_path):
_write_snapshot(tmp_path, _snapshot())
loaded = load_latest_product_code_review_gate(tmp_path)
assert loaded["schema_version"] == "product_code_review_gate_v1"
assert loaded["program_status"]["current_task_id"] == "P2-111"
assert loaded["program_status"]["next_task_id"] == "P2-112"
assert loaded["program_status"]["read_only_mode"] is True
assert loaded["rollups"]["product_scope_count"] == len(loaded["product_review_matrix"]) >= 16
assert loaded["tenant_asset_inventory_summary"]["public_route_count"] >= 31
assert loaded["rollups"]["source_candidate_repo_count"] == 10
assert loaded["gate_boundaries"]["auto_merge_allowed"] is False
assert loaded["gate_boundaries"]["aider_auto_patch_allowed"] is False
assert loaded["gate_boundaries"]["elephantalpha_write_allowed"] is False
assert all(item["runtime_gate_count"] == 0 for item in loaded["product_review_matrix"])
assert all(item["action_button_count"] == 0 for item in loaded["product_review_matrix"])
assert any(item["product_id"] == "PRD-001" for item in loaded["product_review_matrix"])
assert any(tool["tool_id"] == "codeql" for tool in loaded["mainstream_tool_lanes"])
assert any(tool["tool_id"] == "gitleaks" for tool in loaded["mainstream_tool_lanes"])
def test_product_code_review_gate_requires_read_only_mode(tmp_path):
snapshot = _snapshot()
snapshot["program_status"]["read_only_mode"] = False
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="read_only_mode"):
load_latest_product_code_review_gate(tmp_path)
def test_product_code_review_gate_blocks_auto_merge(tmp_path):
snapshot = _snapshot()
snapshot["gate_boundaries"]["auto_merge_allowed"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="gate boundaries"):
load_latest_product_code_review_gate(tmp_path)
def test_product_code_review_gate_requires_rollup_consistency(tmp_path):
snapshot = _snapshot()
snapshot["rollups"]["pre_deploy_gate_count"] = 99
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="pre_deploy_gate_count"):
load_latest_product_code_review_gate(tmp_path)
def test_product_code_review_gate_requires_gate_evidence(tmp_path):
snapshot = _snapshot()
snapshot["pre_deploy_gates"][0]["evidence_refs"] = []
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="evidence_refs"):
load_latest_product_code_review_gate(tmp_path)
def test_product_code_review_gate_requires_reviewer_no_write(tmp_path):
snapshot = _snapshot()
snapshot["ai_reviewer_lanes"][0]["write_allowed"] = True
_write_snapshot(tmp_path, snapshot)
with pytest.raises(ValueError, match="write_allowed"):
load_latest_product_code_review_gate(tmp_path)
def test_product_code_review_gate_fails_when_missing(tmp_path):
with pytest.raises(FileNotFoundError):
load_latest_product_code_review_gate(tmp_path)
def _write_snapshot(tmp_path, payload: dict) -> None:
(tmp_path / "product_code_review_gate_2026-06-19.json").write_text(
json.dumps(payload),
encoding="utf-8",
)
def _snapshot() -> dict:
return {
"schema_version": "product_code_review_gate_v1",
"generated_at": "2026-06-19T00:42:00+08:00",
"program_status": {
"overall_completion_percent": 100,
"current_priority": "P2",
"current_task_id": "P2-111",
"next_task_id": "P2-112",
"read_only_mode": True,
"runtime_authority": "repo_only",
"status_note": "只讀 Code Review Gate。",
},
"source_refs": [".gitea/workflows/code-review.yaml"],
"rollups": {
"product_scope_count": 16,
"public_route_count_minimum": 31,
"source_candidate_repo_count": 10,
"pre_deploy_gate_count": 1,
"post_deploy_gate_count": 1,
"ai_reviewer_count": 2,
"mainstream_tool_count": 2,
"owner_review_required_count": 1,
"critical_gap_count": 1,
"blocked_operation_count": 17,
"active_write_gate_count": 0,
"action_button_count": 0,
},
"pre_deploy_gates": [_gate("pre", "hermes")],
"post_deploy_gates": [_gate("post", "nemotron")],
"ai_reviewer_lanes": [
_reviewer("hermes"),
_reviewer("aider"),
],
"mainstream_tool_lanes": [
_tool("codeql"),
_tool("gitleaks"),
],
"decision_matrix": [
{
"risk_lane": "low",
"reviewer": "Hermes",
"aider_role": "draft",
"required_gate": "owner",
"post_deploy": "smoke",
}
],
"gate_boundaries": {
"read_only_api_allowed": True,
"workflow_write_allowed": False,
"external_scanner_activation_allowed": False,
"paid_ai_review_allowed": False,
"repo_app_install_allowed": False,
"auto_merge_allowed": False,
"production_deploy_authorized": False,
"aider_auto_patch_allowed": False,
"elephantalpha_write_allowed": False,
"secret_read_allowed": False,
"post_deploy_write_allowed": False,
"runtime_execution_allowed": False,
"telegram_send_allowed": False,
"gateway_queue_write_allowed": False,
"host_probe_allowed": False,
"registry_push_allowed": False,
"artifact_signing_allowed": False,
"action_buttons_allowed": False,
},
"next_actions": [
{
"task_id": "P2-112",
"priority": "P1",
"summary": "下一步",
"gate": "owner",
}
],
}
def _gate(gate_id: str, owner_agent: str) -> dict:
return {
"gate_id": gate_id,
"label": gate_id,
"coverage": "repo",
"status": "wired",
"owner_agent": owner_agent,
"evidence_refs": ["docs/LOGBOOK.md"],
"current_gap": "gap",
"next_action": "review",
}
def _reviewer(agent_id: str) -> dict:
return {
"agent_id": agent_id,
"label": agent_id,
"role": "review",
"allowed_output": "packet",
"write_allowed": False,
}
def _tool(tool_id: str) -> dict:
return {
"tool_id": tool_id,
"label": tool_id,
"category": "scanner",
"source_url": "https://example.com",
"integration_status": "candidate",
"recommended_role": "scan",
"blocked_now": ["external lookup"],
}

View File

@@ -0,0 +1,38 @@
from __future__ import annotations
from fastapi import FastAPI
from fastapi.testclient import TestClient
from src.api.v1.agents import router
def test_product_code_review_gate_endpoint_returns_all_product_gate():
app = FastAPI()
app.include_router(router, prefix="/api/v1")
client = TestClient(app)
response = client.get("/api/v1/agents/product-code-review-gate")
assert response.status_code == 200
data = response.json()
assert data["schema_version"] == "product_code_review_gate_v1"
assert data["program_status"]["current_task_id"] == "P2-111"
assert data["program_status"]["next_task_id"] == "P2-112"
assert data["program_status"]["read_only_mode"] is True
assert data["rollups"]["product_scope_count"] == len(data["product_review_matrix"]) >= 16
assert data["tenant_asset_inventory_summary"]["public_route_count"] >= 31
assert data["rollups"]["pre_deploy_gate_count"] == len(data["pre_deploy_gates"]) == 8
assert data["rollups"]["post_deploy_gate_count"] == len(data["post_deploy_gates"]) == 6
assert data["rollups"]["ai_reviewer_count"] == len(data["ai_reviewer_lanes"]) == 5
assert data["rollups"]["mainstream_tool_count"] == len(data["mainstream_tool_lanes"]) == 9
assert data["rollups"]["active_write_gate_count"] == 0
assert data["rollups"]["action_button_count"] == 0
assert data["gate_boundaries"]["auto_merge_allowed"] is False
assert data["gate_boundaries"]["aider_auto_patch_allowed"] is False
assert data["gate_boundaries"]["external_scanner_activation_allowed"] is False
assert data["gate_boundaries"]["artifact_signing_allowed"] is False
assert any(product["product_id"] == "PRD-001" for product in data["product_review_matrix"])
assert any(product["product_id"] == "PRD-006" for product in data["product_review_matrix"])
assert any(tool["tool_id"] == "codeql" for tool in data["mainstream_tool_lanes"])
assert any(tool["tool_id"] == "semgrep" for tool in data["mainstream_tool_lanes"])
assert any(tool["tool_id"] == "osv_scanner" for tool in data["mainstream_tool_lanes"])