Skip to content

Commit

Permalink
Quote state exec arguments on Windows.
Browse files Browse the repository at this point in the history
  • Loading branch information
mitchell-as committed Mar 22, 2024
1 parent d47d8ff commit 364b0c4
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 4 deletions.
4 changes: 2 additions & 2 deletions internal/osutils/shellescape.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type ShellEscape struct {
escapeWith string
}

//NewBashEscaper creates a new instance of ShellEscape that's configured for escaping bash style arguments
// NewBashEscaper creates a new instance of ShellEscape that's configured for escaping bash style arguments
func NewBashEscaper() *ShellEscape {
return &ShellEscape{
regexp.MustCompile(`^[\w]+$`),
Expand All @@ -33,7 +33,7 @@ func NewBatchEscaper() *ShellEscape {
// NewCmdEscaper creates a new instance of ShellEscape that's configured for escaping cmd arguments
func NewCmdEscaper() *ShellEscape {
return &ShellEscape{
regexp.MustCompile(`^[^ &()\[\]{}^=;!'+,~]+$`), // cmd.exe /? lists these characters as requiring quotes
regexp.MustCompile(`^[^ &()\[\]{}^=;!'+,~<>]+$`), // cmd.exe /? lists these characters as requiring quotes
regexp.MustCompile(`"`),
`""`,
}
Expand Down
2 changes: 1 addition & 1 deletion internal/runners/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func (s *Exec) Run(params *Params, args ...string) (rerr error) {
scriptArgs := fmt.Sprintf(`%q "$@"`, exeTarget)
if strings.Contains(s.subshell.Binary(), "cmd") {
lang = language.Batch
scriptArgs = fmt.Sprintf("@ECHO OFF\n%q %%*", exeTarget)
scriptArgs = fmt.Sprintf(`@ECHO OFF\n%q %%*`, exeTarget)
}

sf, err := scriptfile.New(lang, "state-exec", scriptArgs)
Expand Down
7 changes: 6 additions & 1 deletion internal/subshell/sscommon/sscommon.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,12 @@ func runWithCmd(env []string, name string, args ...string) error {
return locale.NewInputError("err_sscommon_unsupported_language", "", ext)
}

return runDirect(env, name, args...)
esc := osutils.NewCmdEscaper()
quoted := make([]string, 0, len(args))
for _, arg := range args {
quoted = append(quoted, esc.Quote(arg))
}
return runDirect(env, name, quoted...)
}

func binaryPathCmd(env []string, name string) (string, error) {
Expand Down
20 changes: 20 additions & 0 deletions test/integration/exec_int_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,26 @@ func (suite *ExecIntegrationTestSuite) TestExecWithPath() {

}

func (suite *ExecIntegrationTestSuite) TestExecQuotedArgs() {
suite.OnlyRunForTags(tagsuite.Exec)
ts := e2e.New(suite.T(), false)
defer ts.Close()

cp := ts.Spawn("checkout", "ActiveState-CLI/Perl-5.32", ".")
cp.Expect("Skipping runtime setup")
cp.Expect("Checked out project")
cp.ExpectExitCode(0)

fileutils.WriteFile(filepath.Join(ts.Dirs.Work, "testargs.txt"), []byte(`printf "Argument: '%s'.\n", $ARGV[0];`))

cp = ts.SpawnWithOpts(
e2e.OptArgs("exec", "perl", "testargs.txt", "a<b"),
e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
)
cp.Expect("Argument: 'a<b'.", e2e.RuntimeSourcingTimeoutOpt)
cp.ExpectExitCode(0)
}

func TestExecIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(ExecIntegrationTestSuite))
}

0 comments on commit 364b0c4

Please sign in to comment.