From e5fe409bf910da3354eb3dcfc10854a965081ea6 Mon Sep 17 00:00:00 2001 From: Michael Makukha Date: Tue, 3 Sep 2024 18:42:01 +0300 Subject: [PATCH] Strip secrets files content (#16) --- .bumpversion.toml | 2 +- README.md | 8 +++--- docs/badge/tests.svg | 8 +++--- pyproject.toml | 4 ++- src/pydantic_file_secrets/__init__.py | 2 +- src/pydantic_file_secrets/__version__.py | 2 +- tests/test_pydantic_source.py | 34 ++++++++++++++++++++++++ tests/test_strip_whitespace.py | 16 +++++++++++ 8 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 tests/test_strip_whitespace.py diff --git a/.bumpversion.toml b/.bumpversion.toml index fa4d1f0..157e399 100644 --- a/.bumpversion.toml +++ b/.bumpversion.toml @@ -1,5 +1,5 @@ [tool.bumpversion] -current_version = "0.2.0" +current_version = "0.2.1" allow_dirty = true files = [ {filename = "src/pydantic_file_secrets/__version__.py"}, diff --git a/README.md b/README.md index 450f4a3..d8d4623 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # pydantic-file-secrets 🔑 -> Use file secrets in nested [Pydantic Settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) models, drop-in replacement of `SecretsSettingsSource`. +> Use file secrets in nested [Pydantic Settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) models, drop-in replacement for `SecretsSettingsSource`. ![GitHub License](https://img.shields.io/github/license/makukha/pydantic-file-secrets) -[![Tests](https://raw.githubusercontent.com/makukha/pydantic-file-secrets/0.2.0/docs/badge/tests.svg)](https://github.com/makukha/pydantic-file-secrets) -[![Coverage](https://raw.githubusercontent.com/makukha/pydantic-file-secrets/0.2.0/docs/badge/coverage.svg)](https://github.com/makukha/pydantic-file-secrets) +[![Tests](https://raw.githubusercontent.com/makukha/pydantic-file-secrets/0.2.1/docs/badge/tests.svg)](https://github.com/makukha/pydantic-file-secrets) +[![Coverage](https://raw.githubusercontent.com/makukha/pydantic-file-secrets/0.2.1/docs/badge/coverage.svg)](https://github.com/makukha/pydantic-file-secrets) [![linting - Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v1.json)](https://github.com/astral-sh/ruff) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) \ -[![pypi](https://img.shields.io/pypi/v/pydantic-file-secrets.svg#0.2.0)](https://pypi.python.org/pypi/pydantic-file-secrets) +[![pypi](https://img.shields.io/pypi/v/pydantic-file-secrets.svg#0.2.1)](https://pypi.python.org/pypi/pydantic-file-secrets) [![versions](https://img.shields.io/pypi/pyversions/pydantic-file-secrets.svg)](https://pypi.org/project/pydantic-file-secrets) [![Pydantic v2](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json)](https://pydantic.dev) diff --git a/docs/badge/tests.svg b/docs/badge/tests.svg index b2ac141..282c9bb 100644 --- a/docs/badge/tests.svg +++ b/docs/badge/tests.svg @@ -1,5 +1,5 @@ - - tests: 28 + + tests: 31 @@ -15,7 +15,7 @@ tests - - 28 + + 31 diff --git a/pyproject.toml b/pyproject.toml index 7236aad..a546717 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,9 @@ build-backend = "pdm.backend" [project] name = "pydantic-file-secrets" dynamic = ["version"] -description = "Use file secrets in nested models of Pydantic Settings." +description = """Use file secrets in nested Pydantic Settings models, \ + drop-in replacement for SecretsSettingsSource. +""" authors = [ {name = "Michael Makukha", email = "m.makukha@gmail.com"}, ] diff --git a/src/pydantic_file_secrets/__init__.py b/src/pydantic_file_secrets/__init__.py index 66d5fa0..0417b5d 100644 --- a/src/pydantic_file_secrets/__init__.py +++ b/src/pydantic_file_secrets/__init__.py @@ -147,7 +147,7 @@ def validate_secrets_path(self, path: Path) -> None: @staticmethod def load_secrets(path: Path) -> dict[str, str]: return { - str(p.relative_to(path)): p.read_text() + str(p.relative_to(path)): p.read_text().strip() for p in path.glob('**/*') if p.is_file() } diff --git a/src/pydantic_file_secrets/__version__.py b/src/pydantic_file_secrets/__version__.py index 9f137b9..9767f90 100644 --- a/src/pydantic_file_secrets/__version__.py +++ b/src/pydantic_file_secrets/__version__.py @@ -1 +1 @@ -__version__ = '0.2.0' +__version__ = '0.2.1' diff --git a/tests/test_pydantic_source.py b/tests/test_pydantic_source.py index ea34d65..4c73ee1 100644 --- a/tests/test_pydantic_source.py +++ b/tests/test_pydantic_source.py @@ -35,3 +35,37 @@ class Settings(BaseSettings): assert conf.key_empty == '' # should be None if working assert conf.key_none == 'null' # should be Null if working assert isinstance(conf.key_enum, TestEnum) # should be True if working + + +def test_str_strip_whitespace_not_specified(secrets_dir): + class Settings(BaseSettings): + key: str + + model_config = SettingsConfigDict( + secrets_dir=secrets_dir, + # str_strip_whitespace not specified + ) + + secrets_dir.add_files( + ('key', ' value '), + ) + + conf = Settings() + assert conf.key == 'value' # spaces are stripped by SecretsSettingsSource + + +def test_str_strip_whitespace_not_respected(secrets_dir): + class Settings(BaseSettings): + key: str + + model_config = SettingsConfigDict( + secrets_dir=secrets_dir, + str_strip_whitespace=False, + ) + + secrets_dir.add_files( + ('key', ' value '), + ) + + conf = Settings() + assert conf.key == 'value' # str_strip_whitespace not respected diff --git a/tests/test_strip_whitespace.py b/tests/test_strip_whitespace.py new file mode 100644 index 0000000..3114329 --- /dev/null +++ b/tests/test_strip_whitespace.py @@ -0,0 +1,16 @@ +def test_strip_whitespace(settings_model, monkeypatch, secrets_dir): + monkeypatch.setenv('DB__USER', 'user') + secrets_dir.add_files( + ('app_key', ' secret1 '), + ('db___password', '\tsecret2\n'), # file name with delimiter + ) + Settings = settings_model( + model_config=dict( + env_nested_delimiter='__', + secrets_dir=secrets_dir, + secrets_nested_delimiter='___', + ), + ) + conf = Settings() + assert conf.app_key == 'secret1' + assert conf.db.password == 'secret2' # noqa: S105