-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.py
More file actions
117 lines (95 loc) · 3.33 KB
/
Copy pathconfig.py
File metadata and controls
117 lines (95 loc) · 3.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
from functools import lru_cache
from pathlib import Path
from typing import Any
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
from python_api.utils.constants import (
DEFAULT_API_HOST,
DEFAULT_API_PORT,
DEFAULT_APP_NAME,
DEFAULT_CORS_ORIGINS,
DEFAULT_DATABASE_URL,
DEFAULT_DEBUG,
DEFAULT_GRPC_ENABLED,
DEFAULT_GRPC_PORT,
DEFAULT_JWT_ACCESS_TOKEN_EXPIRE_HOURS,
DEFAULT_JWT_ALGORITHM,
DEFAULT_JWT_SECRET_KEY,
DEFAULT_OTEL_ENABLED,
DEFAULT_OTEL_ENDPOINT,
DEFAULT_OTEL_SERVICE_NAME,
DEFAULT_PASSWORD_HASH_ROUNDS,
DEFAULT_RATE_LIMIT_BURST,
DEFAULT_RATE_LIMIT_ENABLED,
DEFAULT_RATE_LIMIT_REQUESTS_PER_MINUTE,
DEFAULT_REDIS_KEY_PREFIX,
DEFAULT_REDIS_POOL_SIZE,
DEFAULT_REDIS_URL,
DEFAULT_VERSION,
DEFAULT_WORKERS,
)
KNOWN_INSECURE_SECRETS = {
DEFAULT_JWT_SECRET_KEY,
"change-me-set-a-real-secret-key!",
"change_me",
}
BASE_DIR = Path(__file__).resolve().parent.parent.parent.parent
class Settings(BaseSettings):
app_name: str = DEFAULT_APP_NAME
version: str = DEFAULT_VERSION
debug: bool = DEFAULT_DEBUG
api_host: str = DEFAULT_API_HOST
api_port: int = DEFAULT_API_PORT
workers: int = DEFAULT_WORKERS
database_url: str = DEFAULT_DATABASE_URL
redis_url: str = DEFAULT_REDIS_URL
redis_pool_size: int = DEFAULT_REDIS_POOL_SIZE
redis_key_prefix: str = DEFAULT_REDIS_KEY_PREFIX
jwt_secret_key: str = Field(
default=DEFAULT_JWT_SECRET_KEY,
description="JWT secret key - must be set in production",
)
jwt_algorithm: str = DEFAULT_JWT_ALGORITHM
jwt_access_token_expire_hours: int = DEFAULT_JWT_ACCESS_TOKEN_EXPIRE_HOURS
password_hash_rounds: int = DEFAULT_PASSWORD_HASH_ROUNDS
rate_limit_enabled: bool = DEFAULT_RATE_LIMIT_ENABLED
rate_limit_requests_per_minute: int = DEFAULT_RATE_LIMIT_REQUESTS_PER_MINUTE
rate_limit_burst: int = DEFAULT_RATE_LIMIT_BURST
grpc_enabled: bool = DEFAULT_GRPC_ENABLED
grpc_port: int = DEFAULT_GRPC_PORT
cors_origins: list[str] = Field(
default=DEFAULT_CORS_ORIGINS,
description="CORS allowed origins (comma-separated string or list)",
)
otel_enabled: bool = DEFAULT_OTEL_ENABLED
otel_endpoint: str = DEFAULT_OTEL_ENDPOINT
otel_service_name: str = DEFAULT_OTEL_SERVICE_NAME
otel_insecure: bool = True
model_config = SettingsConfigDict(
env_file=[
BASE_DIR.parent / "config" / "python-api.env",
Path("./config/python-api.env"),
Path(".env"),
],
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
@field_validator("cors_origins", mode="before")
@classmethod
def parse_cors_origins(cls, v: str | list[str]) -> list[str]:
if isinstance(v, str):
if v.strip() == "":
return []
return [origin.strip() for origin in v.split(",")]
return v
@field_validator("jwt_secret_key")
@classmethod
def validate_jwt_secret(cls, v: str, info: Any) -> str:
debug = info.data.get("debug", False) if info.data else False
if not v and not debug:
raise ValueError("JWT_SECRET_KEY must be set in production")
return v
@lru_cache
def get_settings() -> Settings:
return Settings()