From f3f42ad24222880c42d045df36a6f4eb29dd28df Mon Sep 17 00:00:00 2001 From: Beny Dishon K Date: Fri, 31 Jul 2026 15:38:03 +0530 Subject: [PATCH 1/3] fix(update-check): detect nix and linuxbrew installs on linux The linux branch of getUpdateInstructions never inspected execPath outside the npm check, falling through to getLinuxPackageManager(), which only probes which package managers exist on the machine. A nix install on Debian or Ubuntu was told to run 'apt-get install infisical' for a binary in the immutable nix store. Homebrew-on-Linux hit the same gap, since /home/linuxbrew/.linuxbrew/ does not match the /homebrew/ substring the darwin branch checks. Mirrors the existing darwin behaviour: nix returns no instruction rather than a wrong one. Adds unit cases and integration steps to the integration-linux job. Partially addresses Infisical/infisical#226 --- .../workflows/test-update-instructions.yml | 19 +++++++++++++++++++ packages/util/check-for-update.go | 9 +++++++++ packages/util/check-for-update_test.go | 12 ++++++++++++ 3 files changed, 40 insertions(+) diff --git a/.github/workflows/test-update-instructions.yml b/.github/workflows/test-update-instructions.yml index 49c01548d..383c6f4e3 100644 --- a/.github/workflows/test-update-instructions.yml +++ b/.github/workflows/test-update-instructions.yml @@ -115,3 +115,22 @@ jobs: output=$($HOME/.npm-global/lib/node_modules/@infisical/cli/bin/update-hint) echo "Output: $output" echo "$output" | grep -q "npm update -g @infisical/cli" || (echo "Expected npm instruction, got: $output" && exit 1) + + # The runner has apt-get, so without install-source detection this falls + # through to the apt instruction. Asserting empty output is what makes + # this a real regression test for the nix case. + - name: Test nix path detection + run: | + mkdir -p $HOME/nix/store/abc123-infisical-0.0.1/bin + cp update-hint $HOME/nix/store/abc123-infisical-0.0.1/bin/update-hint + output=$($HOME/nix/store/abc123-infisical-0.0.1/bin/update-hint) + echo "Output: $output" + [ -z "$output" ] || (echo "Expected no instruction for nix, got: $output" && exit 1) + + - name: Test linuxbrew path detection + run: | + mkdir -p $HOME/linuxbrew/.linuxbrew/bin + cp update-hint $HOME/linuxbrew/.linuxbrew/bin/update-hint + output=$($HOME/linuxbrew/.linuxbrew/bin/update-hint) + echo "Output: $output" + echo "$output" | grep -q "brew update" || (echo "Expected brew instruction, got: $output" && exit 1) diff --git a/packages/util/check-for-update.go b/packages/util/check-for-update.go index 33289140d..ac352a1c8 100644 --- a/packages/util/check-for-update.go +++ b/packages/util/check-for-update.go @@ -324,6 +324,15 @@ func getUpdateInstructions(goos string, execPath string) string { if isNpm { return "To update, run: npm update -g @infisical/cli" } + // Nix-managed binaries live in the immutable store. The system package + // manager did not install them and cannot update them, so stay quiet + // rather than print a command that will not work. + if strings.Contains(p, "/nix/store/") { + return "" + } + if strings.Contains(p, "linuxbrew") { + return "To update, run: brew update && brew upgrade infisical" + } pkgManager := getLinuxPackageManager() switch pkgManager { case "apt-get": diff --git a/packages/util/check-for-update_test.go b/packages/util/check-for-update_test.go index f460118fb..028e68ada 100644 --- a/packages/util/check-for-update_test.go +++ b/packages/util/check-for-update_test.go @@ -96,6 +96,18 @@ func TestGetUpdateInstructions(t *testing.T) { execPath: "/home/user/.npm-global/lib/node_modules/@infisical/cli/bin/infisical", expected: "npm update -g @infisical/cli", }, + { + name: "linux nix returns empty", + goos: "linux", + execPath: "/nix/store/abc123-infisical-0.41.90/bin/infisical", + expectEmpty: true, + }, + { + name: "linux linuxbrew", + goos: "linux", + execPath: "/home/linuxbrew/.linuxbrew/bin/infisical", + expected: "brew update && brew upgrade infisical", + }, } for _, tt := range tests { From bf50703480550fb52bb6f5e8366d1b14bb92c716 Mon Sep 17 00:00:00 2001 From: Beny Dishon K Date: Fri, 31 Jul 2026 15:45:34 +0530 Subject: [PATCH 2/3] fix(update-check): bound the linuxbrew path match Review feedback: a bare "linuxbrew" substring also classified unrelated paths such as /opt/linuxbrew-tools as Homebrew installs. Uses "linuxbrew/" rather than a fully bounded "/linuxbrew/" so both real layouts still match: the multi-user default (/home/linuxbrew/.linuxbrew) and the single-user prefix (~/.linuxbrew), where the component is preceded by a dot rather than a slash. Adds a single-user case and a negative case for /opt/linuxbrew-tools, plus a notExpected field on the test table to express the negative assertion. --- packages/util/check-for-update.go | 6 +++++- packages/util/check-for-update_test.go | 21 ++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/util/check-for-update.go b/packages/util/check-for-update.go index ac352a1c8..0dde4d0c6 100644 --- a/packages/util/check-for-update.go +++ b/packages/util/check-for-update.go @@ -330,7 +330,11 @@ func getUpdateInstructions(goos string, execPath string) string { if strings.Contains(p, "/nix/store/") { return "" } - if strings.Contains(p, "linuxbrew") { + // Trailing slash so this matches the linuxbrew prefix directory in both + // the multi-user (/home/linuxbrew/.linuxbrew) and single-user + // (~/.linuxbrew) layouts, without classifying unrelated paths such as + // /opt/linuxbrew-tools as a Homebrew install. + if strings.Contains(p, "linuxbrew/") { return "To update, run: brew update && brew upgrade infisical" } pkgManager := getLinuxPackageManager() diff --git a/packages/util/check-for-update_test.go b/packages/util/check-for-update_test.go index 028e68ada..8a09e8e9f 100644 --- a/packages/util/check-for-update_test.go +++ b/packages/util/check-for-update_test.go @@ -23,7 +23,8 @@ func TestGetUpdateInstructions(t *testing.T) { goos string execPath string expected string - expectEmpty bool // true means assert empty result (vs. skipping runtime-dependent cases) + expectEmpty bool // true means assert empty result (vs. skipping runtime-dependent cases) + notExpected string // assert the result does NOT contain this, for paths that must not match a detector }{ // darwin { @@ -108,6 +109,18 @@ func TestGetUpdateInstructions(t *testing.T) { execPath: "/home/linuxbrew/.linuxbrew/bin/infisical", expected: "brew update && brew upgrade infisical", }, + { + name: "linux linuxbrew single-user prefix", + goos: "linux", + execPath: "/home/user/.linuxbrew/bin/infisical", + expected: "brew update && brew upgrade infisical", + }, + { + name: "linux linuxbrew-tools is not a brew install", + goos: "linux", + execPath: "/opt/linuxbrew-tools/bin/infisical", + notExpected: "brew", + }, } for _, tt := range tests { @@ -119,6 +132,12 @@ func TestGetUpdateInstructions(t *testing.T) { } return } + if tt.notExpected != "" { + if strings.Contains(result, tt.notExpected) { + t.Errorf("expected %q not to contain %q", result, tt.notExpected) + } + return + } if tt.expected == "" { return // skip runtime-dependent cases } From b59c9789f60cdaad761c22472bcbbadaff0a7468 Mon Sep 17 00:00:00 2001 From: Beny Dishon K Date: Mon, 28 Sep 2026 16:34:04 +0530 Subject: [PATCH 3/3] fix(update-check): match the .linuxbrew prefix, not any linuxbrew dir The trailing-slash match still classified an unrelated directory such as /home/user/linuxbrew/bin as a Homebrew install and printed a brew upgrade command that cannot update that binary. Both documented Homebrew-on-Linux layouts put the prefix at .linuxbrew, so match that instead. Adds a regression test for the plain linuxbrew path. --- packages/util/check-for-update.go | 10 +++++----- packages/util/check-for-update_test.go | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/util/check-for-update.go b/packages/util/check-for-update.go index 0dde4d0c6..b03747a02 100644 --- a/packages/util/check-for-update.go +++ b/packages/util/check-for-update.go @@ -330,11 +330,11 @@ func getUpdateInstructions(goos string, execPath string) string { if strings.Contains(p, "/nix/store/") { return "" } - // Trailing slash so this matches the linuxbrew prefix directory in both - // the multi-user (/home/linuxbrew/.linuxbrew) and single-user - // (~/.linuxbrew) layouts, without classifying unrelated paths such as - // /opt/linuxbrew-tools as a Homebrew install. - if strings.Contains(p, "linuxbrew/") { + // Match the .linuxbrew prefix shared by the multi-user + // (/home/linuxbrew/.linuxbrew) and single-user (~/.linuxbrew) layouts, so + // neither an unrelated directory named linuxbrew nor a path such as + // /opt/linuxbrew-tools is classified as a Homebrew install. + if strings.Contains(p, ".linuxbrew/") { return "To update, run: brew update && brew upgrade infisical" } pkgManager := getLinuxPackageManager() diff --git a/packages/util/check-for-update_test.go b/packages/util/check-for-update_test.go index 8a09e8e9f..9c14fc4ac 100644 --- a/packages/util/check-for-update_test.go +++ b/packages/util/check-for-update_test.go @@ -115,6 +115,12 @@ func TestGetUpdateInstructions(t *testing.T) { execPath: "/home/user/.linuxbrew/bin/infisical", expected: "brew update && brew upgrade infisical", }, + { + name: "linux plain linuxbrew dir is not a brew install", + goos: "linux", + execPath: "/home/user/linuxbrew/bin/infisical", + notExpected: "brew", + }, { name: "linux linuxbrew-tools is not a brew install", goos: "linux",