preserve unknown kubeconfig fields via serde(flatten)#1964
Merged
clux merged 3 commits intoMar 27, 2026
Conversation
Add `#[serde(flatten)] pub other: BTreeMap<String, serde_json::Value>` to all kubeconfig structs (Kubeconfig, Cluster, AuthInfo, ExecConfig, Context, Preferences, AuthProviderConfig, and Named* wrappers) so that unmodeled fields survive deserialization and can be serialized back without data loss. Also derive Default for ExecConfig, Preferences, and AuthProviderConfig. Update Kubeconfig::merge() to merge extra fields with first-wins-per-key semantics. Add a round-trip test verifying unknown fields are preserved across deserialize/serialize cycles. Signed-off-by: Alexey Lapuka <alexey@twingate.com>
534af76 to
5f7da0d
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1964 +/- ##
=======================================
+ Coverage 76.4% 76.5% +0.2%
=======================================
Files 89 89
Lines 8540 8566 +26
=======================================
+ Hits 6520 6550 +30
+ Misses 2020 2016 -4
🚀 New features to boost your workflow:
|
clux
approved these changes
Mar 26, 2026
Member
clux
left a comment
There was a problem hiding this comment.
Thanks for this. I think this is a good solution that makes us immediately compatible with new fields.
One small downside though, is that this may cause people to not bother contributing new standard fields when they appear in client-go, and ideally this should be a fallback method to access such fields until a release can be made.
I wonder if it makes sense to word something like a "if you are relying on this for standard fields present in upstream client-go, feel free to submit a PR". wdyt?
…consumers relying on standard client-go fields should submit PRs to add them as typed fields rather than using the generic fallback. Also update the round-trip test to use only non-standard field names to avoid collision when standard fields like installHint are later added as typed fields. Signed-off-by: Alexey Lapuka <alexey@twingate.com>
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.
Preserve unknown kubeconfig fields via
serde(flatten)Motivation
When tools read a kubeconfig, modify it (e.g. add a context), and write it back, any
fields not explicitly modeled in the
Kubeconfigstructs are silently dropped. Thiscauses data loss for users with:
installHint(present in upstream Go client-go but missing here)The existing
extensions: Option<Vec<NamedExtension>>fields only capture the structuredextensionskey — they don't preserve arbitrary unknown fields on each struct.Changes
#[serde(flatten)]catch-all on all kubeconfig structsAdded
pub other: BTreeMap<String, serde_json::Value>with#[serde(flatten)]to:Kubeconfig,Preferences,NamedCluster,Cluster,NamedAuthInfo,AuthInfo,AuthProviderConfig,ExecConfig,NamedContext,Context.This follows the existing pattern in
kube-core::schema::SchemaObjectwhich already uses#[serde(flatten)] extensions: BTreeMap<String, Value>for the same purpose.Fields like
installHintonExecConfig(present in upstream Go client-go but not modeledin kube-rs) are now automatically captured in the
othermap without needing dedicatedtyped fields for each one.
Defaultderive for additional structsAdded
Defaultderive toExecConfig,Preferences, andAuthProviderConfig. Thesestructs previously lacked
Default, making it harder to construct them with..Default::default().Merge logic
Updated
Kubeconfig::merge()to merge theothermaps using first-wins-per-keysemantics, consistent with the Kubernetes kubeconfig merge specification.
Round-trip test
Added
kubeconfig_round_trip_preserves_unknown_fieldstest that verifies unknown fieldsat every level (top-level, cluster, context, exec) survive a deserialize→serialize cycle.
Breaking changes
Adding a public field to these structs is technically a semver-breaking change for code
that constructs them with struct literal syntax without
..Default::default(). However:ExecConfig,Preferences,AuthProviderConfigare never constructed with structliterals (only deserialized) — zero downstream impact
Kubeconfig,AuthInfo,Cluster,Contextall deriveDefaultand downstream codeoverwhelmingly uses
..Default::default()NamedCluster,NamedAuthInfo,NamedContextare simple wrappers — the fix is adding..Default::default()to any explicit construction siteThe fix for any affected downstream code is mechanical: add
..Default::default()tostruct literal constructions.
Testing