From 6e2ccefa51665fc6e8c3e0ca92b5f0bc8af697de Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Fri, 5 Jul 2024 12:54:42 +0545 Subject: [PATCH 01/14] feat: add command and stop endpoints --- tests/ociswrapper/ocis/ocis.go | 45 +++++--- tests/ociswrapper/wrapper/handlers/handler.go | 106 ++++++++++++++++-- tests/ociswrapper/wrapper/wrapper.go | 2 + 3 files changed, 123 insertions(+), 30 deletions(-) diff --git a/tests/ociswrapper/ocis/ocis.go b/tests/ociswrapper/ocis/ocis.go index 60e0382d9c4..84d8d309f62 100644 --- a/tests/ociswrapper/ocis/ocis.go +++ b/tests/ociswrapper/ocis/ocis.go @@ -111,7 +111,7 @@ func Start(envMap map[string]any) { close(outChan) } -func Stop() { +func Stop() (bool, string) { log.Println("Stopping oCIS server...") stopSignal = true @@ -119,13 +119,25 @@ func Stop() { if err != nil { if !strings.HasSuffix(err.Error(), "process already finished") { log.Fatalln(err) + } else { + return true, "oCIS server is already stopped" } } cmd.Process.Wait() - waitUntilCompleteShutdown() + return waitUntilCompleteShutdown() } -func listAllServices(startTime time.Time, timeout time.Duration) { +func Restart(envMap map[string]any) (bool, string) { + Stop() + + log.Println("Restarting oCIS server...") + common.Wg.Add(1) + go Start(envMap) + + return WaitForConnection() +} + +func waitAllServices(startTime time.Time, timeout time.Duration) { timeoutS := timeout * time.Second c := exec.Command(config.Get("bin"), "list") @@ -133,15 +145,15 @@ func listAllServices(startTime time.Time, timeout time.Duration) { if err != nil { if time.Since(startTime) <= timeoutS { time.Sleep(500 * time.Millisecond) - listAllServices(startTime, timeout) + waitAllServices(startTime, timeout) } return } log.Println("All services are up") } -func WaitForConnection() bool { - listAllServices(time.Now(), 30) +func WaitForConnection() (bool, string) { + waitAllServices(time.Now(), 30) transport := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, @@ -168,7 +180,7 @@ func WaitForConnection() bool { select { case <-timeout: log.Println(fmt.Sprintf("%v seconds timeout waiting for oCIS server", int64(timeoutValue.Seconds()))) - return false + return false, "Timeout waiting for oCIS server to start" default: req.Header.Set("X-Request-ID", "ociswrapper-"+strconv.Itoa(int(time.Now().UnixMilli()))) @@ -180,12 +192,12 @@ func WaitForConnection() bool { } log.Println("oCIS server is ready to accept requests") - return true + return true, "oCIS server is up and running" } } } -func waitUntilCompleteShutdown() { +func waitUntilCompleteShutdown() (bool, string) { timeout := 30 * time.Second startTime := time.Now() @@ -200,17 +212,14 @@ func waitUntilCompleteShutdown() { if time.Since(startTime) >= timeout { log.Println(fmt.Sprintf("Unable to kill oCIS server after %v seconds", int64(timeout.Seconds()))) - break + return false, "Timeout waiting for oCIS server to stop" } } + return true, "oCIS server stopped successfully" } -func Restart(envMap map[string]any) bool { - Stop() - - log.Println("Restarting oCIS server...") - common.Wg.Add(1) - go Start(envMap) - - return WaitForConnection() +func RunCommand(command string) (int, string) { + c := exec.Command(config.Get("bin"), command) + out, _ := c.CombinedOutput() + return c.ProcessState.ExitCode(), string(out) } diff --git a/tests/ociswrapper/wrapper/handlers/handler.go b/tests/ociswrapper/wrapper/handlers/handler.go index 09e4c64e054..2531612afa4 100644 --- a/tests/ociswrapper/wrapper/handlers/handler.go +++ b/tests/ociswrapper/wrapper/handlers/handler.go @@ -8,11 +8,20 @@ import ( "ociswrapper/ocis" ) +type BasicResponse struct { + Status string `json:"status"` + Message string `json:"message"` +} +type CommandResponse struct { + *BasicResponse + ExitCode int `json:"exitCode"` +} + func parseJsonBody(reqBody io.ReadCloser) (map[string]any, error) { body, _ := io.ReadAll(reqBody) if len(body) == 0 || !json.Valid(body) { - return nil, errors.New("Invalid json data") + return nil, errors.New("invalid json data") } var bodyMap map[string]any @@ -21,17 +30,39 @@ func parseJsonBody(reqBody io.ReadCloser) (map[string]any, error) { return bodyMap, nil } -func sendResponse(res http.ResponseWriter, ocisStatus bool) { - resBody := make(map[string]string) +func sendResponse(res http.ResponseWriter, success bool, message string) { + res.Header().Set("Content-Type", "application/json") - if ocisStatus { + var status string + if success { + status = "OK" res.WriteHeader(http.StatusOK) - resBody["status"] = "OK" - resBody["message"] = "oCIS server is running" } else { + status = "ERROR" res.WriteHeader(http.StatusInternalServerError) - resBody["status"] = "ERROR" - resBody["message"] = "Unable to start oCIS server" + } + + resBody := BasicResponse{ + Status: status, + Message: message, + } + + jsonResponse, _ := json.Marshal(resBody) + res.Write(jsonResponse) +} + +func sendCmdResponse(res http.ResponseWriter, exitCode int, message string) { + var resBody CommandResponse + + res.WriteHeader(http.StatusOK) + if exitCode == 0 { + resBody.Status = "OK" + resBody.ExitCode = exitCode + resBody.Message = message + } else { + resBody.Status = "ERROR" + resBody.ExitCode = exitCode + resBody.Message = message } res.Header().Set("Content-Type", "application/json") @@ -51,9 +82,16 @@ func SetEnvHandler(res http.ResponseWriter, req *http.Request) { return } - ocisStatus := ocis.Restart(environments) + var message string + + success, _ := ocis.Restart(environments) + if success { + message = "oCIS configured successfully" + } else { + message = "Failed to restart oCIS with new configuration" + } - sendResponse(res, ocisStatus) + sendResponse(res, success, message) } func RollbackHandler(res http.ResponseWriter, req *http.Request) { @@ -62,7 +100,51 @@ func RollbackHandler(res http.ResponseWriter, req *http.Request) { return } - ocisStatus := ocis.Restart(nil) + var message string + + success, _ := ocis.Restart(nil) + if success { + message = "oCIS configuration rolled back successfully" + } else { + message = "Failed to restart oCIS with initial configuration" + } + + sendResponse(res, success, message) +} + +func StopOcisHandler(res http.ResponseWriter, req *http.Request) { + if req.Method != http.MethodDelete { + http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + success, message := ocis.Stop() + sendResponse(res, success, message) +} + +func CommandHandler(res http.ResponseWriter, req *http.Request) { + if req.Method != http.MethodPost { + http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + body, err := parseJsonBody(req.Body) + if err != nil { + http.Error(res, "Bad request", http.StatusBadRequest) + return + } + if body["command"] == nil { + http.Error(res, "Bad request", http.StatusBadRequest) + return + } + + command, ok := body["command"].(string) + if !ok || command == "" { + http.Error(res, "Bad request", http.StatusBadRequest) + return + } + + exitCode, out := ocis.RunCommand(command) - sendResponse(res, ocisStatus) + sendCmdResponse(res, exitCode, out) } diff --git a/tests/ociswrapper/wrapper/wrapper.go b/tests/ociswrapper/wrapper/wrapper.go index e5fc80c9aee..3ecf94285f0 100644 --- a/tests/ociswrapper/wrapper/wrapper.go +++ b/tests/ociswrapper/wrapper/wrapper.go @@ -24,6 +24,8 @@ func Start(port string) { mux.HandleFunc("/", http.NotFound) mux.HandleFunc("/config", handlers.SetEnvHandler) mux.HandleFunc("/rollback", handlers.RollbackHandler) + mux.HandleFunc("/command", handlers.CommandHandler) + mux.HandleFunc("/stop", handlers.StopOcisHandler) httpServer.Handler = mux From d1d25ae94012d31cd55d22a6212b42d126cf29eb Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Fri, 5 Jul 2024 13:02:54 +0545 Subject: [PATCH 02/14] feat: add option to skip running ocis --- tests/ociswrapper/cmd/cmd.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/ociswrapper/cmd/cmd.go b/tests/ociswrapper/cmd/cmd.go index d949ddab3d5..0bc430b6214 100644 --- a/tests/ociswrapper/cmd/cmd.go +++ b/tests/ociswrapper/cmd/cmd.go @@ -36,7 +36,9 @@ func serveCmd() *cobra.Command { ocisConfig.Set("adminUsername", cmd.Flag("admin-username").Value.String()) ocisConfig.Set("adminPassword", cmd.Flag("admin-password").Value.String()) - go ocis.Start(nil) + if cmd.Flag("skip-ocis-run").Value.String() == "false" { + go ocis.Start(nil) + } go wrapper.Start(cmd.Flag("port").Value.String()) }, } @@ -49,6 +51,7 @@ func serveCmd() *cobra.Command { serveCmd.Flags().StringP("port", "p", wrapperConfig.Get("port"), "Wrapper API server port") serveCmd.Flags().StringP("admin-username", "", "", "admin username for oCIS server") serveCmd.Flags().StringP("admin-password", "", "", "admin password for oCIS server") + serveCmd.Flags().Bool("skip-ocis-run", false, "Skip running oCIS server") return serveCmd } From 3306a1f277cd7d6affbf4b439c7a9cbf541c75b6 Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Fri, 5 Jul 2024 14:55:03 +0545 Subject: [PATCH 03/14] timeout command execution --- tests/ociswrapper/ocis/ocis.go | 17 ++++++++-- tests/ociswrapper/wrapper/handlers/handler.go | 33 +++++++++---------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/tests/ociswrapper/ocis/ocis.go b/tests/ociswrapper/ocis/ocis.go index 84d8d309f62..32d51602ed8 100644 --- a/tests/ociswrapper/ocis/ocis.go +++ b/tests/ociswrapper/ocis/ocis.go @@ -2,6 +2,7 @@ package ocis import ( "bufio" + "context" "crypto/tls" "fmt" "net/http" @@ -219,7 +220,17 @@ func waitUntilCompleteShutdown() (bool, string) { } func RunCommand(command string) (int, string) { - c := exec.Command(config.Get("bin"), command) - out, _ := c.CombinedOutput() - return c.ProcessState.ExitCode(), string(out) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + c := exec.CommandContext(ctx, config.Get("bin"), command) + output, err := c.CombinedOutput() + if err != nil { + if ctx.Err() == context.DeadlineExceeded { + message := "Command timed out:\n" + string(output) + return c.ProcessState.ExitCode(), message + } + } + + return c.ProcessState.ExitCode(), string(output) } diff --git a/tests/ociswrapper/wrapper/handlers/handler.go b/tests/ociswrapper/wrapper/handlers/handler.go index 2531612afa4..308bc234376 100644 --- a/tests/ociswrapper/wrapper/handlers/handler.go +++ b/tests/ociswrapper/wrapper/handlers/handler.go @@ -52,18 +52,20 @@ func sendResponse(res http.ResponseWriter, success bool, message string) { } func sendCmdResponse(res http.ResponseWriter, exitCode int, message string) { - var resBody CommandResponse + resBody := CommandResponse{ + BasicResponse: &BasicResponse{ + Message: message, + }, + ExitCode: exitCode, + } - res.WriteHeader(http.StatusOK) if exitCode == 0 { - resBody.Status = "OK" - resBody.ExitCode = exitCode - resBody.Message = message + resBody.BasicResponse.Status = "OK" } else { - resBody.Status = "ERROR" - resBody.ExitCode = exitCode - resBody.Message = message + resBody.BasicResponse.Status = "ERROR" } + + res.WriteHeader(http.StatusOK) res.Header().Set("Content-Type", "application/json") jsonResponse, _ := json.Marshal(resBody) @@ -128,23 +130,18 @@ func CommandHandler(res http.ResponseWriter, req *http.Request) { return } - body, err := parseJsonBody(req.Body) - if err != nil { - http.Error(res, "Bad request", http.StatusBadRequest) - return - } - if body["command"] == nil { + if req.Body == nil { http.Error(res, "Bad request", http.StatusBadRequest) return } - command, ok := body["command"].(string) - if !ok || command == "" { + body, err := io.ReadAll(req.Body) + if err != nil { http.Error(res, "Bad request", http.StatusBadRequest) return } - exitCode, out := ocis.RunCommand(command) + exitCode, output := ocis.RunCommand(string(body)) - sendCmdResponse(res, exitCode, out) + sendCmdResponse(res, exitCode, output) } From 733f1852eab1ecb383398d359b377e074d08fbcb Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Fri, 5 Jul 2024 15:08:45 +0545 Subject: [PATCH 04/14] feat: add start endpoint --- tests/ociswrapper/ocis/ocis.go | 7 +++++++ tests/ociswrapper/wrapper/handlers/handler.go | 21 ++++++++++++++++++- tests/ociswrapper/wrapper/wrapper.go | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/ociswrapper/ocis/ocis.go b/tests/ociswrapper/ocis/ocis.go index 32d51602ed8..2957294b7bc 100644 --- a/tests/ociswrapper/ocis/ocis.go +++ b/tests/ociswrapper/ocis/ocis.go @@ -138,6 +138,13 @@ func Restart(envMap map[string]any) (bool, string) { return WaitForConnection() } +func IsOcisRunning() bool { + if cmd != nil { + return cmd.Process.Pid > 0 + } + return false +} + func waitAllServices(startTime time.Time, timeout time.Duration) { timeoutS := timeout * time.Second diff --git a/tests/ociswrapper/wrapper/handlers/handler.go b/tests/ociswrapper/wrapper/handlers/handler.go index 308bc234376..92db245a95b 100644 --- a/tests/ociswrapper/wrapper/handlers/handler.go +++ b/tests/ociswrapper/wrapper/handlers/handler.go @@ -5,6 +5,7 @@ import ( "errors" "io" "net/http" + "ociswrapper/common" "ociswrapper/ocis" ) @@ -115,7 +116,7 @@ func RollbackHandler(res http.ResponseWriter, req *http.Request) { } func StopOcisHandler(res http.ResponseWriter, req *http.Request) { - if req.Method != http.MethodDelete { + if req.Method != http.MethodPost { http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) return } @@ -124,6 +125,24 @@ func StopOcisHandler(res http.ResponseWriter, req *http.Request) { sendResponse(res, success, message) } +func StartOcisHandler(res http.ResponseWriter, req *http.Request) { + if req.Method != http.MethodPost { + http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + if ocis.IsOcisRunning() { + sendResponse(res, false, "oCIS server is already running") + return + } + + common.Wg.Add(1) + go ocis.Start(nil) + + success, message := ocis.WaitForConnection() + sendResponse(res, success, message) +} + func CommandHandler(res http.ResponseWriter, req *http.Request) { if req.Method != http.MethodPost { http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) diff --git a/tests/ociswrapper/wrapper/wrapper.go b/tests/ociswrapper/wrapper/wrapper.go index 3ecf94285f0..35b7873134a 100644 --- a/tests/ociswrapper/wrapper/wrapper.go +++ b/tests/ociswrapper/wrapper/wrapper.go @@ -26,6 +26,7 @@ func Start(port string) { mux.HandleFunc("/rollback", handlers.RollbackHandler) mux.HandleFunc("/command", handlers.CommandHandler) mux.HandleFunc("/stop", handlers.StopOcisHandler) + mux.HandleFunc("/start", handlers.StartOcisHandler) httpServer.Handler = mux From 7f0a1b0cdd52d01604b2dfcee7be119229fb9e7c Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Fri, 5 Jul 2024 15:47:43 +0545 Subject: [PATCH 05/14] fix: cumulative env and clear command var --- tests/ociswrapper/ocis/ocis.go | 21 ++++++++++--------- tests/ociswrapper/wrapper/handlers/handler.go | 16 ++++++++++---- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/tests/ociswrapper/ocis/ocis.go b/tests/ociswrapper/ocis/ocis.go index 2957294b7bc..f3ccb6b66bc 100644 --- a/tests/ociswrapper/ocis/ocis.go +++ b/tests/ociswrapper/ocis/ocis.go @@ -22,8 +22,9 @@ import ( var cmd *exec.Cmd var retryCount = 0 var stopSignal = false +var EnvConfigs = []string{} -func Start(envMap map[string]any) { +func Start(envMap []string) { // wait for the log scanner to finish var wg sync.WaitGroup wg.Add(2) @@ -34,14 +35,11 @@ func Start(envMap map[string]any) { } cmd = exec.Command(config.Get("bin"), "server") - cmd.Env = os.Environ() - var environments []string - if envMap != nil { - for key, value := range envMap { - environments = append(environments, fmt.Sprintf("%s=%v", key, value)) - } + if envMap == nil { + cmd.Env = append(os.Environ(), EnvConfigs...) + } else { + cmd.Env = append(os.Environ(), envMap...) } - cmd.Env = append(cmd.Env, environments...) logs, err := cmd.StderrPipe() if err != nil { @@ -125,10 +123,13 @@ func Stop() (bool, string) { } } cmd.Process.Wait() - return waitUntilCompleteShutdown() + success, message := waitUntilCompleteShutdown() + + cmd = nil + return success, message } -func Restart(envMap map[string]any) (bool, string) { +func Restart(envMap []string) (bool, string) { Stop() log.Println("Restarting oCIS server...") diff --git a/tests/ociswrapper/wrapper/handlers/handler.go b/tests/ociswrapper/wrapper/handlers/handler.go index 92db245a95b..9f3cc6b03f8 100644 --- a/tests/ociswrapper/wrapper/handlers/handler.go +++ b/tests/ociswrapper/wrapper/handlers/handler.go @@ -3,10 +3,12 @@ package handlers import ( "encoding/json" "errors" + "fmt" "io" "net/http" "ociswrapper/common" "ociswrapper/ocis" + "os" ) type BasicResponse struct { @@ -79,15 +81,21 @@ func SetEnvHandler(res http.ResponseWriter, req *http.Request) { return } - environments, err := parseJsonBody(req.Body) + envBody, err := parseJsonBody(req.Body) if err != nil { http.Error(res, "Bad request", http.StatusBadRequest) return } + var envMap []string + for key, value := range envBody { + envMap = append(envMap, fmt.Sprintf("%s=%v", key, value)) + } + ocis.EnvConfigs = append(ocis.EnvConfigs, envMap...) + var message string - success, _ := ocis.Restart(environments) + success, _ := ocis.Restart(ocis.EnvConfigs) if success { message = "oCIS configured successfully" } else { @@ -104,8 +112,8 @@ func RollbackHandler(res http.ResponseWriter, req *http.Request) { } var message string - - success, _ := ocis.Restart(nil) + ocis.EnvConfigs = []string{} + success, _ := ocis.Restart(os.Environ()) if success { message = "oCIS configuration rolled back successfully" } else { From d8dff89c1cd1b22476abf279218ee150c7cbf597 Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Mon, 8 Jul 2024 12:53:43 +0545 Subject: [PATCH 06/14] feat: allow interactive command execution --- tests/ociswrapper/go.mod | 1 + tests/ociswrapper/go.sum | 2 + tests/ociswrapper/ocis/ocis.go | 32 +- .../github.com/creack/pty/.editorconfig | 54 +++ .../vendor/github.com/creack/pty/.gitignore | 4 + .../github.com/creack/pty/.golangci.yml | 324 ++++++++++++++++++ .../github.com/creack/pty/Dockerfile.golang | 17 + .../vendor/github.com/creack/pty/LICENSE | 23 ++ .../vendor/github.com/creack/pty/README.md | 107 ++++++ .../github.com/creack/pty/asm_solaris_amd64.s | 18 + .../vendor/github.com/creack/pty/doc.go | 16 + .../vendor/github.com/creack/pty/ioctl.go | 28 ++ .../vendor/github.com/creack/pty/ioctl_bsd.go | 40 +++ .../github.com/creack/pty/ioctl_inner.go | 20 ++ .../github.com/creack/pty/ioctl_legacy.go | 10 + .../github.com/creack/pty/ioctl_solaris.go | 48 +++ .../creack/pty/ioctl_unsupported.go | 13 + .../vendor/github.com/creack/pty/mktypes.bash | 19 + .../github.com/creack/pty/pty_darwin.go | 68 ++++ .../github.com/creack/pty/pty_dragonfly.go | 83 +++++ .../github.com/creack/pty/pty_freebsd.go | 81 +++++ .../vendor/github.com/creack/pty/pty_linux.go | 54 +++ .../github.com/creack/pty/pty_netbsd.go | 69 ++++ .../github.com/creack/pty/pty_openbsd.go | 47 +++ .../github.com/creack/pty/pty_solaris.go | 171 +++++++++ .../github.com/creack/pty/pty_unsupported.go | 12 + .../vendor/github.com/creack/pty/run.go | 57 +++ .../vendor/github.com/creack/pty/start.go | 25 ++ .../github.com/creack/pty/start_windows.go | 19 + .../creack/pty/test_crosscompile.sh | 60 ++++ .../vendor/github.com/creack/pty/winsize.go | 24 ++ .../github.com/creack/pty/winsize_unix.go | 35 ++ .../creack/pty/winsize_unsupported.go | 23 ++ .../github.com/creack/pty/ztypes_386.go | 12 + .../github.com/creack/pty/ztypes_amd64.go | 12 + .../github.com/creack/pty/ztypes_arm.go | 12 + .../github.com/creack/pty/ztypes_arm64.go | 12 + .../creack/pty/ztypes_dragonfly_amd64.go | 17 + .../creack/pty/ztypes_freebsd_386.go | 16 + .../creack/pty/ztypes_freebsd_amd64.go | 17 + .../creack/pty/ztypes_freebsd_arm.go | 16 + .../creack/pty/ztypes_freebsd_arm64.go | 16 + .../creack/pty/ztypes_freebsd_ppc64.go | 14 + .../creack/pty/ztypes_freebsd_riscv64.go | 13 + .../github.com/creack/pty/ztypes_loong64.go | 12 + .../github.com/creack/pty/ztypes_mipsx.go | 13 + .../creack/pty/ztypes_netbsd_32bit_int.go | 17 + .../creack/pty/ztypes_openbsd_32bit_int.go | 14 + .../github.com/creack/pty/ztypes_ppc.go | 9 + .../github.com/creack/pty/ztypes_ppc64.go | 12 + .../github.com/creack/pty/ztypes_ppc64le.go | 12 + .../github.com/creack/pty/ztypes_riscvx.go | 12 + .../github.com/creack/pty/ztypes_s390x.go | 12 + .../github.com/creack/pty/ztypes_sparcx.go | 12 + tests/ociswrapper/vendor/modules.txt | 3 + 55 files changed, 1884 insertions(+), 5 deletions(-) create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/.editorconfig create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/.gitignore create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/.golangci.yml create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/Dockerfile.golang create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/LICENSE create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/README.md create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/asm_solaris_amd64.s create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/doc.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ioctl.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ioctl_bsd.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ioctl_inner.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ioctl_legacy.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ioctl_solaris.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ioctl_unsupported.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/mktypes.bash create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/pty_darwin.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/pty_dragonfly.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/pty_freebsd.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/pty_linux.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/pty_netbsd.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/pty_openbsd.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/pty_solaris.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/pty_unsupported.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/run.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/start.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/start_windows.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/test_crosscompile.sh create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/winsize.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/winsize_unix.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/winsize_unsupported.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_386.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_amd64.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_arm.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_arm64.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_dragonfly_amd64.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_386.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_amd64.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_arm.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_arm64.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_ppc64.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_riscv64.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_loong64.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_mipsx.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_netbsd_32bit_int.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_openbsd_32bit_int.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc64.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc64le.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_riscvx.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_s390x.go create mode 100644 tests/ociswrapper/vendor/github.com/creack/pty/ztypes_sparcx.go diff --git a/tests/ociswrapper/go.mod b/tests/ociswrapper/go.mod index 999a42e6ab4..1c793d2eae7 100644 --- a/tests/ociswrapper/go.mod +++ b/tests/ociswrapper/go.mod @@ -3,6 +3,7 @@ module ociswrapper go 1.20 require ( + github.com/creack/pty v1.1.21 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect diff --git a/tests/ociswrapper/go.sum b/tests/ociswrapper/go.sum index f3366a91aa3..ac2a55135de 100644 --- a/tests/ociswrapper/go.sum +++ b/tests/ociswrapper/go.sum @@ -1,4 +1,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= +github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= diff --git a/tests/ociswrapper/ocis/ocis.go b/tests/ociswrapper/ocis/ocis.go index f3ccb6b66bc..b53e8e5f071 100644 --- a/tests/ociswrapper/ocis/ocis.go +++ b/tests/ociswrapper/ocis/ocis.go @@ -5,6 +5,7 @@ import ( "context" "crypto/tls" "fmt" + "io" "net/http" "os" "os/exec" @@ -17,6 +18,8 @@ import ( "ociswrapper/common" "ociswrapper/log" "ociswrapper/ocis/config" + + "github.com/creack/pty" ) var cmd *exec.Cmd @@ -228,17 +231,36 @@ func waitUntilCompleteShutdown() (bool, string) { } func RunCommand(command string) (int, string) { + logs := new(strings.Builder) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - c := exec.CommandContext(ctx, config.Get("bin"), command) - output, err := c.CombinedOutput() + // build the command + c := exec.CommandContext(ctx, config.Get("bin"), "idm", "resetpassword", "-u", "admin") + + // Start the command with a pty (pseudo terminal) + // This is required to interact with the command + ptyF, err := pty.Start(c) if err != nil { + log.Panic(err) + } + defer ptyF.Close() + + inputs := []string{"demo", "demo"} + for _, input := range inputs { + fmt.Fprintf(ptyF, "%s\n", input) + } + + var cmdOutput string + if err := c.Wait(); err != nil { if ctx.Err() == context.DeadlineExceeded { - message := "Command timed out:\n" + string(output) - return c.ProcessState.ExitCode(), message + cmdOutput = "Command timed out:\n" } } - return c.ProcessState.ExitCode(), string(output) + // Copy the logs from the pty + io.Copy(logs, ptyF) + cmdOutput += logs.String() + + return c.ProcessState.ExitCode(), cmdOutput } diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/.editorconfig b/tests/ociswrapper/vendor/github.com/creack/pty/.editorconfig new file mode 100644 index 00000000000..349f67aa2dc --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/.editorconfig @@ -0,0 +1,54 @@ +root = true + +# Sane defaults. +[*] +# Always use unix end of line. +end_of_line = lf +# Always insert a new line at the end of files. +insert_final_newline = true +# Don't leave trailing whitespaces. +trim_trailing_whitespace = true +# Default to utf8 encoding. +charset = utf-8 +# Space > tab for consistent aligns. +indent_style = space +# Default to 2 spaces for indent/tabs. +indent_size = 2 +# Flag long lines. +max_line_length = 140 + +# Explicitly define settings for commonly used files. + +[*.go] +indent_style = tab +indent_size = 8 + +[*.feature] +indent_style = space +indent_size = 2 + +[*.json] +indent_style = space +indent_size = 2 + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + +[*.tf] +indent_style = space +indent_size = 2 + +[*.md] +# Don't check line lenghts in files. +max_line_length = 0 + +[{Makefile,*.mk}] +indent_style = tab +indent_size = 8 + +[{Dockerfile,Dockerfile.*}] +indent_size = 4 + +[*.sql] +indent_size = 2 diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/.gitignore b/tests/ociswrapper/vendor/github.com/creack/pty/.gitignore new file mode 100644 index 00000000000..1f0a99f2f2b --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/.gitignore @@ -0,0 +1,4 @@ +[568].out +_go* +_test* +_obj diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/.golangci.yml b/tests/ociswrapper/vendor/github.com/creack/pty/.golangci.yml new file mode 100644 index 00000000000..f023e0f76a0 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/.golangci.yml @@ -0,0 +1,324 @@ +--- +# Reference: https://golangci-lint.run/usage/configuration/ +run: + timeout: 5m + # modules-download-mode: vendor + + # Include test files. + tests: true + + skip-dirs: [] + + skip-files: [] + +output: + # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number". + format: colored-line-number + print-issued-lines: true + print-linter-name: true + +# Linter specific settings. See below in the `linter.enable` section for details on what each linter is doing. +linters-settings: + dogsled: + # Checks assignments with too many blank identifiers. Default is 2. + max-blank-identifiers: 2 + + dupl: + # Tokens count to trigger issue. + threshold: 150 + + errcheck: + # Report about not checking of errors in type assertions: `a := b.(MyStruct)`. + # Enabled as this is often overlooked by developers. + check-type-assertions: true + # Report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`. + # Disabled as we consider that if the developer did type `_`, it was on purpose. + # Note that while this isn't enforced by the linter, each and every case of ignored error should + # be accompanied with a comment explaining why that error is being discarded. + check-blank: false + + exhaustive: + # Indicates that switch statements are to be considered exhaustive if a + # 'default' case is present, even if all enum members aren't listed in the + # switch. + default-signifies-exhaustive: false + + funlen: + # funlen checks the number of lines/statements in a function. + # While is is always best to keep functions short for readability, maintainability and testing, + # the default are a bit too strict (60 lines / 40 statements), increase it to be more flexible. + lines: 160 + statements: 70 + + # NOTE: We don't set `gci` for import order as it supports only one prefix. Use `goimports.local-prefixes` instead. + + gocognit: + # Minimal code complexity to report, defaults to 30 in gocognit, defaults 10 in golangci. + # Use 15 as it allows for some flexibility while preventing too much complexity. + # NOTE: Similar to gocyclo. + min-complexity: 35 + + nestif: + # Minimal complexity of if statements to report. + min-complexity: 8 + + goconst: + # Minimal length of string constant. + min-len: 4 + # Minimal occurrences count to trigger. + # Increase the default from 3 to 5 as small number of const usage can reduce readability instead of improving it. + min-occurrences: 5 + + gocritic: + # Which checks should be disabled; can't be combined with 'enabled-checks'. + # See https://go-critic.github.io/overview#checks-overview + # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` + disabled-checks: + - hugeParam # Very strict check on the size of variables being copied. Too strict for most developer. + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks. + # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - diagnostic + - style + - opinionated + - performance + settings: + rangeValCopy: + sizeThreshold: 1024 # Increase the allowed copied bytes in range. + + cyclop: + max-complexity: 35 + + gocyclo: + # Similar check as gocognit. + # NOTE: We might be able to remove this linter as it is redundant with gocyclo. It is in golangci-lint, so we keep it for now. + min-complexity: 35 + + godot: + # Check all top-level comments, not only declarations. + check-all: true + + gofmt: + # simplify code: gofmt with `-s` option. + simplify: true + + # NOTE: the goheader settings are set per-project. + + goimports: + # Put imports beginning with prefix after 3rd-party packages. + # It's a comma-separated list of prefixes. + local-prefixes: "github.com/creack/pty" + + golint: + # Minimal confidence for issues, default is 0.8. + min-confidence: 0.8 + + gosimple: + # Select the Go version to target. The default is '1.13'. + go: "1.18" + # https://staticcheck.io/docs/options#checks + checks: ["all"] + + gosec: + + govet: + # Enable all available checks from go vet. + enable-all: false + # Report about shadowed variables. + check-shadowing: true + + # NOTE: depguard is disabled as it is very slow and made redundant by gomodguard. + + lll: + # Make sure everyone is on the same level, fix the tab width to go's default. + tab-width: 8 + # Increase the default max line length to give more flexibility. Forcing newlines can reduce readability instead of improving it. + line-length: 180 + + misspell: + locale: US + ignore-words: + + nakedret: + # Make an issue if func has more lines of code than this setting and it has naked returns; default is 30. + # NOTE: Consider setting this to 1 to prevent naked returns. + max-func-lines: 30 + + nolintlint: + # Prevent ununsed directive to avoid stale comments. + allow-unused: false + # Require an explanation of nonzero length after each nolint directive. + require-explanation: true + # Exclude following linters from requiring an explanation. + # NOTE: It is strongly discouraged to put anything in there. + allow-no-explanation: [] + # Enable to require nolint directives to mention the specific linter being suppressed. This ensurce the developer understand the reason being the error. + require-specific: true + + prealloc: + # NOTE: For most programs usage of prealloc will be a premature optimization. + # Keep thing simple, pre-alloc what is obvious and profile the program for more complex scenarios. + # + simple: true # Checkonly on simple loops that have no returns/breaks/continues/gotos in them. + range-loops: true # Check range loops, true by default + for-loops: false # Check suggestions on for loops, false by default + + rowserrcheck: + packages: [] + + staticcheck: + # Select the Go version to target. The default is '1.13'. + go: "1.18" + # https://staticcheck.io/docs/options#checks + checks: ["all"] + + stylecheck: + # Select the Go version to target. The default is '1.13'. + go: "1.18" + # https://staticcheck.io/docs/options#checks + checks: ["all"] # "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"] + + tagliatelle: + # Check the struck tag name case. + case: + # Use the struct field name to check the name of the struct tag. + use-field-name: false + rules: + # Any struct tag type can be used. + # support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower` + json: snake + firestore: camel + yaml: camel + xml: camel + bson: camel + avro: snake + mapstructure: kebab + envconfig: upper + + unparam: + # Don't create an error if an exported code have static params being used. It is often expected in libraries. + # NOTE: It would be nice if this linter would differentiate between a main package and a lib. + check-exported: true + + unused: {} + + whitespace: + multi-if: false # Enforces newlines (or comments) after every multi-line if statement + multi-func: false # Enforces newlines (or comments) after every multi-line function signature + +# Run `golangci-lint help linters` to get the full list of linter with their description. +linters: + disable-all: true + # NOTE: enable-all is deprecated because too many people don't pin versions... + # We still require explicit documentation on why some linters are disabled. + # disable: + # - depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false] + # - exhaustivestruct # Checks if all struct's fields are initialized [fast: true, auto-fix: false] + # - forbidigo # Forbids identifiers [fast: true, auto-fix: false] + # - gci # Gci control golang package import order and make it always deterministic. [fast: true, auto-fix: true] + # - godox # Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false] + # - goerr113 # Golang linter to check the errors handling expressions [fast: true, auto-fix: false] + # - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes [fast: false, auto-fix: false] + # - gomnd # An analyzer to detect magic numbers. [fast: true, auto-fix: false] + # - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false] + # - interfacer # Linter that suggests narrower interface types [fast: false, auto-fix: false] + # - maligned # Tool to detect Go structs that would take less memory if their fields were sorted [fast: false, auto-fix: false] + # - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity [fast: true, auto-fix: false] + # - scopelint # Scopelint checks for unpinned variables in go programs [fast: true, auto-fix: false] + # - wrapcheck # Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false] + # - wsl # Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false] + + # disable-reasons: + # - depguard # Checks whitelisted/blacklisted import path, but runs way too slow. Not that useful. + # - exhaustivestruct # Good concept, but not mature enough (errors on not assignable fields like locks) and too noisy when using AWS SDK as most fields are unused. + # - forbidigo # Great idea, but too strict out of the box. Probably will re-enable soon. + # - gci # Conflicts with goimports/gofumpt. + # - godox # Don't fail when finding TODO, FIXME, etc. + # - goerr113 # Too many false positives. + # - golint # Deprecated (since v1.41.0) due to: The repository of the linter has been archived by the owner. Replaced by revive. + # - gomnd # Checks for magic numbers. Disabled due to too many false positives not configurable (03/01/2020 v1.23.7). + # - gomoddirectives # Doesn't support //nolint to whitelist. + # - interfacer # Deprecated (since v1.38.0) due to: The repository of the linter has been archived by the owner. + # - maligned # Deprecated (since v1.38.0) due to: The repository of the linter has been archived by the owner. Replaced by govet 'fieldalignment'. + # - nlreturn # Actually reduces readability in most cases. + # - scopelint # Deprecated (since v1.39.0) due to: The repository of the linter has been deprecated by the owner. Replaced by exportloopref. + # - wrapcheck # Good concept, but always warns for http coded errors. Need to re-enable and whitelist our error package. + # - wsl # Forces to add newlines around blocks. Lots of false positives, not that useful. + + enable: + - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false] + - bodyclose # checks whether HTTP response body is closed successfully [fast: false, auto-fix: false] + - cyclop # checks function and package cyclomatic complexity [fast: false, auto-fix: false] + - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false] + - dupl # Tool for code clone detection [fast: true, auto-fix: false] + - durationcheck # check for two durations multiplied together [fast: false, auto-fix: false] + - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false] + - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. [fast: false, auto-fix: false] + - errorlint # go-errorlint is a source code linter for Go software that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. [fast: false, auto-fix: false] + - exhaustive # check exhaustiveness of enum switch statements [fast: false, auto-fix: false] + - exportloopref # checks for pointers to enclosing loop variables [fast: false, auto-fix: false] + - forcetypeassert # finds forced type assertions [fast: true, auto-fix: false] + - funlen # Tool for detection of long functions [fast: true, auto-fix: false] + - gochecknoglobals # check that no global variables exist [fast: true, auto-fix: false] + - gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false] + - gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false] + - goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false] + - gocritic # Provides many diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false] + - gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false] + - godot # Check if comments end in a period [fast: true, auto-fix: true] + - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true] + - gofumpt # Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true] + - goheader # Checks is file header matches to pattern [fast: true, auto-fix: false] + - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports [fast: true, auto-fix: true] + - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false] + - goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false] + - gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false] + - gosimple # (megacheck): Linter for Go source code that specializes in simplifying a code [fast: false, auto-fix: false] + - govet # (vet, vetshadow): Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: false, auto-fix: false] + - importas # Enforces consistent import aliases [fast: false, auto-fix: false] + - ineffassign # Detects when assignments to existing variables are not used [fast: true, auto-fix: false] + - lll # Reports long lines [fast: true, auto-fix: false] + - makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false] + - misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true] + - nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false] + - nestif # Reports deeply nested if statements [fast: true, auto-fix: false] + - nilerr # Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false] + - noctx # noctx finds sending http request without context.Context [fast: false, auto-fix: false] + - nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false] + - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test [fast: true, auto-fix: false] + - prealloc # Finds slice declarations that could potentially be preallocated [fast: true, auto-fix: false] + - predeclared # find code that shadows one of Go's predeclared identifiers [fast: true, auto-fix: false] + - promlinter # Check Prometheus metrics naming via promlint [fast: true, auto-fix: false] + - revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. [fast: false, auto-fix: false] + # Disabled due to generic. Work in progress upstream. + # - rowserrcheck # checks whether Err of rows is checked successfully [fast: false, auto-fix: false] + # Disabled due to generic. Work in progress upstream. + # - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. [fast: false, auto-fix: false] + - staticcheck # (megacheck): Staticcheck is a go vet on steroids, applying a ton of static analysis checks [fast: false, auto-fix: false] + - stylecheck # Stylecheck is a replacement for golint [fast: false, auto-fix: false] + # Disabled due to generic. Work in progress upstream. + # - tagliatelle # Checks the struct tags. [fast: true, auto-fix: false] + # - testpackage # linter that makes you use a separate _test package [fast: true, auto-fix: false] + - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers [fast: false, auto-fix: false] + - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes [fast: false, auto-fix: false] + - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code [fast: false, auto-fix: false] + - unconvert # Remove unnecessary type conversions [fast: false, auto-fix: false] + - unparam # Reports unused function parameters [fast: false, auto-fix: false] + # Disabled due to way too many false positive in go1.20. + # - unused # (megacheck): Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false] + # Disabled due to generic. Work in progress upstream. + # - wastedassign # wastedassign finds wasted assignment statements. [fast: false, auto-fix: false] + - whitespace # Tool for detection of leading and trailing whitespace [fast: true, auto-fix: true] + +issues: + exclude: + # Allow shadowing of 'err'. + - 'shadow: declaration of "err" shadows declaration' + # Allow shadowing of `ctx`. + - 'shadow: declaration of "ctx" shadows declaration' + # Maximum issues count per one linter. Set to 0 to disable. Default is 50. + max-per-linter: 10 + # Disable default excludes. Always be explicit on what we exclude. + exclude-use-default: false + # Exclude some linters from running on tests files. + exclude-rules: [] diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/Dockerfile.golang b/tests/ociswrapper/vendor/github.com/creack/pty/Dockerfile.golang new file mode 100644 index 00000000000..b6153421c0a --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/Dockerfile.golang @@ -0,0 +1,17 @@ +ARG GOVERSION=1.18.2 +FROM golang:${GOVERSION} + +# Set base env. +ARG GOOS=linux +ARG GOARCH=amd64 +ENV GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=0 GOFLAGS='-v -ldflags=-s -ldflags=-w' + +# Pre compile the stdlib for 386/arm (32bits). +RUN go build -a std + +# Add the code to the image. +WORKDIR pty +ADD . . + +# Build the lib. +RUN go build diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/LICENSE b/tests/ociswrapper/vendor/github.com/creack/pty/LICENSE new file mode 100644 index 00000000000..6b7558b6b42 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2011 Keith Rarick + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall +be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/README.md b/tests/ociswrapper/vendor/github.com/creack/pty/README.md new file mode 100644 index 00000000000..a4fe7670d4a --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/README.md @@ -0,0 +1,107 @@ +# pty + +Pty is a Go package for using unix pseudo-terminals. + +## Install + +```sh +go get github.com/creack/pty +``` + +## Examples + +Note that those examples are for demonstration purpose only, to showcase how to use the library. They are not meant to be used in any kind of production environment. + +### Command + +```go +package main + +import ( + "io" + "os" + "os/exec" + + "github.com/creack/pty" +) + +func main() { + c := exec.Command("grep", "--color=auto", "bar") + f, err := pty.Start(c) + if err != nil { + panic(err) + } + + go func() { + f.Write([]byte("foo\n")) + f.Write([]byte("bar\n")) + f.Write([]byte("baz\n")) + f.Write([]byte{4}) // EOT + }() + io.Copy(os.Stdout, f) +} +``` + +### Shell + +```go +package main + +import ( + "io" + "log" + "os" + "os/exec" + "os/signal" + "syscall" + + "github.com/creack/pty" + "golang.org/x/term" +) + +func test() error { + // Create arbitrary command. + c := exec.Command("bash") + + // Start the command with a pty. + ptmx, err := pty.Start(c) + if err != nil { + return err + } + // Make sure to close the pty at the end. + defer func() { _ = ptmx.Close() }() // Best effort. + + // Handle pty size. + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGWINCH) + go func() { + for range ch { + if err := pty.InheritSize(os.Stdin, ptmx); err != nil { + log.Printf("error resizing pty: %s", err) + } + } + }() + ch <- syscall.SIGWINCH // Initial resize. + defer func() { signal.Stop(ch); close(ch) }() // Cleanup signals when done. + + // Set stdin in raw mode. + oldState, err := term.MakeRaw(int(os.Stdin.Fd())) + if err != nil { + panic(err) + } + defer func() { _ = term.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort. + + // Copy stdin to the pty and the pty to stdout. + // NOTE: The goroutine will keep reading until the next keystroke before returning. + go func() { _, _ = io.Copy(ptmx, os.Stdin) }() + _, _ = io.Copy(os.Stdout, ptmx) + + return nil +} + +func main() { + if err := test(); err != nil { + log.Fatal(err) + } +} +``` diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/asm_solaris_amd64.s b/tests/ociswrapper/vendor/github.com/creack/pty/asm_solaris_amd64.s new file mode 100644 index 00000000000..7fbef8ee66f --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/asm_solaris_amd64.s @@ -0,0 +1,18 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc +//+build gc + +#include "textflag.h" + +// +// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go +// + +TEXT ·sysvicall6(SB),NOSPLIT,$0-88 + JMP syscall·sysvicall6(SB) + +TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88 + JMP syscall·rawSysvicall6(SB) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/doc.go b/tests/ociswrapper/vendor/github.com/creack/pty/doc.go new file mode 100644 index 00000000000..3c8b3244e8f --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/doc.go @@ -0,0 +1,16 @@ +// Package pty provides functions for working with Unix terminals. +package pty + +import ( + "errors" + "os" +) + +// ErrUnsupported is returned if a function is not +// available on the current platform. +var ErrUnsupported = errors.New("unsupported") + +// Open a pty and its corresponding tty. +func Open() (pty, tty *os.File, err error) { + return open() +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ioctl.go b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl.go new file mode 100644 index 00000000000..7b6b770b7fe --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl.go @@ -0,0 +1,28 @@ +//go:build !windows && go1.12 +// +build !windows,go1.12 + +package pty + +import "os" + +func ioctl(f *os.File, cmd, ptr uintptr) error { + return ioctlInner(f.Fd(), cmd, ptr) // Fall back to blocking io. +} + +// NOTE: Unused. Keeping for reference. +func ioctlNonblock(f *os.File, cmd, ptr uintptr) error { + sc, e := f.SyscallConn() + if e != nil { + return ioctlInner(f.Fd(), cmd, ptr) // Fall back to blocking io (old behavior). + } + + ch := make(chan error, 1) + defer close(ch) + + e = sc.Control(func(fd uintptr) { ch <- ioctlInner(fd, cmd, ptr) }) + if e != nil { + return e + } + e = <-ch + return e +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_bsd.go b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_bsd.go new file mode 100644 index 00000000000..db3bf845bef --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_bsd.go @@ -0,0 +1,40 @@ +//go:build darwin || dragonfly || freebsd || netbsd || openbsd +// +build darwin dragonfly freebsd netbsd openbsd + +package pty + +// from +const ( + _IOC_VOID uintptr = 0x20000000 + _IOC_OUT uintptr = 0x40000000 + _IOC_IN uintptr = 0x80000000 + _IOC_IN_OUT uintptr = _IOC_OUT | _IOC_IN + _IOC_DIRMASK = _IOC_VOID | _IOC_OUT | _IOC_IN + + _IOC_PARAM_SHIFT = 13 + _IOC_PARAM_MASK = (1 << _IOC_PARAM_SHIFT) - 1 +) + +func _IOC_PARM_LEN(ioctl uintptr) uintptr { + return (ioctl >> 16) & _IOC_PARAM_MASK +} + +func _IOC(inout uintptr, group byte, ioctl_num uintptr, param_len uintptr) uintptr { + return inout | (param_len&_IOC_PARAM_MASK)<<16 | uintptr(group)<<8 | ioctl_num +} + +func _IO(group byte, ioctl_num uintptr) uintptr { + return _IOC(_IOC_VOID, group, ioctl_num, 0) +} + +func _IOR(group byte, ioctl_num uintptr, param_len uintptr) uintptr { + return _IOC(_IOC_OUT, group, ioctl_num, param_len) +} + +func _IOW(group byte, ioctl_num uintptr, param_len uintptr) uintptr { + return _IOC(_IOC_IN, group, ioctl_num, param_len) +} + +func _IOWR(group byte, ioctl_num uintptr, param_len uintptr) uintptr { + return _IOC(_IOC_IN_OUT, group, ioctl_num, param_len) +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_inner.go b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_inner.go new file mode 100644 index 00000000000..272b50b971c --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_inner.go @@ -0,0 +1,20 @@ +//go:build !windows && !solaris && !aix +// +build !windows,!solaris,!aix + +package pty + +import "syscall" + +// Local syscall const values. +const ( + TIOCGWINSZ = syscall.TIOCGWINSZ + TIOCSWINSZ = syscall.TIOCSWINSZ +) + +func ioctlInner(fd, cmd, ptr uintptr) error { + _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr) + if e != 0 { + return e + } + return nil +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_legacy.go b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_legacy.go new file mode 100644 index 00000000000..f7e923cd079 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_legacy.go @@ -0,0 +1,10 @@ +//go:build !windows && !go1.12 +// +build !windows,!go1.12 + +package pty + +import "os" + +func ioctl(f *os.File, cmd, ptr uintptr) error { + return ioctlInner(f.Fd(), cmd, ptr) // fall back to blocking io (old behavior) +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_solaris.go b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_solaris.go new file mode 100644 index 00000000000..6fd8bfeee53 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_solaris.go @@ -0,0 +1,48 @@ +//go:build solaris +// +build solaris + +package pty + +import ( + "syscall" + "unsafe" +) + +//go:cgo_import_dynamic libc_ioctl ioctl "libc.so" +//go:linkname procioctl libc_ioctl +var procioctl uintptr + +const ( + // see /usr/include/sys/stropts.h + I_PUSH = uintptr((int32('S')<<8 | 002)) + I_STR = uintptr((int32('S')<<8 | 010)) + I_FIND = uintptr((int32('S')<<8 | 013)) + + // see /usr/include/sys/ptms.h + ISPTM = (int32('P') << 8) | 1 + UNLKPT = (int32('P') << 8) | 2 + PTSSTTY = (int32('P') << 8) | 3 + ZONEPT = (int32('P') << 8) | 4 + OWNERPT = (int32('P') << 8) | 5 + + // see /usr/include/sys/termios.h + TIOCSWINSZ = (uint32('T') << 8) | 103 + TIOCGWINSZ = (uint32('T') << 8) | 104 +) + +type strioctl struct { + icCmd int32 + icTimeout int32 + icLen int32 + icDP unsafe.Pointer +} + +// Defined in asm_solaris_amd64.s. +func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) + +func ioctlInner(fd, cmd, ptr uintptr) error { + if _, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procioctl)), 3, fd, cmd, ptr, 0, 0, 0); errno != 0 { + return errno + } + return nil +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_unsupported.go b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_unsupported.go new file mode 100644 index 00000000000..e17908d44ac --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ioctl_unsupported.go @@ -0,0 +1,13 @@ +//go:build aix +// +build aix + +package pty + +const ( + TIOCGWINSZ = 0 + TIOCSWINSZ = 0 +) + +func ioctlInner(fd, cmd, ptr uintptr) error { + return ErrUnsupported +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/mktypes.bash b/tests/ociswrapper/vendor/github.com/creack/pty/mktypes.bash new file mode 100644 index 00000000000..7f71bda6a65 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/mktypes.bash @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +GOOSARCH="${GOOS}_${GOARCH}" +case "$GOOSARCH" in +_* | *_ | _) + echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2 + exit 1 + ;; +esac + +GODEFS="go tool cgo -godefs" + +$GODEFS types.go |gofmt > ztypes_$GOARCH.go + +case $GOOS in +freebsd|dragonfly|netbsd|openbsd) + $GODEFS types_$GOOS.go |gofmt > ztypes_$GOOSARCH.go + ;; +esac diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/pty_darwin.go b/tests/ociswrapper/vendor/github.com/creack/pty/pty_darwin.go new file mode 100644 index 00000000000..eadf6ab7c79 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/pty_darwin.go @@ -0,0 +1,68 @@ +//go:build darwin +// +build darwin + +package pty + +import ( + "errors" + "os" + "syscall" + "unsafe" +) + +func open() (pty, tty *os.File, err error) { + pFD, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_CLOEXEC, 0) + if err != nil { + return nil, nil, err + } + p := os.NewFile(uintptr(pFD), "/dev/ptmx") + // In case of error after this point, make sure we close the ptmx fd. + defer func() { + if err != nil { + _ = p.Close() // Best effort. + } + }() + + sname, err := ptsname(p) + if err != nil { + return nil, nil, err + } + + if err := grantpt(p); err != nil { + return nil, nil, err + } + + if err := unlockpt(p); err != nil { + return nil, nil, err + } + + t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0) + if err != nil { + return nil, nil, err + } + return p, t, nil +} + +func ptsname(f *os.File) (string, error) { + n := make([]byte, _IOC_PARM_LEN(syscall.TIOCPTYGNAME)) + + err := ioctl(f, syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0]))) + if err != nil { + return "", err + } + + for i, c := range n { + if c == 0 { + return string(n[:i]), nil + } + } + return "", errors.New("TIOCPTYGNAME string not NUL-terminated") +} + +func grantpt(f *os.File) error { + return ioctl(f, syscall.TIOCPTYGRANT, 0) +} + +func unlockpt(f *os.File) error { + return ioctl(f, syscall.TIOCPTYUNLK, 0) +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/pty_dragonfly.go b/tests/ociswrapper/vendor/github.com/creack/pty/pty_dragonfly.go new file mode 100644 index 00000000000..12803de043c --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/pty_dragonfly.go @@ -0,0 +1,83 @@ +//go:build dragonfly +// +build dragonfly + +package pty + +import ( + "errors" + "os" + "strings" + "syscall" + "unsafe" +) + +// same code as pty_darwin.go +func open() (pty, tty *os.File, err error) { + p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) + if err != nil { + return nil, nil, err + } + // In case of error after this point, make sure we close the ptmx fd. + defer func() { + if err != nil { + _ = p.Close() // Best effort. + } + }() + + sname, err := ptsname(p) + if err != nil { + return nil, nil, err + } + + if err := grantpt(p); err != nil { + return nil, nil, err + } + + if err := unlockpt(p); err != nil { + return nil, nil, err + } + + t, err := os.OpenFile(sname, os.O_RDWR, 0) + if err != nil { + return nil, nil, err + } + return p, t, nil +} + +func grantpt(f *os.File) error { + _, err := isptmaster(f) + return err +} + +func unlockpt(f *os.File) error { + _, err := isptmaster(f) + return err +} + +func isptmaster(f *os.File) (bool, error) { + err := ioctl(f, syscall.TIOCISPTMASTER, 0) + return err == nil, err +} + +var ( + emptyFiodgnameArg fiodgnameArg + ioctl_FIODNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg)) +) + +func ptsname(f *os.File) (string, error) { + name := make([]byte, _C_SPECNAMELEN) + fa := fiodgnameArg{Name: (*byte)(unsafe.Pointer(&name[0])), Len: _C_SPECNAMELEN, Pad_cgo_0: [4]byte{0, 0, 0, 0}} + + err := ioctl(f, ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa))) + if err != nil { + return "", err + } + + for i, c := range name { + if c == 0 { + s := "/dev/" + string(name[:i]) + return strings.Replace(s, "ptm", "pts", -1), nil + } + } + return "", errors.New("TIOCPTYGNAME string not NUL-terminated") +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/pty_freebsd.go b/tests/ociswrapper/vendor/github.com/creack/pty/pty_freebsd.go new file mode 100644 index 00000000000..47afcfeec8e --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/pty_freebsd.go @@ -0,0 +1,81 @@ +//go:build freebsd +// +build freebsd + +package pty + +import ( + "errors" + "os" + "syscall" + "unsafe" +) + +func posixOpenpt(oflag int) (fd int, err error) { + r0, _, e1 := syscall.Syscall(syscall.SYS_POSIX_OPENPT, uintptr(oflag), 0, 0) + fd = int(r0) + if e1 != 0 { + err = e1 + } + return fd, err +} + +func open() (pty, tty *os.File, err error) { + fd, err := posixOpenpt(syscall.O_RDWR | syscall.O_CLOEXEC) + if err != nil { + return nil, nil, err + } + p := os.NewFile(uintptr(fd), "/dev/pts") + // In case of error after this point, make sure we close the pts fd. + defer func() { + if err != nil { + _ = p.Close() // Best effort. + } + }() + + sname, err := ptsname(p) + if err != nil { + return nil, nil, err + } + + t, err := os.OpenFile("/dev/"+sname, os.O_RDWR, 0) + if err != nil { + return nil, nil, err + } + return p, t, nil +} + +func isptmaster(f *os.File) (bool, error) { + err := ioctl(f, syscall.TIOCPTMASTER, 0) + return err == nil, err +} + +var ( + emptyFiodgnameArg fiodgnameArg + ioctlFIODGNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg)) +) + +func ptsname(f *os.File) (string, error) { + master, err := isptmaster(f) + if err != nil { + return "", err + } + if !master { + return "", syscall.EINVAL + } + + const n = _C_SPECNAMELEN + 1 + var ( + buf = make([]byte, n) + arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))} + ) + if err := ioctl(f, ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil { + return "", err + } + + for i, c := range buf { + if c == 0 { + return string(buf[:i]), nil + } + } + return "", errors.New("FIODGNAME string not NUL-terminated") +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/pty_linux.go b/tests/ociswrapper/vendor/github.com/creack/pty/pty_linux.go new file mode 100644 index 00000000000..e7e01c0aa5e --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/pty_linux.go @@ -0,0 +1,54 @@ +//go:build linux +// +build linux + +package pty + +import ( + "os" + "strconv" + "syscall" + "unsafe" +) + +func open() (pty, tty *os.File, err error) { + p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) + if err != nil { + return nil, nil, err + } + // In case of error after this point, make sure we close the ptmx fd. + defer func() { + if err != nil { + _ = p.Close() // Best effort. + } + }() + + sname, err := ptsname(p) + if err != nil { + return nil, nil, err + } + + if err := unlockpt(p); err != nil { + return nil, nil, err + } + + t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0) //nolint:gosec // Expected Open from a variable. + if err != nil { + return nil, nil, err + } + return p, t, nil +} + +func ptsname(f *os.File) (string, error) { + var n _C_uint + err := ioctl(f, syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) //nolint:gosec // Expected unsafe pointer for Syscall call. + if err != nil { + return "", err + } + return "/dev/pts/" + strconv.Itoa(int(n)), nil +} + +func unlockpt(f *os.File) error { + var u _C_int + // use TIOCSPTLCK with a pointer to zero to clear the lock. + return ioctl(f, syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) //nolint:gosec // Expected unsafe pointer for Syscall call. +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/pty_netbsd.go b/tests/ociswrapper/vendor/github.com/creack/pty/pty_netbsd.go new file mode 100644 index 00000000000..dd5611dbd70 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/pty_netbsd.go @@ -0,0 +1,69 @@ +//go:build netbsd +// +build netbsd + +package pty + +import ( + "errors" + "os" + "syscall" + "unsafe" +) + +func open() (pty, tty *os.File, err error) { + p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) + if err != nil { + return nil, nil, err + } + // In case of error after this point, make sure we close the ptmx fd. + defer func() { + if err != nil { + _ = p.Close() // Best effort. + } + }() + + sname, err := ptsname(p) + if err != nil { + return nil, nil, err + } + + if err := grantpt(p); err != nil { + return nil, nil, err + } + + // In NetBSD unlockpt() does nothing, so it isn't called here. + + t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0) + if err != nil { + return nil, nil, err + } + return p, t, nil +} + +func ptsname(f *os.File) (string, error) { + /* + * from ptsname(3): The ptsname() function is equivalent to: + * struct ptmget pm; + * ioctl(fd, TIOCPTSNAME, &pm) == -1 ? NULL : pm.sn; + */ + var ptm ptmget + if err := ioctl(f, uintptr(ioctl_TIOCPTSNAME), uintptr(unsafe.Pointer(&ptm))); err != nil { + return "", err + } + name := make([]byte, len(ptm.Sn)) + for i, c := range ptm.Sn { + name[i] = byte(c) + if c == 0 { + return string(name[:i]), nil + } + } + return "", errors.New("TIOCPTSNAME string not NUL-terminated") +} + +func grantpt(f *os.File) error { + /* + * from grantpt(3): Calling grantpt() is equivalent to: + * ioctl(fd, TIOCGRANTPT, 0); + */ + return ioctl(f, uintptr(ioctl_TIOCGRANTPT), 0) +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/pty_openbsd.go b/tests/ociswrapper/vendor/github.com/creack/pty/pty_openbsd.go new file mode 100644 index 00000000000..337c39f3f1c --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/pty_openbsd.go @@ -0,0 +1,47 @@ +//go:build openbsd +// +build openbsd + +package pty + +import ( + "os" + "syscall" + "unsafe" +) + +func cInt8ToString(in []int8) string { + var s []byte + for _, v := range in { + if v == 0 { + break + } + s = append(s, byte(v)) + } + return string(s) +} + +func open() (pty, tty *os.File, err error) { + /* + * from ptm(4): + * The PTMGET command allocates a free pseudo terminal, changes its + * ownership to the caller, revokes the access privileges for all previous + * users, opens the file descriptors for the pty and tty devices and + * returns them to the caller in struct ptmget. + */ + + p, err := os.OpenFile("/dev/ptm", os.O_RDWR|syscall.O_CLOEXEC, 0) + if err != nil { + return nil, nil, err + } + defer p.Close() + + var ptm ptmget + if err := ioctl(p, uintptr(ioctl_PTMGET), uintptr(unsafe.Pointer(&ptm))); err != nil { + return nil, nil, err + } + + pty = os.NewFile(uintptr(ptm.Cfd), cInt8ToString(ptm.Cn[:])) + tty = os.NewFile(uintptr(ptm.Sfd), cInt8ToString(ptm.Sn[:])) + + return pty, tty, nil +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/pty_solaris.go b/tests/ociswrapper/vendor/github.com/creack/pty/pty_solaris.go new file mode 100644 index 00000000000..4e22416b013 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/pty_solaris.go @@ -0,0 +1,171 @@ +//go:build solaris +// +build solaris + +package pty + +/* based on: +http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libc/port/gen/pt.c +*/ + +import ( + "errors" + "os" + "strconv" + "syscall" + "unsafe" +) + +func open() (pty, tty *os.File, err error) { + ptmxfd, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY, 0) + if err != nil { + return nil, nil, err + } + p := os.NewFile(uintptr(ptmxfd), "/dev/ptmx") + // In case of error after this point, make sure we close the ptmx fd. + defer func() { + if err != nil { + _ = p.Close() // Best effort. + } + }() + + sname, err := ptsname(p) + if err != nil { + return nil, nil, err + } + + if err := grantpt(p); err != nil { + return nil, nil, err + } + + if err := unlockpt(p); err != nil { + return nil, nil, err + } + + ptsfd, err := syscall.Open(sname, os.O_RDWR|syscall.O_NOCTTY, 0) + if err != nil { + return nil, nil, err + } + t := os.NewFile(uintptr(ptsfd), sname) + + // In case of error after this point, make sure we close the pts fd. + defer func() { + if err != nil { + _ = t.Close() // Best effort. + } + }() + + // pushing terminal driver STREAMS modules as per pts(7) + for _, mod := range []string{"ptem", "ldterm", "ttcompat"} { + if err := streamsPush(t, mod); err != nil { + return nil, nil, err + } + } + + return p, t, nil +} + +func ptsname(f *os.File) (string, error) { + dev, err := ptsdev(f) + if err != nil { + return "", err + } + fn := "/dev/pts/" + strconv.FormatInt(int64(dev), 10) + + if err := syscall.Access(fn, 0); err != nil { + return "", err + } + return fn, nil +} + +func unlockpt(f *os.File) error { + istr := strioctl{ + icCmd: UNLKPT, + icTimeout: 0, + icLen: 0, + icDP: nil, + } + return ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr))) +} + +func minor(x uint64) uint64 { return x & 0377 } + +func ptsdev(f *os.File) (uint64, error) { + istr := strioctl{ + icCmd: ISPTM, + icTimeout: 0, + icLen: 0, + icDP: nil, + } + + if err := ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil { + return 0, err + } + var errors = make(chan error, 1) + var results = make(chan uint64, 1) + defer close(errors) + defer close(results) + + var err error + var sc syscall.RawConn + sc, err = f.SyscallConn() + if err != nil { + return 0, err + } + err = sc.Control(func(fd uintptr) { + var status syscall.Stat_t + if err := syscall.Fstat(int(fd), &status); err != nil { + results <- 0 + errors <- err + } + results <- uint64(minor(status.Rdev)) + errors <- nil + }) + if err != nil { + return 0, err + } + return <-results, <-errors +} + +type ptOwn struct { + rUID int32 + rGID int32 +} + +func grantpt(f *os.File) error { + if _, err := ptsdev(f); err != nil { + return err + } + pto := ptOwn{ + rUID: int32(os.Getuid()), + // XXX should first attempt to get gid of DEFAULT_TTY_GROUP="tty" + rGID: int32(os.Getgid()), + } + istr := strioctl{ + icCmd: OWNERPT, + icTimeout: 0, + icLen: int32(unsafe.Sizeof(strioctl{})), + icDP: unsafe.Pointer(&pto), + } + if err := ioctl(f, I_STR, uintptr(unsafe.Pointer(&istr))); err != nil { + return errors.New("access denied") + } + return nil +} + +// streamsPush pushes STREAMS modules if not already done so. +func streamsPush(f *os.File, mod string) error { + buf := []byte(mod) + + // XXX I_FIND is not returning an error when the module + // is already pushed even though truss reports a return + // value of 1. A bug in the Go Solaris syscall interface? + // XXX without this we are at risk of the issue + // https://www.illumos.org/issues/9042 + // but since we are not using libc or XPG4.2, we should not be + // double-pushing modules + + if err := ioctl(f, I_FIND, uintptr(unsafe.Pointer(&buf[0]))); err != nil { + return nil + } + return ioctl(f, I_PUSH, uintptr(unsafe.Pointer(&buf[0]))) +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/pty_unsupported.go b/tests/ociswrapper/vendor/github.com/creack/pty/pty_unsupported.go new file mode 100644 index 00000000000..c771020fae5 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/pty_unsupported.go @@ -0,0 +1,12 @@ +//go:build !linux && !darwin && !freebsd && !dragonfly && !netbsd && !openbsd && !solaris +// +build !linux,!darwin,!freebsd,!dragonfly,!netbsd,!openbsd,!solaris + +package pty + +import ( + "os" +) + +func open() (pty, tty *os.File, err error) { + return nil, nil, ErrUnsupported +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/run.go b/tests/ociswrapper/vendor/github.com/creack/pty/run.go new file mode 100644 index 00000000000..4755366200b --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/run.go @@ -0,0 +1,57 @@ +package pty + +import ( + "os" + "os/exec" + "syscall" +) + +// Start assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, +// and c.Stderr, calls c.Start, and returns the File of the tty's +// corresponding pty. +// +// Starts the process in a new session and sets the controlling terminal. +func Start(cmd *exec.Cmd) (*os.File, error) { + return StartWithSize(cmd, nil) +} + +// StartWithAttrs assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, +// and c.Stderr, calls c.Start, and returns the File of the tty's +// corresponding pty. +// +// This will resize the pty to the specified size before starting the command if a size is provided. +// The `attrs` parameter overrides the one set in c.SysProcAttr. +// +// This should generally not be needed. Used in some edge cases where it is needed to create a pty +// without a controlling terminal. +func StartWithAttrs(c *exec.Cmd, sz *Winsize, attrs *syscall.SysProcAttr) (*os.File, error) { + pty, tty, err := Open() + if err != nil { + return nil, err + } + defer func() { _ = tty.Close() }() // Best effort. + + if sz != nil { + if err := Setsize(pty, sz); err != nil { + _ = pty.Close() // Best effort. + return nil, err + } + } + if c.Stdout == nil { + c.Stdout = tty + } + if c.Stderr == nil { + c.Stderr = tty + } + if c.Stdin == nil { + c.Stdin = tty + } + + c.SysProcAttr = attrs + + if err := c.Start(); err != nil { + _ = pty.Close() // Best effort. + return nil, err + } + return pty, err +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/start.go b/tests/ociswrapper/vendor/github.com/creack/pty/start.go new file mode 100644 index 00000000000..9b51635f5e1 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/start.go @@ -0,0 +1,25 @@ +//go:build !windows +// +build !windows + +package pty + +import ( + "os" + "os/exec" + "syscall" +) + +// StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, +// and c.Stderr, calls c.Start, and returns the File of the tty's +// corresponding pty. +// +// This will resize the pty to the specified size before starting the command. +// Starts the process in a new session and sets the controlling terminal. +func StartWithSize(cmd *exec.Cmd, ws *Winsize) (*os.File, error) { + if cmd.SysProcAttr == nil { + cmd.SysProcAttr = &syscall.SysProcAttr{} + } + cmd.SysProcAttr.Setsid = true + cmd.SysProcAttr.Setctty = true + return StartWithAttrs(cmd, ws, cmd.SysProcAttr) +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/start_windows.go b/tests/ociswrapper/vendor/github.com/creack/pty/start_windows.go new file mode 100644 index 00000000000..7e9530ba03c --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/start_windows.go @@ -0,0 +1,19 @@ +//go:build windows +// +build windows + +package pty + +import ( + "os" + "os/exec" +) + +// StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout, +// and c.Stderr, calls c.Start, and returns the File of the tty's +// corresponding pty. +// +// This will resize the pty to the specified size before starting the command. +// Starts the process in a new session and sets the controlling terminal. +func StartWithSize(cmd *exec.Cmd, ws *Winsize) (*os.File, error) { + return nil, ErrUnsupported +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/test_crosscompile.sh b/tests/ociswrapper/vendor/github.com/creack/pty/test_crosscompile.sh new file mode 100644 index 00000000000..40df89add69 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/test_crosscompile.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env sh + +# Test script checking that all expected os/arch compile properly. +# Does not actually test the logic, just the compilation so we make sure we don't break code depending on the lib. + +echo2() { + echo $@ >&2 +} + +trap end 0 +end() { + [ "$?" = 0 ] && echo2 "Pass." || (echo2 "Fail."; exit 1) +} + +cross() { + os=$1 + shift + echo2 "Build for $os." + for arch in $@; do + echo2 " - $os/$arch" + GOOS=$os GOARCH=$arch go build + done + echo2 +} + +set -e + +cross linux amd64 386 arm arm64 ppc64 ppc64le s390x mips mipsle mips64 mips64le riscv64 +cross darwin amd64 arm64 +cross freebsd amd64 386 arm arm64 riscv64 +cross netbsd amd64 386 arm arm64 +cross openbsd amd64 386 arm arm64 +cross dragonfly amd64 +cross solaris amd64 + +# Not expected to work but should still compile. +cross windows amd64 386 arm + +# TODO: Fix compilation error on openbsd/arm. +# TODO: Merge the solaris PR. + +# Some os/arch require a different compiler. Run in docker. +if ! hash docker; then + # If docker is not present, stop here. + return +fi + +# Golang dropped support for darwin 32bits since go1.15. Make sure the lib still compile with go1.14 on those archs. +echo2 "Build for darwin (32bits)." +echo2 " - darwin/386" +docker build -t creack-pty-test -f Dockerfile.golang --build-arg=GOVERSION=1.14 --build-arg=GOOS=darwin --build-arg=GOARCH=386 . +echo2 " - darwin/arm" +docker build -t creack-pty-test -f Dockerfile.golang --build-arg=GOVERSION=1.14 --build-arg=GOOS=darwin --build-arg=GOARCH=arm . + +# Run a single test for an old go version. Would be best with go1.0, but not available on Dockerhub. +# Using 1.6 as it is the base version for the RISCV compiler. +# Would also be better to run all the tests, not just one, need to refactor this file to allow for specifc archs per version. +echo2 "Build for linux - go1.6." +echo2 " - linux/amd64" +docker build -t creack-pty-test -f Dockerfile.golang --build-arg=GOVERSION=1.6 --build-arg=GOOS=linux --build-arg=GOARCH=amd64 . diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/winsize.go b/tests/ociswrapper/vendor/github.com/creack/pty/winsize.go new file mode 100644 index 00000000000..cfa3e5f391e --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/winsize.go @@ -0,0 +1,24 @@ +package pty + +import "os" + +// InheritSize applies the terminal size of pty to tty. This should be run +// in a signal handler for syscall.SIGWINCH to automatically resize the tty when +// the pty receives a window size change notification. +func InheritSize(pty, tty *os.File) error { + size, err := GetsizeFull(pty) + if err != nil { + return err + } + return Setsize(tty, size) +} + +// Getsize returns the number of rows (lines) and cols (positions +// in each line) in terminal t. +func Getsize(t *os.File) (rows, cols int, err error) { + ws, err := GetsizeFull(t) + if err != nil { + return 0, 0, err + } + return int(ws.Rows), int(ws.Cols), nil +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/winsize_unix.go b/tests/ociswrapper/vendor/github.com/creack/pty/winsize_unix.go new file mode 100644 index 00000000000..8dbbcda0f07 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/winsize_unix.go @@ -0,0 +1,35 @@ +//go:build !windows +// +build !windows + +package pty + +import ( + "os" + "syscall" + "unsafe" +) + +// Winsize describes the terminal size. +type Winsize struct { + Rows uint16 // ws_row: Number of rows (in cells). + Cols uint16 // ws_col: Number of columns (in cells). + X uint16 // ws_xpixel: Width in pixels. + Y uint16 // ws_ypixel: Height in pixels. +} + +// Setsize resizes t to s. +func Setsize(t *os.File, ws *Winsize) error { + //nolint:gosec // Expected unsafe pointer for Syscall call. + return ioctl(t, syscall.TIOCSWINSZ, uintptr(unsafe.Pointer(ws))) +} + +// GetsizeFull returns the full terminal size description. +func GetsizeFull(t *os.File) (size *Winsize, err error) { + var ws Winsize + + //nolint:gosec // Expected unsafe pointer for Syscall call. + if err := ioctl(t, syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))); err != nil { + return nil, err + } + return &ws, nil +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/winsize_unsupported.go b/tests/ociswrapper/vendor/github.com/creack/pty/winsize_unsupported.go new file mode 100644 index 00000000000..0d2109938ad --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/winsize_unsupported.go @@ -0,0 +1,23 @@ +//go:build windows +// +build windows + +package pty + +import ( + "os" +) + +// Winsize is a dummy struct to enable compilation on unsupported platforms. +type Winsize struct { + Rows, Cols, X, Y uint16 +} + +// Setsize resizes t to s. +func Setsize(*os.File, *Winsize) error { + return ErrUnsupported +} + +// GetsizeFull returns the full terminal size description. +func GetsizeFull(*os.File) (*Winsize, error) { + return nil, ErrUnsupported +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_386.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_386.go new file mode 100644 index 00000000000..d126f4aa583 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_386.go @@ -0,0 +1,12 @@ +//go:build 386 +// +build 386 + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_amd64.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_amd64.go new file mode 100644 index 00000000000..6c4a7677fc7 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_amd64.go @@ -0,0 +1,12 @@ +//go:build amd64 +// +build amd64 + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_arm.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_arm.go new file mode 100644 index 00000000000..de6fe160ea5 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_arm.go @@ -0,0 +1,12 @@ +//go:build arm +// +build arm + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_arm64.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_arm64.go new file mode 100644 index 00000000000..c4f315cac1a --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_arm64.go @@ -0,0 +1,12 @@ +//go:build arm64 +// +build arm64 + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_dragonfly_amd64.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_dragonfly_amd64.go new file mode 100644 index 00000000000..183c4214711 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_dragonfly_amd64.go @@ -0,0 +1,17 @@ +//go:build amd64 && dragonfly +// +build amd64,dragonfly + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_dragonfly.go + +package pty + +const ( + _C_SPECNAMELEN = 0x3f +) + +type fiodgnameArg struct { + Name *byte + Len uint32 + Pad_cgo_0 [4]byte +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_386.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_386.go new file mode 100644 index 00000000000..d80dbf7172b --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_386.go @@ -0,0 +1,16 @@ +//go:build 386 && freebsd +// +build 386,freebsd + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_freebsd.go + +package pty + +const ( + _C_SPECNAMELEN = 0x3f +) + +type fiodgnameArg struct { + Len int32 + Buf *byte +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_amd64.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_amd64.go new file mode 100644 index 00000000000..bfab4e45825 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_amd64.go @@ -0,0 +1,17 @@ +//go:build amd64 && freebsd +// +build amd64,freebsd + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_freebsd.go + +package pty + +const ( + _C_SPECNAMELEN = 0x3f +) + +type fiodgnameArg struct { + Len int32 + Pad_cgo_0 [4]byte + Buf *byte +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_arm.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_arm.go new file mode 100644 index 00000000000..3a8aeae371d --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_arm.go @@ -0,0 +1,16 @@ +//go:build arm && freebsd +// +build arm,freebsd + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_freebsd.go + +package pty + +const ( + _C_SPECNAMELEN = 0x3f +) + +type fiodgnameArg struct { + Len int32 + Buf *byte +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_arm64.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_arm64.go new file mode 100644 index 00000000000..a83924918a0 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_arm64.go @@ -0,0 +1,16 @@ +//go:build arm64 && freebsd +// +build arm64,freebsd + +// Code generated by cmd/cgo -godefs; DO NOT EDIT. +// cgo -godefs types_freebsd.go + +package pty + +const ( + _C_SPECNAMELEN = 0xff +) + +type fiodgnameArg struct { + Len int32 + Buf *byte +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_ppc64.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_ppc64.go new file mode 100644 index 00000000000..5fa102fcdf6 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_ppc64.go @@ -0,0 +1,14 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_freebsd.go + +package pty + +const ( + _C_SPECNAMELEN = 0x3f +) + +type fiodgnameArg struct { + Len int32 + Pad_cgo_0 [4]byte + Buf *byte +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_riscv64.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_riscv64.go new file mode 100644 index 00000000000..b3c544098ce --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_freebsd_riscv64.go @@ -0,0 +1,13 @@ +// Code generated by cmd/cgo -godefs; DO NOT EDIT. +// cgo -godefs types_freebsd.go + +package pty + +const ( + _C_SPECNAMELEN = 0x3f +) + +type fiodgnameArg struct { + Len int32 + Buf *byte +} diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_loong64.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_loong64.go new file mode 100644 index 00000000000..3beb5c17626 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_loong64.go @@ -0,0 +1,12 @@ +//go:build loong64 +// +build loong64 + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_mipsx.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_mipsx.go new file mode 100644 index 00000000000..281277977ef --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_mipsx.go @@ -0,0 +1,13 @@ +//go:build (mips || mipsle || mips64 || mips64le) && linux +// +build mips mipsle mips64 mips64le +// +build linux + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_netbsd_32bit_int.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_netbsd_32bit_int.go new file mode 100644 index 00000000000..2ab7c45598f --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_netbsd_32bit_int.go @@ -0,0 +1,17 @@ +//go:build (386 || amd64 || arm || arm64) && netbsd +// +build 386 amd64 arm arm64 +// +build netbsd + +package pty + +type ptmget struct { + Cfd int32 + Sfd int32 + Cn [1024]int8 + Sn [1024]int8 +} + +var ( + ioctl_TIOCPTSNAME = 0x48087448 + ioctl_TIOCGRANTPT = 0x20007447 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_openbsd_32bit_int.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_openbsd_32bit_int.go new file mode 100644 index 00000000000..1eb0948167e --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_openbsd_32bit_int.go @@ -0,0 +1,14 @@ +//go:build (386 || amd64 || arm || arm64 || mips64) && openbsd +// +build 386 amd64 arm arm64 mips64 +// +build openbsd + +package pty + +type ptmget struct { + Cfd int32 + Sfd int32 + Cn [16]int8 + Sn [16]int8 +} + +var ioctl_PTMGET = 0x40287401 diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc.go new file mode 100644 index 00000000000..ff0b8fd838f --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc.go @@ -0,0 +1,9 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc64.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc64.go new file mode 100644 index 00000000000..bbb3da83220 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc64.go @@ -0,0 +1,12 @@ +//go:build ppc64 +// +build ppc64 + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc64le.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc64le.go new file mode 100644 index 00000000000..8a4fac3e928 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_ppc64le.go @@ -0,0 +1,12 @@ +//go:build ppc64le +// +build ppc64le + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_riscvx.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_riscvx.go new file mode 100644 index 00000000000..dc5da905061 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_riscvx.go @@ -0,0 +1,12 @@ +//go:build riscv || riscv64 +// +build riscv riscv64 + +// Code generated by cmd/cgo -godefs; DO NOT EDIT. +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_s390x.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_s390x.go new file mode 100644 index 00000000000..3433be7ca08 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_s390x.go @@ -0,0 +1,12 @@ +//go:build s390x +// +build s390x + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_sparcx.go b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_sparcx.go new file mode 100644 index 00000000000..06e44311df8 --- /dev/null +++ b/tests/ociswrapper/vendor/github.com/creack/pty/ztypes_sparcx.go @@ -0,0 +1,12 @@ +//go:build sparc || sparc64 +// +build sparc sparc64 + +// Code generated by cmd/cgo -godefs; DO NOT EDIT. +// cgo -godefs types.go + +package pty + +type ( + _C_int int32 + _C_uint uint32 +) diff --git a/tests/ociswrapper/vendor/modules.txt b/tests/ociswrapper/vendor/modules.txt index 81942bd4b7c..17d24c5d095 100644 --- a/tests/ociswrapper/vendor/modules.txt +++ b/tests/ociswrapper/vendor/modules.txt @@ -1,3 +1,6 @@ +# github.com/creack/pty v1.1.21 +## explicit; go 1.13 +github.com/creack/pty # github.com/inconshreveable/mousetrap v1.1.0 ## explicit; go 1.18 github.com/inconshreveable/mousetrap From 2b88c194bcecbba1076cb7757ac4443d08dc94c9 Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Mon, 8 Jul 2024 14:19:55 +0545 Subject: [PATCH 07/14] refactor: allow any commands and user inputs --- tests/ociswrapper/ocis/ocis.go | 6 +- tests/ociswrapper/wrapper/handlers/handler.go | 76 +++++++++++++------ 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/tests/ociswrapper/ocis/ocis.go b/tests/ociswrapper/ocis/ocis.go index b53e8e5f071..0ca8243262c 100644 --- a/tests/ociswrapper/ocis/ocis.go +++ b/tests/ociswrapper/ocis/ocis.go @@ -230,13 +230,14 @@ func waitUntilCompleteShutdown() (bool, string) { return true, "oCIS server stopped successfully" } -func RunCommand(command string) (int, string) { +func RunCommand(command string, inputs []string) (int, string) { logs := new(strings.Builder) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // build the command - c := exec.CommandContext(ctx, config.Get("bin"), "idm", "resetpassword", "-u", "admin") + cmdArgs := strings.Split(command, " ") + c := exec.CommandContext(ctx, config.Get("bin"), cmdArgs...) // Start the command with a pty (pseudo terminal) // This is required to interact with the command @@ -246,7 +247,6 @@ func RunCommand(command string) (int, string) { } defer ptyF.Close() - inputs := []string{"demo", "demo"} for _, input := range inputs { fmt.Fprintf(ptyF, "%s\n", input) } diff --git a/tests/ociswrapper/wrapper/handlers/handler.go b/tests/ociswrapper/wrapper/handlers/handler.go index 9f3cc6b03f8..5d3b46eca55 100644 --- a/tests/ociswrapper/wrapper/handlers/handler.go +++ b/tests/ociswrapper/wrapper/handlers/handler.go @@ -33,16 +33,15 @@ func parseJsonBody(reqBody io.ReadCloser) (map[string]any, error) { return bodyMap, nil } -func sendResponse(res http.ResponseWriter, success bool, message string) { +func sendResponse(res http.ResponseWriter, statusCode int, message string) { res.Header().Set("Content-Type", "application/json") + res.WriteHeader(statusCode) var status string - if success { + if statusCode == http.StatusOK { status = "OK" - res.WriteHeader(http.StatusOK) } else { status = "ERROR" - res.WriteHeader(http.StatusInternalServerError) } resBody := BasicResponse{ @@ -77,13 +76,13 @@ func sendCmdResponse(res http.ResponseWriter, exitCode int, message string) { func SetEnvHandler(res http.ResponseWriter, req *http.Request) { if req.Method != http.MethodPut { - http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) + sendResponse(res, http.StatusMethodNotAllowed, "") return } envBody, err := parseJsonBody(req.Body) if err != nil { - http.Error(res, "Bad request", http.StatusBadRequest) + sendResponse(res, http.StatusMethodNotAllowed, "Invalid json body") return } @@ -98,16 +97,17 @@ func SetEnvHandler(res http.ResponseWriter, req *http.Request) { success, _ := ocis.Restart(ocis.EnvConfigs) if success { message = "oCIS configured successfully" - } else { - message = "Failed to restart oCIS with new configuration" + sendResponse(res, http.StatusOK, message) + return } - sendResponse(res, success, message) + message = "Failed to restart oCIS with new configuration" + sendResponse(res, http.StatusInternalServerError, message) } func RollbackHandler(res http.ResponseWriter, req *http.Request) { if req.Method != http.MethodDelete { - http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) + sendResponse(res, http.StatusMethodNotAllowed, "") return } @@ -116,31 +116,37 @@ func RollbackHandler(res http.ResponseWriter, req *http.Request) { success, _ := ocis.Restart(os.Environ()) if success { message = "oCIS configuration rolled back successfully" - } else { - message = "Failed to restart oCIS with initial configuration" + sendResponse(res, http.StatusOK, message) + return } - sendResponse(res, success, message) + message = "Failed to restart oCIS with initial configuration" + sendResponse(res, http.StatusInternalServerError, message) } func StopOcisHandler(res http.ResponseWriter, req *http.Request) { if req.Method != http.MethodPost { - http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) + sendResponse(res, http.StatusMethodNotAllowed, "") return } success, message := ocis.Stop() - sendResponse(res, success, message) + if success { + sendResponse(res, http.StatusOK, message) + return + } + + sendResponse(res, http.StatusInternalServerError, message) } func StartOcisHandler(res http.ResponseWriter, req *http.Request) { if req.Method != http.MethodPost { - http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) + sendResponse(res, http.StatusMethodNotAllowed, "") return } if ocis.IsOcisRunning() { - sendResponse(res, false, "oCIS server is already running") + sendResponse(res, http.StatusInternalServerError, "oCIS server is already running") return } @@ -148,27 +154,51 @@ func StartOcisHandler(res http.ResponseWriter, req *http.Request) { go ocis.Start(nil) success, message := ocis.WaitForConnection() - sendResponse(res, success, message) + if success { + sendResponse(res, http.StatusOK, message) + return + } + + sendResponse(res, http.StatusInternalServerError, message) } func CommandHandler(res http.ResponseWriter, req *http.Request) { if req.Method != http.MethodPost { - http.Error(res, "Method not allowed", http.StatusMethodNotAllowed) + sendResponse(res, http.StatusMethodNotAllowed, "") return } if req.Body == nil { - http.Error(res, "Bad request", http.StatusBadRequest) + sendResponse(res, http.StatusBadRequest, "Body is missing") return } - body, err := io.ReadAll(req.Body) + body, err := parseJsonBody(req.Body) if err != nil { - http.Error(res, "Bad request", http.StatusBadRequest) + sendResponse(res, http.StatusBadRequest, "Invalid json body") + return + } + if _, ok := body["command"]; !ok { + sendResponse(res, http.StatusBadRequest, "Command is missing") return } - exitCode, output := ocis.RunCommand(string(body)) + command := body["command"].(string) + + stdIn := []string{} + if _, ok := body["inputs"]; ok { + if inputs, ok := body["inputs"].([]interface{}); ok { + for _, input := range inputs { + if _, ok := input.(string); ok { + stdIn = append(stdIn, input.(string)) + } else { + sendResponse(res, http.StatusBadRequest, "Invalid input data. Expected string") + return + } + } + } + } + exitCode, output := ocis.RunCommand(command, stdIn) sendCmdResponse(res, exitCode, output) } From 86fd73e91251d589d868341c2ad778555f0fe9c3 Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Mon, 8 Jul 2024 16:07:34 +0545 Subject: [PATCH 08/14] refactor: respond 409 conflict if server is already running --- tests/ociswrapper/wrapper/handlers/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ociswrapper/wrapper/handlers/handler.go b/tests/ociswrapper/wrapper/handlers/handler.go index 5d3b46eca55..c2bd1cde55a 100644 --- a/tests/ociswrapper/wrapper/handlers/handler.go +++ b/tests/ociswrapper/wrapper/handlers/handler.go @@ -146,7 +146,7 @@ func StartOcisHandler(res http.ResponseWriter, req *http.Request) { } if ocis.IsOcisRunning() { - sendResponse(res, http.StatusInternalServerError, "oCIS server is already running") + sendResponse(res, http.StatusConflict, "oCIS server is already running") return } From 9baecdfd58dfc28430c35b3523aea8dd419417f0 Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Mon, 8 Jul 2024 16:32:03 +0545 Subject: [PATCH 09/14] fix: return early if the ocis is not running --- tests/ociswrapper/ocis/ocis.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/ociswrapper/ocis/ocis.go b/tests/ociswrapper/ocis/ocis.go index 0ca8243262c..ca8befa1da5 100644 --- a/tests/ociswrapper/ocis/ocis.go +++ b/tests/ociswrapper/ocis/ocis.go @@ -117,6 +117,10 @@ func Stop() (bool, string) { log.Println("Stopping oCIS server...") stopSignal = true + if cmd == nil { + return true, "oCIS server is not running" + } + err := cmd.Process.Signal(syscall.SIGINT) if err != nil { if !strings.HasSuffix(err.Error(), "process already finished") { From fd6e773b7e1d6443c544787c12726a40d42c6d19 Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Mon, 8 Jul 2024 17:21:53 +0545 Subject: [PATCH 10/14] test: prepare cli test suite --- tests/TestHelpers/CliHelper.php | 46 ++++++++++++++++++++++++++ tests/TestHelpers/OcisConfigHelper.php | 30 +++++++++++++++-- tests/acceptance/config/behat.yml | 8 +++++ 3 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 tests/TestHelpers/CliHelper.php diff --git a/tests/TestHelpers/CliHelper.php b/tests/TestHelpers/CliHelper.php new file mode 100644 index 00000000000..fee84ad332b --- /dev/null +++ b/tests/TestHelpers/CliHelper.php @@ -0,0 +1,46 @@ + + * @copyright Copyright (c) 2024 Sajan Gurung sajan@jankaritech.com + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, + * as published by the Free Software Foundation; + * either version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * + */ + +namespace TestHelpers; + +use GuzzleHttp\Exception\ConnectException; +use GuzzleHttp\Exception\GuzzleException; +use GuzzleHttp\Psr7\Request; +use Psr\Http\Message\ResponseInterface; +use TestHelpers\OcisConfigHelper; + +/** + * A helper class for running oCIS CLI commands + */ +class CliHelper { + + /** + * @param array $body + * + * @return ResponseInterface + * @throws GuzzleException + */ + public static function runCommand(array $body): ResponseInterface { + $url = OcisConfigHelper::getWrapperUrl() . "/command"; + return OcisConfigHelper::sendRequest($url, "POST", \json_encode($body)); + } +} \ No newline at end of file diff --git a/tests/TestHelpers/OcisConfigHelper.php b/tests/TestHelpers/OcisConfigHelper.php index aa9781d5820..70e49b01458 100644 --- a/tests/TestHelpers/OcisConfigHelper.php +++ b/tests/TestHelpers/OcisConfigHelper.php @@ -40,7 +40,7 @@ class OcisConfigHelper { * @return ResponseInterface * @throws GuzzleException */ - private static function sendRequest( + public static function sendRequest( string $url, string $method, ?string $body = "" @@ -54,10 +54,18 @@ private static function sendRequest( ); try { - return $client->send($request); + $response = $client->send($request); } catch (ConnectException $e) { throw new \Error("Cannot connect to the ociswrapper at the moment, make sure that ociswrapper is running before proceeding with the test run.\n" . $e->getMessage()); + } catch (GuzzleException $ex) { + $response = $ex->getResponse(); + + if ($response === null) { + throw $ex; + } } + + return $response; } /** @@ -90,4 +98,22 @@ public static function rollbackOcis(): ResponseInterface { $url = self::getWrapperUrl() . "/rollback"; return self::sendRequest($url, "DELETE"); } + + /** + * @return ResponseInterface + * @throws GuzzleException + */ + public static function stopOcis(): ResponseInterface { + $url = self::getWrapperUrl() . "/stop"; + return self::sendRequest($url, "POST"); + } + + /** + * @return ResponseInterface + * @throws GuzzleException + */ + public static function startOcis(): ResponseInterface { + $url = self::getWrapperUrl() . "/start"; + return self::sendRequest($url, "POST"); + } } diff --git a/tests/acceptance/config/behat.yml b/tests/acceptance/config/behat.yml index 17c1604c12b..b3a308d0b06 100644 --- a/tests/acceptance/config/behat.yml +++ b/tests/acceptance/config/behat.yml @@ -368,6 +368,14 @@ default: - SharingNgContext: - SpacesContext: + cliResetPassword: + paths: + - "%paths.base%/../features/cliResetPassword" + context: *common_ldap_suite_context + contexts: + - FeatureContext: *common_feature_context_params + - CliContext: + extensions: rdx\behatvars\BehatVariablesExtension: ~ From 78ca9bacf91f4a8d4ce305e9700fd68ebb0a7067 Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Mon, 8 Jul 2024 17:22:25 +0545 Subject: [PATCH 11/14] test: add cli test for resetting user password --- .../features/bootstrap/CliContext.php | 121 ++++++++++++++++++ .../features/bootstrap/FeatureContext.php | 36 ++++++ .../acceptance/features/bootstrap/WebDav.php | 50 +++++++- .../resetUserPassword.feature | 17 +++ 4 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 tests/acceptance/features/bootstrap/CliContext.php create mode 100644 tests/acceptance/features/cliResetPassword/resetUserPassword.feature diff --git a/tests/acceptance/features/bootstrap/CliContext.php b/tests/acceptance/features/bootstrap/CliContext.php new file mode 100644 index 00000000000..8a4f75bcf89 --- /dev/null +++ b/tests/acceptance/features/bootstrap/CliContext.php @@ -0,0 +1,121 @@ + + * @copyright Copyright (c) 2024 Sajan Gurung sajan@jankaritech.com + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, + * as published by the Free Software Foundation; + * either version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * + */ + +use Behat\Behat\Hook\Scope\BeforeScenarioScope; +use Behat\Behat\Context\Context; +use PHPUnit\Framework\Assert; +use Psr\Http\Message\ResponseInterface; +use TestHelpers\CliHelper; +use TestHelpers\OcisConfigHelper; + +/** + * CLI context + */ +class CliContext implements Context { + private FeatureContext $featureContext; + + /** + * @BeforeScenario + * + * @param BeforeScenarioScope $scope + * + * @return void + */ + public function setUpScenario(BeforeScenarioScope $scope): void { + // Get the environment + $environment = $scope->getEnvironment(); + // Get all the contexts you need in this context + $this->featureContext = $environment->getContext('FeatureContext'); + } + + /** + * @Given the administrator has stopped the server + * + * @return void + */ + public function theAdministratorHasStoppedTheServer(): void { + $response = OcisConfigHelper::stopOcis(); + $this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response); + } + + /** + * @Given the administrator has started the server + * + * @return void + */ + public function theAdministratorHasStartedTheServer(): void { + $response = OcisConfigHelper::startOcis(); + $this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response); + } + + /** + * @When the administrator resets the password of user :user to :password using the CLI + * + * @param string $user + * @param string $password + * + * @return void + */ + public function theAdministratorResetsThePasswordOfUserUsingTheCLI(string $user, string $password): void { + $command = "idm resetpassword -u $user"; + $body = [ + "command" => $command, + "inputs" => [$password, $password] + ]; + + $this->featureContext->setResponse(CliHelper::runCommand($body)); + $this->featureContext->updateUserPassword($user, $password); + } + + /** + * @Then the command should be successful + * + * @return void + */ + public function theCommandShouldBeSuccessful(): void { + $response = $this->featureContext->getResponse(); + $this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response); + + $jsonResponse = $this->featureContext->getJsonDecodedResponse($response); + + Assert::assertSame("OK", $jsonResponse["status"]); + Assert::assertSame(0, $jsonResponse["exitCode"], "Expected exit code to be 0, but got " . $jsonResponse["exitCode"]); + } + + /** + * @Then /^the command output (should|should not) contain "([^"]*)"$/ + * + * @param string $output + * + * @return void + */ + public function theCommandOutputShouldContain(string $shouldOrNot,string $output): void { + $response = $this->featureContext->getResponse(); + $jsonResponse = $this->featureContext->getJsonDecodedResponse($response); + + if ($shouldOrNot === "should") { + Assert::assertStringContainsString($output, $jsonResponse["message"]); + } else { + Assert::assertStringNotContainsString($output, $jsonResponse["message"]); + } + } +} \ No newline at end of file diff --git a/tests/acceptance/features/bootstrap/FeatureContext.php b/tests/acceptance/features/bootstrap/FeatureContext.php index d558882431f..e2ea3a12c1b 100644 --- a/tests/acceptance/features/bootstrap/FeatureContext.php +++ b/tests/acceptance/features/bootstrap/FeatureContext.php @@ -43,6 +43,7 @@ use TestHelpers\GraphHelper; use TestHelpers\WebDavHelper; use TestHelpers\SettingsHelper; +use TestHelpers\OcisConfigHelper; require_once 'bootstrap.php'; @@ -655,6 +656,23 @@ public static function logStep(BeforeStepScope $scope): void { HttpLogger::writeLog(HttpLogger::getScenarioLogPath(), $logMessage); } + /** + * FIRST AfterScenario HOOK + * + * NOTE: This method is called after each scenario having the @env-config tag + * This ensures that the server is running for clean-up purposes + * + * @AfterScenario @env-config + * + * @return void + */ + public function startOcisServer(): void { + $response = OcisConfigHelper::startOcis(); + // 409 is returned if the server is already running + $this->theHTTPStatusCodeShouldBe([200, 409], 'Starting oCIS server', $response); + } + + /** * Get the externally-defined admin username, if any * @@ -1695,6 +1713,24 @@ public function getPasswordForUser(?string $userName): string { return (string)$this->getActualPassword($this->regularUserPassword); } + /** + * @param string $username + * @param string $password + * + * @return void + * @throws Exception + */ + public function updateUserPassword(string $username, string $password): void { + $username = $this->normalizeUsername($username); + if ($username === $this->getAdminUsername()) { + $this->adminPassword = $password; + } elseif (\array_key_exists($username, $this->createdUsers)) { + $this->createdUsers[$username]['password'] = $password; + } else { + throw new Exception("User '$username' not found"); + } + } + /** * Get the display name of the user. * diff --git a/tests/acceptance/features/bootstrap/WebDav.php b/tests/acceptance/features/bootstrap/WebDav.php index 235fa51a400..c4a5ad692aa 100644 --- a/tests/acceptance/features/bootstrap/WebDav.php +++ b/tests/acceptance/features/bootstrap/WebDav.php @@ -443,12 +443,13 @@ public function makeDavRequest( * @param string $user * @param string $folder * @param bool|null $isGivenStep + * @param string|null $password * * @return ResponseInterface * @throws JsonException | GuzzleException * @throws GuzzleException | JsonException */ - public function createFolder(string $user, string $folder, ?bool $isGivenStep = false): ResponseInterface { + public function createFolder(string $user, string $folder, ?bool $isGivenStep = false, ?string $password = null): ResponseInterface { $folder = '/' . \ltrim($folder, '/'); return $this->makeDavRequest( $user, @@ -459,7 +460,7 @@ public function createFolder(string $user, string $folder, ?bool $isGivenStep = "files", null, false, - null, + $password, [], null, $isGivenStep @@ -3349,6 +3350,31 @@ public function userShouldBeAbleToCreateFolder(string $user, string $destination ); } + /** + * @Then user :user should be able to create folder :destination using password :password + * + * @param string $user + * @param string $destination + * @param string $password + * + * @return void + * @throws Exception + */ + public function userShouldBeAbleToCreateFolderUsingPassword(string $user, string $destination, string $password):void { + $user = $this->getActualUsername($user); + $response = $this->createFolder($user, $destination, true, $password); + $this->theHTTPStatusCodeShouldBe( + ["201", "204"], + "HTTP status code was not 201 or 204 while trying to create folder '$destination' for user '$user'", + $response + ); + $this->checkFileOrFolderExistsForUser( + $user, + "folder", + $destination + ); + } + /** * @Then user :user should not be able to create folder :destination * @@ -3369,6 +3395,26 @@ public function userShouldNotBeAbleToCreateFolder(string $user, string $destinat ); } + /** + * @Then user :user should not be able to create folder :destination using password :password + * + * @param string $user + * @param string $destination + * @param string $password + * + * @return void + * @throws Exception + */ + public function userShouldNotBeAbleToCreateFolderUsingPassword(string $user, string $destination, string $password):void { + $user = $this->getActualUsername($user); + $response = $this->createFolder($user, $destination, false, $password); + $this->theHTTPStatusCodeShouldBeBetween(400, 499, $response); + $this->checkFileOrFolderDoesNotExistsForUser( + $user, + "folder", + $destination + ); + } /** * Old style chunking upload * diff --git a/tests/acceptance/features/cliResetPassword/resetUserPassword.feature b/tests/acceptance/features/cliResetPassword/resetUserPassword.feature new file mode 100644 index 00000000000..a0a314652f7 --- /dev/null +++ b/tests/acceptance/features/cliResetPassword/resetUserPassword.feature @@ -0,0 +1,17 @@ +@env-config +Feature: reset user password via CLI command + + + Scenario: reset user password + Given the user "Admin" has created a new user with the following attributes: + | userName | Alice | + | displayName | Alice Hansen | + | password | %alt1% | + And the administrator has stopped the server + When the administrator resets the password of user "Alice" to "newpass" using the CLI + Then the command should be successful + And the command output should contain "Password for user 'uid=Alice,ou=users,o=libregraph-idm' updated." + But the command output should not contain "Failed to update user password: entry does not exist" + And the administrator has started the server + And user "Alice" should be able to create folder "newFolder" using password "newpass" + But user "Alice" should not be able to create folder "anotherFolder" using password "%alt1%" \ No newline at end of file From 13b428ecae5717fbcdf8b7141db62a7846636274 Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Mon, 8 Jul 2024 17:35:23 +0545 Subject: [PATCH 12/14] refactor: remove stdins from the command logs --- tests/TestHelpers/CliHelper.php | 7 ++--- .../features/bootstrap/CliContext.php | 31 ++++++++++--------- .../features/bootstrap/FeatureContext.php | 1 - .../resetUserPassword.feature | 2 +- tests/ociswrapper/ocis/ocis.go | 3 ++ 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/tests/TestHelpers/CliHelper.php b/tests/TestHelpers/CliHelper.php index fee84ad332b..bf281b5c772 100644 --- a/tests/TestHelpers/CliHelper.php +++ b/tests/TestHelpers/CliHelper.php @@ -32,15 +32,14 @@ * A helper class for running oCIS CLI commands */ class CliHelper { - /** * @param array $body * * @return ResponseInterface * @throws GuzzleException */ - public static function runCommand(array $body): ResponseInterface { + public static function runCommand(array $body): ResponseInterface { $url = OcisConfigHelper::getWrapperUrl() . "/command"; return OcisConfigHelper::sendRequest($url, "POST", \json_encode($body)); - } -} \ No newline at end of file + } +} diff --git a/tests/acceptance/features/bootstrap/CliContext.php b/tests/acceptance/features/bootstrap/CliContext.php index 8a4f75bcf89..51a7c7e5af5 100644 --- a/tests/acceptance/features/bootstrap/CliContext.php +++ b/tests/acceptance/features/bootstrap/CliContext.php @@ -45,7 +45,7 @@ public function setUpScenario(BeforeScenarioScope $scope): void { $environment = $scope->getEnvironment(); // Get all the contexts you need in this context $this->featureContext = $environment->getContext('FeatureContext'); - } + } /** * @Given the administrator has stopped the server @@ -53,7 +53,7 @@ public function setUpScenario(BeforeScenarioScope $scope): void { * @return void */ public function theAdministratorHasStoppedTheServer(): void { - $response = OcisConfigHelper::stopOcis(); + $response = OcisConfigHelper::stopOcis(); $this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response); } @@ -63,7 +63,7 @@ public function theAdministratorHasStoppedTheServer(): void { * @return void */ public function theAdministratorHasStartedTheServer(): void { - $response = OcisConfigHelper::startOcis(); + $response = OcisConfigHelper::startOcis(); $this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response); } @@ -76,13 +76,13 @@ public function theAdministratorHasStartedTheServer(): void { * @return void */ public function theAdministratorResetsThePasswordOfUserUsingTheCLI(string $user, string $password): void { - $command = "idm resetpassword -u $user"; - $body = [ - "command" => $command, - "inputs" => [$password, $password] - ]; + $command = "idm resetpassword -u $user"; + $body = [ + "command" => $command, + "inputs" => [$password, $password] + ]; - $this->featureContext->setResponse(CliHelper::runCommand($body)); + $this->featureContext->setResponse(CliHelper::runCommand($body)); $this->featureContext->updateUserPassword($user, $password); } @@ -92,24 +92,25 @@ public function theAdministratorResetsThePasswordOfUserUsingTheCLI(string $user, * @return void */ public function theCommandShouldBeSuccessful(): void { - $response = $this->featureContext->getResponse(); + $response = $this->featureContext->getResponse(); $this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response); $jsonResponse = $this->featureContext->getJsonDecodedResponse($response); - Assert::assertSame("OK", $jsonResponse["status"]); - Assert::assertSame(0, $jsonResponse["exitCode"], "Expected exit code to be 0, but got " . $jsonResponse["exitCode"]); + Assert::assertSame("OK", $jsonResponse["status"]); + Assert::assertSame(0, $jsonResponse["exitCode"], "Expected exit code to be 0, but got " . $jsonResponse["exitCode"]); } /** * @Then /^the command output (should|should not) contain "([^"]*)"$/ * + * @param string $shouldOrNot * @param string $output * * @return void */ - public function theCommandOutputShouldContain(string $shouldOrNot,string $output): void { - $response = $this->featureContext->getResponse(); + public function theCommandOutputShouldContain(string $shouldOrNot, string $output): void { + $response = $this->featureContext->getResponse(); $jsonResponse = $this->featureContext->getJsonDecodedResponse($response); if ($shouldOrNot === "should") { @@ -118,4 +119,4 @@ public function theCommandOutputShouldContain(string $shouldOrNot,string $output Assert::assertStringNotContainsString($output, $jsonResponse["message"]); } } -} \ No newline at end of file +} diff --git a/tests/acceptance/features/bootstrap/FeatureContext.php b/tests/acceptance/features/bootstrap/FeatureContext.php index e2ea3a12c1b..c85700f2710 100644 --- a/tests/acceptance/features/bootstrap/FeatureContext.php +++ b/tests/acceptance/features/bootstrap/FeatureContext.php @@ -672,7 +672,6 @@ public function startOcisServer(): void { $this->theHTTPStatusCodeShouldBe([200, 409], 'Starting oCIS server', $response); } - /** * Get the externally-defined admin username, if any * diff --git a/tests/acceptance/features/cliResetPassword/resetUserPassword.feature b/tests/acceptance/features/cliResetPassword/resetUserPassword.feature index a0a314652f7..c5a015c9d9a 100644 --- a/tests/acceptance/features/cliResetPassword/resetUserPassword.feature +++ b/tests/acceptance/features/cliResetPassword/resetUserPassword.feature @@ -14,4 +14,4 @@ Feature: reset user password via CLI command But the command output should not contain "Failed to update user password: entry does not exist" And the administrator has started the server And user "Alice" should be able to create folder "newFolder" using password "newpass" - But user "Alice" should not be able to create folder "anotherFolder" using password "%alt1%" \ No newline at end of file + But user "Alice" should not be able to create folder "anotherFolder" using password "%alt1%" diff --git a/tests/ociswrapper/ocis/ocis.go b/tests/ociswrapper/ocis/ocis.go index ca8befa1da5..aa4a69dd997 100644 --- a/tests/ociswrapper/ocis/ocis.go +++ b/tests/ociswrapper/ocis/ocis.go @@ -266,5 +266,8 @@ func RunCommand(command string, inputs []string) (int, string) { io.Copy(logs, ptyF) cmdOutput += logs.String() + // TODO: find if there is a better way to remove stdins from the output + cmdOutput = strings.TrimLeft(cmdOutput, strings.Join(inputs, "\r\n")) + return c.ProcessState.ExitCode(), cmdOutput } From 9e6b6bc0f3c10039ef59a0f70768e151aab3a13d Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Mon, 8 Jul 2024 17:59:33 +0545 Subject: [PATCH 13/14] test: run cli test suites --- .drone.star | 8 +++++++- tests/acceptance/config/behat.yml | 4 ++-- .../resetUserPassword.feature | 0 3 files changed, 9 insertions(+), 3 deletions(-) rename tests/acceptance/features/{cliResetPassword => cliCommands}/resetUserPassword.feature (100%) diff --git a/.drone.star b/.drone.star index 9d0b21c6018..e2ac0e84940 100644 --- a/.drone.star +++ b/.drone.star @@ -151,6 +151,12 @@ config = { "OCM_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE": "%s" % dirs["ocmProviders"], }, }, + "cli": { + "suites": [ + "cliCommands", + ], + "skip": False, + }, }, "apiTests": { "numberOfParts": 10, @@ -859,7 +865,7 @@ def localApiTestPipeline(ctx): pipeline = { "kind": "pipeline", "type": "docker", - "name": "localApiTests-%s-%s" % (suite, storage), + "name": "%s-Tests-%s-%s" % ("CLI" if name.startswith("cli") else "API", suite, storage), "platform": { "os": "linux", "arch": "amd64", diff --git a/tests/acceptance/config/behat.yml b/tests/acceptance/config/behat.yml index b3a308d0b06..1644768d081 100644 --- a/tests/acceptance/config/behat.yml +++ b/tests/acceptance/config/behat.yml @@ -368,9 +368,9 @@ default: - SharingNgContext: - SpacesContext: - cliResetPassword: + cliCommands: paths: - - "%paths.base%/../features/cliResetPassword" + - "%paths.base%/../features/cliCommands" context: *common_ldap_suite_context contexts: - FeatureContext: *common_feature_context_params diff --git a/tests/acceptance/features/cliResetPassword/resetUserPassword.feature b/tests/acceptance/features/cliCommands/resetUserPassword.feature similarity index 100% rename from tests/acceptance/features/cliResetPassword/resetUserPassword.feature rename to tests/acceptance/features/cliCommands/resetUserPassword.feature From d8ab9c53a8a1c6ff5c5b0815c744da838c58b41a Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Tue, 9 Jul 2024 11:47:54 +0545 Subject: [PATCH 14/14] docs: add docs on new APIs --- tests/ociswrapper/README.md | 71 ++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/tests/ociswrapper/README.md b/tests/ociswrapper/README.md index cd57f2b7e67..6186e272678 100644 --- a/tests/ociswrapper/README.md +++ b/tests/ociswrapper/README.md @@ -17,10 +17,13 @@ When run, **ociswrapper** starts an API server that exposes some endpoints to re ```bash ./bin/ociswrapper serve --bin= ``` + To check other available options: + ```bash ./bin/ociswrapper serve --help ``` + ```bash --url string oCIS server url (default "https://localhost:9200") --retry string Number of retries to start oCIS server (default "5") @@ -51,9 +54,9 @@ Also, see `./bin/ociswrapper help` for more information. Returns: - * `200 OK` - oCIS is successfully reconfigured - * `400 Bad Request` - request body is not a valid JSON object - * `500 Internal Server Error` - oCIS server is not running + - `200 OK` - oCIS is successfully reconfigured + - `400 Bad Request` - request body is not a valid JSON object + - `500 Internal Server Error` - oCIS server is not running 2. `DELETE /rollback` @@ -61,5 +64,63 @@ Also, see `./bin/ociswrapper help` for more information. Returns: - * `200 OK` - rollback is successful - * `500 Internal Server Error` - oCIS server is not running + - `200 OK` - rollback is successful + - `500 Internal Server Error` - oCIS server is not running + +3. `POST /command` + + Executes the provided command on the oCIS server. The body of the request should be a JSON object with the following structure: + + ```yml + { + "command": "", # without the ocis binary. e.g. "list" + } + ``` + + If the command requires user input, the body of the request should be a JSON object with the following structure: + + ```json + { + "command": "", + "inputs": ["value1"] + } + ``` + + Returns: + + ```json + { + "status": "OK", + "exitCode": 0, + "message": "" + } + OR + { + "status": "ERROR", + "exitCode": , + "message": "" + } + ``` + + - `200 OK` - command is successfully executed + - `400 Bad Request` - request body is not a valid JSON object + - `500 Internal Server Error` + +4. `POST /start` + + Starts the oCIS server. + + Returns: + + - `200 OK` - oCIS server is started + - `409 Conflict` - oCIS server is already running + - `500 Internal Server Error` - Unable to start oCIS server + +5. `POST /stop` + + Stops the oCIS server. + + Returns: + + - `200 OK` - oCIS server is stopped + - `500 Internal Server Error` - Unable to stop oCIS server