Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions cmd/gortex/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,8 @@ func runUpgrade(cmd *cobra.Command, args []string) error {
if !upgradeRun {
fmt.Fprintf(out, "Run:\n %s\n", command)
} else {
parts := strings.Fields(command)
fmt.Fprintf(out, "$ %s\n", command)
ex := exec.CommandContext(cmd.Context(), parts[0], parts[1:]...) //nolint:gosec // command is one of the fixed install-method templates
ex := upgradeExecCommand(cmd, command)
ex.Stdout, ex.Stderr, ex.Stdin = out, cmd.ErrOrStderr(), os.Stdin
if rerr := ex.Run(); rerr != nil {
return fmt.Errorf("upgrade command failed: %w", rerr)
Expand All @@ -212,6 +211,18 @@ func runUpgrade(cmd *cobra.Command, args []string) error {
return nil
}

func upgradeExecCommand(cmd *cobra.Command, command string) *exec.Cmd {
if upgradeCommandNeedsShell(command) {
return exec.CommandContext(cmd.Context(), "sh", "-c", command) //nolint:gosec // fixed installer template, needs shell for pipe
}
parts := strings.Fields(command)
return exec.CommandContext(cmd.Context(), parts[0], parts[1:]...) //nolint:gosec // command is one of the fixed install-method templates
}

func upgradeCommandNeedsShell(command string) bool {
return strings.ContainsAny(command, "|&;<>()$`\\\"'")
}

// goBinDir returns the directory `go install` drops binaries into — $GOBIN, or
// $GOPATH/bin, or ~/go/bin — for install-method detection.
func goBinDir() string {
Expand Down
18 changes: 18 additions & 0 deletions cmd/gortex/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ func TestUpgradeInstallMethodDetection(t *testing.T) {
}
}

func TestUpgradeRunCommandUsesShellOnlyForPipelines(t *testing.T) {
cmd := upgradeExecCommand(rootCmd, "curl -fsSL https://get.gortex.dev | sh")
if got := cmd.Path; got != "sh" {
t.Fatalf("script installer should run through sh, got path %q args %v", got, cmd.Args)
}
if len(cmd.Args) != 3 || cmd.Args[1] != "-c" || cmd.Args[2] != "curl -fsSL https://get.gortex.dev | sh" {
t.Fatalf("script installer command args = %#v", cmd.Args)
}

cmd = upgradeExecCommand(rootCmd, "go install github.com/zzet/gortex/cmd/gortex@latest")
if got := cmd.Path; got != "go" {
t.Fatalf("plain argv command should exec directly, got path %q args %v", got, cmd.Args)
}
if len(cmd.Args) != 3 || cmd.Args[1] != "install" || cmd.Args[2] != "github.com/zzet/gortex/cmd/gortex@latest" {
t.Fatalf("go install command args = %#v", cmd.Args)
}
}

// TestUpgradeReleaseTagParse covers the /releases/latest redirect tag parse.
func TestUpgradeReleaseTagParse(t *testing.T) {
cases := map[string]string{
Expand Down
Loading