diff --git a/tests/test_rest_api_executor.py b/tests/test_rest_api_executor.py index 816628f..7bc2ef1 100644 --- a/tests/test_rest_api_executor.py +++ b/tests/test_rest_api_executor.py @@ -498,7 +498,24 @@ class TestRestApiExecutor: assert redacted["normal_field"] == "visible" def test_redact_sensitive_nested(self): - """Test redaction in nested structures.""" + """A dict under a sensitive key is redacted whole, not recursed into. + + This asserted fine-grained recursion — that `auth.token` was replaced + while `auth`'s other keys stayed readable — and had never passed. The + source redacts the entire value the moment the KEY matches, so + `redacted["config"]["auth"]` is the string, and indexing `["token"]` + into it raises TypeError. + + Settled in favour of the source. Fine-grained redaction has to know + which sub-keys carry the secret, which is a guess about the shape of + data nobody has inspected; redacting on the key cannot be wrong that + way. Real configs here look like + {"auth": {"type": "bearer", "token": "${SOME_API_KEY}"}}, and the cost + of guessing wrong is a credential in a log, which no later fix undoes. + + The price is readability: a reader learns that auth was present, not + that it was bearer. That is the trade being made deliberately. + """ data = { "config": { "database": "mydb", @@ -513,7 +530,10 @@ class TestRestApiExecutor: assert redacted["config"]["database"] == "mydb" assert redacted["config"]["password"] == "***REDACTED***" - assert redacted["config"]["auth"]["token"] == "***REDACTED***" + # The whole sub-dict, not a recursed copy of it. + assert redacted["config"]["auth"] == "***REDACTED***" + # And the secret is nowhere in the output, by any path. + assert "bearer123" not in str(redacted) # Helper Function Tests