devantler-tech / devantler-tech/ksail
fix(talos): custom Hetzner ISO must not inherit the tracked default's version contract
- Dominant language
- Go
- Stars
- 165
- Forks
- 12
- Avg merge
- 5h 51m
- Merged PRs (30d)
- 347
Description
> 🤖 Generated by the Agentic Engineer
### Evidence
`ParseVersionContract` falls back to `v1alpha1.DefaultHetznerTalosVersion` whenever
`spec.cluster.talos.version` is empty, regardless of which ISO the cluster actually
selected (`pkg/fsutil/configmanager/talos/version.go`):
```go
if pinnedVersion == "" {
pinnedVersion = v1alpha1.DefaultHetznerTalosVersion
}
```
`resolveVersionContract` reaches the same fallback via `ParseVersionContract("")`.
### Affected audience and impact
A Hetzner user who pins a **custom or ARM `talos.iso`** but leaves `talos.version`
empty. Config generation derives the machinery version contract from the tracked
**x86 default's** version rather than from the Talos release actually contained in
their ISO. When the default is ahead of that release, KSail emits version-gated
fields the booted `machined` does not recognise, and cluster bootstrap fails.
The coupling is pre-existing, but #6686 makes `DefaultHetznerTalosVersion` advance
on a **schedule** instead of by a reviewed human bump, so the divergence can now
grow unattended between a custom ISO and the default version contract. That is a
change in exposure rate, not a new failure mode — which is why it is filed here
rather than fixed inside that PR.
### Expected behaviour
`DefaultHetznerTalosVersion` is used as the implicit contract **only when the
selected ISO is the tracked default ISO**. For any other ISO the contract is
either derived from that ISO's own Talos release, or the user is required to pin
`talos.version` explicitly with an actionable error naming the flag to set.
### Acceptance criteria
- [ ] A config with a non-default `talos.iso` and empty `talos.version` does **not**
silently inherit `DefaultHetznerTalosVersion`.
- [ ] The default ISO with an empty `talos.version` keeps today's behaviour
(negative control — no regression for the common path).
- [ ] Whichever route is chosen (derive, or require-and-explain) is covered by a
test that fails before the change.
- [ ] Docs state how a custom-ISO user is expected to pin the version.
### Size
Small–medium. The mechanism is one fallback, but the chosen route is a user-facing
design decision: `ParseVersionContract` currently takes only the pinned version, so
either its signature grows to carry the selected ISO, or the empty-version case
becomes an error for non-default ISOs.
Reported by Codex review on #6686 (P1); confirmed against the source.
Contributor guide
Research direction
Read pkg/fsutil/configmanager/talos/version.go, especially ParseVersionContract and resolveVersionContract, and trace how the selected Hetzner ISO reaches them. Add regression coverage for a non-default ISO with an empty talos.version and preserve the default-ISO behavior; update the relevant docs to explain how custom-ISO users pin the version.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- devops, infrastructure
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100