@@ -95,7 +95,7 @@ func (v *referenceGrantValidator) validateReference(
9595 // Check if any ReferenceGrant allows this cross-namespace reference.
9696 for i := range referenceGrants .Items {
9797 grant := & referenceGrants .Items [i ]
98- if v .isReferenceGrantValid (grant , routeNamespace , targetGroup , targetKind ) {
98+ if v .isReferenceGrantValid (grant , routeNamespace , targetGroup , targetKind , gwapiv1b1 . ObjectName ( targetName ) ) {
9999 return nil
100100 }
101101 }
@@ -109,12 +109,13 @@ func (v *referenceGrantValidator) validateReference(
109109}
110110
111111// isReferenceGrantValid checks if a ReferenceGrant allows an AIGatewayRoute to reference the
112- // target resource identified by targetGroup/targetKind.
112+ // target resource identified by targetGroup/targetKind/targetName .
113113func (v * referenceGrantValidator ) isReferenceGrantValid (
114114 grant * gwapiv1b1.ReferenceGrant ,
115115 fromNamespace string ,
116116 targetGroup gwapiv1b1.Group ,
117117 targetKind gwapiv1b1.Kind ,
118+ targetName gwapiv1b1.ObjectName ,
118119) bool {
119120 // Check if the grant allows references from the route's namespace.
120121 fromAllowed := false
@@ -131,7 +132,7 @@ func (v *referenceGrantValidator) isReferenceGrantValid(
131132
132133 // Check if the grant allows references to the target resource.
133134 for _ , to := range grant .Spec .To {
134- if v .matchesTo (& to , targetGroup , targetKind ) {
135+ if v .matchesTo (& to , targetGroup , targetKind , targetName ) {
135136 return true
136137 }
137138 }
@@ -159,22 +160,31 @@ func (v *referenceGrantValidator) matchesFrom(from *gwapiv1b1.ReferenceGrantFrom
159160 return true
160161}
161162
162- // matchesTo checks if a ReferenceGrantTo matches the target resource identified by targetGroup/targetKind.
163- func (v * referenceGrantValidator ) matchesTo (to * gwapiv1b1.ReferenceGrantTo , targetGroup gwapiv1b1.Group , targetKind gwapiv1b1.Kind ) bool {
164- // Check group
163+ // matchesTo checks if a ReferenceGrantTo matches the target resource identified by
164+ // targetGroup/targetKind/targetName.
165+ //
166+ // Per the Gateway API spec, ReferenceGrantTo.Name is optional. When set, the grant is scoped
167+ // to exactly that named resource; when unset, it acts as a wildcard covering every resource of
168+ // the group/kind. Previously we ignored the name field entirely, which quietly promoted any
169+ // name-scoped grant into a wildcard and let an AIGatewayRoute reference *any* backend of the
170+ // same kind in the target namespace — not what the grant author meant.
171+ //
172+ // https://gateway-api.sigs.k8s.io/api-types/referencegrant/
173+ func (v * referenceGrantValidator ) matchesTo (
174+ to * gwapiv1b1.ReferenceGrantTo ,
175+ targetGroup gwapiv1b1.Group ,
176+ targetKind gwapiv1b1.Kind ,
177+ targetName gwapiv1b1.ObjectName ,
178+ ) bool {
165179 if to .Group != targetGroup {
166180 return false
167181 }
168-
169- // Check kind
170182 if to .Kind != targetKind {
171183 return false
172184 }
173-
174- // If a specific name is specified, we would need to check it here,
175- // but ReferenceGrant typically doesn't specify individual resource names
176- // (that's handled by the Name field which is optional in the spec)
177- // For now, we only check group and kind as per Gateway API spec
178-
185+ // Name is optional in ReferenceGrantTo. Unset == wildcard; set == exact match required.
186+ if to .Name != nil && * to .Name != targetName {
187+ return false
188+ }
179189 return true
180190}
0 commit comments