From 23830cf1348be52e328a2655b4142153f0da568d Mon Sep 17 00:00:00 2001 From: Benedick Montales Date: Sun, 29 Mar 2026 21:32:14 +0800 Subject: [PATCH 1/2] fix: stop update from migrating config with stale defaults --- cmd/update.go | 30 ++++++++++---------- cmd/update_test.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/cmd/update.go b/cmd/update.go index c77e6f0..df20d4e 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -34,6 +34,15 @@ var httpClient = &http.Client{ Timeout: requestTimeout, } +var ( + getLatestReleaseFn = getLatestRelease + confirmUpdateFn = ui.Confirm + downloadToTempFileFn = downloadToTempFile + downloadAndParseChecksumsFn = downloadAndParseChecksums + verifyChecksumFn = verifyChecksum + runInstallScriptFn = runInstallScript +) + type release struct { TagName string `json:"tag_name"` HTMLURL string `json:"html_url"` @@ -363,7 +372,7 @@ https://github.com/dkmnx/kairo/blob//scripts/checksums.txt`, return } - latest, err := getLatestRelease() + latest, err := getLatestReleaseFn() if err != nil { ui.PrintError(fmt.Sprintf("Error checking for updates: %v", err)) @@ -380,7 +389,7 @@ https://github.com/dkmnx/kairo/blob//scripts/checksums.txt`, installScriptURL := getInstallScriptURL(runtime.GOOS, latest.TagName) - confirmed, err := ui.Confirm("Do you want to proceed with installation?") + confirmed, err := confirmUpdateFn("Do you want to proceed with installation?") if err != nil { ui.PrintError(fmt.Sprintf("Error reading input: %v", err)) @@ -394,7 +403,7 @@ https://github.com/dkmnx/kairo/blob//scripts/checksums.txt`, cmd.Printf("\nDownloading install script from: %s\n", installScriptURL) - tempFile, err := downloadToTempFile(installScriptURL) + tempFile, err := downloadToTempFileFn(installScriptURL) if err != nil { ui.PrintError(fmt.Sprintf("Error downloading install script: %v", err)) @@ -407,7 +416,7 @@ https://github.com/dkmnx/kairo/blob//scripts/checksums.txt`, cmd.Printf("Downloading checksums from: %s\n", checksumsURL) - checksums, err := downloadAndParseChecksums(checksumsURL) + checksums, err := downloadAndParseChecksumsFn(checksumsURL) if err != nil { ui.PrintError(fmt.Sprintf("Error downloading checksums: %v", err)) @@ -423,7 +432,7 @@ https://github.com/dkmnx/kairo/blob//scripts/checksums.txt`, cmd.Printf("Verifying script integrity...\n") - if err := verifyChecksum(tempFile, expectedHash); err != nil { + if err := verifyChecksumFn(tempFile, expectedHash); err != nil { ui.PrintError(fmt.Sprintf("Security verification failed: %v", err)) cmd.Println("Downloaded script has been removed. Please try again later or report this issue.") @@ -432,21 +441,12 @@ https://github.com/dkmnx/kairo/blob//scripts/checksums.txt`, cmd.Printf("Running install script...\n\n") - if err := runInstallScript(tempFile); err != nil { + if err := runInstallScriptFn(tempFile); err != nil { ui.PrintError(fmt.Sprintf("Error during installation: %v", err)) return } - dir := GetCLIContext(cmd).GetConfigDir() - if dir != "" { - changes, err := config.MigrateConfigOnUpdate(context.Background(), dir) - if err != nil { - cmd.Printf("Warning: config migration failed: %v\n", err) - } else if len(changes) > 0 { - cmd.Printf("%s\n", config.FormatMigrationChanges(changes)) - } - } }, } diff --git a/cmd/update_test.go b/cmd/update_test.go index 82b2f33..f471c3f 100644 --- a/cmd/update_test.go +++ b/cmd/update_test.go @@ -1,6 +1,7 @@ package cmd import ( + "context" "maps" "net/http" "net/http/httptest" @@ -26,6 +27,76 @@ func HijackAndClose(w http.ResponseWriter) { conn.Close() } +func TestUpdateCommand_DoesNotMigrateConfigAfterInstall(t *testing.T) { + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, "config.yaml") + configContent := `default_provider: zai +providers: + zai: + name: Z.AI + base_url: https://api.z.ai/api/anthropic + model: glm-4.7 +` + if err := os.WriteFile(configPath, []byte(configContent), 0600); err != nil { + t.Fatalf("failed to write config: %v", err) + } + + originalVersion := version.Version + version.Version = "v2.3.4" + defer func() { version.Version = originalVersion }() + + originalGetLatestReleaseFn := getLatestReleaseFn + originalConfirmUpdateFn := confirmUpdateFn + originalDownloadToTempFileFn := downloadToTempFileFn + originalDownloadAndParseChecksumsFn := downloadAndParseChecksumsFn + originalVerifyChecksumFn := verifyChecksumFn + originalRunInstallScriptFn := runInstallScriptFn + defer func() { + getLatestReleaseFn = originalGetLatestReleaseFn + confirmUpdateFn = originalConfirmUpdateFn + downloadToTempFileFn = originalDownloadToTempFileFn + downloadAndParseChecksumsFn = originalDownloadAndParseChecksumsFn + verifyChecksumFn = originalVerifyChecksumFn + runInstallScriptFn = originalRunInstallScriptFn + }() + + getLatestReleaseFn = func() (*release, error) { + return &release{TagName: "v2.3.5"}, nil + } + confirmUpdateFn = func(string) (bool, error) { + return true, nil + } + tempScriptPath := filepath.Join(tmpDir, "install.sh") + if err := os.WriteFile(tempScriptPath, []byte("#!/bin/sh\nexit 0\n"), 0755); err != nil { + t.Fatalf("failed to write temp script: %v", err) + } + downloadToTempFileFn = func(string) (string, error) { + return tempScriptPath, nil + } + downloadAndParseChecksumsFn = func(string) (map[string]string, error) { + return map[string]string{getScriptNameForChecksums(runtime.GOOS): "ignored"}, nil + } + verifyChecksumFn = func(string, string) error { + return nil + } + runInstallScriptFn = func(string) error { + return nil + } + + cliCtx := NewCLIContext() + cliCtx.SetConfigDir(tmpDir) + updateCmd.SetContext(WithCLIContext(context.Background(), cliCtx)) + updateCmd.Run(updateCmd, nil) + + updatedConfig, err := os.ReadFile(configPath) + if err != nil { + t.Fatalf("failed to read config after update: %v", err) + } + if !strings.Contains(string(updatedConfig), "model: glm-4.7") { + t.Fatalf("update command should not migrate config after install, got: %s", string(updatedConfig)) + } +} + func TestUpdateCommand(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/repos/dkmnx/kairo/releases/latest" { From ea812a100ece9c248336d30d9955b5bf5d3632b2 Mon Sep 17 00:00:00 2001 From: Benedick Montales Date: Sun, 29 Mar 2026 21:34:08 +0800 Subject: [PATCH 2/2] docs: update changelog for updater migration fix --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c56781..fd5d9b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Update command no longer migrates provider models using stale defaults from the pre-update binary + ## [2.3.5] - 2026-03-29 ### Changed