Skip to content

Commit ca9ced9

Browse files
committed
feat(version): warn when vendored charts drift from the talm binary
talm renders from the project's vendored charts/talm/, never the binary's built-in charts, so upgrading the binary leaves the library frozen at the version that last ran init — drift that was previously invisible. On every config-loading command a release build now compares the two and, by default, prints a non-fatal warning to stderr pointing at `talm init --update`; stdout and the exit code are unchanged. A project (strictCharts: true in Chart.yaml) or an operator (--strict-charts) can promote the warning to a hard error raised before the command body runs. The check is a no-op for dev/source builds, whose embedded charts are a moving target the developer controls, and a best-effort I/O failure never blocks a command. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
1 parent 053c6e3 commit ca9ced9

1 file changed

Lines changed: 43 additions & 0 deletions

File tree

main.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ const cmdNameTalm = "talm"
5151
//nolint:gochecknoglobals // ldflags-injected build version, idiomatic for go release tooling.
5252
var Version = "dev"
5353

54+
// strictChartsFlag is bound to the --strict-charts persistent flag. When set
55+
// (or when Chart.yaml carries strictCharts: true), a content difference
56+
// between the project's vendored charts/talm/ and the binary's built-in copy
57+
// becomes a hard error instead of a warning.
58+
//
59+
//nolint:gochecknoglobals // cobra persistent flag binds to package-level state, consistent with the rest of this file.
60+
var strictChartsFlag bool
61+
5462
// skipConfigCommands lists commands that should not load Chart.yaml config.
5563
// - init: creates the config, so it doesn't exist yet
5664
// - completion: generates shell completion scripts
@@ -121,6 +129,7 @@ func registerRootFlags(cmd *cobra.Command) {
121129
cmd.PersistentFlags().StringVar(&commands.GlobalArgs.Cluster, "cluster", "", "Cluster to connect to if a proxy endpoint is used.")
122130
cmd.PersistentFlags().BoolVar(&commands.GlobalArgs.SkipVerify, "skip-verify", false, "skip TLS certificate verification (keeps client authentication)")
123131
cmd.PersistentFlags().Bool("version", false, "Print the version number of the application")
132+
cmd.PersistentFlags().BoolVar(&strictChartsFlag, "strict-charts", false, "fail if the project's vendored charts/talm/ differs from the talm binary's built-in copy (run `talm init --update` to re-sync)")
124133

125134
// Shell completion for root persistent flags. --nodes /
126135
// --endpoints draw from the in-scope talosconfig contexts.
@@ -185,6 +194,10 @@ func init() {
185194
if err != nil {
186195
return errors.Wrap(err, "error loading configuration")
187196
}
197+
198+
if err := surfaceChartDrift(); err != nil {
199+
return err
200+
}
188201
}
189202

190203
// Ensure talosconfig path is set to project root if not explicitly set via flag
@@ -219,6 +232,36 @@ func init() {
219232
}
220233
}
221234

235+
// surfaceChartDrift compares the project's vendored charts/talm/ against the
236+
// binary's built-in copy and, on a content difference, either fails (strict
237+
// mode, via Chart.yaml strictCharts or --strict-charts) or warns on stderr.
238+
// It is a no-op for dev/source builds, whose embedded charts are a moving
239+
// target the developer controls rather than a released artifact to track.
240+
func surfaceChartDrift() error {
241+
version, ok := strings.CutPrefix(Version, "v")
242+
if !ok {
243+
return nil
244+
}
245+
246+
drift, msg, err := commands.CheckChartDrift(commands.Config.RootDir, version)
247+
248+
switch {
249+
case err != nil:
250+
// Best-effort: a drift-check I/O error must not block the command.
251+
fmt.Fprintf(os.Stderr, "WARN: could not check chart drift: %v\n", err)
252+
case drift && (commands.Config.StrictCharts || strictChartsFlag):
253+
//nolint:wrapcheck // originating error built with errors.New; WithHint adds operator-facing guidance and is the project idiom.
254+
return errors.WithHint(
255+
errors.New(msg),
256+
"run `talm init --update`, or unset strictCharts / drop --strict-charts to downgrade this to a warning",
257+
)
258+
case drift:
259+
fmt.Fprintf(os.Stderr, "WARN: %s\n", msg)
260+
}
261+
262+
return nil
263+
}
264+
222265
func initConfig() {
223266
if len(os.Args) < 2 {
224267
return

0 commit comments

Comments
 (0)