@@ -405,3 +405,59 @@ func TestRegexesWithRatesAllowList(t *testing.T) {
405405 {"GET" , prefix + "/blockme/" , 200 , ClientIP ("20.20.20.20" ), nil },
406406 })
407407}
408+
409+ func TestGlobalUserAgentDecisionLists (t * testing.T ) {
410+ defer reloadConfig (fixtureConfigTest , 1 , t )
411+
412+ reloadConfig (fixtureConfigTestUA , 1 , t )
413+
414+ /*
415+ global_user_agent_decision_lists:
416+ nginx_block:
417+ - "AhrefsBot"
418+ - "SemrushBot"
419+ challenge:
420+ - "Macintosh.*Firefox/\\d+"
421+ */
422+ prefix := "/auth_request?path="
423+ httpTester (t , []TestResource {
424+ {"GET" , "/info" , 200 , nil , []string {"2025-01-01" }},
425+ // AhrefsBot is globally nginx_blocked (403)
426+ {"GET" , prefix + "/ua_ahref" , 403 , ClientUserAgent ("Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/)" ), nil },
427+ // SemrushBot is globally nginx_blocked (403)
428+ {"GET" , prefix + "/ua_semrush" , 403 , ClientUserAgent ("Mozilla/5.0 (compatible; SemrushBot/7.0; +http://www.semrush.com/bot.html)" ), nil },
429+ // Firefox on Mac is globally challenged (429)
430+ {"GET" , prefix + "/ua_firefox_mac" , 429 , ClientUserAgent ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:149.0) Gecko/20100101 Firefox/149.0" ), nil },
431+ // Firefox on Windows does not match the Macintosh pattern — allowed (200)
432+ {"GET" , prefix + "/ua_firefox_win" , 200 , ClientUserAgent ("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0" ), nil },
433+ // Googlebot has no UA rule — allowed (200)
434+ {"GET" , prefix + "/ua_googlebot" , 200 , ClientUserAgent ("Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" ), nil },
435+ })
436+ }
437+
438+ func TestPerSiteUserAgentDecisionLists (t * testing.T ) {
439+ defer reloadConfig (fixtureConfigTest , 1 , t )
440+
441+ reloadConfig (fixtureConfigTestUA , 1 , t )
442+
443+ /*
444+ per_site_user_agent_decision_lists:
445+ "localhost:8081":
446+ allow:
447+ - "GPTBot"
448+
449+ global_decision_lists:
450+ challenge:
451+ - 8.8.8.8
452+ */
453+ prefix := "/auth_request?path="
454+ httpTester (t , []TestResource {
455+ {"GET" , "/info" , 200 , nil , []string {"2025-01-01" }},
456+ // 8.8.8.8 is in global challenge IP list — should be challenged without a UA override
457+ {"GET" , prefix + "/ua_ip_challenge" , 429 , ClientIP ("8.8.8.8" ), nil },
458+ // GPTBot from 8.8.8.8: per-site UA allow overrides the global IP challenge
459+ {"GET" , prefix + "/ua_gptbot_override" , 200 , ClientIPAndUserAgent ("8.8.8.8" , "Mozilla/5.0 (compatible; GPTBot/1.0; +https://openai.com/gptbot)" ), nil },
460+ // AhrefsBot from 8.8.8.8: global IP challenge fires before global UA block (per-site UA has no AhrefsBot rule)
461+ {"GET" , prefix + "/ua_ahref_challenged_ip" , 429 , ClientIPAndUserAgent ("8.8.8.8" , "Mozilla/5.0 (compatible; AhrefsBot/7.0)" ), nil },
462+ })
463+ }
0 commit comments