Skip to content

Fix OptionalEnum transform for complex enums#1934

Merged
clux merged 2 commits into
kube-rs:mainfrom
doxxx93:fix/optional-complex-enum
Feb 5, 2026
Merged

Fix OptionalEnum transform for complex enums#1934
clux merged 2 commits into
kube-rs:mainfrom
doxxx93:fix/optional-complex-enum

Conversation

@doxxx93
Copy link
Copy Markdown
Member

@doxxx93 doxxx93 commented Feb 5, 2026

Fix OptionalEnum transform for complex enums

The OptionalEnum transform from #1908 only checked for first.contains_key("enum"), which handled simple enums but skipped complex enums (those using oneOf). This caused invalid CRDs when optional complex enum fields were used.

Motivation

Fixes additional case reported in #1906 (comment)

After #1908 was merged, @anmazzotti reported that Option<ComplexEnum> still generates invalid CRDs. The OptionalEnum transform only checked for first.contains_key("enum"), which handled simple enums but skipped complex enums (those using oneOf).

When an optional complex enum field is used, the transform would skip it, leaving an invalid anyOf structure in the CRD:

anyOf:
  - oneOf: [...]
  - enum: [null]
    nullable: true
description: "..."  # ❌ Forbidden with anyOf
properties: {...}   # ❌ Forbidden with anyOf
type: object        # ❌ Forbidden with anyOf

Solution

Remove the first.contains_key("enum") check from the OptionalEnum transform. The remaining conditions are sufficient to identify Option<T> patterns:

  • anyOf with exactly 2 elements
  • First element does not have nullable
  • Second element is { "enum": [null], "nullable": true }

This works for all types of optional enums (simple and complex):

description: "..."
nullable: true      # ✅ Correctly added
oneOf: [...]        # ✅ Hoisted to root
properties: {...}
type: object

Added test cases for Option<ComplexEnum> in kube-derive/tests/crd_complex_enum_test.rs.

Note

The flattened optional enum case (#[serde(flatten)] foo: Option<Enum>) reported in the same comment is a schemars limitation, not a kube issue. According to serde documentation, flatten is only supported "within structs that have named fields."

doxxx93 and others added 2 commits February 5, 2026 14:32
Removed comment about issue kube-rs#1906 from the test.

Signed-off-by: doxxx <me@doxxx.dev>
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.3%. Comparing base (8bcdcb5) to head (f605219).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##            main   #1934     +/-   ##
=======================================
+ Coverage   76.3%   76.3%   +0.1%     
=======================================
  Files         88      88             
  Lines       8408    8409      +1     
=======================================
+ Hits        6408    6412      +4     
+ Misses      2000    1997      -3     
Files with missing lines Coverage Δ
kube-core/src/schema.rs 99.1% <100.0%> (+1.0%) ⬆️
kube-derive/tests/crd_complex_enum_test.rs 100.0% <100.0%> (ø)

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Member

@clux clux left a comment

Choose a reason for hiding this comment

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

looks good to me, thank you!

#[test]
fn optional_complex_enum() {
assert_json_eq!(
OptionalComplexEnumTest::crd(),
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.

not necessary now, but i think if we did

-        OptionalComplexEnumTest::crd(),
+        OptionalComplexEnumTest::crd().spec.versions?[0].schema?.open_api_v3_schema?,

on the left hand side of the assert in the future, these tests would be a lot shorter, less indented, and more focused on the actual statement we want to test

Comment thread kube-derive/tests/crd_complex_enum_test.rs
@clux clux added the changelog-fix changelog fix category for prs label Feb 5, 2026
@clux clux added this to the 3.1.0 milestone Feb 5, 2026
@NickLarsenNZ
Copy link
Copy Markdown
Contributor

NickLarsenNZ commented Feb 5, 2026

I don't think we shouldn't assume a fixed order of keys.

Just linking the solution from my first PR that also fixed this: https://github.com/stackabletech/kube-rs/blob/71707abf1109bad01bbf2c46e3b161846049767a/kube-core/src/schema/transform_any_of.rs#L52-L97

Replace the schema with the anyOf subschema and set to nullable when the
only other subschema is the nullable entry.

Used for correcting the schema for optional tagged unit enums.
The non-null subschema is hoisted, and nullable will be set to true.

This will return early without modifications unless:

  • There are exactly 2 anyOf subschemas.
  • One subschema represents the nullability (ie: it has an enum with a single
    null entry, and nullable set to true).

Regardless, once this goes in I can run and check the remaining tests from #1839 which I explicitly didn't bring in with #1921 (because they failed until this fix went in).

@doxxx93
Copy link
Copy Markdown
Member Author

doxxx93 commented Feb 5, 2026

@NickLarsenNZ Thanks for the feedback! You're right that assuming array order isn't ideal. I checked schemars' current behavior and it consistently generates [schema, null] order, so this works for now. But I agree your approach of explicitly identifying which subschema represents nullability is more robust. Would be great to improve this in a follow-up PR.

@NickLarsenNZ
Copy link
Copy Markdown
Contributor

NickLarsenNZ commented Feb 5, 2026

Yeah, that is indeed the current behaviour, but I'm more concerned about it not breaking in the future (since that has already happened before).

So I have no objection to this PR going in as-is, and I can raise a/some follow up issues and subsequent PR(s) to improve that based on the original PRs I raised (if @clux is happy with that).

@clux
Copy link
Copy Markdown
Member

clux commented Feb 5, 2026

Yeah, that is indeed the current behaviour, but I'm more concerned about it not breaking in the future (since that has already happened before).

So I have no objection to this PR going in as-is, and I can raise a/some follow up issues and subsequent PR(s) to improve that based on the original PRs I raised (if @clux is happy with that).

yeah, i agree with the concern. follow-ups would be appreciated!

@clux clux merged commit 4585148 into kube-rs:main Feb 5, 2026
17 checks passed
@doxxx93 doxxx93 deleted the fix/optional-complex-enum branch February 12, 2026 12:11
cchndl pushed a commit to cchndl/kube that referenced this pull request Feb 19, 2026
* feat(predicate): add OptionalComplexEnumTest with nullable field support

Signed-off-by: doxxx93 <doxxx93@gmail.com>

* Remove comment regarding issue kube-rs#1906 in test

Removed comment about issue kube-rs#1906 from the test.

Signed-off-by: doxxx <me@doxxx.dev>

---------

Signed-off-by: doxxx93 <doxxx93@gmail.com>
Signed-off-by: doxxx <me@doxxx.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog-fix changelog fix category for prs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants