From eeeac3543af8425a45a39808d6d40dbc5f6d3e5a Mon Sep 17 00:00:00 2001 From: "Barrera, Angel" Date: Mon, 29 Sep 2025 19:13:42 +0200 Subject: [PATCH] fix: default namespace for cross-namespace ref validation When cross-namespace references are disabled, ensure that UpstreamRef, MetricTemplateRef, and AlertProviderRef default to the canary's namespace if their namespace field is empty. This aligns the validation logic with the rest of the controller and prevents false positives when the namespace is omitted. Fixes #1827 Signed-off-by: Barrera, Angel --- pkg/controller/controller.go | 29 ++++++++++++++++++++++++----- pkg/controller/controller_test.go | 22 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 6a0ead6d..39c72c37 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -345,17 +345,36 @@ func (c *Controller) verifyCanary(canary *flaggerv1.Canary) error { } func verifyNoCrossNamespaceRefs(canary *flaggerv1.Canary) error { - if canary.Spec.UpstreamRef != nil && canary.Spec.UpstreamRef.Namespace != canary.Namespace { - return fmt.Errorf("can't access gloo upstream %s.%s, cross-namespace references are blocked", canary.Spec.UpstreamRef.Name, canary.Spec.UpstreamRef.Namespace) + if canary.Spec.UpstreamRef != nil { + // Default to canary namespace if upstreamRef namespace is empty + namespace := canary.Spec.UpstreamRef.Namespace + if namespace == "" { + namespace = canary.Namespace + } + if namespace != canary.Namespace { + return fmt.Errorf("can't access gloo upstream %s.%s, cross-namespace references are blocked", canary.Spec.UpstreamRef.Name, canary.Spec.UpstreamRef.Namespace) + } } if canary.Spec.Analysis != nil { for _, metric := range canary.Spec.Analysis.Metrics { - if metric.TemplateRef != nil && metric.TemplateRef.Namespace != canary.Namespace { - return fmt.Errorf("can't access metric template %s.%s, cross-namespace references are blocked", metric.TemplateRef.Name, metric.TemplateRef.Namespace) + if metric.TemplateRef != nil { + // Default to canary namespace if templateRef namespace is empty + namespace := metric.TemplateRef.Namespace + if namespace == "" { + namespace = canary.Namespace + } + if namespace != canary.Namespace { + return fmt.Errorf("can't access metric template %s.%s, cross-namespace references are blocked", metric.TemplateRef.Name, metric.TemplateRef.Namespace) + } } } for _, alert := range canary.Spec.Analysis.Alerts { - if alert.ProviderRef.Namespace != canary.Namespace { + // Default to canary namespace if providerRef namespace is empty + namespace := alert.ProviderRef.Namespace + if namespace == "" { + namespace = canary.Namespace + } + if namespace != canary.Namespace { return fmt.Errorf("can't access alert provider %s.%s, cross-namespace references are blocked", alert.ProviderRef.Name, alert.ProviderRef.Namespace) } } diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index aa7a1ee4..2676210d 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -70,6 +70,28 @@ func TestController_verifyCanary(t *testing.T) { }, wantErr: true, }, + { + name: "MetricTemplate in same namespace with no namespace specified should not return an error", + canary: flaggerv1.Canary{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cd-1", + Namespace: "default", + }, + Spec: flaggerv1.CanarySpec{ + Analysis: &flaggerv1.CanaryAnalysis{ + Metrics: []flaggerv1.CanaryMetric{ + { + TemplateRef: &flaggerv1.CrossNamespaceObjectReference{ + Name: "mt-1", + Namespace: "", + }, + }, + }, + }, + }, + }, + wantErr: false, + }, { name: "AlertProvider in a different namespace should return an error", canary: flaggerv1.Canary{