Skip to content

Align operator validation/defaulting with MCP server webhook#69

Merged
Agent-Hellboy merged 4 commits intomainfrom
fix-issue-18-operator-validation-defaulting
Apr 29, 2026
Merged

Align operator validation/defaulting with MCP server webhook#69
Agent-Hellboy merged 4 commits intomainfrom
fix-issue-18-operator-validation-defaulting

Conversation

@Agent-Hellboy
Copy link
Copy Markdown
Owner

@Agent-Hellboy Agent-Hellboy commented Apr 27, 2026

Summary by CodeRabbit

  • New Features

    • Automatic defaulting for server deployments: image tag, replica count, ports, ingress/public path, and gateway-related settings are populated when omitted.
  • Improvements

    • Stricter validation for routing, gateway/OAuth, rollout limits, and analytics API key presence.
    • Validation now provides clearer errors and prevents invalid configurations from proceeding.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f361d9d3-89ce-494f-9614-5a5a9c4a9459

📥 Commits

Reviewing files that changed from the base of the PR and between c492c66 and e3bce69.

📒 Files selected for processing (7)
  • .pre-commit-config.yaml
  • api/v1alpha1/validation.go
  • api/v1alpha1/validation_test.go
  • docs/internals/go-package-reference.md
  • internal/operator/controller.go
  • internal/operator/controller_test.go
  • test/integration/envtest_test.go
✅ Files skipped from review due to trivial changes (2)
  • test/integration/envtest_test.go
  • api/v1alpha1/validation_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/operator/controller_test.go

📝 Walkthrough

Walkthrough

Adds a mutating webhook Default() for MCPServer and moves extensive defaulting/validation into the CRD; the operator controller now delegates MCPServer spec validation/defaulting to the API layer and simplifies its reconciliation logic.

Changes

Cohort / File(s) Summary
API Validation & Defaulting
api/v1alpha1/validation.go
Adds (*MCPServer).Default() webhook and helper functions; defaults image tag, replicas, ports, ingress/publicPath values, gateway auth/policy/session/tool trust, analytics, and rollout settings. Extends ValidateCreate() rules (routing requirements, OAuth issuer when gateway+OAuth, canary replica requirements, stricter rollout value parsing, analytics secretRef checks).
API Validation Tests
api/v1alpha1/validation_test.go
Adds unit tests asserting default population and validation failures (missing canary replicas, missing OAuth issuer, invalid rollout values, ingressHost/ingressPath/ publicPathPrefix prerequisites).
Operator Controller
internal/operator/controller.go
Replaces many operator-side checks with mcpServer.Default() and mcpServer.ValidateCreate() gate; narrows validateIngressConfig() behaviour; removes duplicated operator validations and rollout parsing helper; preserves operator-only fallback for IngressHost and analytics ingest URL.
Operator Controller Tests
internal/operator/controller_test.go
Updates tests to call validateMCPServerSpec(...) and adjust expectations (now deriving IngressHost from reconciler's default and supplying explicit IngressPath in some tests).
Pre-commit & CI hooks
.pre-commit-config.yaml
Replaces generated-doc drift hook with test-focused hooks: adds go-unit-tests, go-integration-tests, and generated-file-drift (regenerates artifacts and fails on diffs for generated files).
Documentation
docs/internals/go-package-reference.md
Documents the new mutating webhook marker for MCPServer (+kubebuilder:webhook for mutate on create/update).
Integration Test Fix
test/integration/envtest_test.go
Adjusts ReconcileAppliesDefaults test input to include explicit IngressPath to match new defaulting/validation expectations.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Client as API Client
    participant APIServer as Kubernetes<br/>API Server
    participant Webhook as MCPServer<br/>Mutating/Validating Webhook
    participant CRD as MCPServer<br/>Stored Resource
    participant Operator as MCPServer<br/>Controller

    User->>Client: Create MCPServer resource
    Client->>APIServer: POST /apis/.../mcpservers
    APIServer->>Webhook: AdmissionRequest (mutate/validate)
    Webhook->>Webhook: Default() sets missing fields
    Webhook->>Webhook: ValidateCreate() enforces rules
    alt Validation fails
        Webhook-->>APIServer: AdmissionResponse (reject + errors)
        APIServer-->>Client: Error response
    else Validation succeeds
        Webhook-->>APIServer: AdmissionResponse (allow, mutated object)
        APIServer->>CRD: Persist mutated MCPServer
        CRD->>Operator: Inform controller (watch event)
        Operator->>Operator: Reconcile using validated/defaulted spec
        Operator-->>CRD: Update status
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I nudged defaults into webhook light,
Fields now whisper, tidy and right.
Controller breathes with less to do,
Specs get checked, then whole again too.
Hop, deploy — a springtime review!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Align operator validation/defaulting with MCP server webhook' accurately and specifically describes the main objective of this changeset, which reorganizes validation and defaulting logic between the operator controller and API webhook.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-issue-18-operator-validation-defaulting

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@Agent-Hellboy
Copy link
Copy Markdown
Owner Author

@codex please review

@Agent-Hellboy
Copy link
Copy Markdown
Owner Author

@coderabbitai please review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

@Agent-Hellboy, sure! I'll kick off a review of this PR right away.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c492c66806

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/operator/controller.go Outdated
Comment on lines +327 to +328
if strings.TrimSpace(mcpServer.Spec.IngressHost) == "" && strings.TrimSpace(mcpServer.Spec.PublicPathPrefix) == "" {
mcpServer.Spec.IngressHost = strings.TrimSpace(r.DefaultIngressHost)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve DefaultIngressHost fallback when deriving publicPathPrefix

setDefaults now calls mcpServer.Default() first, which populates spec.publicPathPrefix from metadata.name; as a result, this if condition is never true for normal named resources, so DefaultIngressHost is never applied. In clusters that rely on MCP_DEFAULT_INGRESS_HOST for host-based routing, servers created without an explicit spec.ingressHost will silently stay hostless and route via path-prefix mode instead of the configured default host.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/operator/controller.go (1)

183-197: ValidateCreate() is duplicated and error labeling is misleading.

Both validateIngressConfig() and validateGatewayConfig() run full ValidateCreate() against the same object. This adds redundant work and can report gateway/rollout/auth validation failures as “Invalid ingress configuration”.

♻️ Suggested simplification
 func (r *MCPServerReconciler) validateIngressConfig(ctx context.Context, mcpServer *mcpv1alpha1.MCPServer, logger logr.Logger) error {
 	if _, err := mcpServer.ValidateCreate(); err != nil {
 		r.updateStatus(ctx, mcpServer, "Error", err.Error(), resourceReadiness{})
-		logOperatorError(logger, err, "Invalid ingress configuration")
+		logOperatorError(logger, err, "Invalid MCPServer specification")
 		return err
 	}
 	return nil
 }

 func (r *MCPServerReconciler) validateGatewayConfig(ctx context.Context, mcpServer *mcpv1alpha1.MCPServer, logger logr.Logger) error {
-	if _, err := mcpServer.ValidateCreate(); err != nil {
-		r.updateStatus(ctx, mcpServer, "Error", err.Error(), resourceReadiness{})
-		logOperatorError(logger, err, "Invalid gateway configuration")
-		return err
-	}
-
 	if gatewayEnabled(mcpServer) {
 		if _, err := r.resolveGatewayImage(mcpServer); err != nil {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/operator/controller.go` around lines 183 - 197, Both
validateIngressConfig and validateGatewayConfig call mcpServer.ValidateCreate(),
causing redundant validation and mislabelled errors; to fix, remove the direct
ValidateCreate() call from these two functions and centralize the call once
(either in the reconcile entrypoint or a new helper like validateCommonConfig
that invokes mcpServer.ValidateCreate()), then have validateIngressConfig and
validateGatewayConfig perform only their specific checks and call
updateStatus/logOperatorError with the correct context-specific messages
("Invalid ingress configuration" in validateIngressConfig and "Invalid gateway
configuration" in validateGatewayConfig) so errors are not misattributed;
reference the functions validateIngressConfig, validateGatewayConfig,
ValidateCreate, updateStatus, and logOperatorError when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/operator/controller.go`:
- Around line 324-329: The fallback for IngressHost runs after calling
mcpServer.Default(), but Default() may populate Spec.PublicPathPrefix from
metadata.name which causes the conditional to be false and prevents applying
DefaultIngressHost; to fix, capture whether PublicPathPrefix was empty before
calling mcpServer.Default() (e.g. save origPrefix :=
strings.TrimSpace(mcpServer.Spec.PublicPathPrefix)), then call
mcpServer.Default(), and only set mcpServer.Spec.IngressHost =
strings.TrimSpace(r.DefaultIngressHost) when
strings.TrimSpace(mcpServer.Spec.IngressHost) == "" && origPrefix == "" so
DefaultIngressHost is applied when the user didn’t supply a publicPathPrefix.

---

Nitpick comments:
In `@internal/operator/controller.go`:
- Around line 183-197: Both validateIngressConfig and validateGatewayConfig call
mcpServer.ValidateCreate(), causing redundant validation and mislabelled errors;
to fix, remove the direct ValidateCreate() call from these two functions and
centralize the call once (either in the reconcile entrypoint or a new helper
like validateCommonConfig that invokes mcpServer.ValidateCreate()), then have
validateIngressConfig and validateGatewayConfig perform only their specific
checks and call updateStatus/logOperatorError with the correct context-specific
messages ("Invalid ingress configuration" in validateIngressConfig and "Invalid
gateway configuration" in validateGatewayConfig) so errors are not
misattributed; reference the functions validateIngressConfig,
validateGatewayConfig, ValidateCreate, updateStatus, and logOperatorError when
making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1bef83eb-d11d-46ee-a645-744457a09bb2

📥 Commits

Reviewing files that changed from the base of the PR and between 68111fb and c492c66.

📒 Files selected for processing (4)
  • api/v1alpha1/validation.go
  • api/v1alpha1/validation_test.go
  • internal/operator/controller.go
  • internal/operator/controller_test.go

Comment thread internal/operator/controller.go
@Agent-Hellboy
Copy link
Copy Markdown
Owner Author

@code-review-assist please review

Agent-Hellboy added a commit that referenced this pull request Apr 29, 2026
@Agent-Hellboy Agent-Hellboy force-pushed the fix-issue-18-operator-validation-defaulting branch from 17d5128 to 93cf12d Compare April 29, 2026 11:21
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Codecov Report

❌ Patch coverage is 46.71533% with 73 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.14%. Comparing base (147f381) to head (e3bce69).
⚠️ Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
api/v1alpha1/validation.go 40.33% 59 Missing and 12 partials ⚠️
internal/operator/controller.go 88.88% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #69      +/-   ##
==========================================
+ Coverage   57.05%   57.14%   +0.09%     
==========================================
  Files          59       59              
  Lines       10489    10436      -53     
==========================================
- Hits         5984     5964      -20     
+ Misses       3939     3903      -36     
- Partials      566      569       +3     
Flag Coverage Δ
pre-merge 57.14% <46.71%> (+0.09%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
internal/operator/controller.go 63.58% <88.88%> (+3.14%) ⬆️
api/v1alpha1/validation.go 36.03% <40.33%> (+10.80%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Agent-Hellboy Agent-Hellboy merged commit 6ef92df into main Apr 29, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant