Files
awoooi/packages/lewooogo-brain/tests/test_guardrails.py
OG T cb5d0ecfe4 feat(phase-6.4g-6.5b): API Synaptic Integration + Dual-State WarRoom UI
Phase 6.4g (API 突觸對接):
- lewooogo-brain dependency binding in apps/api/pyproject.toml
- POST /api/v1/incidents/{id}/propose route (proposals.py)
- Guardrails integration (8/8 tests passed)

Phase 6.5a (視覺皮層建置):
- DualStateIncidentCard.tsx with Nothing.tech visual compliance
- Ping radar animation for alert state
- Tier-based decision layer UI (AI 執行中 / 等待親核)

Phase 6.5b (神經網路串接):
- Main warroom page integration (page.tsx)
- IncidentResponse → DualState mapper function
- Empty state: "系統穩定。0 活躍異常。"

Tests:
- test_guardrails.py (8/8)
- test_incident_engine.py (6/6)
- test_skill_loader.py (6/6)
- Frontend build: 0 errors

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-23 11:58:28 +08:00

210 lines
6.6 KiB
Python
Raw Permalink 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.
"""
Guardrails 單元測試
====================
Phase 6.4e 驗證點 3
確認 GuardrailsValidator 能正確攔截危險指令
"""
import sys
from pathlib import Path
# 添加 src 到 Python Path
src_path = Path(__file__).parent.parent / "src"
sys.path.insert(0, str(src_path))
def test_guardrails_validator_import():
"""測試:能正確 import GuardrailsValidator"""
from lewooogo_brain.engines.proposal_engine import GuardrailsValidator
print("✅ GuardrailsValidator import 成功")
def test_guardrails_block_rm_rf():
"""測試:攔截 rm -rf 指令"""
from lewooogo_brain.engines.proposal_engine import GuardrailsValidator
dangerous_scripts = [
"rm -rf /",
"rm -rf /*",
"sudo rm -rf /home",
"RM -RF /var/log", # 大小寫
]
for script in dangerous_scripts:
is_safe, violation = GuardrailsValidator.validate_script(script)
assert not is_safe, f"Should block: {script}"
assert violation is not None
print(f"✅ 攔截: {script[:30]}...")
def test_guardrails_block_drop_database():
"""測試:攔截 DROP DATABASE 指令"""
from lewooogo_brain.engines.proposal_engine import GuardrailsValidator
scripts = [
"DROP DATABASE awoooi_prod",
"drop table users",
"TRUNCATE incidents",
]
for script in scripts:
is_safe, violation = GuardrailsValidator.validate_script(script)
assert not is_safe, f"Should block: {script}"
print(f"✅ 攔截: {script}")
def test_guardrails_block_kubectl_delete_ns():
"""測試:攔截 kubectl delete namespace 指令"""
from lewooogo_brain.engines.proposal_engine import GuardrailsValidator
scripts = [
"kubectl delete namespace awoooi-prod",
"kubectl delete ns kube-system",
"kubectl delete -A pods",
]
for script in scripts:
is_safe, violation = GuardrailsValidator.validate_script(script)
assert not is_safe, f"Should block: {script}"
print(f"✅ 攔截: {script}")
def test_guardrails_allow_safe_commands():
"""測試:允許安全指令"""
from lewooogo_brain.engines.proposal_engine import GuardrailsValidator
safe_scripts = [
"kubectl get pods -n awoooi-prod",
"kubectl rollout restart deployment/awoooi-api -n awoooi-prod",
"kubectl describe pod abc -n awoooi-prod",
"kubectl logs -f deployment/awoooi-api -n awoooi-prod",
]
for script in safe_scripts:
is_safe, violation = GuardrailsValidator.validate_script(script)
assert is_safe, f"Should allow: {script}, violation: {violation}"
print(f"✅ 允許: {script[:50]}...")
def test_guardrails_namespace_validation():
"""測試Namespace 白名單驗證"""
from lewooogo_brain.engines.proposal_engine import GuardrailsValidator
# 允許的 namespace
is_ok, _ = GuardrailsValidator.validate_namespace("awoooi-prod")
assert is_ok, "awoooi-prod should be allowed"
print("✅ awoooi-prod 允許")
is_ok, _ = GuardrailsValidator.validate_namespace("awoooi-dev")
assert is_ok, "awoooi-dev should be allowed"
print("✅ awoooi-dev 允許")
# 禁止的 namespace
forbidden = ["kube-system", "kube-public", "default"]
for ns in forbidden:
is_ok, violation = GuardrailsValidator.validate_namespace(ns)
assert not is_ok, f"{ns} should be forbidden"
print(f"{ns} 禁止: {violation}")
def test_guardrails_enforce_dry_run():
"""測試:強制 dry-run 標記"""
from lewooogo_brain.engines.proposal_engine import GuardrailsValidator
proposal = {
"action": "kubectl apply -f config.yaml",
"guardrails": {},
}
result = GuardrailsValidator.enforce_dry_run(proposal)
assert result["guardrails"]["require_dry_run"] == True
assert "awoooi-prod" in result["guardrails"]["allowed_namespace"]
print("✅ 強制 dry-run 設定成功")
print(f" - require_dry_run: {result['guardrails']['require_dry_run']}")
print(f" - allowed_namespace: {result['guardrails']['allowed_namespace']}")
def test_proposal_engine_guardrails_integration():
"""測試ProposalEngine 整合 Guardrails"""
import asyncio
from lewooogo_brain.engines.proposal_engine import ProposalEngine
from lewooogo_brain.interfaces.proposal_engine import Proposal
class MockMemory:
async def load_incident(self, incident_id):
from lewooogo_brain.interfaces.incident_processor import (
Incident, IncidentStatus, Severity, Signal
)
from datetime import datetime, timezone
return Incident(
incident_id=incident_id,
status=IncidentStatus.INVESTIGATING,
severity=Severity.P1,
signals=[Signal(
alert_name="TestAlert",
severity=Severity.P1,
source="test",
fired_at=datetime.now(timezone.utc),
)],
affected_services=["test-service"],
)
async def update_incident(self, incident_id, updates):
return True
engine = ProposalEngine(memory=MockMemory())
# 取得預設 Guardrails
guardrails = engine.get_default_guardrails()
assert guardrails.require_dry_run == True
assert "awoooi-prod" in guardrails.allowed_namespace
assert any("rm -rf" in cmd.lower() for cmd in guardrails.forbidden_commands)
print("✅ ProposalEngine Guardrails 整合成功:")
print(f" - require_dry_run: {guardrails.require_dry_run}")
print(f" - allowed_namespace: {guardrails.allowed_namespace}")
print(f" - forbidden_commands: {len(guardrails.forbidden_commands)}")
if __name__ == "__main__":
print("=" * 60)
print("🧪 Guardrails 單元測試")
print("=" * 60)
tests = [
test_guardrails_validator_import,
test_guardrails_block_rm_rf,
test_guardrails_block_drop_database,
test_guardrails_block_kubectl_delete_ns,
test_guardrails_allow_safe_commands,
test_guardrails_namespace_validation,
test_guardrails_enforce_dry_run,
test_proposal_engine_guardrails_integration,
]
passed = 0
failed = 0
for test in tests:
print(f"\n🔬 {test.__name__}")
try:
test()
passed += 1
except AssertionError as e:
print(f"❌ FAILED: {e}")
failed += 1
except Exception as e:
print(f"❌ ERROR: {type(e).__name__}: {e}")
failed += 1
print("\n" + "=" * 60)
print(f"📊 結果: {passed} 通過, {failed} 失敗")
print("=" * 60)
if failed > 0:
sys.exit(1)