fix(awooop): open live copy to controlled automation
Some checks failed
Ansible / Reboot Recovery Contract / validate (push) Waiting to run
CD Pipeline / build-and-deploy (push) Blocked by required conditions
Code Review / ai-code-review (push) Waiting to run
CD Pipeline / tests (push) Successful in 1m39s
CD Pipeline / post-deploy-checks (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-28 01:36:38 +08:00
parent cff10d6a66
commit 060122fcd6
5 changed files with 264 additions and 132 deletions

View File

@@ -9,7 +9,9 @@ state for low / medium / high controlled automation.
from __future__ import annotations
import argparse
import json
from pathlib import Path
from typing import Any
TEXT_FILES = [
@@ -44,6 +46,37 @@ REQUIRED_FRAGMENTS = [
"受控授權閘門",
"controlled gate",
"controlled review",
"AI 受控 Gate",
"AI 受控補齊NO_ACTION",
"等待 AI 受控補齊",
"受控驗收流程",
"負責人脫敏證據收件",
"Controlled Review",
"AI 受控 review",
]
AWOOOP_LIVE_FORBIDDEN_FRAGMENTS = [
"人工 Gate",
"人工介入",
"待人工",
"等待人工",
"人工回覆",
"人工收件",
"人工判斷",
"人工交接",
"人工方案",
"人工確認無需動作",
"人工:{human}",
"需要人工={human}",
"人工覆核",
"人工檢查",
"Owner review",
"Owner Review",
"負責人審查",
]
AWOOOP_ALLOWED_LEGACY_PATH_PREFIXES = [
"awooop.approvals.legacyHitl.",
]
@@ -54,6 +87,38 @@ def _iter_guarded_files(root: Path) -> list[Path]:
return files
def _collect_awooop_message_violations(path: Path, root: Path) -> list[str]:
data = json.loads(path.read_text(encoding="utf-8"))
awooop = data.get("awooop")
if not isinstance(awooop, dict):
return [f"{path.relative_to(root)}: missing awooop namespace"]
violations: list[str] = []
def walk(value: Any, parts: list[str]) -> None:
if isinstance(value, dict):
for key, child in value.items():
walk(child, [*parts, key])
return
if isinstance(value, list):
for index, child in enumerate(value):
walk(child, [*parts, str(index)])
return
if not isinstance(value, str):
return
dotted = ".".join(parts)
if any(dotted.startswith(prefix) for prefix in AWOOOP_ALLOWED_LEGACY_PATH_PREFIXES):
return
for fragment in AWOOOP_LIVE_FORBIDDEN_FRAGMENTS:
if fragment in value:
relative = path.relative_to(root)
violations.append(f"{relative}:{dotted}: forbidden live AwoooP copy {fragment!r}")
walk(awooop, ["awooop"])
return violations
def validate(root: Path) -> None:
root = root.resolve()
violations: list[str] = []
@@ -65,6 +130,8 @@ def validate(root: Path) -> None:
continue
text = path.read_text(encoding="utf-8")
guarded_text.append(text)
if path.name.endswith(".json"):
violations.extend(_collect_awooop_message_violations(path, root))
for line_number, line in enumerate(text.splitlines(), start=1):
for fragment in FORBIDDEN_FRAGMENTS:
if fragment in line: