V10.601 收斂 Gemini 與密鑰治理
All checks were successful
CD Pipeline / deploy (push) Successful in 1m12s

This commit is contained in:
OoO
2026-06-06 14:52:46 +08:00
parent 2efe9bd931
commit d6d8777e41
70 changed files with 211 additions and 116 deletions

View File

@@ -3,6 +3,7 @@
"""Gemini fallback kill-switch contract."""
import re
import subprocess
from pathlib import Path
from services.ai_provider import AIProviderService, AIResponse
@@ -24,6 +25,25 @@ def _rel(path: Path) -> str:
return path.relative_to(ROOT).as_posix()
def _tracked_text_files():
result = subprocess.run(
["git", "ls-files", "-z"],
cwd=ROOT,
check=True,
capture_output=True,
)
for raw in result.stdout.split(b"\0"):
if not raw:
continue
path = ROOT / raw.decode("utf-8")
if path.is_file():
try:
path.read_text(encoding="utf-8")
except UnicodeDecodeError:
continue
yield path
def test_gemini_guard_defaults_disabled(monkeypatch):
from services.gemini_guard import get_gemini_api_key, is_gemini_fallback_enabled
@@ -175,3 +195,51 @@ def test_gemini_outbound_files_are_guarded():
assert offenders == []
assert unguarded == []
def test_tracked_secret_manifests_do_not_contain_live_credentials():
tracked_secret_files = list(ROOT.joinpath("k8s").rglob("*.yaml"))
legacy_secret = ROOT / "k8s 2" / "03-secrets.yaml"
if legacy_secret.exists():
tracked_secret_files.append(legacy_secret)
live_secret_patterns = {
"Google API key": re.compile(r"AIza[0-9A-Za-z_-]{20,}"),
"Telegram bot token": re.compile(r"\d{8,12}:[A-Za-z0-9_-]{30,}"),
"LINE token": re.compile(r"[A-Za-z0-9+/=]{80,}"),
"hardcoded password": re.compile(
r"(POSTGRES_PASSWORD|LOGIN_PASSWORD|APP_PASSWORD|SECRET_KEY):\s*"
r"['\"](?!<)[^'\"]{6,}['\"]"
),
"inline URL password": re.compile(r"://[^:\s/]+:(?!<)[^@\s]+@"),
}
offenders = []
for path in tracked_secret_files:
text = path.read_text(encoding="utf-8")
for label, pattern in live_secret_patterns.items():
if pattern.search(text):
offenders.append(f"{path.relative_to(ROOT).as_posix()}: {label}")
assert offenders == []
def test_tracked_text_files_do_not_contain_known_live_tokens():
live_token_patterns = {
"Google API key": re.compile(r"AIza[0-9A-Za-z_-]{20,}"),
"Google OAuth access token": re.compile(r"ya29\.[0-9A-Za-z_-]{20,}"),
"Google OAuth refresh token": re.compile(r"1//0[0-9A-Za-z_-]{20,}"),
"Google OAuth client secret": re.compile(r"GOCSPX-[0-9A-Za-z_-]{12,}"),
"Telegram bot token": re.compile(r"\d{8,12}:[A-Za-z0-9_-]{30,}"),
"Ollama cloud API key": re.compile(r"\b[0-9a-f]{32}\.[A-Za-z0-9_-]{12,}\b"),
"Superset default password": re.compile(r"Wooo_Superset_\d{4}"),
}
offenders = []
for path in _tracked_text_files():
text = path.read_text(encoding="utf-8")
for label, pattern in live_token_patterns.items():
if pattern.search(text):
offenders.append(f"{_rel(path)}: {label}")
assert offenders == []

View File

@@ -274,6 +274,25 @@ class TestOpenClawReportRouting:
assert result == "Ollama 報告內容足夠完整"
assert calls == [("ollama", "openclaw_weekly")]
def test_report_llm_disables_111_for_long_strategy_reports(self, monkeypatch, reset_state):
FakeOllamaService, _fake_resp = _stub_ollama_generate(
monkeypatch,
content="OpenClaw 報告內容足夠完整,並且只允許 GCP-A/GCP-B 承接長報告。",
)
result = svc._call_ollama_strategy(
"system",
"user",
temperature=0.3,
caller="openclaw_meta",
num_predict=3072,
)
assert result.startswith("OpenClaw 報告內容")
assert FakeOllamaService.instances
call_kwargs = FakeOllamaService.instances[-1].generate_calls[-1]
assert call_kwargs["allow_111_fallback"] is False
def test_report_llm_gemini_is_suffix_fallback_only(self, monkeypatch):
monkeypatch.setenv("GEMINI_API_HARD_DISABLED", "false")
monkeypatch.setenv("GEMINI_FALLBACK_ENABLED", "true")