potiuk commented on code in PR #61776:
URL: https://github.com/apache/airflow/pull/61776#discussion_r2795367514
##########
shared/secrets_masker/tests/secrets_masker/test_secrets_masker.py:
##########
@@ -238,6 +238,213 @@ def test_masking_in_explicit_context_exceptions(self,
logger, caplog):
"""
)
+ def test_redact_exception_with_context_simple(self):
+ """
+ Test _redact_exception_with_context with a simple exception without
context.
+ """
+ masker = SecretsMasker()
+ configure_secrets_masker_for_test(masker)
+ masker.add_mask(PASSWORD)
+
+ exc = RuntimeError(f"Cannot connect to user:{PASSWORD}")
+ masker._redact_exception_with_context_or_cause(exc)
+
+ assert "password" not in str(exc.args[0])
+ assert "user:***" in str(exc.args[0])
+
+ def test_redact_exception_with_implicit_context(self):
+ """
+ Test _redact_exception_with_context with exception __context__
(implicit chaining).
+ """
+ masker = SecretsMasker()
+ configure_secrets_masker_for_test(masker)
+ masker.add_mask(PASSWORD)
+
+ try:
+ try:
+ raise RuntimeError(f"Inner error with {PASSWORD}")
+ except RuntimeError:
+ raise RuntimeError(f"Outer error with {PASSWORD}")
+ except RuntimeError as exc:
+ captured_exc = exc
+
+ masker._redact_exception_with_context_or_cause(captured_exc)
+ assert "password" not in str(captured_exc.args[0])
+ assert "password" not in str(captured_exc.__context__.args[0])
+
+ def test_redact_exception_with_explicit_cause(self):
+ """
+ Test _redact_exception_with_context with exception __cause__ (explicit
chaining).
+ """
+ masker = SecretsMasker()
+ configure_secrets_masker_for_test(masker)
+ masker.add_mask(PASSWORD)
+
+ try:
+ inner = RuntimeError(f"Cause error: {PASSWORD}")
+ raise RuntimeError(f"Main error: {PASSWORD}") from inner
+ except RuntimeError as exc:
+ captured_exc = exc
+
+ masker._redact_exception_with_context_or_cause(captured_exc)
+ assert "password" not in str(captured_exc.args[0])
+ assert "password" not in str(captured_exc.__cause__.args[0])
+
+ def test_redact_exception_with_circular_context_reference(self):
+ """
+ Test _redact_exception_with_context handles circular references
without infinite recursion.
+ """
+ masker = SecretsMasker()
+ configure_secrets_masker_for_test(masker)
+ masker.add_mask(PASSWORD)
+
+ exc1 = RuntimeError(f"Error with {PASSWORD}")
+ exc2 = RuntimeError(f"Another error with {PASSWORD}")
+ # Create circular reference
+ exc1.__context__ = exc2
+ exc2.__context__ = exc1
+
+ # Should not raise RecursionError
+ masker._redact_exception_with_context_or_cause(exc1)
+
+ assert "password" not in str(exc1.args[0])
+ assert "password" not in str(exc2.args[0])
+
+ def test_redact_exception_with_max_context_recursion_depth(self):
+ """
+ Test _redact_exception_with_context respects MAX_RECURSION_DEPTH.
+ Exceptions beyond the depth limit should be skipped (not redacted).
+ """
+ masker = SecretsMasker()
+ configure_secrets_masker_for_test(masker)
+ masker.add_mask(PASSWORD)
+
+ # Create a long chain of exceptions
+ exc_chain = RuntimeError(f"Error 0 with {PASSWORD}")
+ current = exc_chain
+ for i in range(1, 10):
+ new_exc = RuntimeError(f"Error {i} with {PASSWORD}")
+ current.__context__ = new_exc
+ current = new_exc
+
+ masker._redact_exception_with_context_or_cause(exc_chain)
+
+ # Verify redaction happens up to MAX_RECURSION_DEPTH
+ # The check is `len(visited) >= MAX_RECURSION_DEPTH` before adding
current exception
+ # So it processes exactly MAX_RECURSION_DEPTH exceptions (0 through
MAX_RECURSION_DEPTH-1)
+ current = exc_chain
+ for i in range(10):
+ assert current, "We should always get some exception here"
+ if i < masker.MAX_RECURSION_DEPTH:
+ # Should be redacted within the depth limit
+ assert "password" not in str(current.args[0]), f"Exception {i}
should be redacted"
+ else:
+ assert "hit recursion limit" in str(current.args[0]), (
+ f"Exception {i} should indicate recursion depth limit hit"
+ )
+ assert "password" not in str(current.args[0]), f"Exception {i}
should not be present"
+ assert current.__context__ is None, (
+ f"Exception {i} should not have a context due to depth
limit"
+ )
+ break
+ current = current.__context__
+
+ def test_redact_exception_with_circular_cause_reference(self):
+ """
+ Test _redact_exception_with_context_or_cause handles circular
__cause__ references without infinite recursion.
+ """
+ masker = SecretsMasker()
+ configure_secrets_masker_for_test(masker)
+ masker.add_mask(PASSWORD)
+
+ exc1 = RuntimeError(f"Error with {PASSWORD}")
+ exc2 = RuntimeError(f"Another error with {PASSWORD}")
+ # Create circular reference using __cause__
+ exc1.__cause__ = exc2
+ exc2.__cause__ = exc1
+
+ # Should not raise RecursionError
+ masker._redact_exception_with_context_or_cause(exc1)
+
+ assert "password" not in str(exc1.args[0])
+ assert "password" not in str(exc2.args[0])
Review Comment:
BTW. Anyone can be a reviewer here. There is absolutely no problem - and we
absolutely welcome anyone to make reviews.
--
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]