fix: convert internal types to external before unstructured conversion in quota admission#526
Merged
zachsmith1 merged 1 commit intomainfrom Mar 19, 2026
Merged
Conversation
Contributor
scotwells
approved these changes
Mar 19, 2026
…n in quota admission The API server's admission handler decodes native Kubernetes types as internal Go types (e.g. pkg/apis/discovery.EndpointSlice), not external versioned types (e.g. api/discovery/v1.EndpointSlice). Internal types inline ObjectMeta without a "metadata" JSON wrapper, so both json.Marshal and runtime.DefaultUnstructuredConverter.ToUnstructured produce maps without a "metadata" key. This breaks CEL template expressions like trigger.metadata.name used in ClaimCreationPolicies. Use legacyscheme.Scheme.ConvertToVersion to convert internal types to their external versioned form before calling ToUnstructured. Falls back to direct ToUnstructured if the type isn't registered in the scheme. Add chainsaw e2e test for EndpointSlice quota enforcement in a project control plane with deterministic claim names using trigger.metadata.name. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
621c819 to
2659b98
Compare
scotwells
approved these changes
Mar 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The API server's admission handler decodes native Kubernetes types as internal Go types (e.g.
pkg/apis/discovery.EndpointSlice), not external versioned types (e.g.api/discovery/v1.EndpointSlice). Internal types inlineObjectMetawithout ametadataJSON wrapper, so bothjson.Marshalandruntime.DefaultUnstructuredConverter.ToUnstructuredproduce maps without ametadatakey. This breaks CEL template expressions liketrigger.metadata.nameused in ClaimCreationPolicies.Changes
legacyscheme.Scheme.ConvertToVersionto convert internal types to their external versioned form before callingToUnstructured. Falls back to directToUnstructuredif the type isn't registered in the scheme (e.g. unit tests with external types).trigger.metadata.name— the exact pattern that fails without this fix.Root cause investigation
*discovery.EndpointSlice(internal type, not*discoveryv1.EndpointSlice)ObjectMetawithjson:",inline"— nometadatawrapperToUnstructuredproducesobjectMetakey;json.Marshalflattens metadata fields to top leveltrigger.metadata.namefails withno such key: metadataProduction impact
This blocked EndpointSlice creation in project control planes for the network-services-operator, preventing HTTPProxy resources from being fully programmed (no backend EndpointSlice → gateway controller errors).
Test plan
TestStructuredEndpointSliceCELTemplateRendering— verifies both structured and unstructured objects produce correct CEL evaluationstructured-type-enforcement— full quota lifecycle with EndpointSlice in project control plane (passes locally against kind cluster)🤖 Generated with Claude Code