"""The Sentry secret-scrubber (observability.scrub_text / scrub_event). The scrubber is the security-critical part of error tracking: the pipeline puts the Google key in Static Maps URLs, so an unscrubbed exception would ship that key to a third party. These tests pin that it's redacted everywhere an event can carry a string. No sentry-sdk, no network. """ from __future__ import annotations from lawn_estimator.observability import scrub_event, scrub_text def test_redacts_google_key_in_a_url(): url = "https://maps.googleapis.com/maps/api/staticmap?center=41.2,-96&zoom=20&key=AIzaSyABC123secret" out = scrub_text(url) assert "AIzaSyABC123secret" not in out assert "key=REDACTED" in out assert "zoom=20" in out # non-secret params are untouched def test_redacts_common_secret_param_names(): for param in ["api_key", "apikey", "token", "access_token", "password", "client_secret", "signature", "sig", "auth"]: s = f"http://x/y?{param}=SUPERSECRETVALUE&ok=1" out = scrub_text(s) assert "SUPERSECRETVALUE" not in out, param assert "ok=1" in out def test_redacts_bearer_tokens(): out = scrub_text("Authorization: Bearer abc.def.ghi-123") assert "abc.def.ghi-123" not in out and "Bearer REDACTED" in out def test_scrub_is_case_insensitive_on_the_key_name(): assert "SECRETV" not in scrub_text("http://x?KEY=SECRETV") assert "SECRETV" not in scrub_text("http://x?Api_Key=SECRETV") def test_leaves_clean_text_untouched(): clean = "measured 4200 sqft for 5534 Mayberry St; method=lidar+rgb confidence=high" assert scrub_text(clean) == clean def test_scrub_event_deep_walks_nested_structures(): event = { "request": {"url": "https://maps.googleapis.com/x?key=AIzaLEAK1"}, "exception": {"values": [{"value": "GET https://api/x?token=LEAK2 failed"}]}, "breadcrumbs": [{"message": "hit https://a/b?password=LEAK3"}], "extra": {"nested": ["plain", {"deep": "http://q?secret=LEAK4"}]}, "level": "error", } out = scrub_event(event) blob = repr(out) for leak in ("AIzaLEAK1", "LEAK2", "LEAK3", "LEAK4"): assert leak not in blob, leak assert out["level"] == "error" # structure/non-secret values preserved def test_scrub_event_never_raises_on_odd_input(): # A malformed event must not crash the send path. assert scrub_event({"a": 1, "b": None, "c": 3.5}) == {"a": 1, "b": None, "c": 3.5}