diff --git a/src/mvt/common/config.py b/src/mvt/common/config.py index ce29fb33..24bf4072 100644 --- a/src/mvt/common/config.py +++ b/src/mvt/common/config.py @@ -59,13 +59,16 @@ class MVTSettings(BaseSettings): dotenv_settings: PydanticBaseSettingsSource, file_secret_settings: PydanticBaseSettingsSource, ) -> Tuple[PydanticBaseSettingsSource, ...]: - yaml_source = YamlConfigSettingsSource(settings_cls, MVT_CONFIG_PATH) sources: Tuple[PydanticBaseSettingsSource, ...] = ( - yaml_source, + YamlConfigSettingsSource(settings_cls, MVT_CONFIG_PATH), init_settings, ) - # Always load env variables by default - sources = (env_settings,) + sources + # Load env variables only when asked to. initialise() constructs the + # settings once without them so that what gets written back to + # config.yaml never includes values taken from the environment. + # init_settings() returns the keyword arguments passed to the constructor. + if init_settings().get("load_env", True): + sources = (env_settings,) + sources return sources def save_settings( @@ -92,7 +95,7 @@ class MVTSettings(BaseSettings): Afterwards we load the settings again, this time including the env variables. """ - # Set invalid env prefix to avoid loading env variables. + # Construct the settings without env variables so they are not persisted. settings = cls(load_env=False) settings.save_settings() diff --git a/tests/common/test_config.py b/tests/common/test_config.py new file mode 100644 index 00000000..f471a583 --- /dev/null +++ b/tests/common/test_config.py @@ -0,0 +1,30 @@ +# Mobile Verification Toolkit (MVT) +# Copyright (c) 2021-2026 The MVT Authors. +# Use of this software is governed by the MVT License 1.1 that can be found at +# https://license.mvt.re/1.1/ + +import os + +import yaml + +from mvt.common import config +from mvt.common.config import MVTSettings + + +def test_env_variables_are_not_persisted_to_config_file(tmp_path, monkeypatch): + config_path = tmp_path / "config.yaml" + monkeypatch.setattr(config, "MVT_CONFIG_FOLDER", str(tmp_path)) + monkeypatch.setattr(config, "MVT_CONFIG_PATH", str(config_path)) + monkeypatch.setenv("MVT_NETWORK_ACCESS_ALLOWED", "false") + monkeypatch.setenv("MVT_IOS_BACKUP_PASSWORD", "env-only-password") + + settings = MVTSettings.initialise() + + assert os.path.isfile(config_path) + saved = yaml.safe_load(config_path.read_text()) or {} + assert "NETWORK_ACCESS_ALLOWED" not in saved + assert "IOS_BACKUP_PASSWORD" not in saved + + # The environment must still apply to the settings in use. + assert settings.NETWORK_ACCESS_ALLOWED is False + assert settings.IOS_BACKUP_PASSWORD == "env-only-password"