diff --git a/backend/app/platform/config.py b/backend/app/platform/config.py index ccf7914..70eae74 100644 --- a/backend/app/platform/config.py +++ b/backend/app/platform/config.py @@ -17,3 +17,24 @@ _DEFAULT_DATABASE_URL = "postgresql://ecomm:ecomm@localhost:5432/ecomm" def database_url() -> str: """The psycopg DSN for the application database.""" return os.environ.get("ECOMM_DATABASE_URL") or _DEFAULT_DATABASE_URL + + +# Session signing secret. Dev default is intentionally well-known and insecure — a clean +# checkout works with no setup; deployed environments MUST supply ECOMM_SESSION_SECRET from +# Secret Manager (INV-8, §6.6). Rotating it invalidates all sessions at once (§6.2). +_DEFAULT_SESSION_SECRET = "dev-insecure-session-secret-change-me" + + +def session_secret() -> str: + """The HMAC key for signed session cookies (and the one-time-code pepper).""" + return os.environ.get("ECOMM_SESSION_SECRET") or _DEFAULT_SESSION_SECRET + + +def cookie_secure() -> bool: + """Whether to mark the session cookie Secure (HTTPS-only). True in deployed envs.""" + return os.environ.get("ECOMM_COOKIE_SECURE", "").strip().lower() in {"1", "true", "yes", "on"} + + +def mailer_kind() -> str: + """Which mailer adapter to build: 'log' (dev/tests) or 'smtp' (deployed; SLICE-4).""" + return os.environ.get("ECOMM_MAILER") or "log" diff --git a/backend/tests/test_config.py b/backend/tests/test_config.py index 6168d17..bf11e6f 100644 --- a/backend/tests/test_config.py +++ b/backend/tests/test_config.py @@ -11,3 +11,33 @@ def test_database_url_defaults_to_local_compose(monkeypatch): def test_database_url_honors_env(monkeypatch): monkeypatch.setenv("ECOMM_DATABASE_URL", "postgresql://x:y@db:5432/z") assert config.database_url() == "postgresql://x:y@db:5432/z" + + +def test_session_secret_defaults_for_dev(monkeypatch): + monkeypatch.delenv("ECOMM_SESSION_SECRET", raising=False) + # A non-empty dev default so localhost works with no setup; deployed overrides it. + assert config.session_secret() + + +def test_session_secret_honors_env(monkeypatch): + monkeypatch.setenv("ECOMM_SESSION_SECRET", "s3cret") + assert config.session_secret() == "s3cret" + + +def test_cookie_secure_defaults_false(monkeypatch): + monkeypatch.delenv("ECOMM_COOKIE_SECURE", raising=False) + assert config.cookie_secure() is False + + +def test_cookie_secure_truthy_env(monkeypatch): + monkeypatch.setenv("ECOMM_COOKIE_SECURE", "1") + assert config.cookie_secure() is True + monkeypatch.setenv("ECOMM_COOKIE_SECURE", "true") + assert config.cookie_secure() is True + monkeypatch.setenv("ECOMM_COOKIE_SECURE", "0") + assert config.cookie_secure() is False + + +def test_mailer_kind_defaults_to_log(monkeypatch): + monkeypatch.delenv("ECOMM_MAILER", raising=False) + assert config.mailer_kind() == "log"