Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9d5176b

Browse files
FoxHelmssuii2210
authored andcommitted
more explicit secrets path error messages (apache#55015) (apache#59224)
* more explicit secrets path error messages * explicitly catch no value key error * reformat invalid path message * more explicit error getting vault config without value key * explicit error when vault conn_uri key not present * removing warnings from get connection * fixing invalid path message format * remove whitespace * mocking logs in unit test * simplify single use variables * fixing log patch package import * using back compatible package
1 parent d09dde5 commit 9d5176b

4 files changed

Lines changed: 76 additions & 4 deletions

File tree

airflow-core/src/airflow/models/variable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def get(
179179
if var_val is None:
180180
if default_var is not cls.__NO_DEFAULT_SENTINEL:
181181
return default_var
182-
raise KeyError(f"Variable {key} does not exist")
182+
raise KeyError(f"Variable {key} does not exist.")
183183
if deserialize_json:
184184
obj = json.loads(var_val)
185185
mask_secret(obj, key)

providers/hashicorp/src/airflow/providers/hashicorp/_internal_client/vault_client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,9 @@ def _parse_secret_path(self, secret_path: str) -> tuple[str, str]:
421421
if not self.mount_point:
422422
split_secret_path = secret_path.split("/", 1)
423423
if len(split_secret_path) < 2:
424-
raise InvalidPath
424+
raise InvalidPath(
425+
"The variable path you have provided is invalid. Please provide a full path of the format: path/to/secret/variable"
426+
)
425427
return split_secret_path[0], split_secret_path[1]
426428
return self.mount_point, secret_path
427429

providers/hashicorp/src/airflow/providers/hashicorp/secrets/vault.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,13 @@ def get_variable(self, key: str, team_name: str | None = None) -> str | None:
226226
response = self.vault_client.get_secret(
227227
secret_path=(mount_point + "/" if mount_point else "") + secret_path
228228
)
229-
return response.get("value") if response else None
229+
if not response:
230+
return None
231+
try:
232+
return response["value"]
233+
except KeyError:
234+
self.log.warning('Vault secret %s fetched but does not have required key "value"', key)
235+
return None
230236

231237
def get_config(self, key: str) -> str | None:
232238
"""
@@ -245,4 +251,10 @@ def get_config(self, key: str) -> str | None:
245251
response = self.vault_client.get_secret(
246252
secret_path=(mount_point + "/" if mount_point else "") + secret_path
247253
)
248-
return response.get("value") if response else None
254+
if not response:
255+
return None
256+
try:
257+
return response["value"]
258+
except KeyError:
259+
self.log.warning('Vault config %s fetched but does not have required key "value"', key)
260+
return None

providers/hashicorp/tests/unit/hashicorp/secrets/test_vault.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,64 @@ def test_get_variable_value_non_existent_key(self, mock_hvac):
263263
)
264264
assert test_client.get_variable("hello") is None
265265

266+
@mock.patch("airflow.providers.hashicorp._internal_client.vault_client.hvac")
267+
@mock.patch("airflow.utils.log.logging_mixin.logging")
268+
def test_get_variable_does_not_contain_value_key(self, mock_hvac, mock_get_logger):
269+
"""
270+
Test that if the 'value' key is not present in Vault, _VaultClient.get_variable
271+
should log a warning and return None
272+
"""
273+
mock_hvac.Client.return_value = mock.MagicMock()
274+
mock_logger = mock.MagicMock()
275+
mock_get_logger.getLogger.return_value = mock_logger
276+
277+
test_client = VaultBackend(
278+
**{
279+
"variables_path": "variables",
280+
"mount_point": "airflow",
281+
"auth_type": "token",
282+
"url": "http://127.0.0.1:8200",
283+
"token": "s.7AU0I51yv1Q1lxOIg1F3ZRAS",
284+
}
285+
)
286+
test_client._log = mock_logger
287+
test_client.vault_client.get_secret = mock.MagicMock(return_value={"test_key": "data"})
288+
result = test_client.get_variable("hello")
289+
assert result is None
290+
mock_logger.warning.assert_called_with(
291+
'Vault secret %s fetched but does not have required key "value"', "hello"
292+
)
293+
294+
@mock.patch("airflow.providers.hashicorp._internal_client.vault_client.hvac")
295+
@mock.patch("airflow.utils.log.logging_mixin.logging")
296+
def test_get_config_does_not_contain_value_key(self, mock_hvac, mock_get_logger):
297+
"""
298+
Test that if the 'value' key is not present in Vault, _VaultClient.get_config
299+
should log a warning and return None
300+
"""
301+
mock_client = mock.MagicMock()
302+
mock_hvac.Client.return_value = mock_client
303+
mock_logger = mock.MagicMock()
304+
mock_get_logger.getLogger.return_value = mock_logger
305+
306+
kwargs = {
307+
"variables_path": "variables",
308+
"mount_point": "airflow",
309+
"auth_type": "token",
310+
"url": "http://127.0.0.1:8200",
311+
"token": "s.7AU0I51yv1Q1lxOIg1F3ZRAS",
312+
}
313+
test_client = VaultBackend(**kwargs)
314+
test_client._log = mock_logger
315+
response = {"test_key": "data"}
316+
test_client.vault_client.get_secret = mock.MagicMock(return_value=response)
317+
318+
returned_uri = test_client.get_config("sql_alchemy_conn")
319+
assert returned_uri is None
320+
mock_logger.warning.assert_called_with(
321+
'Vault config %s fetched but does not have required key "value"', "sql_alchemy_conn"
322+
)
323+
266324
@mock.patch("airflow.providers.hashicorp._internal_client.vault_client.hvac")
267325
def test_auth_failure_raises_error(self, mock_hvac):
268326
mock_client = mock.MagicMock()

0 commit comments

Comments
 (0)