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
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:
@@ -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],
|
||||
|
||||
193
apps/api/src/services/product_code_review_gate.py
Normal file
193
apps/api/src/services/product_code_review_gate.py
Normal 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")
|
||||
Reference in New Issue
Block a user