Skip to content

Commit db1e172

Browse files
committed
Add validation logic based on environment and validate hosts protocols and SSL in production
1 parent 9320712 commit db1e172

File tree

2 files changed

+28
-10
lines changed

2 files changed

+28
-10
lines changed

scripts/local_with_uvicorn/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
APP_NAME="My Project"
1717
APP_DESCRIPTION="My Project Description"
1818
APP_VERSION="0.1"
19+
APP_BACKEND_HOST="http://localhost:8000"
20+
APP_FRONTEND_HOST="http://localhost:3000"
1921
CONTACT_NAME="Me"
2022
CONTACT_EMAIL="[email protected]"
2123
LICENSE_NAME="MIT"

src/app/core/config.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import os
2+
import warnings
23
from enum import Enum
4+
from typing import Self
35

4-
from pydantic import SecretStr, computed_field, field_validator
6+
from pydantic import SecretStr, computed_field, field_validator, model_validator
57
from pydantic_settings import BaseSettings, SettingsConfigDict
68

79

@@ -20,7 +22,7 @@ class AppSettings(BaseSettings):
2022
def validate_hosts(cls, host: str) -> str:
2123
if host is not None and not (host.startswith("http://") or host.startswith("https://")):
2224
raise ValueError(
23-
f"HOSTS must define their protocol and start with http:// or https://. Received the host {host}."
25+
f"HOSTS must define their protocol and start with http:// or https://. Received the host '{host}'."
2426
)
2527
return host
2628

@@ -183,14 +185,28 @@ class Settings(
183185
extra="ignore",
184186
)
185187

186-
@field_validator("APP_FRONTEND_HOST")
187-
@classmethod
188-
def validate_app_frontend_host_protocol(cls, host: str) -> str:
189-
if EnvironmentSettings.ENVIRONMENT == EnvironmentOption.PRODUCTION and not host.startswith("https://"):
190-
raise ValueError(
191-
f"In production, APP_FRONTEND_HOST must start with the https:// protocol. Received the host {host}."
192-
)
193-
return host
188+
@model_validator(mode="after")
189+
def validate_environment_settings(self) -> Self:
190+
if self.ENVIRONMENT == EnvironmentOption.LOCAL:
191+
pass
192+
elif self.ENVIRONMENT == EnvironmentOption.STAGING:
193+
if "*" in self.CORS_ORIGINS:
194+
warnings.warn(
195+
"For security, in a staging environment CORS_ORIGINS should not include '*'. "
196+
"It's recommended to specify explicit origins (e.g., ['https://staging.example.com'])."
197+
)
198+
elif self.ENVIRONMENT == EnvironmentOption.PRODUCTION:
199+
if "*" in self.CORS_ORIGINS:
200+
raise ValueError(
201+
"For security, in a production environment CORS_ORIGINS cannot include '*'. "
202+
"You must specify explicit allowed origins (e.g., ['https://example.com', 'https://www.example.com'])."
203+
)
204+
if self.APP_FRONTEND_HOST and not self.APP_FRONTEND_HOST.startswith("https://"):
205+
raise ValueError(
206+
"In production, APP_FRONTEND_HOST must start with the https:// protocol. "
207+
f"Received the host '{self.APP_FRONTEND_HOST}'."
208+
)
209+
return self
194210

195211

196212
settings = Settings()

0 commit comments

Comments
 (0)