diff --git a/cmd/thv-operator/api/v1alpha1/virtualmcpserver_types.go b/cmd/thv-operator/api/v1alpha1/virtualmcpserver_types.go index 3b784bbe67..27db742973 100644 --- a/cmd/thv-operator/api/v1alpha1/virtualmcpserver_types.go +++ b/cmd/thv-operator/api/v1alpha1/virtualmcpserver_types.go @@ -162,12 +162,12 @@ type OutgoingAuthConfig struct { // BackendAuthConfig defines authentication configuration for a backend MCPServer type BackendAuthConfig struct { // Type defines the authentication type - // +kubebuilder:validation:Enum=discovered;external_auth_config_ref + // +kubebuilder:validation:Enum=discovered;externalAuthConfigRef;external_auth_config_ref // +kubebuilder:validation:Required Type string `json:"type"` // ExternalAuthConfigRef references an MCPExternalAuthConfig resource - // Only used when Type is "external_auth_config_ref" + // Only used when Type is "externalAuthConfigRef" (or deprecated "external_auth_config_ref") // +optional ExternalAuthConfigRef *ExternalAuthConfigRef `json:"externalAuthConfigRef,omitempty"` } @@ -341,7 +341,11 @@ const ( BackendAuthTypeDiscovered = "discovered" // BackendAuthTypeExternalAuthConfigRef references an MCPExternalAuthConfig resource - BackendAuthTypeExternalAuthConfigRef = "external_auth_config_ref" + BackendAuthTypeExternalAuthConfigRef = "externalAuthConfigRef" + + // DeprecatedBackendAuthTypeExternalAuthConfigRef is the old snake_case value. + // Deprecated: Use BackendAuthTypeExternalAuthConfigRef ("externalAuthConfigRef") instead. + DeprecatedBackendAuthTypeExternalAuthConfigRef = "external_auth_config_ref" ) // Workflow step types @@ -495,10 +499,10 @@ func (*VirtualMCPServer) validateBackendAuth(backendName string, auth BackendAut // Validate type-specific configurations switch auth.Type { - case BackendAuthTypeExternalAuthConfigRef: + case BackendAuthTypeExternalAuthConfigRef, DeprecatedBackendAuthTypeExternalAuthConfigRef: if auth.ExternalAuthConfigRef == nil { return fmt.Errorf( - "spec.outgoingAuth.backends[%s].externalAuthConfigRef is required when type is external_auth_config_ref", + "spec.outgoingAuth.backends[%s].externalAuthConfigRef is required when type is externalAuthConfigRef", backendName) } if auth.ExternalAuthConfigRef.Name == "" { @@ -510,7 +514,7 @@ func (*VirtualMCPServer) validateBackendAuth(backendName string, auth BackendAut default: return fmt.Errorf( - "spec.outgoingAuth.backends[%s].type must be one of: discovered, external_auth_config_ref", + "spec.outgoingAuth.backends[%s].type must be one of: discovered, externalAuthConfigRef", backendName) } diff --git a/cmd/thv-operator/api/v1alpha1/virtualmcpserver_types_test.go b/cmd/thv-operator/api/v1alpha1/virtualmcpserver_types_test.go index 73bfe451e0..b6d28bb7be 100644 --- a/cmd/thv-operator/api/v1alpha1/virtualmcpserver_types_test.go +++ b/cmd/thv-operator/api/v1alpha1/virtualmcpserver_types_test.go @@ -276,7 +276,7 @@ func TestBackendAuthConfigTypes(t *testing.T) { isValid: true, }, { - name: "external_auth_config_ref_valid", + name: "externalAuthConfigRef_valid", authConfig: BackendAuthConfig{ Type: BackendAuthTypeExternalAuthConfigRef, ExternalAuthConfigRef: &ExternalAuthConfigRef{ diff --git a/cmd/thv-operator/controllers/virtualmcpserver_controller.go b/cmd/thv-operator/controllers/virtualmcpserver_controller.go index f55dabfbe1..e43e22c674 100644 --- a/cmd/thv-operator/controllers/virtualmcpserver_controller.go +++ b/cmd/thv-operator/controllers/virtualmcpserver_controller.go @@ -1788,7 +1788,7 @@ func (r *VirtualMCPServerReconciler) convertBackendAuthConfigToVMCP( }, nil } - // For type="external_auth_config_ref", fetch and convert the referenced config + // For type="externalAuthConfigRef", fetch and convert the referenced config if crdConfig.ExternalAuthConfigRef != nil { // Fetch the MCPExternalAuthConfig and convert it externalAuthConfig, err := ctrlutil.GetExternalAuthConfigByName( diff --git a/cmd/thv-operator/controllers/virtualmcpserver_externalauth_test.go b/cmd/thv-operator/controllers/virtualmcpserver_externalauth_test.go index 073d9d3eea..eac97e6e23 100644 --- a/cmd/thv-operator/controllers/virtualmcpserver_externalauth_test.go +++ b/cmd/thv-operator/controllers/virtualmcpserver_externalauth_test.go @@ -638,7 +638,7 @@ func TestBuildOutgoingAuthConfig(t *testing.T) { OutgoingAuth: &mcpv1alpha1.OutgoingAuthConfig{ Source: "discovered", Default: &mcpv1alpha1.BackendAuthConfig{ - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "missing-default-auth", // Auth config doesn't exist }, @@ -676,7 +676,7 @@ func TestBuildOutgoingAuthConfig(t *testing.T) { Source: "discovered", Backends: map[string]mcpv1alpha1.BackendAuthConfig{ "api-backend": { - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "missing-backend-auth", }, @@ -765,7 +765,7 @@ func TestConvertBackendAuthConfigToVMCP(t *testing.T) { validate func(*testing.T, *authtypes.BackendAuthStrategy) }{ { - name: "external_auth_config_ref type", + name: "externalAuthConfigRef type", crdConfig: &mcpv1alpha1.BackendAuthConfig{ Type: mcpv1alpha1.BackendAuthTypeExternalAuthConfigRef, ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ diff --git a/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig_test.go b/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig_test.go index 69365a0afe..4ab18a7812 100644 --- a/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig_test.go +++ b/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig_test.go @@ -196,7 +196,7 @@ func TestConvertBackendAuthConfig(t *testing.T) { Name: "auth-config", }, }, - // For external_auth_config_ref, the type comes from the referenced MCPExternalAuthConfig + // For externalAuthConfigRef, the type comes from the referenced MCPExternalAuthConfig expectedType: "unauthenticated", }, } @@ -219,7 +219,7 @@ func TestConvertBackendAuthConfig(t *testing.T) { }, } - // For external_auth_config_ref test, create the referenced MCPExternalAuthConfig + // For externalAuthConfigRef test, create the referenced MCPExternalAuthConfig var converter *vmcpconfigconv.Converter if tt.authConfig.Type == mcpv1alpha1.BackendAuthTypeExternalAuthConfigRef { // Create a fake MCPExternalAuthConfig @@ -259,7 +259,7 @@ func TestConvertBackendAuthConfig(t *testing.T) { // Note: HeaderInjection and TokenExchange are nil because the CRD's // BackendAuthConfig only stores type and reference information. - // For external_auth_config_ref, the actual auth config is resolved + // For externalAuthConfigRef, the actual auth config is resolved // at runtime from the referenced MCPExternalAuthConfig resource. assert.Nil(t, strategy.HeaderInjection) assert.Nil(t, strategy.TokenExchange) diff --git a/cmd/thv-operator/controllers/virtualmcpserver_watch_test.go b/cmd/thv-operator/controllers/virtualmcpserver_watch_test.go index 2305dc9489..a816da9102 100644 --- a/cmd/thv-operator/controllers/virtualmcpserver_watch_test.go +++ b/cmd/thv-operator/controllers/virtualmcpserver_watch_test.go @@ -751,7 +751,7 @@ func TestMapExternalAuthConfigToVirtualMCPServer(t *testing.T) { Spec: mcpv1alpha1.VirtualMCPServerSpec{ OutgoingAuth: &mcpv1alpha1.OutgoingAuthConfig{ Default: &mcpv1alpha1.BackendAuthConfig{ - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "test-auth", }, @@ -781,7 +781,7 @@ func TestMapExternalAuthConfigToVirtualMCPServer(t *testing.T) { OutgoingAuth: &mcpv1alpha1.OutgoingAuthConfig{ Backends: map[string]mcpv1alpha1.BackendAuthConfig{ "backend1": { - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "test-auth", }, @@ -831,7 +831,7 @@ func TestMapExternalAuthConfigToVirtualMCPServer(t *testing.T) { Spec: mcpv1alpha1.VirtualMCPServerSpec{ OutgoingAuth: &mcpv1alpha1.OutgoingAuthConfig{ Default: &mcpv1alpha1.BackendAuthConfig{ - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "test-auth", }, @@ -1406,7 +1406,7 @@ func TestVmcpReferencesExternalAuthConfig(t *testing.T) { Spec: mcpv1alpha1.VirtualMCPServerSpec{ OutgoingAuth: &mcpv1alpha1.OutgoingAuthConfig{ Default: &mcpv1alpha1.BackendAuthConfig{ - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "test-auth", }, @@ -1424,7 +1424,7 @@ func TestVmcpReferencesExternalAuthConfig(t *testing.T) { OutgoingAuth: &mcpv1alpha1.OutgoingAuthConfig{ Backends: map[string]mcpv1alpha1.BackendAuthConfig{ "backend1": { - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "test-auth", }, @@ -1460,7 +1460,7 @@ func TestVmcpReferencesExternalAuthConfig(t *testing.T) { Spec: mcpv1alpha1.VirtualMCPServerSpec{ OutgoingAuth: &mcpv1alpha1.OutgoingAuthConfig{ Default: &mcpv1alpha1.BackendAuthConfig{ - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "other-auth", }, @@ -1478,13 +1478,13 @@ func TestVmcpReferencesExternalAuthConfig(t *testing.T) { OutgoingAuth: &mcpv1alpha1.OutgoingAuthConfig{ Backends: map[string]mcpv1alpha1.BackendAuthConfig{ "backend1": { - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "other-auth", }, }, "backend2": { - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: "test-auth", }, diff --git a/cmd/thv-operator/pkg/vmcpconfig/converter.go b/cmd/thv-operator/pkg/vmcpconfig/converter.go index 4e8d51eed8..2b29aaefce 100644 --- a/cmd/thv-operator/pkg/vmcpconfig/converter.go +++ b/cmd/thv-operator/pkg/vmcpconfig/converter.go @@ -452,10 +452,20 @@ func (c *Converter) convertBackendAuthConfig( }, nil } - // If type is "external_auth_config_ref", resolve the MCPExternalAuthConfig - if crdConfig.Type == mcpv1alpha1.BackendAuthTypeExternalAuthConfigRef { + // Handle deprecated snake_case value + if crdConfig.Type == mcpv1alpha1.DeprecatedBackendAuthTypeExternalAuthConfigRef { + log.FromContext(ctx).Info( + "backend auth type \"external_auth_config_ref\" is deprecated,"+ + " use \"externalAuthConfigRef\" instead", + "backend", backendName, "vmcp", vmcp.Name, + ) + } + + // If type is "externalAuthConfigRef" (or deprecated "external_auth_config_ref"), resolve the MCPExternalAuthConfig + if crdConfig.Type == mcpv1alpha1.BackendAuthTypeExternalAuthConfigRef || + crdConfig.Type == mcpv1alpha1.DeprecatedBackendAuthTypeExternalAuthConfigRef { if crdConfig.ExternalAuthConfigRef == nil { - return nil, fmt.Errorf("backend %s: external_auth_config_ref type requires externalAuthConfigRef field", backendName) + return nil, fmt.Errorf("backend %s: externalAuthConfigRef type requires externalAuthConfigRef field", backendName) } // Fetch the MCPExternalAuthConfig resource diff --git a/deploy/charts/operator-crds/files/crds/toolhive.stacklok.dev_virtualmcpservers.yaml b/deploy/charts/operator-crds/files/crds/toolhive.stacklok.dev_virtualmcpservers.yaml index 1ae8c86f14..f919af400e 100644 --- a/deploy/charts/operator-crds/files/crds/toolhive.stacklok.dev_virtualmcpservers.yaml +++ b/deploy/charts/operator-crds/files/crds/toolhive.stacklok.dev_virtualmcpservers.yaml @@ -2136,7 +2136,7 @@ spec: externalAuthConfigRef: description: |- ExternalAuthConfigRef references an MCPExternalAuthConfig resource - Only used when Type is "external_auth_config_ref" + Only used when Type is "externalAuthConfigRef" (or deprecated "external_auth_config_ref") properties: name: description: Name is the name of the MCPExternalAuthConfig @@ -2149,6 +2149,7 @@ spec: description: Type defines the authentication type enum: - discovered + - externalAuthConfigRef - external_auth_config_ref type: string required: @@ -2165,7 +2166,7 @@ spec: externalAuthConfigRef: description: |- ExternalAuthConfigRef references an MCPExternalAuthConfig resource - Only used when Type is "external_auth_config_ref" + Only used when Type is "externalAuthConfigRef" (or deprecated "external_auth_config_ref") properties: name: description: Name is the name of the MCPExternalAuthConfig @@ -2178,6 +2179,7 @@ spec: description: Type defines the authentication type enum: - discovered + - externalAuthConfigRef - external_auth_config_ref type: string required: diff --git a/deploy/charts/operator-crds/templates/toolhive.stacklok.dev_virtualmcpservers.yaml b/deploy/charts/operator-crds/templates/toolhive.stacklok.dev_virtualmcpservers.yaml index 572d3ba010..8e7e666468 100644 --- a/deploy/charts/operator-crds/templates/toolhive.stacklok.dev_virtualmcpservers.yaml +++ b/deploy/charts/operator-crds/templates/toolhive.stacklok.dev_virtualmcpservers.yaml @@ -2139,7 +2139,7 @@ spec: externalAuthConfigRef: description: |- ExternalAuthConfigRef references an MCPExternalAuthConfig resource - Only used when Type is "external_auth_config_ref" + Only used when Type is "externalAuthConfigRef" (or deprecated "external_auth_config_ref") properties: name: description: Name is the name of the MCPExternalAuthConfig @@ -2152,6 +2152,7 @@ spec: description: Type defines the authentication type enum: - discovered + - externalAuthConfigRef - external_auth_config_ref type: string required: @@ -2168,7 +2169,7 @@ spec: externalAuthConfigRef: description: |- ExternalAuthConfigRef references an MCPExternalAuthConfig resource - Only used when Type is "external_auth_config_ref" + Only used when Type is "externalAuthConfigRef" (or deprecated "external_auth_config_ref") properties: name: description: Name is the name of the MCPExternalAuthConfig @@ -2181,6 +2182,7 @@ spec: description: Type defines the authentication type enum: - discovered + - externalAuthConfigRef - external_auth_config_ref type: string required: diff --git a/docs/operator/crd-api.md b/docs/operator/crd-api.md index 4789885ba7..b707a8553b 100644 --- a/docs/operator/crd-api.md +++ b/docs/operator/crd-api.md @@ -888,8 +888,8 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `type` _string_ | Type defines the authentication type | | Enum: [discovered external_auth_config_ref]
Required: \{\}
| -| `externalAuthConfigRef` _[api.v1alpha1.ExternalAuthConfigRef](#apiv1alpha1externalauthconfigref)_ | ExternalAuthConfigRef references an MCPExternalAuthConfig resource
Only used when Type is "external_auth_config_ref" | | Optional: \{\}
| +| `type` _string_ | Type defines the authentication type | | Enum: [discovered externalAuthConfigRef external_auth_config_ref]
Required: \{\}
| +| `externalAuthConfigRef` _[api.v1alpha1.ExternalAuthConfigRef](#apiv1alpha1externalauthconfigref)_ | ExternalAuthConfigRef references an MCPExternalAuthConfig resource
Only used when Type is "externalAuthConfigRef" (or deprecated "external_auth_config_ref") | | Optional: \{\}
| #### api.v1alpha1.BearerTokenConfig diff --git a/test/e2e/thv-operator/virtualmcp/virtualmcp_external_auth_test.go b/test/e2e/thv-operator/virtualmcp/virtualmcp_external_auth_test.go index fd1d73e47c..564ac7f04a 100644 --- a/test/e2e/thv-operator/virtualmcp/virtualmcp_external_auth_test.go +++ b/test/e2e/thv-operator/virtualmcp/virtualmcp_external_auth_test.go @@ -281,7 +281,7 @@ var _ = Describe("VirtualMCPServer Inline Unauthenticated Backend Auth", Ordered // Explicitly configure unauthenticated for specific backend Backends: map[string]mcpv1alpha1.BackendAuthConfig{ backendName: { - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: externalAuthConfigName, }, @@ -328,7 +328,7 @@ var _ = Describe("VirtualMCPServer Inline Unauthenticated Backend Auth", Ordered Expect(k8sClient.Get(ctx, types.NamespacedName{Name: vmcpServerName, Namespace: testNamespace}, vmcpServer)).To(Succeed()) Expect(vmcpServer.Spec.OutgoingAuth.Source).To(Equal("inline")) Expect(vmcpServer.Spec.OutgoingAuth.Backends).To(HaveKey(backendName)) - Expect(vmcpServer.Spec.OutgoingAuth.Backends[backendName].Type).To(Equal("external_auth_config_ref")) + Expect(vmcpServer.Spec.OutgoingAuth.Backends[backendName].Type).To(Equal("externalAuthConfigRef")) Expect(vmcpServer.Spec.OutgoingAuth.Backends[backendName].ExternalAuthConfigRef.Name).To(Equal(externalAuthConfigName)) By("Creating MCP client and listing tools") @@ -680,7 +680,7 @@ var _ = Describe("VirtualMCPServer Inline HeaderInjection Backend Auth", Ordered // Explicitly configure headerInjection for specific backend Backends: map[string]mcpv1alpha1.BackendAuthConfig{ backendName: { - Type: "external_auth_config_ref", + Type: "externalAuthConfigRef", ExternalAuthConfigRef: &mcpv1alpha1.ExternalAuthConfigRef{ Name: externalAuthConfigName, }, @@ -730,7 +730,7 @@ var _ = Describe("VirtualMCPServer Inline HeaderInjection Backend Auth", Ordered Expect(k8sClient.Get(ctx, types.NamespacedName{Name: vmcpServerName, Namespace: testNamespace}, vmcpServer)).To(Succeed()) Expect(vmcpServer.Spec.OutgoingAuth.Source).To(Equal("inline")) Expect(vmcpServer.Spec.OutgoingAuth.Backends).To(HaveKey(backendName)) - Expect(vmcpServer.Spec.OutgoingAuth.Backends[backendName].Type).To(Equal("external_auth_config_ref")) + Expect(vmcpServer.Spec.OutgoingAuth.Backends[backendName].Type).To(Equal("externalAuthConfigRef")) Expect(vmcpServer.Spec.OutgoingAuth.Backends[backendName].ExternalAuthConfigRef.Name).To(Equal(externalAuthConfigName)) By("Creating MCP client and listing tools")