devantler-tech / devantler-tech/ksail

fix(talos): custom Hetzner ISO must not inherit the tracked default's version contract

Open
#6,738 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.