Suspend immediately on strong IP-reputation signals (not vpn alone)
docker-build-push / build-push (push) Failing after 15s

datacenter/proxy/tor/abuser is a much cleaner bulk/bot-signup indicator
than vpn, which also flags plenty of privacy-conscious real users. A
strong-flagged signup now suspends immediately regardless of the email
signal; vpn-only still gets the normal held-welcome/ipblock/lowered-
threshold treatment, falling through to the existing combined-signal
suspend only if also paired with a flagged email domain.
This commit is contained in:
pmb
2026-07-21 22:14:39 -07:00
parent 0b0842dc9d
commit 65c9bd5a9e
4 changed files with 221 additions and 26 deletions
+104
View File
@@ -533,6 +533,109 @@ def combined_signal_tests():
assert ("505", "failsuspend") not in sent, "still held, falls back to the normal flagged path"
def strong_ip_suspend_tests():
"""Drive process_signup's strong-IP-signal immediate-suspend path
(IP_SCRUTINY_STRONG_SUSPEND_*): datacenter/proxy/tor/abuser suspend
immediately regardless of the email signal, but vpn alone does not — it
still falls through to the normal hold/welcome path (or the existing
combined-signal suspend, if also paired with a flagged email domain)."""
sent = []
dms = []
actions = []
ipblocks = []
main.send_welcome = lambda account_id, acct: sent.append((account_id, acct))
main.dm_moderator = lambda message: dms.append(message)
main.apply_action = lambda target_id, action, text: actions.append((target_id, action))
main.register_ip_block = lambda ip, acct, org, cidr: ipblocks.append((ip, acct, org, cidr))
main.register_email_domain_block = lambda domain, acct: None
main.fetch_account_counts = lambda account_id: (0, 0)
main.IP_SCRUTINY_ENABLED = True
main.IP_SCRUTINY_DRY_RUN = False
main.IP_SCRUTINY_HOLD_WELCOME = True
main.IP_SCRUTINY_AUTO_IPBLOCK = True
main.CHECK_MAIL_ENABLED = True
main.CHECK_MAIL_API_KEY = "test-key"
main.CHECK_MAIL_DRY_RUN = False
main.CHECK_MAIL_HOLD_WELCOME = True
main.CHECK_MAIL_AUTO_DOMAIN_BLOCK = True
main.SUSPICIOUS_COMBINED_ENABLED = True
main.SUSPICIOUS_COMBINED_ACTION = "suspend"
main.SUSPICIOUS_COMBINED_DRY_RUN = False
main.ABUSE_ALLOWLIST = {"trustedstaff"}
main.IP_SCRUTINY_STRONG_SUSPEND_ENABLED = True
main.IP_SCRUTINY_STRONG_SUSPEND_ACTION = "suspend"
main.IP_SCRUTINY_STRONG_SUSPEND_DRY_RUN = False
ip_classifications = {
"198.51.100.60": ("datacenter", "Example Cloud Hosting Inc", True, "198.51.100.48/28"),
"198.51.100.61": ("proxy", "Example Proxy Networks", True, "198.51.100.48/28"),
"198.51.100.62": ("vpn", "Example VPN Provider", True, "198.51.100.48/28"),
"198.51.100.63": ("vpn", "Example VPN Provider", True, "198.51.100.48/28"),
}
main.classify_signup_ip = lambda ip: ip_classifications[ip]
email_classifications = {
"temp-mail.org": (True, 99),
"gmail.com": (False, 5),
}
main.classify_email_domain = lambda domain: email_classifications[domain]
# A. datacenter (strong), clean email -> suspended immediately regardless
# of the (non-flagged) email signal; ip_block still registered.
main.process_signup("601", "strongdc", "198.51.100.60", "[email protected]")
assert ("601", "suspend") in actions, actions
assert ("601", "strongdc") not in sent, "must not welcome an immediately-suspended signup"
assert any("strongdc" in d and "strong IP signal" in d for d in dms), dms
assert ("198.51.100.60", "strongdc", "Example Cloud Hosting Inc", "198.51.100.48/28") in ipblocks, ipblocks
# B. proxy (strong), no email at all -> still suspended immediately.
actions.clear(); sent.clear(); dms.clear()
main.process_signup("602", "strongproxy", "198.51.100.61")
assert ("602", "suspend") in actions, actions
assert ("602", "strongproxy") not in sent
# C. vpn only (not strong), clean email -> NOT suspended, falls through to
# the normal held-welcome path.
actions.clear(); sent.clear(); dms.clear()
main.process_signup("603", "vpnonly", "198.51.100.62", "[email protected]")
assert ("603", "suspend") not in actions, actions
assert ("603", "vpnonly") not in sent, "still held by the individual IP-scrutiny hold"
# D. vpn (not strong) + flagged email -> not caught by the strong path,
# but still caught by the existing combined-signal suspend.
actions.clear(); sent.clear(); dms.clear()
main.process_signup("604", "vpnplusemail", "198.51.100.63", "[email protected]")
assert ("604", "suspend") in actions, actions
assert ("604", "vpnplusemail") not in sent
assert any("vpnplusemail" in d and "BOTH" in d for d in dms), dms
# E. allowlisted acct with a strong signal -> not suspended.
actions.clear(); sent.clear(); dms.clear()
main.process_signup("605", "trustedstaff", "198.51.100.60", "[email protected]")
assert ("605", "suspend") not in actions, "allowlisted acct must not be auto-suspended"
# F. strong signal, but IP_SCRUTINY_STRONG_SUSPEND_DRY_RUN -> DM only, no
# real suspend; falls through to the normal held-welcome path.
actions.clear(); sent.clear(); dms.clear()
main.IP_SCRUTINY_STRONG_SUSPEND_DRY_RUN = True
main.process_signup("606", "drystrong", "198.51.100.60", "[email protected]")
assert ("606", "suspend") not in actions, "dry-run must not call apply_action"
assert any("[DRY-RUN]" in d and "drystrong" in d for d in dms), dms
assert ("606", "drystrong") not in sent, "still held by the individual IP-scrutiny hold"
# G. strong signal, live, but apply_action fails -> falls back to the
# normal held-welcome path instead of silently dropping the signup.
actions.clear(); sent.clear(); dms.clear()
main.IP_SCRUTINY_STRONG_SUSPEND_DRY_RUN = False
def boom(target_id, action, text):
raise main.httpx.HTTPError("boom")
main.apply_action = boom
main.process_signup("607", "failstrong", "198.51.100.60", "[email protected]")
assert ("607", "failstrong") not in sent, "still held, falls back to the normal flagged path"
def suspicious_watch_tests():
"""Drive maybe_start_suspicious_watch: baseline capture on flagged
signups only, never on clean ones, and never twice for the same account."""
@@ -684,6 +787,7 @@ if __name__ == "__main__":
email_scrutiny_tests()
range_cache_tests()
combined_signal_tests()
strong_ip_suspend_tests()
suspicious_watch_tests()
suspicious_sweep_tests()
print("ALL TESTS PASSED")