Background
MCPServer and (as of #5630) MCPRemoteProxy both validate the OIDC CA bundle reference and surface a CABundleRefValidated status condition (Valid / NotFound / Invalid). VirtualMCPServer is now the only OIDC-capable workload type without this.
VirtualMCPServer does mount the OIDC CA bundle — cmd/thv-operator/controllers/virtualmcpserver_deployment.go:321 calls the shared ctrlutil.AddOIDCConfigRefCABundleVolumes helper via vmcp.Spec.IncomingAuth.OIDCConfigRef — but it performs no validation of the referenced ConfigMap/key and sets no condition. If the CA bundle ConfigMap is missing or the key is absent, the volume is silently mounted referencing a non-existent ConfigMap (the pod fails to start) with no kubectl-visible signal. This is exactly the silent-acceptance gap the .claude/rules/operator.md "Status Condition Parity" rule warns about.
Scope
Add validateCABundleRef + a CABundleRefValidated condition to VirtualMCPServer, mirroring the MCPRemoteProxy implementation (#5630). Investigation notes on the concrete work:
- Types: add
ConditionTypeVirtualMCPServerCABundleRefValidated + 3 reason constants in cmd/thv-operator/api/v1beta1/virtualmcpserver_types.go (mirror the TelemetryConfigRefValidated block).
- StatusManager: vMCP routes conditions through
pkg/virtualmcpserverstatus (StatusManager/StatusCollector), not direct r.Status().Update. Add a SetCABundleRefValidatedCondition(...) to the interface + collector and regenerate the mock (task gen).
- Controller: add
validateCABundleRef(ctx, vmcp, statusManager) reading vmcp.Spec.IncomingAuth.OIDCConfigRef → oidcCfg.Spec.Inline.CABundleRef, reusing validation.ValidateCABundleSource + ConfigMap/key existence checks. Guard with vmcp.Spec.IncomingAuth != nil. Wire into runValidations (virtualmcpserver_controller.go) following the advisory (non-error-returning) validator pattern.
- Tests: unit + envtest in
cmd/thv-operator/test-integration/virtualmcp/.
Estimated effort: comparable to #5630, slightly more plumbing due to the StatusManager/mock indirection. No new CRD spec fields, so no schema change.
Surfaced during review of #5630 (which closed the same gap for MCPRemoteProxy, ref #4113).
Background
MCPServerand (as of #5630)MCPRemoteProxyboth validate the OIDC CA bundle reference and surface aCABundleRefValidatedstatus condition (Valid / NotFound / Invalid).VirtualMCPServeris now the only OIDC-capable workload type without this.VirtualMCPServerdoes mount the OIDC CA bundle —cmd/thv-operator/controllers/virtualmcpserver_deployment.go:321calls the sharedctrlutil.AddOIDCConfigRefCABundleVolumeshelper viavmcp.Spec.IncomingAuth.OIDCConfigRef— but it performs no validation of the referenced ConfigMap/key and sets no condition. If the CA bundle ConfigMap is missing or the key is absent, the volume is silently mounted referencing a non-existent ConfigMap (the pod fails to start) with no kubectl-visible signal. This is exactly the silent-acceptance gap the.claude/rules/operator.md"Status Condition Parity" rule warns about.Scope
Add
validateCABundleRef+ aCABundleRefValidatedcondition toVirtualMCPServer, mirroring theMCPRemoteProxyimplementation (#5630). Investigation notes on the concrete work:ConditionTypeVirtualMCPServerCABundleRefValidated+ 3 reason constants incmd/thv-operator/api/v1beta1/virtualmcpserver_types.go(mirror theTelemetryConfigRefValidatedblock).pkg/virtualmcpserverstatus(StatusManager/StatusCollector), not directr.Status().Update. Add aSetCABundleRefValidatedCondition(...)to the interface + collector and regenerate the mock (task gen).validateCABundleRef(ctx, vmcp, statusManager)readingvmcp.Spec.IncomingAuth.OIDCConfigRef→oidcCfg.Spec.Inline.CABundleRef, reusingvalidation.ValidateCABundleSource+ ConfigMap/key existence checks. Guard withvmcp.Spec.IncomingAuth != nil. Wire intorunValidations(virtualmcpserver_controller.go) following the advisory (non-error-returning) validator pattern.cmd/thv-operator/test-integration/virtualmcp/.Estimated effort: comparable to #5630, slightly more plumbing due to the StatusManager/mock indirection. No new CRD spec fields, so no schema change.
Surfaced during review of #5630 (which closed the same gap for
MCPRemoteProxy, ref #4113).