File size: 2,503 Bytes
4e35ad0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
"""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}