refactor(settings): validate cross-field rules in the model

The "AUTH_TYPE=oidc requires OIDC_ISSUER, OIDC_CLIENT_ID and
OIDC_FRONTEND_URL" check lived in app.py, so it only ran when the Flask
app was imported; a worker or script with the same misconfiguration
started fine. It is now a model validator on the auth group and runs
wherever Settings is loaded, with the same message.

DEPLOYMENT_TYPE, which app.py read straight from the environment to
decide whether a missing JWT_SECRET_KEY is fatal, is a documented
setting on the server group now, so it shows up in the reference like
every other variable the app reads.
This commit is contained in:
arc53-machine committed 2026-09-17 11:09:09 +01:00
1 parent 95d0799494
commit a8dab8864d
5 files changed
+43 -12

No files matched your search

+1 -10
View File
@@ -1,5 +1,4 @@
import logging
import os
import platform
import uuid
@@ -170,16 +169,8 @@ def enforce_document_upload_request_size_limit():
# only local development may use the atomic filesystem fallback.
settings.JWT_SECRET_KEY = resolve_jwt_secret_key(
settings.JWT_SECRET_KEY,
os.getenv("DEPLOYMENT_TYPE"),
settings.DEPLOYMENT_TYPE,
)
if settings.AUTH_TYPE == "oidc":
_missing_oidc = [
name
for name in ("OIDC_ISSUER", "OIDC_CLIENT_ID", "OIDC_FRONTEND_URL")
if not getattr(settings, name)
]
if _missing_oidc:
raise RuntimeError(f"AUTH_TYPE=oidc requires settings: {', '.join(_missing_oidc)}")
SIMPLE_JWT_TOKEN = None
if settings.AUTH_TYPE == "simple_jwt":
payload = {"sub": "local"}
+13 -1
View File
@@ -4,11 +4,15 @@ from __future__ import annotations
from typing import Literal, Optional
from pydantic import Field, field_validator
from pydantic import Field, field_validator, model_validator
from docsgpt.core.settings._shared import SettingsGroup, normalize_choice, normalize_secret
#: Settings an OIDC deployment cannot run without; checked when AUTH_TYPE=oidc.
OIDC_REQUIRED = ("OIDC_ISSUER", "OIDC_CLIENT_ID", "OIDC_FRONTEND_URL")
class AuthSettings(SettingsGroup):
"""How users authenticate: none, a shared token, per-session JWTs, or OIDC SSO."""
@@ -91,3 +95,11 @@ class AuthSettings(SettingsGroup):
def _normalize_auth_type(cls, v):
# ``AUTH_TYPE=None`` and ``AUTH_TYPE=`` in .env both mean "no authentication".
return normalize_choice(normalize_secret(v))
@model_validator(mode="after")
def _require_oidc_settings(self):
if self.AUTH_TYPE == "oidc":
missing = [name for name in OIDC_REQUIRED if not getattr(self, name)]
if missing:
raise ValueError(f"AUTH_TYPE=oidc requires settings: {', '.join(missing)}")
return self
+7
View File
@@ -12,6 +12,13 @@ from docsgpt.core.settings._shared import SettingsGroup
class ServerSettings(SettingsGroup):
"""Serving the UI, public URLs, and process-level knobs of the API server."""
DEPLOYMENT_TYPE: Optional[str] = Field(
default=None,
description=(
"Deployment class, e.g. cloud or production. A production class refuses to run without a "
"configured JWT_SECRET_KEY instead of generating a local one on disk."
),
)
SERVE_UI: bool = Field(
default=True, description="Serve the web UI shipped in the package (docsgpt/static) from the API process."
)