diff --git a/controller/hybridgateway/route/status.go b/controller/hybridgateway/route/status.go index d321e12479..8fe9e4d271 100644 --- a/controller/hybridgateway/route/status.go +++ b/controller/hybridgateway/route/status.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/go-logr/logr" + "github.com/samber/lo" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -453,10 +454,11 @@ func BuildResolvedRefsCondition(ctx context.Context, logger logr.Logger, cl clie bRefNamespace = string(*bRef.Namespace) } - // BackendRef group kind. - bRefGK := string(*bRef.Kind) - if gr := string(*bRef.Group); gr != "" { - bRefGK = fmt.Sprintf("%s/%s", gr, bRefGK) + // BackendRef group/kind (default to core/Service when unset). + bRefGroup, bRefKind := backendRefGroupKind(bRef.Group, bRef.Kind) + bRefGK := bRefKind + if bRefGroup != "" { + bRefGK = fmt.Sprintf("%s/%s", bRefGroup, bRefKind) } // Check if the group kind is supported for the reference. @@ -918,21 +920,22 @@ func FilterOutGVKByKind(expectedGVKs []schema.GroupVersionKind, kindToFilter str return filtered } +// backendRefGroupKind returns the effective group and kind for a BackendRef, +// applying Gateway API defaults: kind defaults to "Service" and group defaults +// to "" (core) when nil or empty. +func backendRefGroupKind(group *gwtypes.Group, kind *gwtypes.Kind) (string, string) { + g := string(lo.FromPtr(group)) + k := string(lo.FromPtr(kind)) + if k == "" { + k = "Service" + } + return g, k +} + // IsBackendRefSupported returns true if the BackendRef group and kind are supported by Gateway API. // Only core "Service" is supported. func IsBackendRefSupported(group *gwtypes.Group, kind *gwtypes.Kind) bool { - if kind == nil { - return false - } - - k := string(*kind) - - // Acceptable group values for Service: nil, "", "core". - var g string - if group != nil { - g = string(*group) - } - + g, k := backendRefGroupKind(group, kind) return (g == "" || g == "core") && k == "Service" } @@ -955,15 +958,7 @@ func IsExtensionRefSupported(group gwtypes.Group, kind gwtypes.Kind) bool { // Returns: // - bool: true if the reference is permitted by the grant, false otherwise func IsHTTPReferenceGranted(grantSpec gwtypes.ReferenceGrantSpec, backendRef gwtypes.HTTPBackendRef, fromNamespace string) bool { - var backendRefGroup gwtypes.Group - var backendRefKind gwtypes.Kind - - if backendRef.Group != nil { - backendRefGroup = *backendRef.Group - } - if backendRef.Kind != nil { - backendRefKind = *backendRef.Kind - } + bRefGroup, bRefKind := backendRefGroupKind(backendRef.Group, backendRef.Kind) for _, from := range grantSpec.From { if from.Group != gwtypes.GroupName || from.Kind != "HTTPRoute" || fromNamespace != string(from.Namespace) { @@ -971,14 +966,15 @@ func IsHTTPReferenceGranted(grantSpec gwtypes.ReferenceGrantSpec, backendRef gwt } for _, to := range grantSpec.To { - if to.Group == "" { - to.Group = "core" + toGroup := string(to.Group) + if toGroup == "" { + toGroup = "core" } - if backendRefGroup == "" { - backendRefGroup = "core" + if bRefGroup == "" { + bRefGroup = "core" } - if backendRefGroup == to.Group && - backendRefKind == to.Kind && + if gwtypes.Group(bRefGroup) == gwtypes.Group(toGroup) && + gwtypes.Kind(bRefKind) == to.Kind && (to.Name == nil || *to.Name == backendRef.Name) { return true } diff --git a/controller/hybridgateway/route/status_test.go b/controller/hybridgateway/route/status_test.go index 855109e36f..8136d5790c 100644 --- a/controller/hybridgateway/route/status_test.go +++ b/controller/hybridgateway/route/status_test.go @@ -1561,10 +1561,16 @@ func TestIsBackendRefSupported(t *testing.T) { want: false, }, { - name: "nil kind", + name: "nil kind defaults to Service", group: groupPtr("core"), kind: nil, - want: false, + want: true, + }, + { + name: "empty kind defaults to Service", + group: groupPtr("core"), + kind: kindPtr(""), + want: true, }, } @@ -1612,6 +1618,58 @@ func TestIsHTTPReferenceGranted(t *testing.T) { fromNamespace: "default", want: true, }, + { + name: "granted when backend kind/group default to core/Service", + grantSpec: gwtypes.ReferenceGrantSpec{ + From: []gwtypes.ReferenceGrantFrom{{ + Group: gwtypes.GroupName, + Kind: "HTTPRoute", + Namespace: gwtypes.Namespace("default"), + }}, + To: []gwtypes.ReferenceGrantTo{{ + Group: gwtypes.Group("core"), + Kind: gwtypes.Kind("Service"), + Name: ptrObjName("my-service"), + }}, + }, + backendRef: gwtypes.HTTPBackendRef{ + BackendRef: gwtypes.BackendRef{ + BackendObjectReference: gwtypes.BackendObjectReference{ + Name: gwtypes.ObjectName("my-service"), + Kind: nil, + Group: nil, + }, + }, + }, + fromNamespace: "default", + want: true, + }, + { + name: "granted when backend kind is empty string (defaults to Service)", + grantSpec: gwtypes.ReferenceGrantSpec{ + From: []gwtypes.ReferenceGrantFrom{{ + Group: gwtypes.GroupName, + Kind: "HTTPRoute", + Namespace: gwtypes.Namespace("default"), + }}, + To: []gwtypes.ReferenceGrantTo{{ + Group: gwtypes.Group("core"), + Kind: gwtypes.Kind("Service"), + Name: ptrObjName("my-service"), + }}, + }, + backendRef: gwtypes.HTTPBackendRef{ + BackendRef: gwtypes.BackendRef{ + BackendObjectReference: gwtypes.BackendObjectReference{ + Name: gwtypes.ObjectName("my-service"), + Kind: kindPtr(""), + Group: groupPtr(""), + }, + }, + }, + fromNamespace: "default", + want: true, + }, { name: "not granted when group does not match", grantSpec: gwtypes.ReferenceGrantSpec{ diff --git a/test/conformance/skipped_tests_test.go b/test/conformance/skipped_tests_test.go index f0cfd26cef..a5d760a6f3 100644 --- a/test/conformance/skipped_tests_test.go +++ b/test/conformance/skipped_tests_test.go @@ -47,7 +47,6 @@ var skippedTestsForHybrid = []string{ tests.HTTPRoutePathMatchOrder.ShortName, tests.HTTPRouteQueryParamMatching.ShortName, tests.HTTPRouteReferenceGrant.ShortName, - tests.HTTPRouteSimpleSameNamespace.ShortName, tests.HTTPRouteExactPathMatching.ShortName, tests.HTTPRouteHostnameIntersection.ShortName, tests.HTTPRouteCrossNamespace.ShortName,