Summary
SSH keys entered in the TUI User step are written to Config.SSHKeys (top-level) but never to Config.Users[0].SSHKeys. The Butane template only renders per-user SSH keys when Users is non-empty, so the generated Ignition config produces a user account with no SSH keys.
Severity: Critical
This silently produces an installed system that the user cannot log into.
Root Cause
In internal/tui/tui.go applyFields(), the User step handler writes the SSH key to the wrong place:
case "ssh_key":
if f.value != "" {
cfg.SSHKeys = []string{f.value} // ← top-level SSHKeys
}
But it also creates a UserConfig (or updates Users[0].Username) without copying the SSH key into Users[0].SSHKeys.
Meanwhile, the Butane template in internal/ignition/ignition.go only uses per-user keys when Users is populated:
{{- range .Users}}
- name: "{{.Username}}"
...
{{- if .SSHKeys}} ← this is user.SSHKeys, which is empty
ssh_authorized_keys:
{{- range .SSHKeys}}
The top-level SSHKeys is only used in the else branch for the default core user (when Users is empty). Since the TUI always creates a UserConfig, that branch is never reached.
Steps to Reproduce
- Start knuckle
- Navigate to the User step
- Enter a username (e.g.,
admin) and an SSH key (e.g., ssh-ed25519 AAAA... user@host)
- Continue to Review → Install
- Inspect the generated Butane YAML
Expected
The SSH key appears under the user's ssh_authorized_keys in the Butane output.
Actual
The user entry has no ssh_authorized_keys block. The SSH key is stored in Config.SSHKeys but never rendered.
Fix
In applyFields(), when processing the ssh_key field, also write to cfg.Users[0].SSHKeys:
case "ssh_key":
if f.value != "" {
cfg.SSHKeys = []string{f.value}
if len(cfg.Users) > 0 {
cfg.Users[0].SSHKeys = []string{f.value}
}
}
Summary
SSH keys entered in the TUI User step are written to
Config.SSHKeys(top-level) but never toConfig.Users[0].SSHKeys. The Butane template only renders per-user SSH keys whenUsersis non-empty, so the generated Ignition config produces a user account with no SSH keys.Severity: Critical
This silently produces an installed system that the user cannot log into.
Root Cause
In
internal/tui/tui.goapplyFields(), the User step handler writes the SSH key to the wrong place:But it also creates a
UserConfig(or updatesUsers[0].Username) without copying the SSH key intoUsers[0].SSHKeys.Meanwhile, the Butane template in
internal/ignition/ignition.goonly uses per-user keys whenUsersis populated:The top-level
SSHKeysis only used in theelsebranch for the defaultcoreuser (whenUsersis empty). Since the TUI always creates aUserConfig, that branch is never reached.Steps to Reproduce
admin) and an SSH key (e.g.,ssh-ed25519 AAAA... user@host)Expected
The SSH key appears under the user's
ssh_authorized_keysin the Butane output.Actual
The user entry has no
ssh_authorized_keysblock. The SSH key is stored inConfig.SSHKeysbut never rendered.Fix
In
applyFields(), when processing thessh_keyfield, also write tocfg.Users[0].SSHKeys: