diff --git a/tests/agent/test_redact.py b/tests/agent/test_redact.py index 3d40be4e3f..68307c7381 100644 --- a/tests/agent/test_redact.py +++ b/tests/agent/test_redact.py @@ -560,7 +560,22 @@ class TestConfigKeyRedosResistance: text = ".".join(["segment"] * 100) + " end" t0 = time.perf_counter() assert redact_sensitive_text(text) == text - assert time.perf_counter() - t0 < 1.0 + assert time.perf_counter() - t0 < 2.0 + + def test_long_dotted_run_with_keyword_completes_fast(self): + """Exercise _CFG_DOTTED_RE directly (bypasses the keyword pre-gate). + + The pre-gate skips the regex when no secret keyword is present, so + test_long_dotted_run_completes_fast only guards the pre-gate. This + test includes a keyword but no '=' so the regex runs and must still + complete quickly thanks to the possessive quantifiers. + """ + import time + + text = ".".join(["segment"] * 100) + ".token end" + t0 = time.perf_counter() + assert redact_sensitive_text(text) == text + assert time.perf_counter() - t0 < 2.0 def test_long_dotted_secret_still_redacted(self): # Possessive quantifiers must not change matching behavior. @@ -569,6 +584,25 @@ class TestConfigKeyRedosResistance: assert "Sup3rS3cret!" not in result assert ".password=" in result + def test_yaml_assign_redos_resistance(self): + """_YAML_ASSIGN_RE must not backtrack excessively on long inputs.""" + import time + + # 100 lines of a long dotted key with a secret keyword but no + # matching colon-value form — stresses the regex without matching. + line = "a." * 50 + "token not_an_assignment" + text = "\n".join([line] * 100) + t0 = time.perf_counter() + redact_sensitive_text(text) + assert time.perf_counter() - t0 < 2.0 + + def test_yaml_assign_secret_still_redacted(self): + # Possessive quantifiers must not change YAML matching behavior. + text = "spring.datasource.password: hunter2" + result = redact_sensitive_text(text) + assert "hunter2" not in result + assert "password:" in result + class TestXaiToken: KEY = "xai-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstu"