Skip to content

validate: Recognize Kubernetes built-in resources#197

Merged
adamwg merged 2 commits into
crossplane:mainfrom
ihopenre-eng:fix/validate-kubernetes-builtins
Jul 24, 2026
Merged

validate: Recognize Kubernetes built-in resources#197
adamwg merged 2 commits into
crossplane:mainfrom
ihopenre-eng:fix/validate-kubernetes-builtins

Conversation

@ihopenre-eng

@ihopenre-eng ihopenre-eng commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Description of your changes

crossplane resource validate previously handled a missing custom schema by checking whether the client-go scheme recognized the GVK, then marking every recognized resource as valid without decoding it. That weakened --error-on-missing-schemas and allowed unknown fields or basic type mismatches to pass silently.

This update builds a typed validation scheme from:

  • the client-go Kubernetes scheme
  • apiextensions.k8s.io/v1 for CustomResourceDefinition
  • apiregistration.k8s.io/v1 for APIService

When no custom schema exists, the validator now instantiates the registered type and strictly decodes the resource into it. Unknown fields and values that cannot populate typed fields produce schema errors and an invalid result. GVKs absent from the composed scheme continue to report missingSchema.

Strict decoding intentionally does not attempt API-server admission or semantic validation.

Regression coverage includes valid Secret, Deployment, CustomResourceDefinition, and APIService resources, plus an unknown Secret field and a mistyped Deployment replica count.

Fixes #195

Validation

  • Regression test reproduced the previous false-valid and missing-scheme behavior before the implementation
  • go test ./pkg/validate -count=1
  • go vet ./pkg/validate
  • golangci-lint v2.11.4 run --new-from-rev=origin/main ./pkg/validate/... (0 issues)
  • go mod tidy
  • Repository-pinned gomod2nix generate --with-deps with GOOS=linux GOARCH=amd64
  • git diff --check
  • CGO_ENABLED=0 go test ./... reached and passed the changed packages; the Windows run still reports unrelated path-separator and CRLF fixture failures in Linux-oriented tests outside this change

I have:

@ihopenre-eng
ihopenre-eng requested review from a team, jcogilvie and tampakrap as code owners July 16, 2026 10:05
@ihopenre-eng
ihopenre-eng requested review from negz and removed request for a team July 16, 2026 10:05
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Built-in Kubernetes resources are now recognized through registered Kubernetes schemes and strictly validated without CRD schemas. Tests cover valid built-in resources and invalid fields or types.

Changes

Built-in resource validation

Layer / File(s) Summary
Recognize and strictly validate built-in resources
pkg/validate/validate.go
Registers Kubernetes schemes, strictly decodes recognized GVKs, reports schema field errors, and retains missing-schema handling for unknown kinds.
Validate built-in resource fixtures
pkg/validate/validate_test.go
Adds valid Secret, Deployment, CustomResourceDefinition, and APIService fixtures plus invalid unknown-field and incorrect-type cases.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: jcogilvie

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes address #195 by recognizing built-in Kubernetes resources and avoiding false missing-schema results.
Out of Scope Changes check ✅ Passed The code and test changes stay focused on Kubernetes built-in resource validation and related regression coverage.
Breaking Changes ✅ Passed No files under apis/** or cmd/** changed; the PR only touches pkg/validate and dependency files, so this breaking-change check doesn’t trigger.
Feature Gate Requirement ✅ Passed PASS: This is a bug fix in pkg/validate/cmd/crossplane/resource, not an apis/** change or new experimental feature, so no feature gate is required.
Title check ✅ Passed The title is concise, under 72 characters, and accurately describes recognizing Kubernetes built-in resources.
Description check ✅ Passed The description directly explains the validation fallback and tests for built-in Kubernetes resources.

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

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

Comment thread pkg/validate/validate.go Outdated

sv, ok := schemaValidators[gvk]
if !ok {
if kubescheme.Scheme.Recognizes(gvk) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for picking this up, and for the tests + validation notes in the description, much appreciated.

I think the direction needs a rethink before this lands, though. Scheme.Recognizes(gvk) is a lookup in the type registry (GVK → reflect.Type), it never touches the object. So after this change the following validates as Valid ?:

apiVersion: v1
kind: Secret
metadata:
  name: foo
spec:
  totally: bogus
  replicas: "three"

That's a behaviour change beyond silencing the message. MissingSchema is its own bucket in computeSummary and only fails the run behind --error-on-missing-schemas (see ResultError). Marking built-ins Valid means users who explicitly opted into "everything I rendered was schema-checked" silently lose that guarantee, and don't get the [!] line either. We'd be trading a noisy true statement for a quiet false one.

A few specific points:

1. Status semantics. If we keep the recognize-only approach, it needs its own status (ValidationStatusSkipped / ValidationStatusUnvalidated) that does not roll into Valid. Reading #195 again, the complaint is really that [!] could not find CRD/XRD for: v1, Kind=Secret is alarming for something that can never have a CRD. That's fixable with wording and severity alone.

2. Scheme coverage is inconsistent. k8s.io/client-go/kubernetes/scheme is pinned to whatever client-go the CLI vendors, and it doesn't include apiextensions.k8s.io/v1 CustomResourceDefinition or apiregistration.k8s.io/v1 APIService, those live in other schemes. So a composed Secret would report valid while a composed CustomResourceDefinition still reports missingSchema. Composing CRDs via provider-kubernetes is common enough that this asymmetry will generate follow-up issues.

3. There's a cheap path to actual validation. Once Recognizes returns true, the typed Go struct is available. Strict-decoding into it catches unknown fields and type mismatches, most of what people want from validate, with no OpenAPI plumbing, no cluster access, and no new dependency:

if obj, err := kubescheme.Scheme.New(gvk); err == nil {
    // marshal in.Object, strict-decode into obj via
    // json.NewSerializerWithOptions(..., json.SerializerOptions{Strict: true})
    // strict errors → unknown/mistyped fields
}

It won't cover required fields, CEL, or value constraints, but that's a limitation we can name honestly in the status and docs, rather than reporting Valid.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank you — agreed on the status semantics and validation gap. I addressed this in b4e956e by replacing the recognition-only shortcut with strict typed decoding. The composed scheme now includes client-go built-ins, apiextensions/v1, and apiregistration/v1, so Secret, Deployment, CustomResourceDefinition, and APIService follow the same path. Unknown fields and basic type mismatches now produce schema errors and an invalid result; unregistered custom GVKs remain missingSchema. The tests cover all four valid scheme families plus an unknown Secret field and a mistyped Deployment replica count. The implementation also documents that strict decoding does not provide admission or semantic validation. I added the matching kube-aggregator dependency for APIService coverage and regenerated the Nix module metadata.

Signed-off-by: ihopenre-eng <247072151+ihopenre-eng@users.noreply.github.com>
Signed-off-by: ihopenre-eng <247072151+ihopenre-eng@users.noreply.github.com>
@ihopenre-eng
ihopenre-eng force-pushed the fix/validate-kubernetes-builtins branch from b1a3de7 to b4e956e Compare July 24, 2026 07:13

@haarchri haarchri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM thanks for this

@adamwg
adamwg merged commit cf03c1d into crossplane:main Jul 24, 2026
11 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.

crossplane resource validate: could not find CRD/XRD for: v1

3 participants