Skip to content

Wire embedded auth server into VirtualMCPServer converter and deployment#4383

Merged
jhrozek merged 3 commits intomainfrom
vmcp-add-as-scaffolding-5
Mar 27, 2026
Merged

Wire embedded auth server into VirtualMCPServer converter and deployment#4383
jhrozek merged 3 commits intomainfrom
vmcp-add-as-scaffolding-5

Conversation

@jhrozek
Copy link
Copy Markdown
Contributor

@jhrozek jhrozek commented Mar 26, 2026

Summary

  • The VirtualMCPServer operator had no way to convert an inline AuthServerConfig into an authserver.RunConfig or mount auth server secrets onto the vMCP pod. This blocks end-to-end OAuth flows for vMCP.
  • Export BuildAuthServerRunConfig from controllerutil (previously unexported, MCPServer-only) and call it from the vMCP converter, reusing ~450 lines of conversion logic (signing keys, HMAC secrets, upstream providers, Redis/Sentinel storage).
  • Operator: serialize RunConfig as a separate ConfigMap key (authserver-config.yaml), mount auth server volumes/env vars on the deployment, cross-validate auth server config against backend strategies. Spec validation errors now set a status condition instead of requeueing indefinitely.
  • Binary: load sibling authserver-config.yaml if present, construct EmbeddedAuthServer, fail closed on errors.

Fixes #4284

Type of change

  • New feature

Test plan

  • Unit tests (task test)
  • Manual testing (describe below)

Tested end-to-end as part of the full vmcp-add-as-scaffolding-5 branch with a deployed VirtualMCPServer running the embedded auth server.

Changes

File Change
controllerutil/authserver.go Export BuildAuthServerRunConfig, take explicit allowedAudiences/scopesSupported params instead of *oidc.OIDCConfig
vmcpconfig/converter.go Convert() returns (*Config, *RunConfig, error); add convertAuthServerConfig, deriveAllowedAudiences, deriveScopesSupported
virtualmcpserver_vmcpconfig.go Serialize RunConfig as second ConfigMap key; cross-validate via ValidateAuthServerIntegration with status condition on failure
virtualmcpserver_controller.go Add SpecValidationError type and handleSpecValidationError helper for no-requeue on spec errors
virtualmcpserver_deployment.go Mount auth server volumes and env vars when AuthServerConfig is set
cmd/vmcp/app/commands.go loadAuthServerConfig loads sibling file; construct EmbeddedAuthServer in runServe

Special notes for reviewers

  • deriveAllowedAudiences uses only Resource (RFC 8707), no fallback to Audience — consistent with the MCPServer path which hard-requires ResourceURL.
  • deriveScopesSupported normalizes empty slices to nil so the auth server always applies its default scopes when none are configured.
  • The SpecValidationError type distinguishes spec errors (no requeue, set status condition) from transient errors (requeue with backoff), matching the existing validateAuthServerConfig pattern.

🤖 Generated with Claude Code

@github-actions github-actions bot added the size/L Large PR: 600-999 lines changed label Mar 26, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 26, 2026

Codecov Report

❌ Patch coverage is 67.54386% with 37 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.49%. Comparing base (d57d73b) to head (62337a2).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
cmd/vmcp/app/commands.go 44.00% 14 Missing ⚠️
...perator/controllers/virtualmcpserver_controller.go 41.66% 6 Missing and 1 partial ⚠️
...perator/controllers/virtualmcpserver_deployment.go 0.00% 5 Missing and 1 partial ⚠️
...perator/controllers/virtualmcpserver_vmcpconfig.go 75.00% 4 Missing and 1 partial ⚠️
cmd/thv-operator/pkg/vmcpconfig/converter.go 88.63% 3 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4383      +/-   ##
==========================================
- Coverage   69.49%   69.49%   -0.01%     
==========================================
  Files         485      485              
  Lines       49841    49935      +94     
==========================================
+ Hits        34638    34703      +65     
- Misses      12528    12549      +21     
- Partials     2675     2683       +8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jhrozek jhrozek force-pushed the vmcp-add-as-scaffolding-5 branch from 8050a55 to 0810bda Compare March 26, 2026 15:55
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Mar 26, 2026
@jhrozek jhrozek requested a review from tgrunnagle March 26, 2026 16:01
tgrunnagle
tgrunnagle previously approved these changes Mar 26, 2026
@tgrunnagle
Copy link
Copy Markdown
Contributor

Regarding the failing test, this is what claude suggests

"E2E test bug in test/e2e/thv-operator/virtualmcp/virtualmcp_authserver_config_test.go: the test creates a VirtualMCPServer with IncomingAuth.Type = "anonymous" alongside a non-nil AuthServerConfig. During reconciliation, runValidations → validateAuthServerConfig will pass (issuer + upstreams are set) and momentarily set AuthServerConfigValidated = True. But then ensureVmcpConfigConfigMap → ValidateAuthServerIntegration → validateAuthServerRequiresOIDC will fail ("embedded auth server requires OIDC incoming auth"), overwriting the condition to False. The test waits for "True" and will always time out. The test needs either OIDC incoming auth configured, or the test should assert that the condition ends up False (if anonymous auth with an embedded AS is intentionally unsupported).E2E test bug in test/e2e/thv-operator/virtualmcp/virtualmcp_authserver_config_test.go: the test creates a VirtualMCPServer with IncomingAuth.Type = "anonymous" alongside a non-nil AuthServerConfig. During reconciliation, runValidations → validateAuthServerConfig will pass (issuer + upstreams are set) and momentarily set AuthServerConfigValidated = True. But then ensureVmcpConfigConfigMap → ValidateAuthServerIntegration → validateAuthServerRequiresOIDC will fail ("embedded auth server requires OIDC incoming auth"), overwriting the condition to False. The test waits for "True" and will always time out. The test needs either OIDC incoming auth configured, or the test should assert that the condition ends up False (if anonymous auth with an embedded AS is intentionally unsupported)."

jerm-dro
jerm-dro previously approved these changes Mar 26, 2026
@jhrozek jhrozek dismissed stale reviews from jerm-dro and tgrunnagle via d1d62a3 March 26, 2026 22:33
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Mar 26, 2026
@jhrozek jhrozek force-pushed the vmcp-add-as-scaffolding-5 branch from d1d62a3 to 21a42ec Compare March 27, 2026 10:08
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Mar 27, 2026
@jhrozek
Copy link
Copy Markdown
Contributor Author

jhrozek commented Mar 27, 2026

@jerm-dro would you mind re-stamping? There were conflicts plus rebasing the PR atop origin/main caused one function to go over the cyclomatic limit. No changes to the PR logic.

@tgrunnagle
Copy link
Copy Markdown
Contributor

@jhrozek I can stamp after merge conflicts are resolved

jhrozek and others added 3 commits March 27, 2026 15:15
The VirtualMCPServer operator lacked the ability to convert an inline
EmbeddedAuthServerConfig into an authserver.RunConfig and mount the
necessary secrets onto the vMCP pod.

Export BuildAuthServerRunConfig from controllerutil (previously the
unexported buildEmbeddedAuthServerRunnerConfig used only by MCPServer)
and call it from the VirtualMCPServer converter. This avoids duplicating
~450 lines of conversion logic (signing keys, HMAC secrets, upstream
providers, Redis storage with Sentinel) and ensures both controllers
use identical mount paths, env var naming, and Redis key prefix format.

Operator side: serialize the RunConfig as a separate ConfigMap key
(authserver-config.yaml) alongside config.yaml. Mount auth server
volumes and env vars onto the deployment via GenerateAuthServerVolumes
and GenerateAuthServerEnvVars. Cross-validate auth server config
against backend strategies via ValidateAuthServerIntegration.

Binary side: load sibling authserver-config.yaml if present, construct
EmbeddedAuthServer, and pass it to the server config. Fail closed on
read errors other than file-not-found.

Fixes #4284
ValidateAuthServerIntegration (added in 0810bda) requires OIDC
incoming auth when AuthServerConfig is present. The pre-existing E2E
test used anonymous auth, causing the condition to be overwritten to
False and the test to time out.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Convert function exceeded the gocyclo threshold (17 > 15) after
the rebase added both SessionStorage and AuthServerConfig conversion.
Extract the SessionStorage block into a standalone helper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jhrozek jhrozek force-pushed the vmcp-add-as-scaffolding-5 branch from 21a42ec to 62337a2 Compare March 27, 2026 15:36
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Mar 27, 2026
@jhrozek jhrozek merged commit 7cff3cd into main Mar 27, 2026
115 of 127 checks passed
@jhrozek jhrozek deleted the vmcp-add-as-scaffolding-5 branch March 27, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large PR: 600-999 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wire GenerateAuthServerConfig into VirtualMCPServer deployment controller

3 participants