71 lines
2.4 KiB
Python
71 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""Central guard for Gemini API egress.
|
|
|
|
Gemini is emergency fallback only in this project. A plain API key must never be
|
|
enough to spend money: traffic is blocked by default with a hard kill switch, and
|
|
operators must explicitly unlock emergency fallback before any code path may
|
|
initialize the SDK or call the REST API.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
|
|
_TRUE_VALUES = {"1", "true", "yes", "on"}
|
|
_FALSE_VALUES = {"0", "false", "no", "off"}
|
|
|
|
|
|
def _env_flag(name: str, default: str) -> bool:
|
|
value = os.getenv(name, default).strip().lower()
|
|
if value in _TRUE_VALUES:
|
|
return True
|
|
if value in _FALSE_VALUES:
|
|
return False
|
|
return default.strip().lower() in _TRUE_VALUES
|
|
|
|
|
|
def is_gemini_hard_disabled() -> bool:
|
|
"""Master kill switch. Default true means zero Gemini API egress."""
|
|
return _env_flag("GEMINI_API_HARD_DISABLED", "true")
|
|
|
|
|
|
def _context_allowed(context: str | None) -> bool:
|
|
"""Optional allowlist for emergency fallback contexts."""
|
|
raw = os.getenv("GEMINI_ALLOWED_CONTEXTS", "").strip()
|
|
if not raw:
|
|
return True
|
|
if not context:
|
|
return False
|
|
allowed = {item.strip() for item in raw.split(",") if item.strip()}
|
|
return context in allowed
|
|
|
|
|
|
def is_gemini_fallback_enabled(context: str | None = None) -> bool:
|
|
"""Return whether Gemini fallback traffic is allowed for this process."""
|
|
if is_gemini_hard_disabled():
|
|
return False
|
|
if not _env_flag("GEMINI_FALLBACK_ENABLED", "false"):
|
|
return False
|
|
return _context_allowed(context)
|
|
|
|
|
|
def get_gemini_api_key(context: str | None = None) -> str:
|
|
"""Return the Gemini API key only when fallback traffic is enabled."""
|
|
if not is_gemini_fallback_enabled(context):
|
|
return ""
|
|
return os.getenv("GEMINI_API_KEY", "")
|
|
|
|
|
|
def gemini_disabled_message(context: str | None = None) -> str:
|
|
"""Human-readable reason for telemetry and error paths."""
|
|
suffix = f" ({context})" if context else ""
|
|
if is_gemini_hard_disabled():
|
|
return f"Gemini API hard-disabled by GEMINI_API_HARD_DISABLED=true{suffix}"
|
|
if not _env_flag("GEMINI_FALLBACK_ENABLED", "false"):
|
|
return f"Gemini fallback disabled by GEMINI_FALLBACK_ENABLED=false{suffix}"
|
|
if not _context_allowed(context):
|
|
return f"Gemini fallback context not allowed by GEMINI_ALLOWED_CONTEXTS{suffix}"
|
|
return f"Gemini fallback disabled{suffix}"
|