Skip to content

fix(operator): move defaults to admission webhook#194

Open
Agent-Hellboy wants to merge 2 commits into
mainfrom
operator/admission_defaults_validation
Open

fix(operator): move defaults to admission webhook#194
Agent-Hellboy wants to merge 2 commits into
mainfrom
operator/admission_defaults_validation

Conversation

@Agent-Hellboy
Copy link
Copy Markdown
Owner

Summary

  • Move MCPServer defaulting into the admission webhook path and register webhook markers on API root types so controller-gen emits webhook configs.
  • Keep reconciler compatibility for legacy/unadmitted objects by defaulting an in-memory copy without patching stored spec fields.
  • Wire setup to install webhook service/configuration, generate webhook TLS, mount serving certs into the operator, and inject the CA bundle.
  • Refresh generated manifests/docs and update tests for webhook setup and non-persisted defaults.

Fixes #18

Validation

  • go test ./... -count=1
  • go vet ./...
  • pre-commit run gitleaks --all-files
  • Commit hook: gitleaks, go fmt, staticcheck, go vet, go unit tests, go integration tests, generated file drift

@Agent-Hellboy Agent-Hellboy marked this pull request as ready for review May 15, 2026 19:19
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request transitions the application and persistence of default values from the operator's reconciliation loop to Kubernetes admission webhooks. It introduces a mechanism to pass environment-specific defaults to the webhooks via a new options structure and updates the reconciler to use in-memory defaulting for legacy objects. Additionally, the CLI setup process is enhanced to manage webhook TLS certificates and manifest injection. Review feedback identifies a missing yaml import in the setup package, suggests extending the CA certificate's lifespan for better rotation practices, and recommends using reliable path resolution for reading configuration files.


func injectOperatorWebhookCABundle(webhookYAML, caBundlePEM []byte) ([]byte, error) {
caBundle := base64.StdEncoding.EncodeToString(caBundlePEM)
decoder := yaml.NewDecoder(bytes.NewReader(webhookYAML))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

The yaml package is used here (via yaml.NewDecoder), but it is not included in the file's import block. This will cause a compilation error. Please add "gopkg.in/yaml.v3" to the imports.

Comment on lines +1781 to +1791
caTemplate := x509.Certificate{
SerialNumber: caSerialNumber,
Subject: pkix.Name{
CommonName: operatorWebhookServiceName + "-ca",
},
NotBefore: now.Add(-1 * time.Hour),
NotAfter: now.AddDate(1, 0, 0),
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
BasicConstraintsValid: true,
IsCA: true,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The CA certificate and the serving certificate are configured with the same expiration date (1 year from now). It is a best practice for a Certificate Authority to have a longer lifetime than the certificates it signs to ensure continuity during rotation. Consider increasing the NotAfter duration for the caTemplate.

References
  1. Certificates signed by a CA should generally have a shorter lifespan than the CA itself to avoid simultaneous expiration issues.

Comment on lines +1826 to +1834
serviceYAML, err := os.ReadFile("config/webhook/service.yaml")
if err != nil {
return fmt.Errorf("read operator webhook service manifest: %w", err)
}
if err := kube.ApplyManifestContent(kubectl.CommandArgs, string(serviceYAML)); err != nil {
return err
}

webhookYAML, err := os.ReadFile("config/webhook/manifests.yaml")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

These os.ReadFile calls use relative paths (config/webhook/...). While consistent with some other parts of this file, this makes the setup command fragile if executed from a directory other than the repository root. Consider using assetpath.ResolveRepoAssetPath to resolve these paths reliably.

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: 907caeb45e

ℹ️ 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".

if requeue {
return ctrl.Result{}, nil
}
mcpServer = r.defaultedMCPServerForReconcile(mcpServer)
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 Reinstate reconcile-time validation fallback

The reconcile loop now defaults the object and proceeds without any MCPServer spec validation, but webhook registration is still conditional on MCP_ENABLE_WEBHOOKS (cmd/operator/main.go). In installs where that env var is unset/false (for example config/default style deployments or older operator pods), malformed CRs such as OAuth without required issuer fields or invalid rollout values bypass admission and reach reconciliation, causing late runtime/deployment failures instead of deterministic API rejection. Please keep controller-side validation as a fallback (or hard-require webhooks at startup) so non-webhook environments don’t silently accept invalid specs.

Useful? React with 👍 / 👎.

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.

use Admission webhook to apply default and validate things inside operator

1 participant