mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
fix(secret): uppercase in filename on linux (#3304)
* fix(secret): uppercase in filename * test(uppercase): fix test * refactor(secret): apply feedbacks * refactor(path): apply feedbacks * fix(test): fix path in test * cleanup and correct tests Co-authored-by: Jean Arhancetebehere <jean.arhancetebehere@ubisoft.com> Co-authored-by: Samuel Colvin <s@muelcolvin.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Update `SecretsSettingsSource` to respect `config.case_sensitive`
|
||||
@@ -269,7 +269,11 @@ class SecretsSettingsSource:
|
||||
|
||||
for field in settings.__fields__.values():
|
||||
for env_name in field.field_info.extra['env_names']:
|
||||
path = secrets_path / env_name
|
||||
path = find_case_path(secrets_path, env_name, settings.__config__.case_sensitive)
|
||||
if not path:
|
||||
# path does not exist, we curently don't return a warning for this
|
||||
continue
|
||||
|
||||
if path.is_file():
|
||||
secret_value = path.read_text().strip()
|
||||
if field.is_complex():
|
||||
@@ -279,12 +283,11 @@ class SecretsSettingsSource:
|
||||
raise SettingsError(f'error parsing JSON for "{env_name}"') from e
|
||||
|
||||
secrets[field.alias] = secret_value
|
||||
elif path.exists():
|
||||
else:
|
||||
warnings.warn(
|
||||
f'attempted to load secret file "{path}" but found a {path_type(path)} instead.',
|
||||
stacklevel=4,
|
||||
)
|
||||
|
||||
return secrets
|
||||
|
||||
def __repr__(self) -> str:
|
||||
@@ -304,3 +307,15 @@ def read_env_file(
|
||||
return {k.lower(): v for k, v in file_vars.items()}
|
||||
else:
|
||||
return file_vars
|
||||
|
||||
|
||||
def find_case_path(dir_path: Path, file_name: str, case_sensitive: bool) -> Optional[Path]:
|
||||
"""
|
||||
Find a file within path's directory matching filename, optionally ignoring case.
|
||||
"""
|
||||
for f in dir_path.iterdir():
|
||||
if f.name == file_name:
|
||||
return f
|
||||
elif not case_sensitive and f.name.lower() == file_name.lower():
|
||||
return f
|
||||
return None
|
||||
|
||||
@@ -890,6 +890,33 @@ def test_secrets_path(tmp_path):
|
||||
assert Settings().dict() == {'foo': 'foo_secret_value_str'}
|
||||
|
||||
|
||||
def test_secrets_case_sensitive(tmp_path):
|
||||
(tmp_path / 'SECRET_VAR').write_text('foo_env_value_str')
|
||||
|
||||
class Settings(BaseSettings):
|
||||
secret_var: Optional[str]
|
||||
|
||||
class Config:
|
||||
secrets_dir = tmp_path
|
||||
case_sensitive = True
|
||||
|
||||
assert Settings().dict() == {'secret_var': None}
|
||||
|
||||
|
||||
def test_secrets_case_insensitive(tmp_path):
|
||||
(tmp_path / 'SECRET_VAR').write_text('foo_env_value_str')
|
||||
|
||||
class Settings(BaseSettings):
|
||||
secret_var: Optional[str]
|
||||
|
||||
class Config:
|
||||
secrets_dir = tmp_path
|
||||
case_sensitive = False
|
||||
|
||||
settings = Settings().dict()
|
||||
assert settings == {'secret_var': 'foo_env_value_str'}
|
||||
|
||||
|
||||
def test_secrets_path_url(tmp_path):
|
||||
(tmp_path / 'foo').write_text('http://www.example.com')
|
||||
(tmp_path / 'bar').write_text('snap')
|
||||
@@ -940,6 +967,7 @@ def test_secrets_missing(tmp_path):
|
||||
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
Settings()
|
||||
|
||||
assert exc_info.value.errors() == [{'loc': ('foo',), 'msg': 'field required', 'type': 'value_error.missing'}]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user