Files
ewoooc/tests/test_code_review_pipeline_security.py
OoO 6cad59f83e
All checks were successful
CD Pipeline / deploy (push) Successful in 2m23s
feat(code-review): ADR-020 全自動修復政策 — 拆掉 CRITICAL/HIGH HITL 閘門
post-deploy code review pipeline 改為「任何 finding 一律觸發 AiderHeal」,
局部覆寫 ADR-012 L3 HITL(不影響 schema migration / 流量切換 /
customer-facing 廣播 / AIOps prod SSH 等其他 L3 場景)。安全網改為
Git revert + Gitea CI/CD 健康檢查 + 主開關 CODE_REVIEW_AUTO_FIX_ENABLED。

實作:
  • _ea_orchestrate / _guard_ea_decision / rule fallback 三條路徑統一為
    has_findings AND AUTO_FIX_ENABLED → auto_fix=true
  • _guard 強制 LLM 即使回 auto_fix=False 也升級為 true(核心保證)
  • CODE_REVIEW_AUTO_FIX_ENABLED 預設 false → true
  • Telegram 文案移除「需人工審查」,改顯示主開關狀態
  • action_plan status pending_review → auto_disabled(語意對齊)
  • aider_heal_executor 標頭 ADR-014 → ADR-020、補「直推 main」分支策略

文件:
  • 新增 docs/adr/ADR-020-code-review-full-autoheal.md
  • ADR-012 加 Note 行反向引用 ADR-020
  • README 索引收錄

測試:tests/test_code_review_pipeline_security.py 反轉 HITL 期望,
新增 5 case(含 LLM 降級被 guard 拒絕、LLM human_review_needed=true 被改 false)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 23:44:01 +08:00

114 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
def test_verify_internal_token_requires_env_by_default(monkeypatch):
import services.code_review_pipeline_service as module
monkeypatch.setattr(module, "INTERNAL_TOKEN", "")
monkeypatch.setattr(module, "ALLOW_INSECURE_WEBHOOK", False)
assert module.verify_internal_token("") is False
assert module.verify_internal_token("anything") is False
def test_verify_internal_token_allows_explicit_dev_override(monkeypatch):
import services.code_review_pipeline_service as module
monkeypatch.setattr(module, "INTERNAL_TOKEN", "")
monkeypatch.setattr(module, "ALLOW_INSECURE_WEBHOOK", True)
assert module.verify_internal_token("") is True
def test_code_review_guard_auto_fixes_high_risk_findings(monkeypatch):
"""ADR-020CRITICAL/HIGH 不再走 HITL一律 auto_fix=true。"""
import services.code_review_pipeline_service as module
monkeypatch.setattr(module, "AUTO_FIX_ENABLED", True)
pipeline = module.CodeReviewPipeline("abcdef123456", ["services/example.py"])
pipeline.state["severity_summary"] = {"critical": 1, "high": 1, "medium": 0, "low": 0}
guarded = pipeline._guard_ea_decision(
{"priority": "critical", "auto_fix": True, "reasoning": "建議修復", "fix_files": ["services/example.py"]},
[
{"severity": "CRITICAL", "file": "services/example.py"},
{"severity": "HIGH", "file": "services/example.py"},
],
)
assert guarded["auto_fix"] is True
assert guarded["human_review_needed"] is False
def test_code_review_guard_main_switch_can_disable_auto_fix(monkeypatch):
"""ADR-020主開關 CODE_REVIEW_AUTO_FIX_ENABLED=false 可即時切斷自動修復鏈,但不再回退到 HITL。"""
import services.code_review_pipeline_service as module
monkeypatch.setattr(module, "AUTO_FIX_ENABLED", False)
pipeline = module.CodeReviewPipeline("abcdef123456", ["services/example.py"])
pipeline.state["severity_summary"] = {"critical": 0, "high": 0, "medium": 1, "low": 0}
guarded = pipeline._guard_ea_decision(
{"priority": "medium", "auto_fix": True, "reasoning": "建議修復", "fix_files": ["services/example.py"]},
[{"severity": "MEDIUM", "file": "services/example.py"}],
)
assert guarded["auto_fix"] is False
# ADR-020即使主開關關掉也不再標記 human_review_needed不存在 HITL 通道)
assert guarded["human_review_needed"] is False
def test_code_review_no_findings_no_auto_fix(monkeypatch):
"""無 finding 時auto_fix=false 但不應標記為 human_review_needed。"""
import services.code_review_pipeline_service as module
monkeypatch.setattr(module, "AUTO_FIX_ENABLED", True)
pipeline = module.CodeReviewPipeline("abcdef123456", ["services/example.py"])
pipeline.state["severity_summary"] = {"critical": 0, "high": 0, "medium": 0, "low": 0}
guarded = pipeline._guard_ea_decision(
{"priority": "low", "auto_fix": False, "reasoning": "無 finding", "fix_files": []},
[],
)
assert guarded["auto_fix"] is False
assert guarded["human_review_needed"] is False
def test_guard_upgrades_llm_false_to_true_when_findings_exist(monkeypatch):
"""ADR-020 核心保證:即使 LLM EA 回傳 auto_fix=False只要有 finding 且主開關開guard 必升級為 true。"""
import services.code_review_pipeline_service as module
monkeypatch.setattr(module, "AUTO_FIX_ENABLED", True)
pipeline = module.CodeReviewPipeline("abcdef123456", ["services/example.py"])
pipeline.state["severity_summary"] = {"critical": 0, "high": 0, "medium": 1, "low": 0}
guarded = pipeline._guard_ea_decision(
{"priority": "medium", "auto_fix": False, "reasoning": "LLM 保守判斷", "fix_files": ["services/example.py"]},
[{"severity": "MEDIUM", "file": "services/example.py"}],
)
# ADR-020 不允許 LLM 把決策降級為 HITL
assert guarded["auto_fix"] is True
assert guarded["human_review_needed"] is False
def test_guard_upgrades_llm_human_review_true_to_false(monkeypatch):
"""ADR-020即使 LLM 回 human_review_needed=trueguard 也應強制改為 false。"""
import services.code_review_pipeline_service as module
monkeypatch.setattr(module, "AUTO_FIX_ENABLED", True)
pipeline = module.CodeReviewPipeline("abcdef123456", ["services/example.py"])
pipeline.state["severity_summary"] = {"critical": 1, "high": 0, "medium": 0, "low": 0}
guarded = pipeline._guard_ea_decision(
{
"priority": "critical",
"auto_fix": False,
"human_review_needed": True,
"reasoning": "LLM 想走人工審查",
"fix_files": ["services/example.py"],
},
[{"severity": "CRITICAL", "file": "services/example.py"}],
)
assert guarded["auto_fix"] is True
assert guarded["human_review_needed"] is False