fix(security): keep Gemini key out of request URLs
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 15m5s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 15m5s
This commit is contained in:
@@ -10,7 +10,7 @@ Google Gemini Cloud API (gemini-2.0-flash)
|
||||
2026-04-29 ogt + Claude Code: P0 SECRET LEAK 修復
|
||||
發現 prod log 出現完整 API key 明碼(feedback_secret_debug_output_ban 鐵律)
|
||||
根因:httpx HTTPStatusError str() 會包含完整 URL(含 ?key=... query string)
|
||||
修法:_sanitize_error 移除 URL query string + redact key
|
||||
修法:改用 x-goog-api-key header,並保留 _sanitize_error 當防線
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -22,7 +22,7 @@ import httpx
|
||||
import structlog
|
||||
|
||||
from src.core.config import get_settings
|
||||
from src.services.ai_providers.interfaces import AIProvider, AIResult, is_provider_enabled_by_env
|
||||
from src.services.ai_providers.interfaces import AIResult, is_provider_enabled_by_env
|
||||
from src.services.model_registry import get_model_registry
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
@@ -91,7 +91,8 @@ class GeminiProvider:
|
||||
model_name = registry.get_model("gemini", "rca")
|
||||
|
||||
response = await client.post(
|
||||
f"https://generativelanguage.googleapis.com/v1beta/models/{model_name}:generateContent?key={settings.GEMINI_API_KEY}",
|
||||
f"https://generativelanguage.googleapis.com/v1beta/models/{model_name}:generateContent",
|
||||
headers={"x-goog-api-key": settings.GEMINI_API_KEY},
|
||||
json={
|
||||
"contents": [{"parts": [{"text": prompt}]}],
|
||||
"generationConfig": {
|
||||
|
||||
@@ -715,7 +715,7 @@ async def _call_gemini(prompt: str, api_key: str) -> str | None:
|
||||
async with httpx.AsyncClient(timeout=30) as client:
|
||||
resp = await client.post(
|
||||
url,
|
||||
params={"key": api_key},
|
||||
headers={"x-goog-api-key": api_key},
|
||||
json={"contents": [{"parts": [{"text": prompt}]}],
|
||||
"generationConfig": {"temperature": 0.1}},
|
||||
)
|
||||
|
||||
@@ -119,7 +119,8 @@ class ChatManager:
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
resp = await client.post(
|
||||
f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent?key={api_key}",
|
||||
f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent",
|
||||
headers={"x-goog-api-key": api_key},
|
||||
json={
|
||||
"system_instruction": {"parts": [{"text": system_prompt}]},
|
||||
"contents": [{"parts": [{"text": user_message}]}],
|
||||
|
||||
@@ -244,7 +244,7 @@ class HeartbeatReportService:
|
||||
model_status[required] = ok
|
||||
|
||||
return {
|
||||
"probe": ProbeResult(True, f"✅ 正常", round(latency, 1)),
|
||||
"probe": ProbeResult(True, "✅ 正常", round(latency, 1)),
|
||||
"models": model_status,
|
||||
}
|
||||
except Exception as e:
|
||||
@@ -279,7 +279,8 @@ class HeartbeatReportService:
|
||||
async with httpx.AsyncClient(timeout=_PROBE_TIMEOUT) as client:
|
||||
t0 = asyncio.get_event_loop().time()
|
||||
resp = await client.get(
|
||||
f"https://generativelanguage.googleapis.com/v1beta/models?key={settings.GEMINI_API_KEY}",
|
||||
"https://generativelanguage.googleapis.com/v1beta/models",
|
||||
headers={"x-goog-api-key": settings.GEMINI_API_KEY},
|
||||
)
|
||||
latency = (asyncio.get_event_loop().time() - t0) * 1000
|
||||
if resp.status_code == 200:
|
||||
|
||||
@@ -105,7 +105,8 @@ async def probe_gemini_version() -> ProviderVersionInfo:
|
||||
async with httpx.AsyncClient(timeout=8.0) as client:
|
||||
resp = await client.get(
|
||||
"https://generativelanguage.googleapis.com/v1beta/models",
|
||||
params={"key": api_key, "pageSize": 50},
|
||||
params={"pageSize": 50},
|
||||
headers={"x-goog-api-key": api_key},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
|
||||
@@ -507,7 +507,8 @@ class OpenClawService:
|
||||
model_name = registry.get_model("gemini", "rca")
|
||||
|
||||
response = await client.post(
|
||||
f"https://generativelanguage.googleapis.com/v1beta/models/{model_name}:generateContent?key={settings.GEMINI_API_KEY}",
|
||||
f"https://generativelanguage.googleapis.com/v1beta/models/{model_name}:generateContent",
|
||||
headers={"x-goog-api-key": settings.GEMINI_API_KEY},
|
||||
json={
|
||||
"contents": [{"parts": [{"text": prompt}]}],
|
||||
"generationConfig": {
|
||||
|
||||
Reference in New Issue
Block a user