Skip to content

Commit d54d146

Browse files
authored
Azure Key Vault: Don't load disabled secret (#578)
1 parent 3b83fc2 commit d54d146

File tree

2 files changed

+52
-13
lines changed

2 files changed

+52
-13
lines changed

pydantic_settings/sources/providers/azure.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ def __init__(
4646
self._loaded_secrets = {}
4747
self._secret_client = secret_client
4848
self._secret_names: list[str] = [
49-
secret.name for secret in self._secret_client.list_properties_of_secrets() if secret.name
49+
secret.name for secret in self._secret_client.list_properties_of_secrets() if secret.name and secret.enabled
5050
]
5151

5252
def __getitem__(self, key: str) -> str | None:
53-
if key not in self._loaded_secrets:
53+
if key not in self._loaded_secrets and key in self._secret_names:
5454
try:
5555
self._loaded_secrets[key] = self._secret_client.get_secret(key).value
5656
except Exception:
@@ -68,7 +68,6 @@ def __iter__(self) -> Iterator[str]:
6868
class AzureKeyVaultSettingsSource(EnvSettingsSource):
6969
_url: str
7070
_credential: TokenCredential
71-
_secret_client: SecretClient
7271

7372
def __init__(
7473
self,

tests/test_source_azure_key_vault.py

+50-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44

55
import pytest
6+
from azure.keyvault.secrets import SecretClient
67
from pydantic import BaseModel, Field
78
from pytest_mock import MockerFixture
89

@@ -23,9 +24,6 @@
2324
azure_key_vault = False
2425

2526

26-
MODULE = 'pydantic_settings.sources.providers.azure'
27-
28-
2927
@pytest.mark.skipif(not azure_key_vault, reason='pydantic-settings[azure-key-vault] is not installed')
3028
class TestAzureKeyVaultSettingsSource:
3129
"""Test AzureKeyVaultSettingsSource."""
@@ -36,7 +34,10 @@ def test___init__(self, mocker: MockerFixture) -> None:
3634
class AzureKeyVaultSettings(BaseSettings):
3735
"""AzureKeyVault settings."""
3836

39-
mocker.patch(f'{MODULE}.SecretClient.list_properties_of_secrets', return_value=[])
37+
mocker.patch(
38+
f'{AzureKeyVaultSettingsSource.__module__}.{SecretClient.list_properties_of_secrets.__qualname__}',
39+
return_value=[],
40+
)
4041

4142
AzureKeyVaultSettingsSource(
4243
AzureKeyVaultSettings, 'https://my-resource.vault.azure.net/', DefaultAzureCredential()
@@ -55,11 +56,17 @@ class AzureKeyVaultSettings(BaseSettings):
5556
sql_server_user: str = Field(..., alias='SqlServerUser')
5657
sql_server: SqlServer = Field(..., alias='SqlServer')
5758

58-
expected_secrets = [type('', (), {'name': 'SqlServerUser'}), type('', (), {'name': 'SqlServer--Password'})]
59+
expected_secrets = [
60+
type('', (), {'name': 'SqlServerUser', 'enabled': True}),
61+
type('', (), {'name': 'SqlServer--Password', 'enabled': True}),
62+
]
5963
expected_secret_value = 'SecretValue'
60-
mocker.patch(f'{MODULE}.SecretClient.list_properties_of_secrets', return_value=expected_secrets)
6164
mocker.patch(
62-
f'{MODULE}.SecretClient.get_secret',
65+
f'{AzureKeyVaultSettingsSource.__module__}.{SecretClient.list_properties_of_secrets.__qualname__}',
66+
return_value=expected_secrets,
67+
)
68+
mocker.patch(
69+
f'{AzureKeyVaultSettingsSource.__module__}.{SecretClient.get_secret.__qualname__}',
6370
side_effect=self._raise_resource_not_found_when_getting_parent_secret_name,
6471
)
6572
obj = AzureKeyVaultSettingsSource(
@@ -71,6 +78,33 @@ class AzureKeyVaultSettings(BaseSettings):
7178
assert settings['SqlServerUser'] == expected_secret_value
7279
assert settings['SqlServer']['Password'] == expected_secret_value
7380

81+
def test_do_not_load_disabled_secrets(self, mocker: MockerFixture) -> None:
82+
class AzureKeyVaultSettings(BaseSettings):
83+
"""AzureKeyVault settings."""
84+
85+
SqlServerPassword: str
86+
DisabledSqlServerPassword: str
87+
88+
disabled_secret_name = 'SqlServerPassword'
89+
expected_secrets = [
90+
type('', (), {'name': disabled_secret_name, 'enabled': False}),
91+
]
92+
mocker.patch(
93+
f'{AzureKeyVaultSettingsSource.__module__}.{SecretClient.list_properties_of_secrets.__qualname__}',
94+
return_value=expected_secrets,
95+
)
96+
mocker.patch(
97+
f'{AzureKeyVaultSettingsSource.__module__}.{SecretClient.get_secret.__qualname__}',
98+
return_value=KeyVaultSecret(SecretProperties(), 'SecretValue'),
99+
)
100+
obj = AzureKeyVaultSettingsSource(
101+
AzureKeyVaultSettings, 'https://my-resource.vault.azure.net/', DefaultAzureCredential()
102+
)
103+
104+
settings = obj()
105+
106+
assert disabled_secret_name not in settings
107+
74108
def test_azure_key_vault_settings_source(self, mocker: MockerFixture) -> None:
75109
"""Test AzureKeyVaultSettingsSource."""
76110

@@ -99,11 +133,17 @@ def settings_customise_sources(
99133
),
100134
)
101135

102-
expected_secrets = [type('', (), {'name': 'SqlServerUser'}), type('', (), {'name': 'SqlServer--Password'})]
136+
expected_secrets = [
137+
type('', (), {'name': 'SqlServerUser', 'enabled': True}),
138+
type('', (), {'name': 'SqlServer--Password', 'enabled': True}),
139+
]
103140
expected_secret_value = 'SecretValue'
104-
mocker.patch(f'{MODULE}.SecretClient.list_properties_of_secrets', return_value=expected_secrets)
105141
mocker.patch(
106-
f'{MODULE}.SecretClient.get_secret',
142+
f'{AzureKeyVaultSettingsSource.__module__}.{SecretClient.list_properties_of_secrets.__qualname__}',
143+
return_value=expected_secrets,
144+
)
145+
mocker.patch(
146+
f'{AzureKeyVaultSettingsSource.__module__}.{SecretClient.get_secret.__qualname__}',
107147
side_effect=self._raise_resource_not_found_when_getting_parent_secret_name,
108148
)
109149

0 commit comments

Comments
 (0)