Skip to content

fix(kubernetes): render the OIDC UID header only from v1.33 - #4407

Merged
Aleksei Sviridkin (lexfrei) merged 2 commits into
mainfrom
fix/oidc-uid-header-v133-floor
Sep 24, 2026
Merged

Aleksei Sviridkin (lexfrei) merged 2 commits into
mainfrom
fix/oidc-uid-header-v133-floor

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does

Stacked on #4398; review the diff against fix/kamaji-pin-hash-reset.

The tenant Kubernetes chart now renders --requestheader-uid-headers=X-Remote-Uid only from an effective Kubernetes version of v1.33, where RemoteRequestHeaderUID is beta and on by default. It no longer renders a --feature-gates term of its own on any version. On v1.32 it used to add a term enabling that gate, which is alpha there, whenever it could read the operator's entries and they left the gate unset; no release tag contains that path, so dropping it now changes nothing a user has run.

The chart still reads --emulated-version, because emulation moves the effective version: --emulated-version=1.32 on a v1.35 tenant puts the gate back to alpha-and-off, and the header flag is not rendered there. It still reads the operator's --feature-gates entries for an opt-out (RemoteRequestHeaderUID=false, or AllBeta=false with no explicit =true), so the header flag never lands next to a disabled gate. AllAlpha is no longer read, since it says nothing about a beta gate.

An unquoted --emulated-version=value entry whose kube version has a non-zero patch component now fails the render and names the entry. The rule mirrors upstream rather than the regex in #4396: toVersionMap parses each value with version.Parse and refuses only ver.Patch() != 0 (staging/src/k8s.io/component-base/compatibility/registry.go lines 320-326 at v1.35.0, the same code in staging/src/k8s.io/apiserver/pkg/util/version/registry.go at v1.31.0). version.Parse takes ^\s*v?([0-9]+(?:\.[0-9]+)*)(.*)*$ (versionMatchRE in k8s.io/apimachinery/pkg/util/version/version.go, identical at v0.31.1 and v0.35.0). So 1.32, v1.32, 1.32-rc, 1.32.0 and 1.32.0-rc all start an apiserver emulating 1.32, and 1.32.4 and 1.32.4-rc do not. A ^[0-9]+\.[0-9]+$ check would have refused the first four. The chart extracts the numeric run with the same pattern, reads the minor from it, and fails only on a non-zero third component. A quoted value is still left unread.

Two deliberate narrowings:

  • The chart no longer refuses a mix of bare and kube:-prefixed --feature-gates terms. Once the chart writes no gate term, the spelling of the operator's terms no longer concerns anything it renders. The apiserver still refuses the mix (component-base/compatibility/registry.go:405 at v1.35.0), and the chart now passes it through like the other fatal gate values it already leaves to the apiserver: unknown names, unparseable values, quoted terms.
  • On v1.32 the chart now neither renders nor judges the UID flags, as it already did on v1.31. An operator's own --requestheader-uid-headers entry without the gate reaches an apiserver that refuses it, which is how every released chart version behaved. A cluster built from main that already runs a v1.32 tenant with OIDC on loses the chart's --requestheader-uid-headers and gate term on the next render; no release carried them. That holds only while no release is cut from main before this merges; a release that carries the v1.32 gate term first would turn this into a breaking change for v1.32 tenants, whose migration is to write both flags into extraArgs themselves.

An element such as kube=1.32=x is now split at its first = only, the way toVersionMap splits it with SplitN(compVer, "=", 2). The chart used to skip that element, which the apiserver reads as 1.32, and so rendered the header flag against an emulated 1.32. That gap predates this branch.

Rebased onto #4398 at fb2e57c3b, which reads a two-element --feature-gates and --emulated-version separately. That behaviour carries over unchanged under the v1.33 floor: behind a hidden --emulated-version only an explicit RemoteRequestHeaderUID=false is refused beside a header entry, while a blanket AllBeta=false waits for a reading, because a lower emulated version can make the gate alpha again; nothing is refused as an opt-out behind a hidden --feature-gates value; the empty-element refusal applies behind both; and behind either one X-Remote-Uid is added only beside a uid-headers list of the operator's. The README breaking-changes note from #4398 now says the chart refuses neither the mixed gate spelling nor two kube emulated versions. In docs/oidc-tenant.md the paragraphs that list refusals now name the managed-flag move and refusal from #4398 and no longer carry a count, and the two-element paragraph now says what the chart renders behind a hidden value.

Tests: helm unittest goes from 308 on #4398 to 298. 26 cases are deleted. 25 of them pinned the v1.32 gate term, AllAlpha handling or the mixed-spelling refusal. One emulated a version below 1.32, which the below-floor emulation case now covers. v1.32 cases that tested parsing rather than the gate are retargeted to v1.34. Sixteen cases are added: the patch-level refusal, the version parsing below the floor and above it (on v1.35 emulating 1.33-rc, v1.33, 1.33.0 and kube=1.33=x, where only a correct minor renders the header), the first-= split, a pin that a mixed gate spelling now passes through, emulation landing exactly on 1.33, and a v1.32 opt-out beside a header entry passing through untouched.

Coverage notes, not applied: no case pins that the patch-level refusal stays off with spec.oidc.mode: None, where the block that holds it does not run. The case "splits a component element at its first equals sign only" pins that the kube element of kube=1.32=x is read. It does not pin the split itself, because the version pattern ignores what follows the numbers either way.

The extraArgs field description still calls the field the escape hatch for apiserver flags unrelated to OIDC. It is unchanged here, and it stays accurate for the v1.32 advice in the guide, because the UID flags belong to the aggregation layer rather than to OIDC.

Optional, not applied: on v1.32 the chart could refuse an operator's --requestheader-uid-headers entry that comes without the gate, since the gate is off by default there and the apiserver will not start. The same skip also drops two refusals the branch history had at 1.32, a header entry beside RemoteRequestHeaderUID=false and a header list ending in a comma; both now reach an apiserver that refuses them. It stays out so that v1.32 matches v1.31 and the released charts, where the chart judges none of these flags.

Not applied: for a value with a zero-prefixed major such as 01.32.4, the patch refusal suggests 01.32. The apiserver refuses both values over the leading zero, so the configuration fails either way and only the suggested fix is off.

Why the patch refusal stays while the mixed-spelling refusal goes: the patch refusal is about --emulated-version, which the chart reads itself to decide what to render. The mixed spelling concerns --feature-gates, which the chart no longer writes to.

Not split out: the --emulated-version parsing and the patch-level refusal share the fix commit with the floor move, because both change how the same value is read. The change also removes a comment from hack/e2e-chainsaw/_lib/run-kubernetes.sh that became false, so select-e2e runs the full suite for this PR.

Default path: renders of the parent and this branch through tests/values/common.yaml and tests/values/oidc-system.yaml at v1.31 to v1.35 are byte-identical, once the randomly generated Kamaji token fields are masked, except for OIDC System at v1.32, which loses exactly the two UID lines.

Screenshots

Not a UI change.

Downstream repositories

The only field that changes is the description of version, which returns to its earlier wording. The website's kubernetes reference page is regenerated from the README on the next tag, and the Terraform provider keeps its own copy of that description, which already reads "Kubernetes major.minor version to deploy.".

Closes #4373

Closes #4396

Release note

fix(kubernetes): the tenant chart renders the aggregation-layer UID header flag with OIDC on only from an effective Kubernetes v1.33, and never renders a --feature-gates term of its own. v1.32 tenants render no UID flags, which matches every released version, so nothing regresses. This supersedes the v1.32 clause of the #3539 release note. An unquoted --emulated-version entry with a patch-level kube version such as 1.32.4, which the kube-apiserver refuses, now fails the render and names the entry.

Summary by CodeRabbit

  • New Features
    • OIDC-enabled clusters on Kubernetes 1.33 and later now receive the UID request-header setting without an added feature-gate flag.
    • Chart rendering now checks Kubernetes and Talos version compatibility and prevents rendering when worker deployments do not meet ownership or retention requirements.
  • Bug Fixes
    • Emulated Kubernetes versions with non-zero patch components now fail with a clear error; supported version formats are recognized more consistently.
  • Documentation
    • Updated version and OIDC guidance to reflect current chart behavior.

@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: cozystack/cozystack/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 4038be73-5b92-46ad-b063-7bac82ce36ed

📥 Commits

Reviewing files that changed from the base of the PR and between 339cffe and a92e89e.

📒 Files selected for processing (10)
  • api/apps/v1alpha1/kubernetes/types.go
  • docs/oidc-tenant.md
  • hack/e2e-chainsaw/_lib/run-kubernetes.sh
  • packages/apps/kubernetes/README.md
  • packages/apps/kubernetes/hack/update-versions.sh
  • packages/apps/kubernetes/templates/cluster.yaml
  • packages/apps/kubernetes/tests/oidc_test.yaml
  • packages/apps/kubernetes/values.schema.json
  • packages/apps/kubernetes/values.yaml
  • packages/system/kubernetes-rd/cozyrds/kubernetes.yaml
💤 Files with no reviewable changes (1)
  • hack/e2e-chainsaw/_lib/run-kubernetes.sh

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The Kubernetes chart now renders the OIDC UID-header flag from effective version 1.33 and no longer adds its own feature-gate flag. It updates emulated-version parsing and render guards. OIDC tests and documentation reflect the revised behavior.

Changes

Kubernetes OIDC flag handling

Layer / File(s) Summary
UID-header and emulated-version logic
packages/apps/kubernetes/templates/cluster.yaml
The chart removes automatic RemoteRequestHeaderUID gate rendering and uses effective minor 33 as the UID-header floor. It updates operator gate opt-out parsing, parses emulated versions with a version pattern, and rejects unquoted values with non-zero patch components. The template also updates the Talos support-matrix and worker MachineDeployment render guards.
OIDC rendering and parsing tests
packages/apps/kubernetes/tests/oidc_test.yaml, hack/e2e-chainsaw/_lib/run-kubernetes.sh
Tests cover the v1.33 floor, feature-gate opt-outs and overrides, and emulated-version parsing and patch rejection. The e2e helper keeps its existing apiserver flag assertions; an explanatory comment is removed.
Updated OIDC and Kubernetes version descriptions
docs/oidc-tenant.md, packages/apps/kubernetes/README.md, api/apps/v1alpha1/kubernetes/types.go, packages/apps/kubernetes/hack/update-versions.sh, packages/apps/kubernetes/values.yaml, packages/apps/kubernetes/values.schema.json, packages/system/kubernetes-rd/cozyrds/kubernetes.yaml
The OIDC guide and chart README describe the changed flag rendering and emulated-version handling. Version descriptions no longer describe the removed v1.32 feature-gate rendering. The README also updates its account of which extraArgs combinations the chart refuses.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to a92e8

The chart’s v1.33 UID-header behavior and documentation are aligned. No actionable issue remains to block merge after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The whole-PR change summary includes changes unrelated to [#4373] and [#4396]. In packages/apps/kubernetes/templates/cluster.yaml, it adds or changes the Talos support-matrix guard and adds a render… Remove the unrelated Talos and worker-adoption guard changes from this pull request, or link them to their own directly related issue and submit them separately.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: rendering the OIDC UID header only from Kubernetes v1.33.
Linked Issues check ✅ Passed The PR meets the coding requirements in [#4373] and [#4396]. For [#4373], the chart uses v1.33 as the effective-version floor, removes chart-rendered --feature-gates, renders no UID flags below v1.3…
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Full details: Out of Scope Changes check

Explanation

The whole-PR change summary includes changes unrelated to [#4373] and [#4396]. In packages/apps/kubernetes/templates/cluster.yaml, it adds or changes the Talos support-matrix guard and adds a render-time guard for worker MachineDeployment adoption and Helm pruning. These changes do not implement the OIDC UID-version decision or --emulated-version patch validation.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@github-actions github-actions Bot added size/XXL This PR changes 1000+ lines, ignoring generated files area/kubernetes Issues or PRs related to the tenant Kubernetes app kind/bug Categorizes issue or PR as related to a bug labels Sep 23, 2026

@IvanHunters IvanHunters left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict

LGTM with non-blocking notes

Reviewed 3b1427523 against merge-base 15cdc47fd. I found nothing blocking. The v1.32 render now matches every released tag, and the new patch-level refusal only rejects values the pinned kube-apiserver already refuses.

Caveats

  • I diffed full helm template output of base against head with tests/values/{common,oidc-system}.yaml at v1.31–v1.35. With the random Kamaji tokens masked, the only change is the two UID lines at v1.32 with OIDC System, and CustomConfig gives the same result. None of v1.5.4, v1.6.3 or v1.7.0-alpha.1 renders --requestheader-uid-headers, so upgrading from a release changes nothing on v1.31 or v1.32 because of this PR.
  • The upstream rules check out at the pinned tags. toVersionMap refuses Patch() != 0 at v1.31.14 (apiserver/pkg/util/version/registry.go:327) and at v1.33.13 (component-base/compatibility/registry.go:303). At v1.35.6 RemoteRequestHeaderUID is still 1.32 alpha and 1.33 beta, and its spec has no MinCompatibilityVersion, so --min-compatibility-version can't turn the gate off under the header flag. Kamaji 26.9.4-edge doesn't touch --emulated-version, so the value does reach the apiserver and the refusal never fires on an entry the control plane would drop. These edge inputs render the way upstream version.Parse reads them: 1.32-rc, v1.33.0, kube=1.32=x, kube=1.34.0-rc.1, 1.32.0.5, 1.32.04, and a value padded with spaces.
  • Mixed kube gate spelling is now passed through. On the base branch, kube:Foo=true next to Bar=true on v1.33+ with OIDC on failed the render. On head it renders and the apiserver refuses it at startup (registry.go:363 at v1.33.13), so the operator gets a crash-looping control plane instead of a render error. No release had that check, so this costs observability, not correctness.
  • Clusters built from main running v1.32 with OIDC lose the header flag and the gate term on the next reconcile, silently, and aggregated API servers stop getting the caller's UID. Expected, and the PR body says so.
  • Optional follow-up, not blocking: two --emulated-version shapes still render cleanly even though the apiserver refuses both at startup. One is a trailing comma (kube=1.33,), which hands toVersionMap an empty element for version.Parse. The other is a zero-prefixed major (kube=01.33). The parent branch renders both the same way, so this PR doesn't change them. If the goal is a render error instead of a crash-loop, they fit next to the patch-level refusal.
  • This is stacked on #4398 and I didn't re-review that delta. It includes the header flag on v1.33+ OIDC tenants, which is new compared with v1.6.3 and changes extraArgs, so an upgrade rolls those tenants' control planes.
  • Nothing ran against a live cluster. I didn't watch Kamaji's hash-based argument rebuild during the v1.32 extraArgs change.
  • helm unittest: 239/239 pass. Reverting any of seven pieces of the new logic turns the OIDC suite red: the floor, the patch refusal, the first-= split, the quoted-value guard, the version parse, the explicit-true override of AllBeta=false, and the empty component.

@lexfrei

Copy link
Copy Markdown
Contributor Author

IvanHunters I rebased this onto the new head of #4398 (a23e84324) after that PR's review. The two commits are the ones you approved at 3b1427523, merged with the split #4398 introduced. A hidden --feature-gates value still holds back the opt-out refusal, a hidden --emulated-version no longer does, the empty-element refusal runs either way, and X-Remote-Uid is added beside an operator's own header list. The guide lost two sentences that claimed more than the chart does: the version.Parse equivalence, which a zero-prefixed major breaks, and "these flags" where only the header flag is rendered. helm unittest passes 278/278, and the default path still differs from the parent only in the two UID lines at v1.32 with OIDC System. The trailing-comma and zero-prefixed --emulated-version shapes stay out, since the parent renders them the same way and the apiserver refuses both at startup.

@lexfrei
Aleksei Sviridkin (lexfrei) force-pushed the fix/kamaji-pin-hash-reset branch 2 times, most recently from 57125eb to e4c2dc8 Compare September 23, 2026 17:12
@lexfrei

Copy link
Copy Markdown
Contributor Author

IvanHunters #4398 moved again after its own review, so this is rebased onto e4c2dc85a. The commits are unchanged in substance. Behind a hidden --emulated-version, only an explicit RemoteRequestHeaderUID=false is refused beside a header entry now, and a blanket AllBeta=false waits for a reading. The README breaking-changes note says the chart refuses neither the mixed gate spelling nor two kube emulated versions, which is true once this PR removes the mixed-spelling refusal. helm unittest passes 282/282 (296 on the parent), and the default path still differs from the parent only in the two UID lines at v1.32 with OIDC System.

@IvanHunters IvanHunters left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict

LGTM with non-blocking notes

I rendered base and head across every version and --emulated-version / --feature-gates shape I could think of. Each difference is one of the three changes the PR intends, and the upstream claims in the description hold when checked against real kube-apiserver binaries.

Findings

  • [MINOR] packages/apps/kubernetes/templates/cluster.yaml:606, below the floor the chart now passes an operator's apiserver-fatal header entry through without a word
  • [MINOR] packages/apps/kubernetes/tests/oidc_test.yaml:2258, the parsing cases cannot tell "read as 1.32" from "misread"

Caveats

  • v1.32 OIDC tenants built from main lose both UID lines on the next render, which rolls the control plane. No release carries them: git tag --contains d870b392f, the commit that added them, prints nothing.
  • The mixed bare/kube: gate spelling is no longer refused. The apiserver still refuses it (set kube feature gates ... do not mix use, confirmed on v1.35.6), so all that's lost is the earlier, clearer error.
  • The patch-level --emulated-version refusal sits inside the OIDC block, so with spec.oidc.mode: None an entry such as --emulated-version=1.32.4 still renders and crash-loops as before. The release note reads as if the refusal were unconditional; saying "with OIDC on" there would match the code.
  • The patch refusal never fires where the apiserver would have started: across the matrix head refuses only 1.32.4, 1.32.4-rc and 1.33.5, and v1.31.14 and v1.35.6 both refuse a non-zero patch in toVersionMap.

{{- end }}
{{- $uidHeaderUnsupported = le $effectiveMinor 31 }}
{{- $uidGateRequired = eq $effectiveMinor 32 }}
{{- $uidHeaderUnsupported = lt $effectiveMinor 33 }}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[MINOR] below the floor the chart now passes an operator's apiserver-fatal header entry through without a word

With OIDC on and an effective version of 1.32, an operator's own --requestheader-uid-headers=X-Remote-Uid now passes through with no gate term, and kube-apiserver v1.32.13 refuses it (--requestheader-uid-headers requires the "RemoteRequestHeaderUID" feature to be enabled). At the merge-base the chart added --feature-gates=RemoteRequestHeaderUID=true for exactly this input. This only affects clusters built from main and matches released charts, so it is not a regression. From v1.33 the chart already refuses the equivalent header-plus-opt-out shape, and refusing a header entry below the floor when no term enables the gate would give v1.32 the same signal. The same skip also drops two render-time refusals the merge-base had at 1.32, a header entry beside --feature-gates=RemoteRequestHeaderUID=false and a header list ending in a comma; both now pass through to an apiserver that refuses them.

# in packages/apps/kubernetes
$ helm template k . --namespace tenant-root -f tests/values/common.yaml -f tests/values/oidc-system.yaml --set version=v1.32 --set-json 'controlPlane.apiServer.extraArgs=["--requestheader-uid-headers=X-Remote-Uid"]' | grep -A3 '^    extraArgs:'
    extraArgs:
      - --requestheader-uid-headers=X-Remote-Uid
      - --authentication-config=/etc/kubernetes/authentication-config/config.yaml
    extraVolumeMounts:

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.

I'm leaving this one out. Below the floor the chart reads none of the UID flags, the same as on v1.31 and in every released chart. Refusing a header entry on v1.32 would bring back the version-specific gate reasoning this PR removes, and it would apply to only one minor. The PR body lists it as a named item, together with the two refusals you point out that the branch history had at 1.32.

# strconv.ParseBool rejects tRuE, so the apiserver never enables the gate on
# it. Folding case before the match would read it as ownership and withhold
# the chart's own term.
- it: reads a suffixed --emulated-version as the minor it names

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[MINOR] the parsing cases cannot tell "read as 1.32" from "misread"

Every new parsing case emulates 1.32, below the floor, so a correct minor and a garbage minor (atoi gives 0) render identically. If the minor is taken without the $versionPattern extraction, only "ignores an --emulated-version whose minor is not a number" goes red:

# in packages/apps/kubernetes
$ sed -i '' 's/splitList "." (regexReplaceAll $versionPattern $emulatedKubeVersion "${1}")/splitList "." $emulatedKubeVersion/' templates/cluster.yaml
$ helm unittest . -f tests/oidc_test.yaml -f tests/oidc_withhold_test.yaml
Tests:       1 failed, 124 passed, 125 total
$ git checkout -- templates/cluster.yaml

Add above-floor positive cases: on v1.35, emulate 1.33-rc, v1.33, 1.33.0 and kube=1.33=x, and assert --requestheader-uid-headers=X-Remote-Uid is rendered.

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.

Every parsing case sat below the floor, where a minor of 32 and a minor of 0 render the same. I added four cases on v1.35 that emulate 1.33-rc, v1.33, 1.33.0 and kube=1.33=x and assert that --requestheader-uid-headers=X-Remote-Uid renders. Your mutation now turns 1.33-rc and kube=1.33=x red, next to the 1.garbage case. v1.33 and 1.33.0 stay green under it, because splitList "." puts 33 at index 1 for both with or without the pattern. Taking the minor from the major turns all four red, and taking it from the last component turns 1.33.0 red.

@lexfrei

Copy link
Copy Markdown
Contributor Author

IvanHunters Rebased onto the current #4398 head (fb2e57c3b). The two commits are unchanged, apart from the docs merge and the four new test cases. Where the docs name the managed-flag refusal, they now cover the move into admissionControllers and preferredAddressTypes as well, and the README breaking-changes note says the chart refuses neither the mixed gate spelling nor two kube emulated versions. helm unittest passes 298/298, down from 308 on the parent. The default-path render still differs from the parent only in the two UID lines at v1.32 with OIDC System.

IvanHunters
IvanHunters previously approved these changes Sep 24, 2026

@IvanHunters IvanHunters left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict

LGTM with non-blocking notes

I found nothing blocking at 823762bf against merge-base fb2e57c3. Since my last review your own change moved only in the tests and the guide (plus the regenerated cozyrds schema); templates/cluster.yaml contributes the same diff it did at 90b05a10, and the rest of the movement comes from the rebase onto the new #4398 head. Default renders still change only for OIDC System at v1.32, and the patch-level refusal only rejects values the pinned kube-apiserver already refuses.

From my earlier round

  • The parsing cases now tell a correct minor from a misread one. The four above-floor cases at tests/oidc_test.yaml:2281-2346 go red under each of the three ways of misreading the minor: dropping the $versionPattern extraction reddens 1.33-rc and kube=1.33=x, reading the major reddens all four, and reading the last component reddens 1.33.0. Closed.
  • The v1.32 pass-through of an operator's own header entry stays, as you decided. I rendered that input on v1.6.3 and the head gives the same extraArgs, so no released chart loses anything. I'm not holding it.

Caveats

  • All of this assumes no release is cut from main first. main adds --feature-gates=RemoteRequestHeaderUID=true beside a bare header entry at v1.32, and neither v1.6.3 nor v1.7.0-alpha.1 does. If a release goes out from main before this merges, v1.32 tenants on it lose that term on upgrade, and an operator who wrote only --requestheader-uid-headers=X-Remote-Uid reaches an apiserver that refuses it, with no render error. Merging before the next cut from main avoids that.
  • Dropping the mixed gate-spelling refusal gives up a render-time error. That configuration is fatal to the apiserver, so it now shows up as a crash-looping control plane rather than as a failed render. The PR says so and the README note covers it.
  • I didn't run the live rollout. On main-built v1.32 OIDC tenants extraArgs loses two entries, so the control plane rolls. A render cannot show that the rollout converges.
  • What I ran rather than read: kube-apiserver version.Parse at v1.35.6 over 24 --emulated-version values against the chart's reading of each, and the gate's stage in --help at every pinned version (Alpha at v1.32, Beta from v1.33). Reverting the floor, the patch refusal, the first-= split or the minor extraction each turns tests/oidc_test.yaml red.

Recommended follow-ups

  • Upgrade a v1.32 OIDC tenant built from main to this chart on a test cluster and confirm the control plane rolls.

RemoteRequestHeaderUID is alpha and off on v1.32, so the chart had to
enable an alpha gate on v1.32 tenants with OIDC on to make
--requestheader-uid-headers start. From v1.33 the gate is beta and on
by default. No release has shipped the v1.32 path, so moving the floor
to an effective v1.33 now removes a behaviour no released chart had:
the chart renders no --feature-gates term of its own, and below the
floor it renders no UID flag and runs none of the UID checks, as it
already did on v1.31. The refusal of a list that ends in a bare flag
still applies there, because it guards the --authentication-config the
chart appends on every version.

The refusal of a kube gate spelling mixed between bare and
kube:-prefixed terms goes too. Once the chart writes no gate term, the
spelling of the operator's terms no longer concerns anything it
renders, and the chart already passes other gate values the apiserver
refuses, unknown names and unparseable values, through to it.

--emulated-version is still read, because emulation moves the
effective version below the floor. Its kube version is now read from
the numbers at the start of the value, with the element split at its
first equals sign as toVersionMap splits it, so v1.32, 1.32.0 and
1.32-rc all read as 1.32. With OIDC on, an --emulated-version entry
without quotes whose kube version has a non-zero patch component fails
the render and names the entry: the apiserver refuses such a value and
would otherwise only crash-loop.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <[email protected]>
The tenant OIDC guide, the version field description and the e2e
helper comment still described a --feature-gates term rendered on
v1.32. Left as they were, they would tell an operator that the chart
switches that alpha gate on, which it no longer does. The guide now
says what a v1.32 tenant has to write itself to get the UID, and which
--emulated-version values fail the render, so an operator who meets
that refusal finds it explained. The breaking-changes note in the
README said the chart refuses the mixed gate spelling while OIDC is
on; with that refusal gone it would promise a render error that no
longer comes.

The version description returns to its earlier wording in values.yaml
and in the update-versions.sh template, because that template rewrites
the line on every version bump and would otherwise bring the old text
back. make generate carries it into the schema, README, API types and
ApplicationDefinition.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <[email protected]>
Base automatically changed from fix/kamaji-pin-hash-reset to main September 24, 2026 18:26
@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 564f540 into main Sep 24, 2026
49 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the fix/oidc-uid-header-v133-floor branch September 24, 2026 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/kubernetes Issues or PRs related to the tenant Kubernetes app kind/bug Categorizes issue or PR as related to a bug size/XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

2 participants