"""Configuration safety guards. A production API booted with a placeholder ``JWT_SECRET`` lets anyone forge a token for any tenant. These tests pin the fail-closed behaviour. """ from __future__ import annotations import pytest from pydantic import ValidationError from app.core.config import DEVELOPMENT_CORS_ORIGINS, MIN_SECRET_LENGTH, Settings _SAFE = { "app_env": "production", "jwt_secret": "s" * MIN_SECRET_LENGTH, "encryption_key": "k" * 44, "cors_origins": "https://app.example.com", } def _build(**overrides) -> Settings: return Settings(**{**_SAFE, **overrides}) def test_development_tolerates_placeholder_secrets(): """A fresh clone must run with zero configuration.""" settings = Settings( app_env="development", jwt_secret="change-me", encryption_key="" ) assert settings.is_production is False def test_development_cors_allows_both_loopback_spellings(): """``localhost`` and ``127.0.0.1`` are different browser origins. Listing only one makes the dev UI fail with an opaque "Disallowed CORS origin" — which is exactly what happened when the frontend was started with ``-H 127.0.0.1`` while the API allowed only ``localhost``. """ origins = Settings(app_env="development").cors_origin_list assert "http://localhost:3000" in origins assert "http://127.0.0.1:3000" in origins def test_production_rejects_the_placeholder_secret(): with pytest.raises(ValidationError, match="placeholder"): _build(jwt_secret="change-me") @pytest.mark.parametrize("secret", ["", "short", "x" * (MIN_SECRET_LENGTH - 1)]) def test_production_rejects_a_short_secret(secret: str): with pytest.raises(ValidationError, match="JWT_SECRET"): _build(jwt_secret=secret) def test_production_requires_an_encryption_key(): """Without it, stored provider credentials cannot be encrypted at rest.""" with pytest.raises(ValidationError, match="ENCRYPTION_KEY"): _build(encryption_key="") def test_production_rejects_wildcard_cors(): with pytest.raises(ValidationError, match="CORS_ORIGINS"): _build(cors_origins="*") def test_production_rejects_the_development_cors_default(): """A production deploy left on the dev allowlist has not been configured.""" with pytest.raises(ValidationError, match="development default"): _build(cors_origins=DEVELOPMENT_CORS_ORIGINS) def test_production_accepts_a_fully_configured_environment(): settings = _build() assert settings.is_production is True assert settings.cors_origin_list == ["https://app.example.com"]