Skip to content

feat(init): add --image flag to override the preset values.yaml image - #150

Merged
Aleksei Sviridkin (lexfrei) merged 3 commits into
mainfrom
feat/init-image-flag
May 8, 2026
Merged

feat(init): add --image flag to override the preset values.yaml image#150
Aleksei Sviridkin (lexfrei) merged 3 commits into
mainfrom
feat/init-image-flag

Conversation

@lexfrei

Copy link
Copy Markdown
Contributor

What changed

talm init writes the chosen preset chart unchanged, including the hard-coded installer image (the cozystack preset pins ghcr.io/cozystack/cozystack/talos:v1.12.6). Operators using a custom or factory-built Talos image have to edit values.yaml after every fresh init. The new --image flag makes the override declarative at init time:

talm init --preset cozystack --name cluster \
  --image factory.talos.dev/installer/<sha>:<version>

How

  • A line-anchored regex finds the top-level image: line in the preset's values.yaml and ReplaceAllFunc rewrites it. ReplaceAllFunc is used over ReplaceAll because the latter expands $0 / $1 / $name / ${name} in the replacement, which would silently corrupt image refs containing $.
  • --image is rejected up front in PreRunE when combined with --encrypt, --decrypt, or --update — the flag rewrites preset content at write time and silently no-ops on those paths otherwise.
  • validateImageOverride runs in RunE before any file is written, so a flag/preset mismatch (e.g. --image --preset generic, since generic has no image: field) errors out before the project is half-initialized on disk.
  • README updated with the new flag's usage and scope.

Tests

  • applyImageOverride covers: empty-override no-op, replacement preserving surrounding content, missing-field error, four quoting styles (double/single/unquoted/trailing-comment), four $-expansion forms ($0, $1, $tenant, ${name}) round-tripping verbatim through yaml.Unmarshal.
  • validateImageOverride covers happy + sad paths.
  • initCmd.PreRunE rejects --image with each of --encrypt, --decrypt, --update.
  • updateTalmLibraryChart defensively rejects --image for direct callers.

Closes #24.

talm init writes the preset chart unchanged, including a hard-coded
installer image (e.g. ghcr.io/cozystack/cozystack/talos:v1.12.6 in
cozystack). Operators using a custom or factory-built Talos image
have to edit values.yaml after every fresh init. The new --image flag
makes the override declarative at init time:

  talm init --preset cozystack --name cluster --image \
    factory.talos.dev/installer/<sha>:<version>

Implementation is a minimal regex substitution on the preset values
content before write. The helper applyImageOverride is line-anchored,
returns the input unchanged for an empty override OR for a values
file that does not declare image (so a preset without the field is
not silently fabricated), and %q-quotes the override value so a
reference with characters YAML would otherwise re-interpret stays
parsed as a string.

Tests in pkg/commands/init_test.go cover the four contract corners:
empty override, present-image substitution with surrounding content
preserved, missing-image short-circuit, and shell-meta safe quoting.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@lexfrei has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 7 minutes and 28 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1a3e50f9-2afa-44f0-a616-45ad88b1ff8a

📥 Commits

Reviewing files that changed from the base of the PR and between a2abbf9 and ea09b7c.

📒 Files selected for processing (3)
  • README.md
  • pkg/commands/init.go
  • pkg/commands/init_test.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/init-image-flag

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 and usage tips.

@lexfrei
Aleksei Sviridkin (lexfrei) marked this pull request as ready for review May 8, 2026 08:39

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new --image flag to the talm init command, allowing users to override the Talos installer image in the preset's values.yaml during initial setup. The implementation includes validation to ensure the flag is only used on initial initialization and that the selected preset supports an image field. Feedback suggests optimizing regex usage by using MatchString to avoid unnecessary allocations and notes a redundant validation check in the image application logic.

Comment thread pkg/commands/init.go
Comment on lines +548 to +550
if !imageLineRe.Match(values) {
return nil, fmt.Errorf("--image was set but the preset values.yaml does not declare a top-level image: field; remove --image, choose a different preset, or add the image field manually")
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This check is redundant because validateImageOverride is already called in RunE (line 425) to ensure the image: field exists before any files are written. While it makes the function safer in isolation, it results in a second regex match for the same content during the write loop.

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.

The duplication is intentional. Documented in ab4313d — the inner check is unreachable under the talm init flow because validateImageOverride runs first in RunE against the same bytes, but the guard makes applyImageOverride safe for direct callers (the unit tests in init_test.go exercise it that way, and a future code path that skips the validator should not silently corrupt values.yaml). The cost is one regex match on a values.yaml that fits in a few KB; happy to take that for the looser coupling.

Comment thread pkg/commands/init.go Outdated
if parts[1] != "values.yaml" {
continue
}
if !imageLineRe.Match([]byte(content)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Use imageLineRe.MatchString(content) instead of converting the string to a byte slice. This avoids an unnecessary allocation and is more idiomatic when the input is already a string.

Suggested change
if !imageLineRe.Match([]byte(content)) {
if !imageLineRe.MatchString(content) {

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.

Applied in ea09b7c — switched to imageLineRe.MatchString(content) since the input is already a string.

Address review feedback from gemini-code-assist on
pkg/commands/init.go:548: the inner imageLineRe.Match is redundant
under the talm init flow because validateImageOverride runs first
against the same bytes from presetFiles. Document that the guard is
intentional defense in depth so the helper stays safe for direct
callers (unit tests, future code paths that might skip the
validator) instead of dropping it and creating a hidden coupling
between the validator and the helper.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Address review feedback from gemini-code-assist on
pkg/commands/init.go:574: the input is already a string, so call
imageLineRe.MatchString(content) directly instead of forcing a
[]byte conversion. Tiny allocation saving and the idiomatic Go
form when the regex input arrives as a string.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 7a21e6a into main May 8, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: the possibility to add a image as parameter when using talm init

2 participants