diff --git a/.gitignore b/.gitignore index 570a6ba3..7fe7de22 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /build /log agent +.vagrant/ diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index 326ed831..a26a412d 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -111,7 +111,6 @@ blocks: - stty_restoration - epilogue_on_pass - epilogue_on_fail - - ssh_jump_points - unicode - unknown_command - broken_unicode diff --git a/Makefile b/Makefile index 198b6bf1..08500785 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ serve: .PHONY: serve test: - go test -short -v ./... + go test -p 1 -short -v ./... .PHONY: test build: @@ -48,6 +48,10 @@ build: env GOOS=linux GOARCH=386 go build -o build/agent main.go .PHONY: build +build.windows: + rm -rf build + env GOOS=windows GOARCH=amd64 go build -o build/agent.exe main.go + e2e: build ruby test/e2e/$(TEST).rb diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 00000000..b3f3824f --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,8 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + # https://github.com/gusztavvargadr/packer/ + config.vm.box = "gusztavvargadr/windows-server-2019-standard" + config.vm.provision "shell", path: "scripts/provision-windows-box.ps1" +end diff --git a/go.mod b/go.mod index 49c8cc4f..5dfb2325 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.9.0 github.com/stretchr/testify v1.7.0 - golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 // indirect + golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 golang.org/x/text v0.3.7 // indirect gopkg.in/ini.v1 v1.64.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index 6cd55b44..e920757f 100644 --- a/go.sum +++ b/go.sum @@ -78,7 +78,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -236,8 +235,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/renderedtext/go-watchman v0.0.0-20210705111746-70108070d074 h1:6YLKgGc2PwDM3oEpAUavoiyjjpIH44HmjWSswwWTBa8= -github.com/renderedtext/go-watchman v0.0.0-20210705111746-70108070d074/go.mod h1:Z+qanDzSoUGCbcrTM7G6YCA9ST2KBdte7sCz+HQAp7I= github.com/renderedtext/go-watchman v0.0.0-20210809121718-0632d0d12b0a h1:pRX9qebwT+TMdBojMspqDtU1RFLIbH5VzI8aI9yMiyE= github.com/renderedtext/go-watchman v0.0.0-20210809121718-0632d0d12b0a/go.mod h1:Z+qanDzSoUGCbcrTM7G6YCA9ST2KBdte7sCz+HQAp7I= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -448,7 +445,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -460,7 +456,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -657,7 +652,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c= gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.64.0 h1:Mj2zXEXcNb5joEiSA0zc3HZpTst/iyjNiR4CN8tDzOg= gopkg.in/ini.v1 v1.64.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/main.go b/main.go index f34405ad..409754ae 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "path" + "path/filepath" "strings" "time" @@ -90,7 +91,7 @@ func getLogLevel() log.Level { func getLogFilePath() string { logFilePath := os.Getenv("SEMAPHORE_AGENT_LOG_FILE_PATH") if logFilePath == "" { - return "/tmp/agent_log" + return filepath.Join(os.TempDir(), "agent_log") } parentDirectory := path.Dir(logFilePath) diff --git a/pkg/api/job_request.go b/pkg/api/job_request.go index eacc5edf..8b606767 100644 --- a/pkg/api/job_request.go +++ b/pkg/api/job_request.go @@ -4,8 +4,11 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io/fs" "io/ioutil" "path/filepath" + "strconv" + "strings" yaml "gopkg.in/yaml.v3" ) @@ -46,6 +49,27 @@ type File struct { Mode string `json:"mode" yaml:"mode"` } +func (f *File) NormalizePath(homeDir string) string { + if filepath.IsAbs(f.Path) { + return filepath.FromSlash(f.Path) + } + + if strings.HasPrefix(f.Path, "~") { + return filepath.FromSlash(strings.ReplaceAll(f.Path, "~", homeDir)) + } + + return filepath.FromSlash(filepath.Join(homeDir, f.Path)) +} + +func (f *File) ParseMode() (fs.FileMode, error) { + fileMode, err := strconv.ParseUint(f.Mode, 8, 32) + if err != nil { + return 0, fmt.Errorf("bad file permission '%s'", f.Mode) + } + + return fs.FileMode(fileMode), nil +} + type Callbacks struct { Finished string `json:"finished" yaml:"finished"` TeardownFinished string `json:"teardown_finished" yaml:"teardown_finished"` diff --git a/pkg/eventlogger/default.go b/pkg/eventlogger/default.go index 979f607c..5a5888ac 100644 --- a/pkg/eventlogger/default.go +++ b/pkg/eventlogger/default.go @@ -3,6 +3,8 @@ package eventlogger import ( "errors" "fmt" + "os" + "path/filepath" "github.com/semaphoreci/agent/pkg/api" ) @@ -22,7 +24,8 @@ func CreateLogger(request *api.JobRequest) (*Logger, error) { } func Default() (*Logger, error) { - backend, err := NewFileBackend("/tmp/job_log.json") + path := filepath.Join(os.TempDir(), "job_log.json") + backend, err := NewFileBackend(path) if err != nil { return nil, err } diff --git a/pkg/eventlogger/httpbackend.go b/pkg/eventlogger/httpbackend.go index 369167d5..16d8bcbb 100644 --- a/pkg/eventlogger/httpbackend.go +++ b/pkg/eventlogger/httpbackend.go @@ -4,6 +4,8 @@ import ( "bytes" "fmt" "net/http" + "os" + "path/filepath" "sync" "time" @@ -22,7 +24,8 @@ type HTTPBackend struct { } func NewHTTPBackend(url, token string) (*HTTPBackend, error) { - fileBackend, err := NewFileBackend("/tmp/job_log.json") + path := filepath.Join(os.TempDir(), "job_log.json") + fileBackend, err := NewFileBackend(path) if err != nil { return nil, err } diff --git a/pkg/executors/authorized_keys.go b/pkg/executors/authorized_keys.go index 65d32c80..22c679c2 100644 --- a/pkg/executors/authorized_keys.go +++ b/pkg/executors/authorized_keys.go @@ -12,9 +12,13 @@ func InjectEntriesToAuthorizedKeys(keys []api.PublicKey) error { return nil } - sshDirectory := filepath.Join(UserHomeDir(), ".ssh") + homeDir, err := os.UserHomeDir() + if err != nil { + return err + } - err := os.MkdirAll(sshDirectory, os.ModePerm) + sshDirectory := filepath.Join(homeDir, ".ssh") + err = os.MkdirAll(sshDirectory, os.ModePerm) if err != nil { return err } diff --git a/pkg/executors/docker_compose_executor.go b/pkg/executors/docker_compose_executor.go index c2fdf526..aaa63785 100644 --- a/pkg/executors/docker_compose_executor.go +++ b/pkg/executors/docker_compose_executor.go @@ -7,10 +7,11 @@ import ( "os" "os/exec" "path" + "path/filepath" + "runtime" "strings" "time" - pty "github.com/creack/pty" watchman "github.com/renderedtext/go-watchman" api "github.com/semaphoreci/agent/pkg/api" "github.com/semaphoreci/agent/pkg/config" @@ -56,6 +57,11 @@ func NewDockerComposeExecutor(request *api.JobRequest, logger *eventlogger.Logge } func (e *DockerComposeExecutor) Prepare() int { + if runtime.GOOS == "windows" { + log.Error("docker-compose executor is not supported in Windows") + return 1 + } + err := os.MkdirAll(e.tmpDirectory, os.ModePerm) if err != nil { return 1 @@ -204,8 +210,8 @@ func (e *DockerComposeExecutor) startBashSession() int { log.Debug("Starting stateful shell") // #nosec - cmd := exec.Command( - "docker-compose", + executable := "docker-compose" + args := []string{ "--ansi", "never", "-f", @@ -220,9 +226,9 @@ func (e *DockerComposeExecutor) startBashSession() int { fmt.Sprintf("%s:%s:ro", e.tmpDirectory, e.tmpDirectory), e.mainContainerName, "bash", - ) + } - shell, err := shell.NewShell(cmd, e.tmpDirectory) + shell, err := shell.NewShellFromExecAndArgs(executable, args, e.tmpDirectory) if err != nil { log.Errorf("Failed to start stateful shell err: %+v", err) @@ -538,7 +544,7 @@ func (e *DockerComposeExecutor) pullDockerImages() int { e.mainContainerName, "true") - tty, err := pty.Start(cmd) + tty, err := shell.StartPTY(cmd) if err != nil { log.Errorf("Failed to initialize docker pull, err: %+v", err) return 1 @@ -586,43 +592,30 @@ func (e *DockerComposeExecutor) ExportEnvVars(envVars []api.EnvVar, hostEnvVars e.Logger.LogCommandFinished(directive, exitCode, commandStartedAt, commandFinishedAt) }() - envFile := "" - - for _, env := range envVars { - e.Logger.LogCommandOutput(fmt.Sprintf("Exporting %s\n", env.Name)) - - value, err := env.Decode() - - if err != nil { - exitCode = 1 - return exitCode - } - - envFile += fmt.Sprintf("export %s=%s\n", env.Name, ShellQuote(string(value))) - } - - for _, env := range hostEnvVars { - e.Logger.LogCommandOutput(fmt.Sprintf("Exporting %s\n", env.Name)) - envFile += fmt.Sprintf("export %s=%s\n", env.Name, ShellQuote(env.Value)) + environment, err := shell.CreateEnvironment(envVars, hostEnvVars) + if err != nil { + log.Errorf("Error creating environment: %v", err) + exitCode = 1 + return exitCode } - envPath := fmt.Sprintf("%s/.env", e.tmpDirectory) - - // #nosec - err := ioutil.WriteFile(envPath, []byte(envFile), 0644) + envFileName := filepath.Join(e.tmpDirectory, ".env") + err = environment.ToFile(envFileName, func(name string) { + e.Logger.LogCommandOutput(fmt.Sprintf("Exporting %s\n", name)) + }) if err != nil { exitCode = 255 return exitCode } - cmd := fmt.Sprintf("source %s", envPath) + cmd := fmt.Sprintf("source %s", envFileName) exitCode = e.RunCommand(cmd, true, "") if exitCode != 0 { return exitCode } - cmd = fmt.Sprintf("echo 'source %s' >> ~/.bash_profile", envPath) + cmd = fmt.Sprintf("echo 'source %s' >> ~/.bash_profile", envFileName) exitCode = e.RunCommand(cmd, true, "") if exitCode != 0 { return exitCode diff --git a/pkg/executors/docker_compose_executor_test.go b/pkg/executors/docker_compose_executor_test.go index f3482c40..100354d8 100644 --- a/pkg/executors/docker_compose_executor_test.go +++ b/pkg/executors/docker_compose_executor_test.go @@ -3,6 +3,7 @@ package executors import ( "encoding/base64" "os/exec" + "runtime" "testing" "time" @@ -66,6 +67,10 @@ func startComposeExecutor() (*DockerComposeExecutor, *eventlogger.Logger, *event } func Test__DockerComposeExecutor(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("docker-compose executor is not yet support in Windows") + } + e, _, testLoggerBackend := startComposeExecutor() e.RunCommand("echo 'here'", false, "") @@ -78,14 +83,14 @@ func Test__DockerComposeExecutor(t *testing.T) { e.RunCommand(multilineCmd, false, "") envVars := []api.EnvVar{ - api.EnvVar{Name: "A", Value: "Zm9vCg=="}, + {Name: "A", Value: "Zm9vCg=="}, } e.ExportEnvVars(envVars, []config.HostEnvVar{}) e.RunCommand("echo $A", false, "") files := []api.File{ - api.File{ + { Path: "/tmp/random-file.txt", Content: "YWFhYmJiCgo=", Mode: "0600", @@ -139,6 +144,10 @@ func Test__DockerComposeExecutor(t *testing.T) { } func Test__DockerComposeExecutor__StopingRunningJob(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("docker-compose executor is not yet support in Windows") + } + e, _, testLoggerBackend := startComposeExecutor() go func() { diff --git a/pkg/executors/shell_executor.go b/pkg/executors/shell_executor.go index fd558b1f..3ba9e99e 100644 --- a/pkg/executors/shell_executor.go +++ b/pkg/executors/shell_executor.go @@ -2,9 +2,10 @@ package executors import ( "fmt" - "io/ioutil" - "os/exec" + "os" "path" + "path/filepath" + "runtime" "strings" "time" @@ -17,23 +18,31 @@ import ( type ShellExecutor struct { Executor - - Logger *eventlogger.Logger - Shell *shell.Shell - jobRequest *api.JobRequest - - tmpDirectory string + Logger *eventlogger.Logger + Shell *shell.Shell + jobRequest *api.JobRequest + tmpDirectory string + hasSSHJumpPoint bool + shouldUpdateBashProfile bool + cleanupAfterClose []string } -func NewShellExecutor(request *api.JobRequest, logger *eventlogger.Logger) *ShellExecutor { +func NewShellExecutor(request *api.JobRequest, logger *eventlogger.Logger, selfHosted bool) *ShellExecutor { return &ShellExecutor{ - Logger: logger, - jobRequest: request, - tmpDirectory: "/tmp", + Logger: logger, + jobRequest: request, + tmpDirectory: os.TempDir(), + hasSSHJumpPoint: !selfHosted, + shouldUpdateBashProfile: !selfHosted, + cleanupAfterClose: []string{}, } } func (e *ShellExecutor) Prepare() int { + if !e.hasSSHJumpPoint { + return 0 + } + return e.setUpSSHJumpPoint() } @@ -65,15 +74,13 @@ func (e *ShellExecutor) setUpSSHJumpPoint() int { } func (e *ShellExecutor) Start() int { - cmd := exec.Command("bash", "--login") - - shell, err := shell.NewShell(cmd, e.tmpDirectory) + sh, err := shell.NewShell(e.tmpDirectory) if err != nil { - log.Debug(shell) + log.Debug(sh) return 1 } - e.Shell = shell + e.Shell = sh err = e.Shell.Start() if err != nil { @@ -97,42 +104,53 @@ func (e *ShellExecutor) ExportEnvVars(envVars []api.EnvVar, hostEnvVars []config e.Logger.LogCommandFinished(directive, exitCode, commandStartedAt, commandFinishedAt) }() - envFile := "" - - for _, env := range envVars { - e.Logger.LogCommandOutput(fmt.Sprintf("Exporting %s\n", env.Name)) - - value, err := env.Decode() - - if err != nil { - exitCode = 1 - return exitCode - } - - envFile += fmt.Sprintf("export %s=%s\n", env.Name, ShellQuote(string(value))) + environment, err := shell.CreateEnvironment(envVars, hostEnvVars) + if err != nil { + exitCode = 1 + return exitCode } - for _, env := range hostEnvVars { - e.Logger.LogCommandOutput(fmt.Sprintf("Exporting %s\n", env.Name)) - envFile += fmt.Sprintf("export %s=%s\n", env.Name, ShellQuote(env.Value)) + /* + * In windows, no PTY is used, so the environment state + * is tracked in the shell itself. + */ + if runtime.GOOS == "windows" { + e.Shell.Env.Append(environment, func(name, value string) { + e.Logger.LogCommandOutput(fmt.Sprintf("Exporting %s\n", name)) + }) + + exitCode = 0 + return exitCode } - // #nosec - err := ioutil.WriteFile("/tmp/.env", []byte(envFile), 0644) + /* + * If not windows, we use a PTY, so there's no need to track + * the environment state here. + */ + envFileName := filepath.Join(e.tmpDirectory, fmt.Sprintf(".env-%d", time.Now().UnixNano())) + err = environment.ToFile(envFileName, func(name string) { + e.Logger.LogCommandOutput(fmt.Sprintf("Exporting %s\n", name)) + }) if err != nil { exitCode = 1 return exitCode } - exitCode = e.RunCommand("source /tmp/.env", true, "") + e.cleanupAfterClose = append(e.cleanupAfterClose, envFileName) + + cmd := fmt.Sprintf("source %s", envFileName) + exitCode = e.RunCommand(cmd, true, "") if exitCode != 0 { return exitCode } - exitCode = e.RunCommand("echo 'source /tmp/.env' >> ~/.bash_profile", true, "") - if exitCode != 0 { - return exitCode + if e.shouldUpdateBashProfile { + cmd = fmt.Sprintf("echo 'source %s' >> ~/.bash_profile", envFileName) + exitCode = e.RunCommand(cmd, true, "") + if exitCode != 0 { + return exitCode + } } return exitCode @@ -145,6 +163,12 @@ func (e *ShellExecutor) InjectFiles(files []api.File) int { e.Logger.LogCommandStarted(directive) + homeDir, err := os.UserHomeDir() + if err != nil { + log.Errorf("Error finding home directory: %v\n", err) + return 1 + } + for _, f := range files { output := fmt.Sprintf("Injecting %s with file mode %s\n", f.Path, f.Mode) @@ -157,45 +181,40 @@ func (e *ShellExecutor) InjectFiles(files []api.File) int { return exitCode } - tmpPath := fmt.Sprintf("%s/file", e.tmpDirectory) - - // #nosec - err = ioutil.WriteFile(tmpPath, []byte(content), 0644) + destPath := f.NormalizePath(homeDir) + err = os.MkdirAll(path.Dir(destPath), 0644) if err != nil { - e.Logger.LogCommandOutput(err.Error() + "\n") - exitCode = 255 + e.Logger.LogCommandOutput(fmt.Sprintf("Failed to create directories for '%s': %v\n", destPath, err)) + exitCode = 1 break } - destPath := "" - - if f.Path[0] == '/' || f.Path[0] == '~' { - destPath = f.Path - } else { - destPath = "~/" + f.Path + // #nosec + destFile, err := os.OpenFile(destPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644) + if err != nil { + e.Logger.LogCommandOutput(fmt.Sprintf("Failed to create destination path '%s': %v\n", destPath, err)) + exitCode = 1 + break } - cmd := fmt.Sprintf("mkdir -p %s", path.Dir(destPath)) - exitCode = e.RunCommand(cmd, true, "") - if exitCode != 0 { - output := fmt.Sprintf("Failed to create destination path %s", destPath) - e.Logger.LogCommandOutput(output + "\n") + _, err = destFile.Write(content) + if err != nil { + e.Logger.LogCommandOutput(err.Error() + "\n") + exitCode = 255 break } - cmd = fmt.Sprintf("cp %s %s", tmpPath, destPath) - exitCode = e.RunCommand(cmd, true, "") - if exitCode != 0 { - output := fmt.Sprintf("Failed to move to destination path %s %s", tmpPath, destPath) - e.Logger.LogCommandOutput(output + "\n") + fileMode, err := f.ParseMode() + if err != nil { + e.Logger.LogCommandOutput(err.Error() + "\n") + exitCode = 1 break } - cmd = fmt.Sprintf("chmod %s %s", f.Mode, destPath) - exitCode = e.RunCommand(cmd, true, "") - if exitCode != 0 { - output := fmt.Sprintf("Failed to set file mode to %s", f.Mode) - e.Logger.LogCommandOutput(output + "\n") + err = os.Chmod(destPath, fileMode) + if err != nil { + e.Logger.LogCommandOutput(fmt.Sprintf("Failed to set file mode '%s' for '%s': %v\n", f.Mode, destPath, err)) + exitCode = 1 break } } @@ -246,11 +265,28 @@ func (e *ShellExecutor) Stop() int { log.Error(err) } - log.Debug("Process killing finished without errors") + err = e.Shell.Terminate() + if err != nil { + log.Errorf("Error terminating shell: %v", err) + return 1 + } + exitCode := e.Cleanup() + if exitCode != 0 { + log.Errorf("Error cleaning up executor resources: %v", err) + return exitCode + } + + log.Debug("Process killing finished without errors") return 0 } func (e *ShellExecutor) Cleanup() int { + for _, resource := range e.cleanupAfterClose { + if err := os.Remove(resource); err != nil { + log.Errorf("Error removing %s: %v\n", resource, err) + } + } + return 0 } diff --git a/pkg/executors/shell_executor_test.go b/pkg/executors/shell_executor_test.go index aca1ec82..f7c9da61 100644 --- a/pkg/executors/shell_executor_test.go +++ b/pkg/executors/shell_executor_test.go @@ -23,7 +23,7 @@ func Test__ShellExecutor(t *testing.T) { }, } - e := NewShellExecutor(request, testLogger) + e := NewShellExecutor(request, testLogger, true) e.Prepare() e.Start() @@ -35,17 +35,18 @@ func Test__ShellExecutor(t *testing.T) { echo 'etc exists, multiline huzzahh!' fi ` + e.RunCommand(multilineCmd, false, "") envVars := []api.EnvVar{ - api.EnvVar{Name: "A", Value: "Zm9vCg=="}, + {Name: "A", Value: "Zm9vCg=="}, } e.ExportEnvVars(envVars, []config.HostEnvVar{}) e.RunCommand("echo $A", false, "") files := []api.File{ - api.File{ + { Path: "/tmp/random-file.txt", Content: "YWFhYmJiCgo=", Mode: "0600", @@ -102,7 +103,7 @@ func Test__ShellExecutor__StopingRunningJob(t *testing.T) { }, } - e := NewShellExecutor(request, testLogger) + e := NewShellExecutor(request, testLogger, true) e.Prepare() e.Start() @@ -139,7 +140,7 @@ func Test__ShellExecutor__LargeCommandOutput(t *testing.T) { }, } - e := NewShellExecutor(request, testLogger) + e := NewShellExecutor(request, testLogger, true) e.Prepare() e.Start() diff --git a/pkg/executors/ssh_jump_point.go b/pkg/executors/ssh_jump_point.go index 12242de3..df59a9a2 100644 --- a/pkg/executors/ssh_jump_point.go +++ b/pkg/executors/ssh_jump_point.go @@ -1,12 +1,15 @@ package executors -import "os" - -const SSHJumpPointPath = "/tmp/ssh_jump_point" +import ( + "os" + "path/filepath" +) func SetUpSSHJumpPoint(script string) error { + path := filepath.Join(os.TempDir(), "ssh_jump_point") + // #nosec - f, err := os.OpenFile(SSHJumpPointPath, os.O_WRONLY|os.O_CREATE, 0644) + f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644) if err != nil { return err } diff --git a/pkg/executors/utils.go b/pkg/executors/utils.go deleted file mode 100644 index bb584e69..00000000 --- a/pkg/executors/utils.go +++ /dev/null @@ -1,32 +0,0 @@ -package executors - -import ( - "os" - "regexp" - "runtime" - "strings" -) - -func UserHomeDir() string { - if runtime.GOOS == "windows" { - home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") - if home == "" { - home = os.Getenv("USERPROFILE") - } - return home - } - return os.Getenv("HOME") -} - -func ShellQuote(s string) string { - pattern := regexp.MustCompile(`[^\w@%+=:,./-]`) - - if len(s) == 0 { - return "''" - } - if pattern.MatchString(s) { - return "'" + strings.Replace(s, "'", "'\"'\"'", -1) + "'" - } - - return s -} diff --git a/pkg/jobs/job.go b/pkg/jobs/job.go index 7af5188e..d622a53a 100644 --- a/pkg/jobs/job.go +++ b/pkg/jobs/job.go @@ -2,6 +2,7 @@ package jobs import ( "bytes" + "encoding/base64" "fmt" "net/http" "time" @@ -37,6 +38,7 @@ type JobOptions struct { ExposeKvmDevice bool FileInjections []config.FileInjection FailOnMissingFiles bool + SelfHosted bool } func NewJob(request *api.JobRequest, client *http.Client) (*Job, error) { @@ -46,6 +48,7 @@ func NewJob(request *api.JobRequest, client *http.Client) (*Job, error) { ExposeKvmDevice: true, FileInjections: []config.FileInjection{}, FailOnMissingFiles: false, + SelfHosted: false, }) } @@ -85,7 +88,7 @@ func NewJobWithOptions(options *JobOptions) (*Job, error) { func CreateExecutor(request *api.JobRequest, logger *eventlogger.Logger, jobOptions JobOptions) (executors.Executor, error) { switch request.Executor { case executors.ExecutorTypeShell: - return executors.NewShellExecutor(request, logger), nil + return executors.NewShellExecutor(request, logger, jobOptions.SelfHosted), nil case executors.ExecutorTypeDockerCompose: executorOptions := executors.DockerComposeExecutorOptions{ ExposeKvmDevice: jobOptions.ExposeKvmDevice, @@ -132,13 +135,9 @@ func (job *Job) RunWithOptions(options RunOptions) { if executorRunning { result = job.RunRegularCommands(options.EnvVars) log.Debug("Exporting job result") - job.RunCommandsUntilFirstFailure([]api.Command{ - { - Directive: fmt.Sprintf("export SEMAPHORE_JOB_RESULT=%s", result), - }, - }) if result != JobStopped { + log.Debug("Handling epilogues") job.handleEpilogues(result) } } @@ -204,6 +203,15 @@ func (job *Job) RunRegularCommands(hostEnvVars []config.HostEnvVar) string { } func (job *Job) handleEpilogues(result string) { + envVars := []api.EnvVar{ + {Name: "SEMAPHORE_JOB_RESULT", Value: base64.RawStdEncoding.EncodeToString([]byte(result))}, + } + + exitCode := job.Executor.ExportEnvVars(envVars, []config.HostEnvVar{}) + if exitCode != 0 { + log.Errorf("Error setting SEMAPHORE_JOB_RESULT: exit code %d", exitCode) + } + job.executeIfNotStopped(func() { log.Info("Starting epilogue always commands") job.RunCommandsUntilFirstFailure(job.Request.EpilogueAlwaysCommands) diff --git a/pkg/listener/job_processor.go b/pkg/listener/job_processor.go index 30e19b1d..83e3f33b 100644 --- a/pkg/listener/job_processor.go +++ b/pkg/listener/job_processor.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" "os/signal" + "runtime" "syscall" "time" @@ -14,6 +15,7 @@ import ( jobs "github.com/semaphoreci/agent/pkg/jobs" selfhostedapi "github.com/semaphoreci/agent/pkg/listener/selfhostedapi" "github.com/semaphoreci/agent/pkg/retry" + "github.com/semaphoreci/agent/pkg/shell" log "github.com/sirupsen/logrus" ) @@ -172,6 +174,7 @@ func (p *JobProcessor) RunJob(jobID string) { ExposeKvmDevice: false, FileInjections: p.FileInjections, FailOnMissingFiles: p.FailOnMissingFiles, + SelfHosted: true, }) if err != nil { @@ -267,20 +270,27 @@ func (p *JobProcessor) Shutdown(reason ShutdownReason, code int) { } func (p *JobProcessor) executeShutdownHook(reason ShutdownReason) { - if p.ShutdownHookPath != "" { - log.Infof("Executing shutdown hook from %s", p.ShutdownHookPath) + if p.ShutdownHookPath == "" { + return + } - // #nosec - cmd := exec.Command("bash", p.ShutdownHookPath) - cmd.Env = os.Environ() - cmd.Env = append(cmd.Env, fmt.Sprintf("SEMAPHORE_AGENT_SHUTDOWN_REASON=%s", reason)) + var cmd *exec.Cmd + log.Infof("Executing shutdown hook from %s", p.ShutdownHookPath) - output, err := cmd.Output() - if err != nil { - log.Errorf("Error executing shutdown hook: %v", err) - log.Errorf("Output: %s", string(output)) - } else { - log.Infof("Output: %s", string(output)) - } + // #nosec + if runtime.GOOS == "windows" { + args := append(shell.Args(), p.ShutdownHookPath) + cmd = exec.Command(shell.Executable(), args...) + } else { + cmd = exec.Command("bash", p.ShutdownHookPath) + } + + cmd.Env = append(os.Environ(), fmt.Sprintf("SEMAPHORE_AGENT_SHUTDOWN_REASON=%s", reason)) + output, err := cmd.Output() + if err != nil { + log.Errorf("Error executing shutdown hook: %v", err) + log.Errorf("Output: %s", string(output)) + } else { + log.Infof("Output: %s", string(output)) } } diff --git a/pkg/osinfo/name.go b/pkg/osinfo/name.go new file mode 100644 index 00000000..e16e86ec --- /dev/null +++ b/pkg/osinfo/name.go @@ -0,0 +1,17 @@ +// +build !windows + +package osinfo + +import "runtime" + +func Name() string { + switch runtime.GOOS { + case "linux": + return namelinux() + case "darwin": + return namemac() + default: + // TODO handle other OSes + return "" + } +} diff --git a/pkg/osinfo/name_windows.go b/pkg/osinfo/name_windows.go new file mode 100644 index 00000000..6cf0a258 --- /dev/null +++ b/pkg/osinfo/name_windows.go @@ -0,0 +1,16 @@ +package osinfo + +import ( + "fmt" + "golang.org/x/sys/windows" +) + +func Name() string { + info := windows.RtlGetVersion() + return fmt.Sprintf( + "Windows %d.%d - Build %d", + info.MajorVersion, + info.MinorVersion, + info.BuildNumber, + ) +} diff --git a/pkg/osinfo/osinfo.go b/pkg/osinfo/osinfo.go index 7a207e8a..143c8b27 100644 --- a/pkg/osinfo/osinfo.go +++ b/pkg/osinfo/osinfo.go @@ -8,18 +8,6 @@ import ( "strings" ) -func Name() string { - switch runtime.GOOS { - case "linux": - return namelinux() - case "darwin": - return namemac() - default: - // TODO handle other OSes - return "" - } -} - func Hostname() string { hostname, err := os.Hostname() if err != nil { diff --git a/pkg/server/server.go b/pkg/server/server.go index 3c379db2..1007c91c 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "net/http" "os" + "path/filepath" "strconv" handlers "github.com/gorilla/handlers" @@ -103,7 +104,7 @@ func (s *Server) Status(w http.ResponseWriter, r *http.Request) { jsonString, _ := json.Marshal(m) - fmt.Fprintf(w, string(jsonString)) + fmt.Fprint(w, string(jsonString)) } func (s *Server) isAlive(w http.ResponseWriter, r *http.Request) { @@ -144,7 +145,10 @@ func (s *Server) JobLogs(w http.ResponseWriter, r *http.Request) { func (s *Server) AgentLogs(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "text/plain") - logfile, err := os.Open("/tmp/agent_log") + logsPath := filepath.Join(os.TempDir(), "agent_log") + + // #nosec + logfile, err := os.Open(logsPath) if err != nil { w.WriteHeader(404) @@ -206,6 +210,7 @@ func (s *Server) Run(w http.ResponseWriter, r *http.Request) { Client: s.HTTPClient, ExposeKvmDevice: true, FileInjections: []config.FileInjection{}, + SelfHosted: false, }) if err != nil { diff --git a/pkg/shell/env.go b/pkg/shell/env.go new file mode 100644 index 00000000..693f7a02 --- /dev/null +++ b/pkg/shell/env.go @@ -0,0 +1,145 @@ +package shell + +import ( + "fmt" + "io/ioutil" + "regexp" + "sort" + "strings" + + "github.com/semaphoreci/agent/pkg/api" + "github.com/semaphoreci/agent/pkg/config" +) + +type Environment struct { + env map[string]string +} + +func CreateEnvironment(envVars []api.EnvVar, HostEnvVars []config.HostEnvVar) (*Environment, error) { + newEnv := Environment{} + for _, envVar := range envVars { + value, err := envVar.Decode() + if err != nil { + return nil, err + } + + newEnv.Set(envVar.Name, string(value)) + } + + for _, envVar := range HostEnvVars { + newEnv.Set(envVar.Name, envVar.Value) + } + + return &newEnv, nil +} + +/* + * Create an environment by reading a file created with + * an environment dump in Windows with the 'SET > ' command. + */ +func CreateEnvironmentFromFile(fileName string) (*Environment, error) { + // #nosec + bytes, err := ioutil.ReadFile(fileName) + if err != nil { + return nil, err + } + + contents := string(bytes) + contents = strings.TrimSpace(contents) + contents = strings.Replace(contents, "\r\n", "\n", -1) + + lines := strings.Split(contents, "\n") + environment := Environment{env: map[string]string{}} + + for _, line := range lines { + nameAndValue := strings.SplitN(line, "=", 2) + if len(nameAndValue) == 2 { + environment.Set(nameAndValue[0], nameAndValue[1]) + } + } + + return &environment, nil +} + +func (e *Environment) IsEmpty() bool { + return e.env != nil || len(e.env) == 0 +} + +func (e *Environment) Set(name, value string) { + if e.env == nil { + e.env = map[string]string{} + } + + e.env[name] = value +} + +func (e *Environment) Get(key string) (string, bool) { + v, ok := e.env[key] + return v, ok +} + +func (e *Environment) Remove(key string) { + _, ok := e.Get(key) + if ok { + delete(e.env, key) + } +} + +func (e *Environment) Keys() []string { + var keys []string + for k := range e.env { + keys = append(keys, k) + } + + sort.Strings(keys) + return keys +} + +func (e *Environment) Append(otherEnv *Environment, callback func(name, value string)) { + for _, name := range otherEnv.Keys() { + value, _ := otherEnv.Get(name) + e.Set(name, value) + if callback != nil { + callback(name, value) + } + } +} + +func (e *Environment) ToSlice() []string { + arr := []string{} + for name, value := range e.env { + arr = append(arr, fmt.Sprintf("%s=%s", name, value)) + } + + return arr +} + +func (e *Environment) ToFile(fileName string, callback func(name string)) error { + fileContent := "" + for _, name := range e.Keys() { + value, _ := e.Get(name) + fileContent += fmt.Sprintf("export %s=%s\n", name, shellQuote(value)) + callback(name) + } + + // #nosec + err := ioutil.WriteFile(fileName, []byte(fileContent), 0644) + if err != nil { + return err + } + + return nil +} + +func shellQuote(s string) string { + pattern := regexp.MustCompile(`[^\w@%+=:,./-]`) + + if len(s) == 0 { + return "''" + } + if pattern.MatchString(s) { + return "'" + strings.Replace(s, "'", "'\"'\"'", -1) + "'" + } + + return s +} diff --git a/pkg/shell/output_buffer.go b/pkg/shell/output_buffer.go index 7d297426..b4ab9c7a 100644 --- a/pkg/shell/output_buffer.go +++ b/pkg/shell/output_buffer.go @@ -58,7 +58,7 @@ func (b *OutputBuffer) Flush() (string, bool) { timeSinceLastAppend := 1 * time.Millisecond if b.lastAppend != nil { - timeSinceLastAppend = time.Now().Sub(*b.lastAppend) + timeSinceLastAppend = time.Since(*b.lastAppend) } log.Debugf("Flushing. %d bytes in the buffer", len(b.bytes)) diff --git a/pkg/shell/output_buffer_test.go b/pkg/shell/output_buffer_test.go index a87978d5..04d07689 100644 --- a/pkg/shell/output_buffer_test.go +++ b/pkg/shell/output_buffer_test.go @@ -31,14 +31,14 @@ func Test__OutputBuffer__SimpleAscii__ShorterThanMinimalCutLength(t *testing.T) input := []byte("aaa") buffer.Append(input) - flushed, ok := buffer.Flush() + _, ok := buffer.Flush() // We need to wait a bit before flushing, the buffer is still too short assert.Equal(t, ok, false) time.Sleep(OutputBufferMaxTimeSinceLastAppend) - flushed, ok = buffer.Flush() + flushed, ok := buffer.Flush() assert.Equal(t, ok, true) assert.Equal(t, flushed, string(input)) } diff --git a/pkg/shell/process.go b/pkg/shell/process.go index a1fbe167..17839094 100644 --- a/pkg/shell/process.go +++ b/pkg/shell/process.go @@ -3,64 +3,91 @@ package shell import ( "flag" "fmt" + "io" "io/ioutil" "math/rand" + "os" + "os/exec" + "path/filepath" "regexp" + "runtime" "strconv" "strings" + "syscall" "time" log "github.com/sirupsen/logrus" ) -type Process struct { - Command string - Shell *Shell - - StartedAt int - FinishedAt int - ExitCode int +/* + * Windows does not support a PTY yet. To allow changing directories, + * and setting/unsetting environment variables, we need to keep track + * of the environment on every command executed. We do that by + * getting the whole environment after a command is executed and + * updating our shell with it. + */ +const WindowsPwshScript = ` +$ErrorActionPreference = "STOP" +%s +if ($LASTEXITCODE -eq $null) {$Env:SEMAPHORE_AGENT_CURRENT_CMD_EXIT_STATUS = 0} else {$Env:SEMAPHORE_AGENT_CURRENT_CMD_EXIT_STATUS = $LASTEXITCODE} +$Env:SEMAPHORE_AGENT_CURRENT_DIR = $PWD | Select-Object -ExpandProperty Path +Get-ChildItem Env: | Foreach-Object {"$($_.Name)=$($_.Value)"} | Set-Content "%s.env.after" +exit $Env:SEMAPHORE_AGENT_CURRENT_CMD_EXIT_STATUS +` + +type Config struct { + Shell *Shell + StoragePath string + Command string +} +type Process struct { + Command string + Shell *Shell + StoragePath string + StartedAt int + FinishedAt int + ExitCode int OnStdoutCallback func(string) - - startMark string - endMark string - commandEndRegex *regexp.Regexp - - tempStoragePath string - cmdFilePath string - - inputBuffer []byte - outputBuffer *OutputBuffer + Pid int + startMark string + endMark string + commandEndRegex *regexp.Regexp + inputBuffer []byte + outputBuffer *OutputBuffer + SysProcAttr *syscall.SysProcAttr } func randomMagicMark() string { return fmt.Sprintf("949556c7-%d", time.Now().Unix()) } -func NewProcess(cmd string, tempStoragePath string, shell *Shell) *Process { +func NewProcess(config Config) *Process { startMark := randomMagicMark() + "-start" endMark := randomMagicMark() + "-end" commandEndRegex := regexp.MustCompile(endMark + " " + `(\d+)` + "[\r\n]+") return &Process{ - Command: cmd, - ExitCode: 1, - - Shell: shell, - - startMark: startMark, - endMark: endMark, - + Shell: config.Shell, + StoragePath: config.StoragePath, + Command: config.Command, + ExitCode: 1, + startMark: startMark, + endMark: endMark, commandEndRegex: commandEndRegex, - tempStoragePath: tempStoragePath, - cmdFilePath: tempStoragePath + "/current-agent-cmd", - - outputBuffer: NewOutputBuffer(), + outputBuffer: NewOutputBuffer(), } } +func (p *Process) CmdFilePath() string { + return filepath.Join(p.StoragePath, "current-agent-cmd") +} + +func (p *Process) EnvironmentFilePath() string { + return fmt.Sprintf("%s.env.after", p.CmdFilePath()) +} + func (p *Process) OnStdout(callback func(string)) { p.OnStdoutCallback = callback } @@ -105,7 +132,6 @@ func (p *Process) flushInputBufferTill(index int) { func (p *Process) Run() { instruction := p.constructShellInstruction() - p.StartedAt = int(time.Now().Unix()) defer func() { p.FinishedAt = int(time.Now().Unix()) @@ -117,7 +143,132 @@ func (p *Process) Run() { return } - _, err = p.Shell.Write(instruction) + /* + * If the agent is running in an non-windows environment, + * we use a PTY session to run commands. + */ + if runtime.GOOS != "windows" { + p.runWithPTY(instruction) + return + } + + // In windows, so no PTY support. + p.setup() + p.runWithoutPTY(instruction) + + /* + * If we are not using a PTY, we need to keep track of shell "state" ourselves. + * We use a file with all the environment variables available after the command + * is executed. From that file, we can update our shell "state". + */ + after, _ := CreateEnvironmentFromFile(p.EnvironmentFilePath()) + + /* + * CMD.exe does not have an environment variable such as $PWD, + * so we use a custom one to get the current working directory + * after a command is executed. + */ + newCwd, _ := after.Get("SEMAPHORE_AGENT_CURRENT_DIR") + p.Shell.Chdir(newCwd) + + /* + * We use two custom environment variables to track + * things we need, but we don't want to mess the environment + * so we remove them before updating our shell state. + */ + after.Remove("SEMAPHORE_AGENT_CURRENT_DIR") + after.Remove("SEMAPHORE_AGENT_CURRENT_CMD_EXIT_STATUS") + p.Shell.UpdateEnvironment(after) +} + +func (p *Process) runWithoutPTY(instruction string) { + cmd, reader, writer := p.buildNonPTYCommand(instruction) + err := cmd.Start() + if err != nil { + log.Errorf("Error starting command: %v\n", err) + p.ExitCode = 1 + return + } + + /* + * In Windows, we need to assign the process created by the command + * with the job object handle we created for it earlier, + * for process termination purposes. + */ + p.Pid = cmd.Process.Pid + err = p.afterCreation(p.Shell.windowsJobObject) + if err != nil { + log.Errorf("Process after creation procedure failed: %v", err) + } + + /* + * Start reading the command's output and wait until it finishes. + */ + done := make(chan bool, 1) + go p.readNonPTY(reader, done) + waitResult := cmd.Wait() + + /* + * Command is done, We close our output writer + * so our output reader knows the command is over. + */ + err = writer.Close() + if err != nil { + log.Errorf("Error closing writer: %v", err) + } + + /* + * Let's wait for the reader to finish, just to make sure + * we don't leave any goroutines hanging around. + */ + log.Debug("Waiting for reading to finish") + <-done + + /* + * The command was successful, so we just return. + */ + if waitResult == nil { + p.ExitCode = 0 + return + } + + /* + * The command returned an error, so we need to figure out the exit code from it. + * If we can't figure it out, we just use 1 and carry on. + */ + if err, ok := waitResult.(*exec.ExitError); ok { + if s, ok := err.Sys().(syscall.WaitStatus); ok { + p.ExitCode = s.ExitStatus() + } else { + log.Errorf("Could not cast *exec.ExitError to syscall.WaitStatus: %v\n", err) + p.ExitCode = 1 + } + } else { + log.Errorf("Unexpected %T returned after Wait(): %v", waitResult, waitResult) + p.ExitCode = 1 + } +} + +func (p *Process) buildNonPTYCommand(instruction string) (*exec.Cmd, *io.PipeReader, *io.PipeWriter) { + args := append(p.Shell.Args, instruction) + + // #nosec + cmd := exec.Command(p.Shell.Executable, args...) + cmd.Dir = p.Shell.Cwd + cmd.SysProcAttr = p.SysProcAttr + + if p.Shell.Env != nil { + cmd.Env = append(os.Environ(), p.Shell.Env.ToSlice()...) + } + + reader, writer := io.Pipe() + cmd.Stdout = writer + cmd.Stderr = writer + return cmd, reader, writer +} + +func (p *Process) runWithPTY(instruction string) { + _, err := p.Shell.Write(instruction) if err != nil { log.Errorf("Error writing instruction: %v", err) return @@ -127,6 +278,10 @@ func (p *Process) Run() { } func (p *Process) constructShellInstruction() string { + if runtime.GOOS == "windows" { + return fmt.Sprintf(`%s.ps1`, p.CmdFilePath()) + } + // // A process is sending a complex instruction to the shell. The instruction // does the following: @@ -139,22 +294,27 @@ func (p *Process) constructShellInstruction() string { // template := `echo -e "\001 %s"; source %s; AGENT_CMD_RESULT=$?; echo -e "\001 %s $AGENT_CMD_RESULT"; echo "exit $AGENT_CMD_RESULT" | sh` - return fmt.Sprintf(template, p.startMark, p.cmdFilePath, p.endMark) + return fmt.Sprintf(template, p.startMark, p.CmdFilePath(), p.endMark) } +/* + * Multiline commands don't work very well with the start/finish marker. + * scheme. To circumvent this, we are storing the command in a file. + */ func (p *Process) loadCommand() error { - // - // Multiline commands don't work very well with the start/finish marker - // scheme. To circumvent this, we are storing the command in a file - // + if runtime.GOOS != "windows" { + return p.writeCommandToFile(p.CmdFilePath(), p.Command) + } + + cmdFilePath := fmt.Sprintf("%s.ps1", p.CmdFilePath()) + command := fmt.Sprintf(WindowsPwshScript, p.Command, p.CmdFilePath()) + return p.writeCommandToFile(cmdFilePath, command) +} +func (p *Process) writeCommandToFile(cmdFilePath, command string) error { // #nosec - err := ioutil.WriteFile(p.cmdFilePath, []byte(p.Command), 0644) + err := ioutil.WriteFile(cmdFilePath, []byte(command), 0644) if err != nil { - // TODO: log something - // e.Logger.LogCommandStarted(command) - // e.Logger.LogCommandOutput(fmt.Sprintf("Failed to run command: %+v\n", err)) - return err } @@ -179,6 +339,30 @@ func (p *Process) readBufferSize() int { return rand.Intn(max-min) + min } +func (p *Process) readNonPTY(reader *io.PipeReader, done chan bool) { + for { + log.Debug("Reading started") + buffer := make([]byte, p.readBufferSize()) + n, err := reader.Read(buffer) + if err != nil && err != io.EOF { + log.Errorf("Error while reading. Error: %v", err) + } + + p.inputBuffer = append(p.inputBuffer, buffer[0:n]...) + log.Debugf("reading data from command. Input buffer: %#v", string(p.inputBuffer)) + p.flushInputAll() + p.StreamToStdout() + + if err == io.EOF { + log.Debug("Finished reading") + p.flushOutputBuffer() + break + } + } + + done <- true +} + // // Read state from shell into the inputBuffer // diff --git a/pkg/shell/process_setup.go b/pkg/shell/process_setup.go new file mode 100644 index 00000000..1cdbfe83 --- /dev/null +++ b/pkg/shell/process_setup.go @@ -0,0 +1,17 @@ +// +build !windows + +package shell + +/* + * For non-windows agents, we handle job termination + * by closing the TTY associated with the job. + * Therefore, no special handling here is necessary. + */ + +func (p *Process) setup() { + +} + +func (p *Process) afterCreation(jobObject uintptr) error { + return nil +} diff --git a/pkg/shell/process_setup_windows.go b/pkg/shell/process_setup_windows.go new file mode 100644 index 00000000..553a2c22 --- /dev/null +++ b/pkg/shell/process_setup_windows.go @@ -0,0 +1,30 @@ +// +build windows + +package shell + +import ( + "golang.org/x/sys/windows" +) + +func (p *Process) setup() { + p.SysProcAttr = &windows.SysProcAttr{ + CreationFlags: windows.CREATE_UNICODE_ENVIRONMENT | windows.CREATE_NEW_PROCESS_GROUP, + } +} + +func (p *Process) afterCreation(jobObject uintptr) error { + permissions := uint32(windows.PROCESS_QUERY_LIMITED_INFORMATION | windows.PROCESS_SET_QUOTA | windows.PROCESS_TERMINATE) + processHandle, err := windows.OpenProcess(permissions, false, uint32(p.Pid)) + if err != nil { + return err + } + + defer windows.CloseHandle(processHandle) + + err = windows.AssignProcessToJobObject(windows.Handle(jobObject), processHandle) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/shell/pty.go b/pkg/shell/pty.go new file mode 100644 index 00000000..4538a9cd --- /dev/null +++ b/pkg/shell/pty.go @@ -0,0 +1,14 @@ +// +build !windows + +package shell + +import ( + "os" + "os/exec" + + pty "github.com/creack/pty" +) + +func StartPTY(command *exec.Cmd) (*os.File, error) { + return pty.Start(command) +} diff --git a/pkg/shell/pty_windows.go b/pkg/shell/pty_windows.go new file mode 100644 index 00000000..c7b8fa1c --- /dev/null +++ b/pkg/shell/pty_windows.go @@ -0,0 +1,13 @@ +// +build windows + +package shell + +import ( + "errors" + "os" + "os/exec" +) + +func StartPTY(c *exec.Cmd) (*os.File, error) { + return nil, errors.New("PTY is not supported on Windows") +} diff --git a/pkg/shell/shell.go b/pkg/shell/shell.go index 42b2cab1..ded0767e 100644 --- a/pkg/shell/shell.go +++ b/pkg/shell/shell.go @@ -6,34 +6,68 @@ import ( "fmt" "os" "os/exec" + "runtime" "strings" "time" - pty "github.com/creack/pty" log "github.com/sirupsen/logrus" ) type Shell struct { + Executable string + Args []string BootCommand *exec.Cmd StoragePath string TTY *os.File ExitSignal chan string + Env *Environment + Cwd string + + /* + * A job object handle used to interrupt the command + * process in case of a stop request. + */ + windowsJobObject uintptr } -func NewShell(bootCommand *exec.Cmd, storagePath string) (*Shell, error) { +func NewShell(storagePath string) (*Shell, error) { + return NewShellFromExecAndArgs(Executable(), Args(), storagePath) +} + +func NewShellFromExecAndArgs(executable string, args []string, storagePath string) (*Shell, error) { exitChannel := make(chan string, 1) + cwd, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("error finding current working directory: %v", err) + } + return &Shell{ - BootCommand: bootCommand, + Executable: executable, + Args: args, StoragePath: storagePath, ExitSignal: exitChannel, + Env: &Environment{}, + Cwd: cwd, }, nil } func (s *Shell) Start() error { + + /* + * In windows, we don't use a PTY, so we need to create a job object + * to assign the processes started by the user. + */ + if runtime.GOOS == "windows" { + s.Setup() + return nil + } + log.Debug("Starting stateful shell") - tty, err := pty.Start(s.BootCommand) + // #nosec + s.BootCommand = exec.Command(s.Executable, s.Args...) + tty, err := StartPTY(s.BootCommand) if err != nil { log.Errorf("Failed to start stateful shell: %v", err) return err @@ -182,7 +216,12 @@ func (s *Shell) silencePromptAndDisablePS1() error { } func (s *Shell) NewProcess(command string) *Process { - return NewProcess(command, s.StoragePath, s) + return NewProcess( + Config{ + Command: command, + Shell: s, + StoragePath: s.StoragePath, + }) } func (s *Shell) Close() error { @@ -194,7 +233,7 @@ func (s *Shell) Close() error { } } - if s.BootCommand.Process != nil { + if s.BootCommand != nil && s.BootCommand.Process != nil { err := s.BootCommand.Process.Kill() if err != nil && !errors.Is(err, os.ErrProcessDone) { log.Errorf("Process killing procedure returned an error %+v", err) @@ -204,3 +243,29 @@ func (s *Shell) Close() error { return nil } + +func (s *Shell) Chdir(newCwd string) { + if newCwd != s.Cwd { + s.Cwd = newCwd + } +} + +func (s *Shell) UpdateEnvironment(newEnvironment *Environment) { + s.Env = newEnvironment +} + +func Executable() string { + if runtime.GOOS == "windows" { + return "powershell" + } + + return "bash" +} + +func Args() []string { + if runtime.GOOS == "windows" { + return []string{"-NoProfile", "-NonInteractive"} + } + + return []string{"--login"} +} diff --git a/pkg/shell/shell_setup.go b/pkg/shell/shell_setup.go new file mode 100644 index 00000000..d6f67c23 --- /dev/null +++ b/pkg/shell/shell_setup.go @@ -0,0 +1,17 @@ +// +build !windows + +package shell + +/* + * For non-windows agents, we handle job termination + * by closing the TTY associated with the job. + * Therefore, no special handling here is necessary. + */ + +func (s *Shell) Setup() { + +} + +func (s *Shell) Terminate() error { + return nil +} diff --git a/pkg/shell/shell_setup_windows.go b/pkg/shell/shell_setup_windows.go new file mode 100644 index 00000000..6f04edcf --- /dev/null +++ b/pkg/shell/shell_setup_windows.go @@ -0,0 +1,44 @@ +// +build windows + +package shell + +import ( + "unsafe" + + log "github.com/sirupsen/logrus" + "golang.org/x/sys/windows" +) + +func (s *Shell) Setup() { + jobObject, err := windows.CreateJobObject(nil, nil) + if err != nil { + log.Errorf("Error creating job object: %v", err) + return + } + + info := windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION{ + BasicLimitInformation: windows.JOBOBJECT_BASIC_LIMIT_INFORMATION{ + LimitFlags: windows.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, + }, + } + + _, err = windows.SetInformationJobObject( + jobObject, + windows.JobObjectExtendedLimitInformation, + uintptr(unsafe.Pointer(&info)), + uint32(unsafe.Sizeof(info)), + ) + + if err != nil { + log.Errorf("Error setting job object information: %v", err) + return + } + + log.Debugf("Successfully created job object: %v", jobObject) + s.windowsJobObject = uintptr(jobObject) +} + +func (s *Shell) Terminate() error { + log.Debugf("Terminating all processes assigned to job object %v", s.windowsJobObject) + return windows.CloseHandle(windows.Handle(s.windowsJobObject)) +} diff --git a/pkg/shell/shell_test.go b/pkg/shell/shell_test.go index f63ace0c..91d612cf 100644 --- a/pkg/shell/shell_test.go +++ b/pkg/shell/shell_test.go @@ -4,7 +4,6 @@ import ( "bytes" "io/ioutil" "log" - "os/exec" "testing" assert "github.com/stretchr/testify/assert" @@ -80,9 +79,7 @@ func tempStorageFolder() string { func bashShell() *Shell { dir := tempStorageFolder() - cmd := exec.Command("bash", "--login") - - shell, _ := NewShell(cmd, dir) + shell, _ := NewShell(dir) shell.Start() return shell diff --git a/scripts/provision-windows-box.ps1 b/scripts/provision-windows-box.ps1 new file mode 100644 index 00000000..9216465c --- /dev/null +++ b/scripts/provision-windows-box.ps1 @@ -0,0 +1,43 @@ +$ErrorActionPreference = "Stop" + +function Add-To-Path { + param ( + $Path + ) + + $Content = "if (-not (`$env:Path.Split(';').Contains('$Path'))) { `$env:Path = '$Path;' + `$env:Path }" + $ProfilePath = $profile.AllUsersAllHosts + Write-Output "Adding $Path to `$env:Path, using profile $ProfilePath..." + + if (-not (Test-Path $profilePath)) { + Write-Output "$ProfilePath does not exist. Creating it..." + New-Item $ProfilePath > $null + Set-Content $ProfilePath $Content + } else { + Add-Content -Path $ProfilePath -Value $Content + } +} + +Write-Output "Installing golang..." +choco install -y golang +If ($lastexitcode -ne 0) { Exit $lastexitcode } + +Write-Output "Installing Git for Windows" +choco install -y git --version 2.31.0 +If ($lastexitcode -ne 0) { Exit $lastexitcode } + +Add-To-Path -Path "C:\Program Files\Go\bin" +Add-To-Path -Path "C:\Program Files\Git\bin" + +Write-Output "Importing the choco profile module..." +$ChocolateyInstall = Convert-Path "$((Get-Command choco).path)\..\.." +Import-Module "$ChocolateyInstall\helpers\chocolateyProfile.psm1" +Write-Output "Refreshing the current session environment..." +Update-SessionEnvironment + +go version +If ($lastexitcode -ne 0) { Exit $lastexitcode } + +# no mismatched line endings +git config --system core.autocrlf false +If ($lastexitcode -ne 0) { Exit $lastexitcode } diff --git a/test/e2e/docker/broken_unicode.rb b/test/e2e/docker/broken_unicode.rb index 2f18c62b..de01ac9b 100644 --- a/test/e2e/docker/broken_unicode.rb +++ b/test/e2e/docker/broken_unicode.rb @@ -60,8 +60,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"\ufffd\ufffd\ufffd\ufffd\ufffd"} {"event":"cmd_finished", "timestamp":"*", "directive": "echo | awk '{ printf(\\\"%c%c%c%c%c\\\", 150, 150, 150, 150, 150) }'","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/check_dev_kvm.rb b/test/e2e/docker/check_dev_kvm.rb index 14384bf8..4396ec15 100644 --- a/test/e2e/docker/check_dev_kvm.rb +++ b/test/e2e/docker/check_dev_kvm.rb @@ -59,8 +59,10 @@ {"event":"cmd_output", "timestamp":"*", "output":"kvm\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"ls /dev | grep kvm","event":"cmd_finished","exit_code":0,"finished_at":"*","started_at":"*","timestamp":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG when "listen" then @@ -82,8 +84,10 @@ {"event":"cmd_started", "timestamp":"*", "directive":"ls /dev | grep kvm"} {"event":"cmd_finished", "timestamp":"*", "directive":"ls /dev | grep kvm","event":"cmd_finished","exit_code":1,"finished_at":"*","started_at":"*","timestamp":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/docker/command_aliases.rb b/test/e2e/docker/command_aliases.rb index acc109da..d57de016 100644 --- a/test/e2e/docker/command_aliases.rb +++ b/test/e2e/docker/command_aliases.rb @@ -56,7 +56,8 @@ {"event":"cmd_output", "timestamp":"*", "output":"Running: echo Hello World\\n"} {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"Display Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/container_custom_name.rb b/test/e2e/docker/container_custom_name.rb index 342e3eff..977bb276 100644 --- a/test/e2e/docker/container_custom_name.rb +++ b/test/e2e/docker/container_custom_name.rb @@ -83,7 +83,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"$PATH:/etc/a\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo $D","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/container_env_vars.rb b/test/e2e/docker/container_env_vars.rb index 9967c7e4..230e644b 100644 --- a/test/e2e/docker/container_env_vars.rb +++ b/test/e2e/docker/container_env_vars.rb @@ -60,7 +60,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"bar\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo $FOO","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/container_options.rb b/test/e2e/docker/container_options.rb index 8a3bbc60..2f807fa2 100644 --- a/test/e2e/docker/container_options.rb +++ b/test/e2e/docker/container_options.rb @@ -61,7 +61,9 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello World"} {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/docker_in_docker.rb b/test/e2e/docker/docker_in_docker.rb index 274047fc..7018e5d8 100644 --- a/test/e2e/docker/docker_in_docker.rb +++ b/test/e2e/docker/docker_in_docker.rb @@ -55,7 +55,9 @@ {"event":"cmd_started", "timestamp":"*", "directive":"docker run alpine uname 2>/dev/null | grep Linux"} {"event":"cmd_output", "timestamp":"*", "output":"Linux\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"docker run alpine uname 2>/dev/null | grep Linux","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/docker_private_image_gcr.rb b/test/e2e/docker/docker_private_image_gcr.rb index fac6ab3a..0454d210 100644 --- a/test/e2e/docker/docker_private_image_gcr.rb +++ b/test/e2e/docker/docker_private_image_gcr.rb @@ -77,7 +77,9 @@ {"directive":"echo Hello World","event":"cmd_started","timestamp":"*"} {"event":"cmd_output","output":"Hello World\\n","timestamp":"*"} {"directive":"echo Hello World","event":"cmd_finished","exit_code":0,"finished_at":"*","started_at":"*","timestamp":"*"} - {"directive":"export SEMAPHORE_JOB_RESULT=passed","event":"cmd_started","timestamp":"*"} - {"directive":"export SEMAPHORE_JOB_RESULT=passed","event":"cmd_finished","exit_code":0,"finished_at":"*","started_at":"*","timestamp":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished","result":"passed","timestamp":"*"} LOG diff --git a/test/e2e/docker/docker_registry_private_image.rb b/test/e2e/docker/docker_registry_private_image.rb index 93997489..062559bf 100644 --- a/test/e2e/docker/docker_registry_private_image.rb +++ b/test/e2e/docker/docker_registry_private_image.rb @@ -80,7 +80,9 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello World"} {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/dockerhub_private_image.rb b/test/e2e/docker/dockerhub_private_image.rb index 6982d5b1..c2391a31 100644 --- a/test/e2e/docker/dockerhub_private_image.rb +++ b/test/e2e/docker/dockerhub_private_image.rb @@ -78,7 +78,9 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello World"} {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/env_vars.rb b/test/e2e/docker/env_vars.rb index 0fb40206..cf52729e 100644 --- a/test/e2e/docker/env_vars.rb +++ b/test/e2e/docker/env_vars.rb @@ -83,7 +83,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"$PATH:/etc/a\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo $D","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/epilogue_on_fail.rb b/test/e2e/docker/epilogue_on_fail.rb index 7c9d5d08..88cb990b 100644 --- a/test/e2e/docker/epilogue_on_fail.rb +++ b/test/e2e/docker/epilogue_on_fail.rb @@ -27,15 +27,15 @@ ], "epilogue_always_commands": [ - { "directive": "echo Hello Epilogue" } + { "directive": "echo Hello Epilogue $SEMAPHORE_JOB_RESULT" } ], "epilogue_on_pass_commands": [ - { "directive": "echo Hello On Pass Epilogue" } + { "directive": "echo Hello On Pass Epilogue $SEMAPHORE_JOB_RESULT" } ], "epilogue_on_fail_commands": [ - { "directive": "echo Hello On Fail Epilogue" } + { "directive": "echo Hello On Fail Epilogue $SEMAPHORE_JOB_RESULT" } ], "callbacks": { @@ -67,16 +67,17 @@ {"event":"cmd_started", "timestamp":"*", "directive":"false"} {"event":"cmd_finished", "timestamp":"*", "directive":"false","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello Epilogue"} - {"event":"cmd_output", "timestamp":"*", "output":"Hello Epilogue\\n"} - {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello Epilogue","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello Epilogue $SEMAPHORE_JOB_RESULT"} + {"event":"cmd_output", "timestamp":"*", "output":"Hello Epilogue failed\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello Epilogue $SEMAPHORE_JOB_RESULT","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello On Fail Epilogue"} - {"event":"cmd_output", "timestamp":"*", "output":"Hello On Fail Epilogue\\n"} - {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello On Fail Epilogue","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello On Fail Epilogue $SEMAPHORE_JOB_RESULT"} + {"event":"cmd_output", "timestamp":"*", "output":"Hello On Fail Epilogue failed\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello On Fail Epilogue $SEMAPHORE_JOB_RESULT","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/docker/epilogue_on_pass.rb b/test/e2e/docker/epilogue_on_pass.rb index 0786c07e..0614fd55 100644 --- a/test/e2e/docker/epilogue_on_pass.rb +++ b/test/e2e/docker/epilogue_on_pass.rb @@ -27,15 +27,15 @@ ], "epilogue_always_commands": [ - { "directive": "echo Hello Epilogue" } + { "directive": "echo Hello Epilogue $SEMAPHORE_JOB_RESULT" } ], "epilogue_on_pass_commands": [ - { "directive": "echo Hello On Pass Epilogue" } + { "directive": "echo Hello On Pass Epilogue $SEMAPHORE_JOB_RESULT" } ], "epilogue_on_fail_commands": [ - { "directive": "echo Hello On Fail Epilogue" } + { "directive": "echo Hello On Fail Epilogue $SEMAPHORE_JOB_RESULT" } ], "callbacks": { @@ -68,16 +68,17 @@ {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello Epilogue"} - {"event":"cmd_output", "timestamp":"*", "output":"Hello Epilogue\\n"} - {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello Epilogue","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello Epilogue $SEMAPHORE_JOB_RESULT"} + {"event":"cmd_output", "timestamp":"*", "output":"Hello Epilogue passed\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello Epilogue $SEMAPHORE_JOB_RESULT","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello On Pass Epilogue"} - {"event":"cmd_output", "timestamp":"*", "output":"Hello On Pass Epilogue\\n"} - {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello On Pass Epilogue","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello On Pass Epilogue $SEMAPHORE_JOB_RESULT"} + {"event":"cmd_output", "timestamp":"*", "output":"Hello On Pass Epilogue passed\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello On Pass Epilogue $SEMAPHORE_JOB_RESULT","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/failed_job.rb b/test/e2e/docker/failed_job.rb index 1475322d..51ac3392 100644 --- a/test/e2e/docker/failed_job.rb +++ b/test/e2e/docker/failed_job.rb @@ -54,7 +54,9 @@ {"event":"cmd_finished", "timestamp":"*", "directive":"Injecting Files","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"false"} {"event":"cmd_finished", "timestamp":"*", "directive":"false","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/docker/file_injection.rb b/test/e2e/docker/file_injection.rb index 01384668..4289f145 100644 --- a/test/e2e/docker/file_injection.rb +++ b/test/e2e/docker/file_injection.rb @@ -23,7 +23,7 @@ "files": [ { "path": "test.txt", "content": "#{`echo "hello" | base64 | tr -d '\n'`}", "mode": "0644" }, { "path": "/a/b/c", "content": "#{`echo "hello" | base64 | tr -d '\n'`}", "mode": "0644" }, - { "path": "/tmp/a", "content": "#{`echo "hello" | base64 | tr -d '\n'`}", "mode": "+x" } + { "path": "/tmp/a", "content": "#{`echo "hello" | base64 | tr -d '\n'`}", "mode": "0600" } ], "commands": [ @@ -61,7 +61,7 @@ {"event":"cmd_started", "timestamp":"*", "directive":"Injecting Files"} {"event":"cmd_output", "timestamp":"*", "output":"Injecting test.txt with file mode 0644\\n"} {"event":"cmd_output", "timestamp":"*", "output":"Injecting /a/b/c with file mode 0644\\n"} - {"event":"cmd_output", "timestamp":"*", "output":"Injecting /tmp/a with file mode +x\\n"} + {"event":"cmd_output", "timestamp":"*", "output":"Injecting /tmp/a with file mode 0600\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"Injecting Files","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"cat test.txt"} @@ -73,10 +73,12 @@ {"event":"cmd_finished", "timestamp":"*", "directive":"cat /a/b/c","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"stat -c '%a' /tmp/a"} - {"event":"cmd_output", "timestamp":"*", "output":"755\\n"} + {"event":"cmd_output", "timestamp":"*", "output":"600\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"stat -c '%a' /tmp/a","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/file_injection_broken_file_mode.rb b/test/e2e/docker/file_injection_broken_file_mode.rb index ad4e3a87..ba118a5a 100644 --- a/test/e2e/docker/file_injection_broken_file_mode.rb +++ b/test/e2e/docker/file_injection_broken_file_mode.rb @@ -61,7 +61,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"Failed to set file mode to obviously broken\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"Injecting Files","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/docker/hello_world.rb b/test/e2e/docker/hello_world.rb index d56577da..cbca96ce 100644 --- a/test/e2e/docker/hello_world.rb +++ b/test/e2e/docker/hello_world.rb @@ -55,7 +55,9 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello World"} {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/host_setup_commands.rb b/test/e2e/docker/host_setup_commands.rb index dd77fe2e..4241b0fe 100644 --- a/test/e2e/docker/host_setup_commands.rb +++ b/test/e2e/docker/host_setup_commands.rb @@ -58,7 +58,9 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello World"} {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/job_stopping_on_epilogue.rb b/test/e2e/docker/job_stopping_on_epilogue.rb index 4fe622fa..5ccbbe85 100644 --- a/test/e2e/docker/job_stopping_on_epilogue.rb +++ b/test/e2e/docker/job_stopping_on_epilogue.rb @@ -44,8 +44,10 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echo 'here'"} {"event":"cmd_output", "timestamp":"*", "output":"here\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo 'here'","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"sleep infinity"} {"event":"cmd_finished", "timestamp":"*", "directive":"sleep infinity","exit_code":1,"finished_at":"*","started_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"stopped"} diff --git a/test/e2e/docker/multiple_containers.rb b/test/e2e/docker/multiple_containers.rb index fbb6f51f..4c8cbad3 100644 --- a/test/e2e/docker/multiple_containers.rb +++ b/test/e2e/docker/multiple_containers.rb @@ -59,7 +59,9 @@ {"event":"cmd_started", "timestamp":"*", "directive":"docker ps -a | grep postgres | wc -l"} {"event":"cmd_output", "timestamp":"*", "output":"1\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"docker ps -a | grep postgres | wc -l","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/stty_restoration.rb b/test/e2e/docker/stty_restoration.rb index 8c5356f9..a2bac135 100644 --- a/test/e2e/docker/stty_restoration.rb +++ b/test/e2e/docker/stty_restoration.rb @@ -63,8 +63,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/unicode.rb b/test/e2e/docker/unicode.rb index 33b13d72..413c3c29 100644 --- a/test/e2e/docker/unicode.rb +++ b/test/e2e/docker/unicode.rb @@ -62,7 +62,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"諸説存在し。\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo 特定の伝説に拠る物語の由来については諸説存在し。特定の伝説に拠る物語の由来については諸説存在し。特定の伝説に拠る物語の由来については諸説存在し。","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/docker/unknown_command.rb b/test/e2e/docker/unknown_command.rb index 92e7a40f..6e5ebf8f 100644 --- a/test/e2e/docker/unknown_command.rb +++ b/test/e2e/docker/unknown_command.rb @@ -57,7 +57,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"bash: echhhho: command not found\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echhhho Hello World","exit_code":127,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/self-hosted/docker_compose_host_env_vars.rb b/test/e2e/self-hosted/docker_compose_host_env_vars.rb index 34a6149f..f9fce855 100644 --- a/test/e2e/self-hosted/docker_compose_host_env_vars.rb +++ b/test/e2e/self-hosted/docker_compose_host_env_vars.rb @@ -94,7 +94,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"$PATH:/etc/a\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo $D","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/self-hosted/docker_compose_host_files.rb b/test/e2e/self-hosted/docker_compose_host_files.rb index 236d41dd..13711b0b 100644 --- a/test/e2e/self-hosted/docker_compose_host_files.rb +++ b/test/e2e/self-hosted/docker_compose_host_files.rb @@ -81,7 +81,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"Hello from file2.txt"} {"event":"cmd_finished", "timestamp":"*", "directive":"cat /tmp/agent/file2.txt","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/self-hosted/docker_compose_missing_host_files.rb b/test/e2e/self-hosted/docker_compose_missing_host_files.rb index 335c21ae..d82d94b7 100644 --- a/test/e2e/self-hosted/docker_compose_missing_host_files.rb +++ b/test/e2e/self-hosted/docker_compose_missing_host_files.rb @@ -87,7 +87,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"cat: /tmp/agent/notfound.txt: No such file or directory\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"cat /tmp/agent/notfound.txt","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/self-hosted/no_ssh_jump_points.rb b/test/e2e/self-hosted/no_ssh_jump_points.rb index 47af62de..d19ae123 100644 --- a/test/e2e/self-hosted/no_ssh_jump_points.rb +++ b/test/e2e/self-hosted/no_ssh_jump_points.rb @@ -42,7 +42,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"0\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"ls -1q ~/.ssh | wc -l","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG \ No newline at end of file diff --git a/test/e2e/self-hosted/shell_host_env_vars.rb b/test/e2e/self-hosted/shell_host_env_vars.rb index df2cc8d3..ced10156 100644 --- a/test/e2e/self-hosted/shell_host_env_vars.rb +++ b/test/e2e/self-hosted/shell_host_env_vars.rb @@ -75,7 +75,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"$PATH:/etc/a\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo $D","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/shell/broken_unicode.rb b/test/e2e/shell/broken_unicode.rb index 9e5bb347..e02aa33a 100644 --- a/test/e2e/shell/broken_unicode.rb +++ b/test/e2e/shell/broken_unicode.rb @@ -41,8 +41,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"\ufffd\ufffd\ufffd\ufffd\ufffd"} {"event":"cmd_finished", "timestamp":"*", "directive": "echo | awk '{ printf(\\\"%c%c%c%c%c\\\", 150, 150, 150, 150, 150) }'","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/shell/command_aliases.rb b/test/e2e/shell/command_aliases.rb index f91ba630..1c6d9187 100644 --- a/test/e2e/shell/command_aliases.rb +++ b/test/e2e/shell/command_aliases.rb @@ -37,7 +37,8 @@ {"event":"cmd_output", "timestamp":"*", "output":"Running: echo Hello World\\n"} {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"Display Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/shell/env_vars.rb b/test/e2e/shell/env_vars.rb index dda413b7..cca49122 100644 --- a/test/e2e/shell/env_vars.rb +++ b/test/e2e/shell/env_vars.rb @@ -64,7 +64,8 @@ {"event":"cmd_output", "timestamp":"*", "output":"$PATH:/etc/a\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo $D","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/shell/epilogue_on_fail.rb b/test/e2e/shell/epilogue_on_fail.rb index b963cd34..021b68a3 100644 --- a/test/e2e/shell/epilogue_on_fail.rb +++ b/test/e2e/shell/epilogue_on_fail.rb @@ -47,8 +47,9 @@ {"event":"cmd_started", "timestamp":"*", "directive":"false"} {"event":"cmd_finished", "timestamp":"*", "directive":"false","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello Epilogue"} {"event":"cmd_output", "timestamp":"*", "output":"Hello Epilogue\\n"} diff --git a/test/e2e/shell/epilogue_on_pass.rb b/test/e2e/shell/epilogue_on_pass.rb index 5122ebbf..a9d0e940 100644 --- a/test/e2e/shell/epilogue_on_pass.rb +++ b/test/e2e/shell/epilogue_on_pass.rb @@ -48,8 +48,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello Epilogue"} {"event":"cmd_output", "timestamp":"*", "output":"Hello Epilogue\\n"} diff --git a/test/e2e/shell/failed_job.rb b/test/e2e/shell/failed_job.rb index c6f128e6..ae684497 100644 --- a/test/e2e/shell/failed_job.rb +++ b/test/e2e/shell/failed_job.rb @@ -35,7 +35,8 @@ {"event":"cmd_finished", "timestamp":"*", "directive":"Injecting Files","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"false"} {"event":"cmd_finished", "timestamp":"*", "directive":"false","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/shell/file_injection.rb b/test/e2e/shell/file_injection.rb index d578049a..d4d1d9f8 100644 --- a/test/e2e/shell/file_injection.rb +++ b/test/e2e/shell/file_injection.rb @@ -12,7 +12,7 @@ "files": [ { "path": "test.txt", "content": "#{`echo "hello" | base64`.strip}", "mode": "0644" }, { "path": "/a/b/c", "content": "#{`echo "hello" | base64`.strip}", "mode": "0644" }, - { "path": "/tmp/a", "content": "#{`echo "hello" | base64`.strip}", "mode": "+x" } + { "path": "/tmp/a", "content": "#{`echo "hello" | base64`.strip}", "mode": "0600" } ], "commands": [ @@ -42,7 +42,7 @@ {"event":"cmd_started", "timestamp":"*", "directive":"Injecting Files"} {"event":"cmd_output", "timestamp":"*", "output":"Injecting test.txt with file mode 0644\\n"} {"event":"cmd_output", "timestamp":"*", "output":"Injecting /a/b/c with file mode 0644\\n"} - {"event":"cmd_output", "timestamp":"*", "output":"Injecting /tmp/a with file mode +x\\n"} + {"event":"cmd_output", "timestamp":"*", "output":"Injecting /tmp/a with file mode 0600\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"Injecting Files","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"cat test.txt"} @@ -54,10 +54,12 @@ {"event":"cmd_finished", "timestamp":"*", "directive":"cat /a/b/c","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"stat -c '%a' /tmp/a"} - {"event":"cmd_output", "timestamp":"*", "output":"755\\n"} + {"event":"cmd_output", "timestamp":"*", "output":"600\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"stat -c '%a' /tmp/a","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/shell/file_injection_broken_file_mode.rb b/test/e2e/shell/file_injection_broken_file_mode.rb index e7e30046..58e2aa13 100644 --- a/test/e2e/shell/file_injection_broken_file_mode.rb +++ b/test/e2e/shell/file_injection_broken_file_mode.rb @@ -39,10 +39,11 @@ {"event":"cmd_started", "timestamp":"*", "directive":"Injecting Files"} {"event":"cmd_output", "timestamp":"*", "output":"Injecting test.txt with file mode obviously broken\\n"} - {"event":"cmd_output", "timestamp":"*", "output":"Failed to set file mode to obviously broken\\n"} + {"event":"cmd_output", "timestamp":"*", "output":"bad file permission 'obviously broken'\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"Injecting Files","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/shell/hello_world.rb b/test/e2e/shell/hello_world.rb index c6b2b8b8..aec80e80 100644 --- a/test/e2e/shell/hello_world.rb +++ b/test/e2e/shell/hello_world.rb @@ -36,7 +36,8 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello World"} {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/shell/job_stopping_on_epilogue.rb b/test/e2e/shell/job_stopping_on_epilogue.rb index 4fe622fa..33f82eb2 100644 --- a/test/e2e/shell/job_stopping_on_epilogue.rb +++ b/test/e2e/shell/job_stopping_on_epilogue.rb @@ -44,8 +44,9 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echo 'here'"} {"event":"cmd_output", "timestamp":"*", "output":"here\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo 'here'","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"started_at":"*","finished_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"sleep infinity"} {"event":"cmd_finished", "timestamp":"*", "directive":"sleep infinity","exit_code":1,"finished_at":"*","started_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"stopped"} diff --git a/test/e2e/shell/killing_root_bash.rb b/test/e2e/shell/killing_root_bash.rb index 71be096d..e83238c5 100644 --- a/test/e2e/shell/killing_root_bash.rb +++ b/test/e2e/shell/killing_root_bash.rb @@ -47,7 +47,8 @@ {"event":"cmd_finished", "timestamp":"*", "directive":"sleep infinity &","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"exit 1"} {"event":"cmd_finished", "timestamp":"*", "directive":"exit 1","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":1,"started_at":"*","finished_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":1,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/shell/set_e.rb b/test/e2e/shell/set_e.rb index e22d6fe4..9a086870 100644 --- a/test/e2e/shell/set_e.rb +++ b/test/e2e/shell/set_e.rb @@ -51,7 +51,8 @@ {"event":"cmd_finished", "timestamp":"*", "directive":"set -e","exit_code":0,"finished_at":"*","started_at":"*"} {"event":"cmd_started", "timestamp":"*", "directive":"false"} {"event":"cmd_finished", "timestamp":"*", "directive":"false","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":1,"started_at":"*","finished_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":1,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/shell/set_pipefail.rb b/test/e2e/shell/set_pipefail.rb index 932dc0ce..a6cc9e99 100644 --- a/test/e2e/shell/set_pipefail.rb +++ b/test/e2e/shell/set_pipefail.rb @@ -52,7 +52,8 @@ {"event":"cmd_started", "timestamp":"*", "directive":"cat non_existant | sort"} {"event":"cmd_output", "timestamp":"*", "output":"cat: non_existant: No such file or directory\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"cat non_existant | sort","exit_code":1,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":1,"started_at":"*","finished_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":1,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e/shell/stty_restoration.rb b/test/e2e/shell/stty_restoration.rb index 002f5554..df921f57 100644 --- a/test/e2e/shell/stty_restoration.rb +++ b/test/e2e/shell/stty_restoration.rb @@ -39,7 +39,8 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echo Hello World"} {"event":"cmd_output", "timestamp":"*", "output":"Hello World\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo Hello World","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/shell/unicode.rb b/test/e2e/shell/unicode.rb index 9a54f627..2e0d0e51 100644 --- a/test/e2e/shell/unicode.rb +++ b/test/e2e/shell/unicode.rb @@ -64,8 +64,9 @@ {"event":"cmd_output", "timestamp":"*", "output":"━━━━━━━━━━━━━━━━━━━━━━\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echo ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━","exit_code":0,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=passed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"passed"} LOG diff --git a/test/e2e/shell/unknown_command.rb b/test/e2e/shell/unknown_command.rb index fd419e99..44522b59 100644 --- a/test/e2e/shell/unknown_command.rb +++ b/test/e2e/shell/unknown_command.rb @@ -36,7 +36,8 @@ {"event":"cmd_started", "timestamp":"*", "directive":"echhhho Hello World"} {"event":"cmd_output", "timestamp":"*", "output":"bash: echhhho: command not found\\n"} {"event":"cmd_finished", "timestamp":"*", "directive":"echhhho Hello World","exit_code":127,"finished_at":"*","started_at":"*"} - {"event":"cmd_started", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed"} - {"event":"cmd_finished", "timestamp":"*", "directive":"export SEMAPHORE_JOB_RESULT=failed","exit_code":0,"finished_at":"*","started_at":"*"} + {"event":"cmd_started", "timestamp":"*", "directive":"Exporting environment variables"} + {"event":"cmd_output", "timestamp":"*", "output":"Exporting SEMAPHORE_JOB_RESULT\\n"} + {"event":"cmd_finished", "timestamp":"*", "directive":"Exporting environment variables","exit_code":0,"started_at":"*","finished_at":"*"} {"event":"job_finished", "timestamp":"*", "result":"failed"} LOG diff --git a/test/e2e_support/docker-compose-listen.yml b/test/e2e_support/docker-compose-listen.yml index e4b2574e..5f39f3a1 100644 --- a/test/e2e_support/docker-compose-listen.yml +++ b/test/e2e_support/docker-compose-listen.yml @@ -6,7 +6,7 @@ services: context: ../.. dockerfile: Dockerfile.test - command: 'bash -c "service ssh restart && ./agent start --config-file /tmp/agent/config.yaml"' + command: 'bash -c "service ssh restart && SEMAPHORE_AGENT_LOG_LEVEL=DEBUG ./agent start --config-file /tmp/agent/config.yaml"' ports: - "30000:8000"