diff --git a/management/internals/modules/reverseproxy/service/service.go b/management/internals/modules/reverseproxy/service/service.go index b4fdf0d05..dd9d73566 100644 --- a/management/internals/modules/reverseproxy/service/service.go +++ b/management/internals/modules/reverseproxy/service/service.go @@ -817,7 +817,8 @@ func restrictionsFromAPI(r *api.AccessRestrictions) (AccessRestrictions, error) res.CrowdSecMode = string(*r.CrowdsecMode) } if r.AllowMatch != nil { - if !r.AllowMatch.Valid() { + // Empty is the default (all), the same as omitting the field. + if *r.AllowMatch != "" && !r.AllowMatch.Valid() { return AccessRestrictions{}, fmt.Errorf("invalid allow_match %q", *r.AllowMatch) } res.AllowMatch = string(*r.AllowMatch) diff --git a/management/internals/modules/reverseproxy/service/service_test.go b/management/internals/modules/reverseproxy/service/service_test.go index ea638e0b7..5ec992c03 100644 --- a/management/internals/modules/reverseproxy/service/service_test.go +++ b/management/internals/modules/reverseproxy/service/service_test.go @@ -1433,6 +1433,18 @@ func TestRestrictions_AllowMatch_EmptyDefaultsToAll(t *testing.T) { assert.Nil(t, apiOut.AllowMatch, "empty allow_match is omitted from the API response") } +func TestRestrictions_AllowMatch_ExplicitEmptyIsAccepted(t *testing.T) { + // A client echoing back an empty allow_match means the default, the same as + // omitting it, and must not be rejected as an invalid enum value. + empty := api.AccessRestrictionsAllowMatch("") + model, err := restrictionsFromAPI(&api.AccessRestrictions{ + AllowedCidrs: &[]string{"203.0.113.0/24"}, + AllowMatch: &empty, + }) + require.NoError(t, err) + assert.Empty(t, model.AllowMatch, "explicit empty allow_match stays empty, meaning all") +} + func TestRestrictions_AllowMatchOnly_Preserved(t *testing.T) { // allow_match set without any list must not be dropped by the emptiness // guards, so it round-trips through both the API and proto conversions. diff --git a/proxy/internal/restrict/restrict_test.go b/proxy/internal/restrict/restrict_test.go index 8ab3ae124..686bbe1e9 100644 --- a/proxy/internal/restrict/restrict_test.go +++ b/proxy/internal/restrict/restrict_test.go @@ -284,6 +284,13 @@ func TestFilter_Check_AllowMatchAny(t *testing.T) { config: FilterConfig{AllowMatch: AllowMatchAny, AllowedCIDRs: []string{"203.0.113.0/24"}, AllowedCountries: []string{"US"}}, addr: "1.1.1.1", geo: &unavailableGeo{}, want: DenyGeoUnavailable, }, + { + // The CIDR short-circuit must not skip the country blocklist: with geo + // down the address cannot be cleared against it, so it fails closed. + name: "CIDR match still needs geo for a country blocklist", + config: FilterConfig{AllowMatch: AllowMatchAny, AllowedCIDRs: []string{"203.0.113.0/24"}, BlockedCountries: []string{"CN"}}, + addr: "203.0.113.7", geo: &unavailableGeo{}, want: DenyGeoUnavailable, + }, { name: "block gate wins over allowed CIDR (blocked country)", config: FilterConfig{AllowMatch: AllowMatchAny, AllowedCIDRs: []string{"0.0.0.0/0"}, BlockedCountries: []string{"CN"}},