From 28967c7c378fac987a4370abcfaf057920659b82 Mon Sep 17 00:00:00 2001 From: Pavel Eliseev Date: Sun, 4 Oct 2026 16:10:08 +0300 Subject: [PATCH] fix(contract): redact input values in settings errors Refs #87 --- app/config.py | 2 +- tests/test_contracts_settings_privacy.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/test_contracts_settings_privacy.py diff --git a/app/config.py b/app/config.py index 088cf37..55a6e73 100644 --- a/app/config.py +++ b/app/config.py @@ -14,7 +14,7 @@ ROOT_DIR = Path(__file__).resolve().parent.parent class Settings(BaseSettings): # Empty values in .env (e.g. `TG_BOT_TOKEN=`) fall back to defaults instead of failing validation. - model_config = SettingsConfigDict(env_file=".env", extra="ignore", env_ignore_empty=True) + model_config = SettingsConfigDict(env_file=".env", extra="ignore", env_ignore_empty=True, hide_input_in_errors=True) # Two separate databases (ADR-003): identity holds direct identifiers, clinical holds pseudonymised data. identity_db_url: str = "postgresql+asyncpg://identity_app:identity_app@localhost:5432/identity" diff --git a/tests/test_contracts_settings_privacy.py b/tests/test_contracts_settings_privacy.py new file mode 100644 index 0000000..cb926c1 --- /dev/null +++ b/tests/test_contracts_settings_privacy.py @@ -0,0 +1,21 @@ +"""Startup validation errors must not print configuration credentials.""" + +import pytest +from pydantic import ValidationError + +from app.config import Settings + + +def test_incomplete_max_configuration_does_not_expose_token(): + with pytest.raises(ValidationError) as error: + Settings(_env_file=None, max_enabled=True, max_bot_token="SYNTHETIC_SECRET") + message = str(error.value) + assert "MAX_BOT_USERNAME" in message + assert "SYNTHETIC_SECRET" not in message and "input_value" not in message + + +def test_invalid_field_does_not_expose_accidentally_pasted_secret(): + with pytest.raises(ValidationError) as error: + Settings(_env_file=None, max_enabled="SYNTHETIC_SECRET") + assert "max_enabled" in str(error.value) + assert "SYNTHETIC_SECRET" not in str(error.value)