-
Notifications
You must be signed in to change notification settings - Fork 4
fix(ci): reject incompatible Kubernetes and Talos pins #3583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
devantler
merged 7 commits into
main
from
codex/platform-kubernetes-talos-compatibility-3536
Sep 4, 2026
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
cd91b5a
fix(ci): reject incompatible Kubernetes and Talos pins
devantler 1baa283
docs(ci): document the Talos/Kubernetes compatibility validator entry…
devantler 06c122c
fix(ci): gate the direct-push route on Talos/Kubernetes compatibility
devantler 3d8e469
Merge remote-tracking branch 'origin/main' into codex/platform-kubern…
devantler 0fecb05
fix(ci): gate production deploys on version compatibility
devantler 8e6d75f
fix(ci): validate heal deployments against main
devantler 9adb4ef
docs(ci): describe merge-group validation
devantler File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # Kubernetes/Talos compatibility check | ||
|
|
||
| Run from the repository root: | ||
|
|
||
| ```sh | ||
| go run ./scripts/validate-talos-kubernetes-compatibility ksail.prod.yaml | ||
| go test ./scripts/validate-talos-kubernetes-compatibility | ||
| ``` | ||
|
|
||
| The check reads the explicit Kubernetes and Talos pins from one KSail YAML | ||
| document. It calls the versioned Talos machinery library's | ||
| `KubernetesVersion.SupportedWith` predicate, the same predicate used by Talos | ||
| runtime configuration validation. It starts no cluster, reads no credentials, | ||
| and does not generate machine secrets. | ||
|
|
||
| `talosctl validate`, including `--strict`, does not invoke runtime validation; | ||
| it accepts the incompatible Kubernetes v1.37.0 / Talos v1.13.9 pairing offline. | ||
| The regression tests exercise that exact pairing and the supported v1.36.4 | ||
| control through the upstream compatibility predicate instead. | ||
|
|
||
| The required Talos validation job runs this check when production pins, its | ||
| validator, the Talos installer, or Go dependency inputs change. Unknown Talos | ||
| release families fail closed; update the reviewed machinery dependency when | ||
| adopting a release it does not yet understand. No compatibility table is copied | ||
| into this repository. | ||
|
|
||
| Passing this check proves a declared version pairing only. It does not prove | ||
| the fleet has completed an OS rollout or authorize merging a staged upgrade. | ||
| A Talos OS upgrade must still land and finish separately before Kubernetes is | ||
| raised, as documented beside the production pins. |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "fmt" | ||
| "io" | ||
| "os" | ||
| "regexp" | ||
|
|
||
| "github.com/siderolabs/talos/pkg/machinery/api/machine" | ||
| "github.com/siderolabs/talos/pkg/machinery/compatibility" | ||
| "gopkg.in/yaml.v3" | ||
| ) | ||
|
|
||
| var versionPin = regexp.MustCompile(`^v[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$`) | ||
|
|
||
| // main validates the Kubernetes and Talos version pins in the ksail config | ||
| // named by the single optional argument, defaulting to ksail.prod.yaml. It exits | ||
| // 2 on usage error, 1 when the pins are rejected, and 0 when they are compatible. | ||
| func main() { | ||
| path := "ksail.prod.yaml" | ||
| if len(os.Args) > 2 { | ||
| fmt.Fprintln(os.Stderr, "usage: validate-talos-kubernetes-compatibility [ksail-config]") | ||
| os.Exit(2) | ||
| } | ||
| if len(os.Args) == 2 { | ||
| path = os.Args[1] | ||
| } | ||
| if err := validate(path); err != nil { | ||
| fmt.Fprintln(os.Stderr, err) | ||
| os.Exit(1) | ||
| } | ||
| fmt.Printf("%s: pinned Kubernetes/Talos versions are compatible\n", path) | ||
| } | ||
|
|
||
| // validate reports whether the ksail config at path pins a Kubernetes version that | ||
| // Talos verifies as compatible with its pinned Talos version. It fails closed on | ||
| // unreadable, malformed, multi-document, or unpinned input rather than treating an | ||
| // unvalidated pin as acceptable. | ||
| func validate(path string) error { | ||
| data, err := os.ReadFile(path) | ||
| if err != nil { | ||
| return fmt.Errorf("read version pins: %w", err) | ||
| } | ||
| var config struct { | ||
| Spec struct { | ||
| Cluster struct { | ||
| Kubernetes string `yaml:"kubernetesVersion"` | ||
| Talos struct { | ||
| Version string `yaml:"version"` | ||
| } `yaml:"talos"` | ||
| } `yaml:"cluster"` | ||
| } `yaml:"spec"` | ||
| } | ||
| decoder := yaml.NewDecoder(bytes.NewReader(data)) | ||
| if err := decoder.Decode(&config); err != nil { | ||
| return fmt.Errorf("parse version pins: %w", err) | ||
| } | ||
| var extra any | ||
| if err := decoder.Decode(&extra); err != io.EOF { | ||
| return fmt.Errorf("%s: expected exactly one YAML document", path) | ||
| } | ||
| talosPin, kubernetesPin := config.Spec.Cluster.Talos.Version, config.Spec.Cluster.Kubernetes | ||
| if !versionPin.MatchString(talosPin) || !versionPin.MatchString(kubernetesPin) { | ||
| return fmt.Errorf("%s: explicit vMAJOR.MINOR.PATCH Talos and Kubernetes pins are required (got Talos %q, Kubernetes %q)", path, talosPin, kubernetesPin) | ||
| } | ||
| talos, err := compatibility.ParseTalosVersion(&machine.VersionInfo{Tag: talosPin}) | ||
| if err != nil { | ||
| return fmt.Errorf("parse Talos pin %q: %w", talosPin, err) | ||
| } | ||
| kubernetes, err := compatibility.ParseKubernetesVersion(kubernetesPin) | ||
| if err != nil { | ||
| return fmt.Errorf("parse Kubernetes pin %q: %w", kubernetesPin, err) | ||
| } | ||
| // Talos calls this same upstream predicate from RuntimeValidate. The offline | ||
| // talosctl validate command does not call it, even with --strict. Unknown | ||
| // Talos release families fail closed rather than inheriting an old ceiling. | ||
| if err := kubernetes.SupportedWith(talos); err != nil { | ||
| return fmt.Errorf("%s: Kubernetes %s is not verified compatible with Talos %s: %w. Choose compatible pins; complete any Talos upgrade separately before raising Kubernetes. If the Talos release is unknown, update the reviewed machinery dependency and revalidate", path, kubernetesPin, talosPin, err) | ||
| } | ||
| return nil | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.