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

   `SecretsMasker.redact` only walks `dict`, `list`, `tuple` and `set`. Any 
other container is returned unchanged, so a registered secret inside it reaches 
the logs and rendered output in the clear. The same gap exists on the 
fail-closed path for a sensitive key (`_redact_all`), which replaces the 
contents of the four known containers and nothing else.
   
   Reproduction on `main`, with `hunter2-secret` registered through `add_mask`:
   
   | value | `redact(value)` on `main` |
   |---|---|
   | `frozenset({"hunter2-secret"})` | `frozenset({'hunter2-secret'})` |
   | `collections.deque(["hunter2-secret"])` | `deque(['hunter2-secret'])` |
   | `MappingProxyType({"k": "hunter2-secret"})` | `mappingproxy({'k': 
'hunter2-secret'})` |
   | `{"a": {"b": frozenset({"hunter2-secret"})}}` | secret unchanged |
   
   This change walks `frozenset`, `collections.deque` and any 
`collections.abc.Mapping` the same way as their `dict`, `list` and `tuple` 
counterparts, on both `_redact` and `_redact_all`. `frozenset` is returned as a 
tuple like `set`, `deque` as a list, and a non-`dict` mapping as a `dict`. 
`dict` and `str` keep their existing early checks and the `Mapping` ABC is only 
consulted last, so the common leaf types do not pay for it.
   
   Not changed on purpose: dict keys are still not masked (a registered secret 
equal to a key name such as `secret` would rename the key and change the output 
structure, which `test_redact` rules out), and `bytes`, dataclasses and 
arbitrary objects are still returned as they are.
   
   ##### Tests run
   
   - `shared/secrets_masker/tests`: 212 passed, 1 skipped, 1 xfailed, 1 failed. 
The failure is `test_redact_filehandles`, which fails identically on unmodified 
`main` in my environment (Windows), so it is not caused by this change.
   - The 5 new tests (`test_redact_masks_secret_in_container_types[...]` and 
`test_redact_masks_every_leaf_of_other_container_types_under_a_sensitive_name`) 
fail on `main` and pass with the change.
   - `ruff check` and `ruff format --check` on `shared/secrets_masker`: passed.
   - Not run: `prek`, mypy, `breeze verify`.
   
   ##### Performance
   
   Secret masking is on the hot path of every log line, so I measured both 
paths before and after (4 alternating runs each, best of 7 repeats, 200 random 
secrets of 8-32 chars, `str` of 190 chars containing one secret, and a 
structlog-style event dict with nested values; control is `sum(range(200))`):
   
   | | main | this PR |
   |---|---|---|
   | `redact(str)` | 95.8-100.4 us | 95.2-100.2 us |
   | `redact(event dict)` | 293-325 us | 298-313 us |
   | control | 1.24-1.38 us | 1.28-1.37 us |
   
   No change outside the noise. My first version checked `Mapping` before 
`dict` and measured 6-9% slower on the event dict, which is why the ABC check 
now comes last.
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes (please specify the tool below)
   
   Generated-by: Claude Code (Sonnet 5.5) following [the 
guidelines](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