"""Tests for security hardening: JWT secret startup check, CORS config, credential handling.""" import os from unittest.mock import patch import pytest class TestJWTSecretStartupCheck: """Test the startup guard that refuses default JWT secret in non-dev environments.""" def test_default_secret_in_production_raises(self): """Starting with default secret and APP_ENV=production must raise RuntimeError.""" with patch.dict(os.environ, {"APP_ENV": "production"}): # Reload config to pick up the new APP_ENV import importlib import SPARC.config importlib.reload(SPARC.config) from SPARC.auth import _DEFAULT_JWT_SECRET, check_jwt_secret # Patch JWT_SECRET to the default with patch("SPARC.auth.JWT_SECRET", _DEFAULT_JWT_SECRET): with pytest.raises(RuntimeError, match="FATAL.*JWT_SECRET"): check_jwt_secret() # Restore config with patch.dict(os.environ, {"APP_ENV": "development"}): importlib.reload(SPARC.config) def test_default_secret_in_development_succeeds(self): """Starting with default secret and APP_ENV=development must not raise.""" with patch.dict(os.environ, {"APP_ENV": "development"}): import importlib import SPARC.config importlib.reload(SPARC.config) from SPARC.auth import _DEFAULT_JWT_SECRET, check_jwt_secret with patch("SPARC.auth.JWT_SECRET", _DEFAULT_JWT_SECRET): # Should not raise check_jwt_secret() # Restore importlib.reload(SPARC.config) def test_custom_secret_in_production_succeeds(self): """Starting with a custom secret in production must not raise.""" with patch.dict(os.environ, {"APP_ENV": "production"}): import importlib import SPARC.config importlib.reload(SPARC.config) from SPARC.auth import check_jwt_secret with patch("SPARC.auth.JWT_SECRET", "my-secure-random-secret-abc123"): # Should not raise check_jwt_secret() with patch.dict(os.environ, {"APP_ENV": "development"}): importlib.reload(SPARC.config) def test_default_secret_unset_env_succeeds(self): """When APP_ENV is unset (defaults to development), default secret is allowed.""" with patch.dict(os.environ, {}, clear=False): # Remove APP_ENV if present env = os.environ.copy() env.pop("APP_ENV", None) with patch.dict(os.environ, env, clear=True): import importlib import SPARC.config importlib.reload(SPARC.config) from SPARC.auth import _DEFAULT_JWT_SECRET, check_jwt_secret with patch("SPARC.auth.JWT_SECRET", _DEFAULT_JWT_SECRET): # Should not raise (defaults to development) check_jwt_secret() with patch.dict(os.environ, {"APP_ENV": "development"}): importlib.reload(SPARC.config) class TestCORSConfig: """Test that CORS origins are configurable via environment variable.""" def test_default_cors_origins(self): """When CORS_ORIGINS is unset, defaults to localhost origins.""" with patch.dict(os.environ, {"CORS_ORIGINS": ""}): import importlib import SPARC.config importlib.reload(SPARC.config) assert SPARC.config.cors_origins == [ "http://localhost:3000", "http://localhost:5173", ] def test_custom_cors_origins(self): """Setting CORS_ORIGINS configures allowed origins.""" with patch.dict(os.environ, {"CORS_ORIGINS": "https://sparc.example.com,https://app.example.com"}): import importlib import SPARC.config importlib.reload(SPARC.config) assert SPARC.config.cors_origins == [ "https://sparc.example.com", "https://app.example.com", ] # Restore with patch.dict(os.environ, {"CORS_ORIGINS": ""}): importlib.reload(SPARC.config) def test_single_cors_origin(self): """A single origin without comma works correctly.""" with patch.dict(os.environ, {"CORS_ORIGINS": "https://sparc.example.com"}): import importlib import SPARC.config importlib.reload(SPARC.config) assert SPARC.config.cors_origins == ["https://sparc.example.com"] with patch.dict(os.environ, {"CORS_ORIGINS": ""}): importlib.reload(SPARC.config)