|
| 1 | +import tomllib |
| 2 | +from pathlib import Path |
1 | 3 | from typing import Literal |
2 | 4 |
|
3 | | -from pydantic import Field |
4 | | -from pydantic_settings import BaseSettings, SettingsConfigDict |
| 5 | +from pydantic import BaseModel, ConfigDict, Field |
5 | 6 |
|
6 | 7 | from app.domain.execution import LanguageInfoDomain |
7 | 8 | from app.runtime_registry import EXAMPLE_SCRIPTS as EXEC_EXAMPLE_SCRIPTS |
8 | 9 | from app.runtime_registry import SUPPORTED_RUNTIMES as RUNTIME_MATRIX |
9 | 10 |
|
10 | 11 |
|
11 | | -class Settings(BaseSettings): |
| 12 | +class Settings(BaseModel): |
| 13 | + """Application settings loaded from TOML configuration files. |
| 14 | +
|
| 15 | + All config is read from TOML — no environment variables, no .env files. |
| 16 | +
|
| 17 | + Load order (each layer overrides the previous): |
| 18 | + 1. config_path — base settings (committed to git) |
| 19 | + 2. secrets_path — sensitive overrides (gitignored, mounted from K8s Secret in prod) |
| 20 | + 3. override_path — per-worker service overrides (TRACING_SERVICE_NAME, etc.) |
| 21 | +
|
| 22 | + Usage: |
| 23 | + Settings() # config.toml + secrets |
| 24 | + Settings(config_path="config.test.toml") # test config (has own secrets) |
| 25 | + Settings(override_path="config.coordinator.toml") # base + secrets + worker |
| 26 | + """ |
| 27 | + |
| 28 | + model_config = ConfigDict(extra="forbid") |
| 29 | + |
| 30 | + def __init__( |
| 31 | + self, |
| 32 | + config_path: str = "config.toml", |
| 33 | + override_path: str | None = None, |
| 34 | + secrets_path: str = "secrets.toml", |
| 35 | + ) -> None: |
| 36 | + with open(config_path, "rb") as f: |
| 37 | + data = tomllib.load(f) |
| 38 | + if Path(secrets_path).is_file(): |
| 39 | + with open(secrets_path, "rb") as f: |
| 40 | + data |= tomllib.load(f) |
| 41 | + if override_path: |
| 42 | + with open(override_path, "rb") as f: |
| 43 | + data |= tomllib.load(f) |
| 44 | + super().__init__(**data) |
| 45 | + |
12 | 46 | PROJECT_NAME: str = "integr8scode" |
13 | 47 | DATABASE_NAME: str = "integr8scode_db" |
14 | 48 | API_V1_STR: str = "/api/v1" |
15 | 49 | SECRET_KEY: str = Field( |
16 | | - ..., # Actual key be loaded from .env file |
| 50 | + ..., |
17 | 51 | min_length=32, |
18 | 52 | description="Secret key for JWT token signing. Must be at least 32 characters.", |
19 | 53 | ) |
@@ -145,27 +179,14 @@ class Settings(BaseSettings): |
145 | 179 | OTEL_RESOURCE_ATTRIBUTES: str | None = None |
146 | 180 |
|
147 | 181 | # Web server (Gunicorn/Uvicorn) concurrency settings |
148 | | - # These are read from environment and used by the runtime entrypoint |
149 | | - # and by app.main when started directly via uvicorn. |
150 | 182 | WEB_CONCURRENCY: int = 4 |
151 | 183 | WEB_THREADS: int = 1 |
152 | 184 | WEB_TIMEOUT: int = 60 |
153 | 185 | WEB_BACKLOG: int = 2048 |
154 | 186 |
|
155 | | - # Additional MongoDB settings (for docker-compose compatibility) |
156 | | - MONGO_ROOT_USER: str | None = None |
157 | | - MONGO_ROOT_PASSWORD: str | None = None |
158 | | - |
159 | 187 | # Development mode detection |
160 | 188 | DEVELOPMENT_MODE: bool = False |
161 | | - SECURE_COOKIES: bool = True # Can be overridden in .env for development |
| 189 | + SECURE_COOKIES: bool = True |
162 | 190 |
|
163 | 191 | # Logging configuration |
164 | 192 | LOG_LEVEL: str = Field(default="DEBUG", description="Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)") |
165 | | - |
166 | | - model_config = SettingsConfigDict( |
167 | | - env_file=".env", |
168 | | - env_file_encoding="utf-8", |
169 | | - case_sensitive=True, |
170 | | - extra="forbid", # Raise error on extra fields |
171 | | - ) |
|
0 commit comments