60 lines
2.4 KiB
Python
60 lines
2.4 KiB
Python
"""Einstellungen aus Umgebungsvariablen (Präfix DBMCP_)."""
|
|
|
|
import os
|
|
from collections.abc import Mapping
|
|
from dataclasses import dataclass
|
|
|
|
|
|
def _list(value: str) -> tuple[str, ...]:
|
|
return tuple(v.strip().lower() for v in value.split(",") if v.strip())
|
|
|
|
|
|
def _bool(value: str) -> bool:
|
|
return value.strip().lower() in ("1", "true", "yes", "on")
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Settings:
|
|
# Schlüssel der Clients: Geheimnis -> Name (für das Audit-Log); DBMCP_API_KEYS="bifroest:geheim,…"
|
|
api_keys: Mapping[str, str]
|
|
# Datenbank-Hosts, zu denen verbunden werden darf: exakt oder als Endung (".db.intern")
|
|
allowed_hosts: tuple[str, ...] = ()
|
|
allow_local: bool = False
|
|
connect_timeout: float = 5
|
|
query_timeout: float = 15
|
|
max_rows: int = 500
|
|
max_tables: int = 300
|
|
sample_rows: int = 5
|
|
max_cell_chars: int = 200
|
|
max_sql_chars: int = 10000
|
|
# Host-Header, die der MCP-Transport annimmt (Schutz vor DNS-Rebinding); leer = keine Prüfung
|
|
http_hosts: tuple[str, ...] = ()
|
|
# Nur für die lokale Entwicklung: ohne Schlüssel starten
|
|
insecure_no_auth: bool = False
|
|
bind: str = "0.0.0.0"
|
|
port: int = 8080
|
|
|
|
@classmethod
|
|
def from_env(cls, env: Mapping[str, str] = os.environ) -> "Settings":
|
|
keys = {}
|
|
for entry in env.get("DBMCP_API_KEYS", "").split(","):
|
|
name, sep, secret = entry.strip().partition(":")
|
|
if entry.strip():
|
|
if not sep or not name or len(secret) < 16:
|
|
raise ValueError("DBMCP_API_KEYS: Einträge als name:geheimnis, Geheimnis mindestens 16 Zeichen")
|
|
keys[secret] = name
|
|
settings = cls(
|
|
api_keys=keys,
|
|
allowed_hosts=_list(env.get("DBMCP_ALLOWED_HOSTS", "")),
|
|
allow_local=_bool(env.get("DBMCP_ALLOW_LOCAL", "")),
|
|
connect_timeout=float(env.get("DBMCP_CONNECT_TIMEOUT_SECONDS", 5)),
|
|
query_timeout=float(env.get("DBMCP_QUERY_TIMEOUT_SECONDS", 15)),
|
|
max_rows=int(env.get("DBMCP_MAX_ROWS", 500)),
|
|
http_hosts=_list(env.get("DBMCP_HTTP_HOSTS", "")),
|
|
insecure_no_auth=_bool(env.get("DBMCP_INSECURE_NO_AUTH", "")),
|
|
bind=env.get("DBMCP_BIND", "0.0.0.0"),
|
|
port=int(env.get("DBMCP_PORT", 8080)),
|
|
)
|
|
if not settings.api_keys and not settings.insecure_no_auth:
|
|
raise ValueError("DBMCP_API_KEYS fehlt (nur für die Entwicklung: DBMCP_INSECURE_NO_AUTH=true)")
|
|
return settings
|