potiuk opened a new pull request, #70869:
URL: https://github.com/apache/airflow/pull/70869

   `CloudSecretManagerBackend.get_conn_value` and `get_variable` both accept a
   `team_name`, but the helper they delegate to has no such parameter:
   
   ```python
   def get_conn_value(self, conn_id: str, team_name: str | None = None) -> str 
| None:
       ...
       return self._get_secret(self.connections_prefix, conn_id)   # team_name 
dropped
   
   def _get_secret(self, path_prefix: str, secret_id: str) -> str | None:
   ```
   
   The argument was discarded at the call boundary, so the backend built the 
team
   agnostic secret name in every case and a team scoped lookup resolved whatever
   that name pointed at. No team scoping was applied at all.
   
   ### Approach
   
   The team scope is threaded through and the team scoped name is resolved 
first,
   using the same `<team><TEAM_SEP><secret id>` convention the other secrets
   backends use (`TEAM_SEP = "--"`, matching the Azure Key Vault backend).
   
   1. **team scoped lookup first** — safe by construction, since it can only 
ever
      build the caller's own namespace;
   2. after it misses, an id that already spells out a team scoped name is
      **refused**, because the team agnostic name would otherwise land inside 
some
      team's namespace;
   3. otherwise the team agnostic lookup proceeds as before.
   
   **The id is never parsed to work out which team it names**, because it cannot
   be: a team name may itself contain the separator, so nothing in the string
   distinguishes team `a` with id `b--c` from team `a--b` with id `c`. 
Comparing the
   id against the prefix the caller's own team builds looks equivalent and is 
not —
   a caller in team `a` matches `a--b`'s namespace on the prefix and would read 
its
   secrets. Only the caller's own namespace is ever constructed, never parsed.
   
   `get_config` is unchanged in behaviour for ordinary configuration keys; it 
shares
   `_get_secret`, so a config id that spells out a team scoped name is now 
refused
   too, which matches how the Azure backend already behaves.
   
   ### Behaviour change
   
   - A team scoped lookup now resolves the team scoped secret name, where 
before it
     silently resolved the team agnostic one. Deployments that ran multi-team 
mode
     against this backend and relied on the old behaviour must store secrets 
under
     the team scoped name.
   - An id that spells out a team scoped name is no longer resolvable through 
the
     team agnostic name from any scope.
   - Single-team and non-team deployments are unaffected.
   
   ### Test plan
   
   - [x] 
`providers/google/tests/unit/google/cloud/secrets/test_secret_manager.py` —
         36 pass (30 existing, 6 new)
   - [x] New `TestCloudSecretManagerBackendTeamScope`: resolved for its own 
team;
         not resolved for another team; not resolved without a team scope; team
         agnostic secrets still resolve for any scope; Variables scoped 
identically
   - [x] `test_team_whose_name_extends_the_callers_is_not_readable` — a team 
named
         `team_a--prod` is not readable by a caller in `team_a`, and still 
reaches its
         own secret with the bare id
   - [x] 5 of the 6 new tests fail against the unmodified backend; the sixth is 
a
         no-regression guard for team agnostic lookups
   - [x] `ruff check` / `ruff format` clean
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes — Claude Opus 5 (1M context)
   
   Generated-by: Claude Opus 5 (1M context) following the guidelines at
   
https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to