@@ -260,6 +260,50 @@ describe('free mode country access', () => {
260260 } )
261261 } )
262262
263+ test ( 'allowLocalhost bypasses gating when no CF country and no client IP' , async ( ) => {
264+ const access = await getFreeModeCountryAccess ( makeReq ( ) , {
265+ ipinfoToken : 'test-token' ,
266+ allowLocalhost : true ,
267+ } )
268+ expect ( access . allowed ) . toBe ( true )
269+ expect ( access . countryCode ) . toBe ( 'US' )
270+ expect ( access . blockReason ) . toBe ( null )
271+ expect ( access . ipPrivacy ?. signals ) . toEqual ( [ ] )
272+ } )
273+
274+ test ( 'allowLocalhost bypasses gating for loopback client IPs' , async ( ) => {
275+ const access = await getFreeModeCountryAccess (
276+ makeReq ( { 'x-forwarded-for' : '127.0.0.1' } ) ,
277+ {
278+ ipinfoToken : 'test-token' ,
279+ allowLocalhost : true ,
280+ } ,
281+ )
282+ expect ( access . allowed ) . toBe ( true )
283+ expect ( access . countryCode ) . toBe ( 'US' )
284+ expect ( access . blockReason ) . toBe ( null )
285+ } )
286+
287+ test ( 'allowLocalhost does not bypass when cf-ipcountry is set' , async ( ) => {
288+ const access = await getFreeModeCountryAccess (
289+ makeReq ( { 'cf-ipcountry' : 'FR' } ) ,
290+ {
291+ ipinfoToken : 'test-token' ,
292+ allowLocalhost : true ,
293+ } ,
294+ )
295+ expect ( access . allowed ) . toBe ( false )
296+ expect ( access . blockReason ) . toBe ( 'country_not_allowed' )
297+ } )
298+
299+ test ( 'allowLocalhost off (default) keeps the strict missing-IP block' , async ( ) => {
300+ const access = await getFreeModeCountryAccess ( makeReq ( ) , {
301+ ipinfoToken : 'test-token' ,
302+ } )
303+ expect ( access . allowed ) . toBe ( false )
304+ expect ( access . blockReason ) . toBe ( 'missing_client_ip' )
305+ } )
306+
263307 test ( 'treats is_anonymous as blocking even when service is present' , async ( ) => {
264308 const fetch = async ( ) =>
265309 Response . json ( {
0 commit comments