diff --git a/CHANGELOG.md b/CHANGELOG.md index bb19b4b..b19eb69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ All notable changes to this project are documented in this file. The format foll ### Changed -- Public risk-signal slugs are `network_check_incomplete`, `banned_ip`, `private_relay` and `latency_test`. Webhook flag parsers still accept `stun_not_checked`, `rate_limited`, `privacy_relay` and `ws_tcp_latency`. The score marker band stays `rate_limited`. History columns stay `is_stun_not_checked`, `is_rate_limited`, `is_privacy_relay` and `is_latency_test`. +- Public risk-signal slugs are `network_check_incomplete`, `rate_limited`, `private_relay` and `latency_test`. Webhook flag parsers still accept `stun_not_checked`, `banned_ip`, `privacy_relay` and `ws_tcp_latency`. History columns stay `is_stun_not_checked`, `is_rate_limited`, `is_privacy_relay` and `is_latency_test`. - `DetectionFlags` follows webhook schema `2026-10-13`: 20 public booleans. `vpn` covers a network VPN and an in-browser VPN or proxy. `os_mismatch` covers either operating-system mismatch check. The public set adds `ws_tcp_latency`, `device_spoofing`, `rate_limited`, `ai_bot` and `ai_browser`. ### Added diff --git a/src/shieldlabs/_models.py b/src/shieldlabs/_models.py index ba83071..4c91bb2 100644 --- a/src/shieldlabs/_models.py +++ b/src/shieldlabs/_models.py @@ -83,7 +83,7 @@ class SignalName: DATACENTER_IP = "datacenter_ip" ABUSER = "abuser" TIMEZONE_MISMATCH = "timezone_mismatch" - RATE_LIMITED = "banned_ip" + RATE_LIMITED = "rate_limited" @dataclass(frozen=True) @@ -174,7 +174,7 @@ class DetectionFlags: latency_test: bool = False anti_detect_browser: bool = False device_spoofing: bool = False - banned_ip: bool = False + rate_limited: bool = False incognito: bool = False search_bot: bool = False ai_bot: bool = False @@ -190,7 +190,7 @@ def from_dict(cls, data: Mapping[str, Any]) -> DetectionFlags: "private_relay": "privacy_relay", "network_check_incomplete": "stun_not_checked", "latency_test": "ws_tcp_latency", - "banned_ip": "rate_limited", + "rate_limited": "banned_ip", } return cls( **{ diff --git a/src/shieldlabs/_normalize.py b/src/shieldlabs/_normalize.py index 0f87ac7..d5384fe 100644 --- a/src/shieldlabs/_normalize.py +++ b/src/shieldlabs/_normalize.py @@ -51,7 +51,7 @@ "latency_test", "anti_detect_browser", "device_spoofing", - "banned_ip", + "rate_limited", "incognito", "search_bot", "ai_bot", @@ -72,6 +72,7 @@ "latency_test": "is_latency_test", "anti_detect_browser": "is_antidetect", "device_spoofing": "is_device_spoof", + "rate_limited": "is_rate_limited", "banned_ip": "is_rate_limited", "incognito": "is_incognito", "search_bot": "is_search_bot", @@ -109,7 +110,9 @@ "Browser VPN/Proxy": "vpn", "Browser Automation": "browser_automation", "Port scan routed via proxy (antidetect browser pattern)": "proxy_routed_antidetect", - "User has been banned 1H, to many requests": "banned_ip", + "User has been banned 1H, to many requests": "rate_limited", + "private_relay": "private_relay", + "network_check_incomplete": "network_check_incomplete", } _PREFIX_SLUGS: tuple[tuple[str, str], ...] = ( @@ -118,6 +121,7 @@ ("OS mismatch2", "os_mismatch"), ("TCP handshake", "tcp_handshake_v2"), ("Latency test", "latency_test"), + ("latency_test", "latency_test"), ("JavaScript disabled", "javascript_disabled"), ) diff --git a/tests/data/normalization-cases.json b/tests/data/normalization-cases.json index e3ff0d1..339d7fe 100644 --- a/tests/data/normalization-cases.json +++ b/tests/data/normalization-cases.json @@ -127,7 +127,7 @@ "latency_test": false, "anti_detect_browser": true, "device_spoofing": false, - "banned_ip": false, + "rate_limited": false, "incognito": false, "search_bot": false, "ai_bot": false, @@ -246,7 +246,7 @@ "latency_test": false, "anti_detect_browser": false, "device_spoofing": false, - "banned_ip": false, + "rate_limited": false, "incognito": true, "search_bot": false, "ai_bot": false, @@ -385,7 +385,7 @@ "latency_test": false, "anti_detect_browser": false, "device_spoofing": false, - "banned_ip": false, + "rate_limited": false, "incognito": false, "search_bot": false, "ai_bot": false, @@ -485,7 +485,7 @@ "risk_score": 999, "signals": [ { - "name": "banned_ip", + "name": "rate_limited", "weight": 999, "description": "User has been banned 1H, to many requests" } @@ -504,7 +504,7 @@ "latency_test": false, "anti_detect_browser": false, "device_spoofing": false, - "banned_ip": false, + "rate_limited": false, "incognito": false, "search_bot": false, "ai_bot": false, @@ -621,7 +621,7 @@ "latency_test": false, "anti_detect_browser": false, "device_spoofing": false, - "banned_ip": false, + "rate_limited": false, "incognito": false, "search_bot": true, "ai_bot": false, @@ -769,7 +769,7 @@ "latency_test": false, "anti_detect_browser": true, "device_spoofing": false, - "banned_ip": false, + "rate_limited": false, "incognito": false, "search_bot": false, "ai_bot": false, @@ -899,7 +899,7 @@ "latency_test": false, "anti_detect_browser": false, "device_spoofing": false, - "banned_ip": false, + "rate_limited": false, "incognito": false, "search_bot": false, "ai_bot": false, @@ -1047,7 +1047,7 @@ "latency_test": false, "anti_detect_browser": false, "device_spoofing": false, - "banned_ip": false, + "rate_limited": false, "incognito": false, "search_bot": false, "ai_bot": false, diff --git a/tests/data/signal-slug-cases.json b/tests/data/signal-slug-cases.json index 66772c5..d60ec55 100644 --- a/tests/data/signal-slug-cases.json +++ b/tests/data/signal-slug-cases.json @@ -59,7 +59,7 @@ }, { "description": "User has been banned 1H, to many requests", - "slug": "banned_ip" + "slug": "rate_limited" }, { "description": "Antidetect browser (turn_block)", diff --git a/tests/test_normalization.py b/tests/test_normalization.py index c396371..cfd7c98 100644 --- a/tests/test_normalization.py +++ b/tests/test_normalization.py @@ -272,7 +272,7 @@ def test_history_page_rows_match_normalization_cases() -> None: def test_known_signal_names_are_plain_strings() -> None: assert SignalName.ANTIDETECT_BROWSER == "antidetect_browser" assert SignalName.STUN_LATE_CORRECTION == "stun_late_correction" - assert SignalName.RATE_LIMITED == "banned_ip" + assert SignalName.RATE_LIMITED == "rate_limited" def test_models_are_frozen() -> None: