This is an automated email from the ASF dual-hosted git repository.
Miretpl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new cfe3f0bbd70 Apply the ambiguous-id refusal to get_config in the Key
Vault backend (#70899)
cfe3f0bbd70 is described below
commit cfe3f0bbd707af63f9ca64c563a1a695a974d3f8
Author: Jarek Potiuk <[email protected]>
AuthorDate: Sat Aug 1 23:52:29 2026 +0200
Apply the ambiguous-id refusal to get_config in the Key Vault backend
(#70899)
Follow-up to #70876. The check used to live in _get_secret, which all three
getters share. Moving it up into get_conn_value and get_variable left
get_config
reaching _get_secret unguarded, so the helper's claim that such an id is
refused
for every lookup stopped being true. Not a cross-team read -- get_config
never
receives a team_name -- but two getters and the docstring disagreed with the
third.
The same gap was found in review of the Amazon sibling (#70878) and fixed
there;
this is the Azure half, which had already merged by then.
_names_a_team_namespace stays an instance method here, unlike Amazon's: it
builds
the candidate path with self.build_path and self.sep.
The refusal-logging assertion uses getMessage() rather than msg, since how a
record carries its payload differs between the Airflow version this runs on
and
the ones the provider compat tests use.
---
.../providers/microsoft/azure/secrets/key_vault.py | 11 ++++++++---
.../unit/microsoft/azure/secrets/test_key_vault.py | 18 ++++++++++++++----
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git
a/providers/microsoft/azure/src/airflow/providers/microsoft/azure/secrets/key_vault.py
b/providers/microsoft/azure/src/airflow/providers/microsoft/azure/secrets/key_vault.py
index 29610e010bd..7162663ca1d 100644
---
a/providers/microsoft/azure/src/airflow/providers/microsoft/azure/secrets/key_vault.py
+++
b/providers/microsoft/azure/src/airflow/providers/microsoft/azure/secrets/key_vault.py
@@ -190,6 +190,10 @@ class AzureKeyVaultBackend(BaseSecretsBackend,
LoggingMixin):
if self.config_prefix is None:
return None
+ if self._names_a_team_namespace(key):
+ self._log_refusal("configuration option", key)
+ return None
+
return self._get_secret(self.config_prefix, key)
@staticmethod
@@ -229,9 +233,10 @@ class AzureKeyVaultBackend(BaseSecretsBackend,
LoggingMixin):
A team scoped secret is named ``<team>{TEAM_SEP}<secret id>``, so an
id that itself
contains the team separator makes the built name ambiguous: team ``a``
with id ``b--c``
- and team ``a--b`` with id ``c`` produce the same string. Such an id is
refused for
- *every* lookup -- team scoped as well as team agnostic -- because the
ambiguity exists
- in both directions and the caller's own namespace is not a safe
harbour for it.
+ and team ``a--b`` with id ``c`` produce the same string. Such an id is
refused by every
+ getter -- connections, variables and configuration options, team
scoped as well as team
+ agnostic -- because the ambiguity exists in both directions and the
caller's own
+ namespace is not a safe harbour for it.
The id is never parsed to work out *which* team it names, because it
cannot be: nothing
in the string distinguishes the two readings above. Comparing the id
against the prefix
diff --git
a/providers/microsoft/azure/tests/unit/microsoft/azure/secrets/test_key_vault.py
b/providers/microsoft/azure/tests/unit/microsoft/azure/secrets/test_key_vault.py
index ce04849a23a..b3f44d2299c 100644
---
a/providers/microsoft/azure/tests/unit/microsoft/azure/secrets/test_key_vault.py
+++
b/providers/microsoft/azure/tests/unit/microsoft/azure/secrets/test_key_vault.py
@@ -17,6 +17,7 @@
# under the License.
from __future__ import annotations
+import logging
from unittest import mock
from azure.core.exceptions import ResourceNotFoundError
@@ -199,10 +200,19 @@ class TestAzureKeyVaultBackend:
assert backend.get_conn_value("prod--my_db") is None
assert backend.get_variable("prod__hello") is None
-
- refusals = [r for r in caplog.records if "is ambiguous and is not
looked up" in r.getMessage()]
- assert len(refusals) == 2
- assert all(r.levelname == "WARNING" for r in refusals)
+ assert backend.get_config("prod--sql_alchemy_conn") is None
+
+ # Airflow logs through structlog, which renders the format args into
``msg`` before the
+ # stdlib record is built, so ``record.args`` is empty and there is
nothing structured to
+ # assert on. Assert on level, logger and the refused id rather than
the wording.
+ refusals = [
+ r
+ for r in caplog.records
+ if r.levelno == logging.WARNING and
r.name.endswith(type(backend).__name__)
+ ]
+ assert len(refusals) == 3
+ for refused_id in ("prod--my_db", "prod__hello",
"prod--sql_alchemy_conn"):
+ assert sum(refused_id in r.getMessage() for r in refusals) == 1
mock_client.get_secret.assert_not_called()
@mock.patch(f"{KEY_VAULT_MODULE}.AzureKeyVaultBackend._get_secret")