From 06b460ce76b9e83ef9a663f1abce1a785ac07219 Mon Sep 17 00:00:00 2001 From: davesavic Date: Tue, 2 Jan 2024 13:42:51 +1000 Subject: [PATCH] Added tests for remote and local --- Makefile | 5 + cmd/init.go | 2 +- cmd/run.go | 2 +- coverage.out | 38 ++++ go.mod | 4 +- go.sum | 8 +- {ploy => pkg/ploy}/ploy.go | 31 ++- pkg/ploy/ploy_test.go | 339 ++++++++++++++++++++++++++++++ pkg/ploy/testdata/id_rsa.test | 27 +++ pkg/ploy/testdata/id_rsa.test.pub | 1 + 10 files changed, 436 insertions(+), 21 deletions(-) create mode 100644 coverage.out rename {ploy => pkg/ploy}/ploy.go (88%) create mode 100644 pkg/ploy/ploy_test.go create mode 100644 pkg/ploy/testdata/id_rsa.test create mode 100644 pkg/ploy/testdata/id_rsa.test.pub diff --git a/Makefile b/Makefile index 4c7c227..73b7cfa 100644 --- a/Makefile +++ b/Makefile @@ -29,3 +29,8 @@ release: trap - ERR; .PHONY: release + +test: + go test ./... -cover -coverprofile=coverage.out + +.PHONY: test diff --git a/cmd/init.go b/cmd/init.go index d986d49..8cf29a3 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -5,7 +5,7 @@ package cmd import ( "encoding/json" - "github.com/davesavic/ploy/ploy" + "github.com/davesavic/ploy/pkg/ploy" "github.com/spf13/cobra" "log" "os" diff --git a/cmd/run.go b/cmd/run.go index b7079ed..fc248eb 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -6,7 +6,7 @@ package cmd import ( "encoding/json" "fmt" - "github.com/davesavic/ploy/ploy" + "github.com/davesavic/ploy/pkg/ploy" "github.com/spf13/cobra" "log" "os" diff --git a/coverage.out b/coverage.out new file mode 100644 index 0000000..a1de68f --- /dev/null +++ b/coverage.out @@ -0,0 +1,38 @@ +mode: set +github.com/davesavic/ploy/pkg/ploy/ploy.go:49.75,51.13 2 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:51.13,53.3 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:55.2,57.26 2 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:57.26,59.3 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:61.2,61.31 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:61.31,65.14 3 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:65.14,67.4 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:69.3,70.17 2 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:70.17,72.4 1 0 +github.com/davesavic/ploy/pkg/ploy/ploy.go:74.3,75.17 2 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:75.17,77.4 1 0 +github.com/davesavic/ploy/pkg/ploy/ploy.go:79.3,88.17 3 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:88.17,90.4 1 0 +github.com/davesavic/ploy/pkg/ploy/ploy.go:92.3,92.30 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:92.30,94.15 2 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:94.15,96.5 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:98.4,98.31 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:98.31,101.19 3 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:101.19,103.6 1 0 +github.com/davesavic/ploy/pkg/ploy/ploy.go:105.5,106.19 2 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:106.19,108.6 1 0 +github.com/davesavic/ploy/pkg/ploy/ploy.go:110.5,112.60 2 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:112.60,114.6 1 0 +github.com/davesavic/ploy/pkg/ploy/ploy.go:118.3,118.40 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:118.40,120.4 1 0 +github.com/davesavic/ploy/pkg/ploy/ploy.go:123.2,123.26 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:126.53,130.27 3 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:130.27,132.3 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:139.74,143.13 3 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:143.13,145.3 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:147.2,147.29 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:147.29,149.14 2 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:149.14,151.4 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:153.3,153.26 1 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:153.26,160.18 6 1 +github.com/davesavic/ploy/pkg/ploy/ploy.go:160.18,162.5 1 0 +github.com/davesavic/ploy/pkg/ploy/ploy.go:166.2,166.26 1 1 diff --git a/go.mod b/go.mod index 76526c5..8eedadc 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,14 @@ module github.com/davesavic/ploy go 1.21.4 require ( + github.com/gliderlabs/ssh v0.3.6 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 - golang.org/x/crypto v0.16.0 + golang.org/x/crypto v0.17.0 ) require ( + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index 56f8dad..8f94253 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -7,6 +9,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gliderlabs/ssh v0.3.6 h1:ZzjlDa05TcFRICb3anf/dSPN3ewz1Zx6CMLPWgkm3b8= +github.com/gliderlabs/ssh v0.3.6/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -59,8 +63,8 @@ go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= diff --git a/ploy/ploy.go b/pkg/ploy/ploy.go similarity index 88% rename from ploy/ploy.go rename to pkg/ploy/ploy.go index 41486f8..fb6593d 100644 --- a/ploy/ploy.go +++ b/pkg/ploy/ploy.go @@ -47,7 +47,10 @@ type RemotePipelineExecutor struct { } func (r *RemotePipelineExecutor) Execute(pipeline string) (string, error) { - pl := r.Config.Pipelines[pipeline] + pl, exists := r.Config.Pipelines[pipeline] + if !exists { + return "", fmt.Errorf("pipeline %s is not defined", pipeline) + } var out bytes.Buffer @@ -89,7 +92,7 @@ func (r *RemotePipelineExecutor) Execute(pipeline string) (string, error) { for _, t := range pl.Tasks { commands, exists := r.Config.Tasks[t] if !exists { - return "", fmt.Errorf("task %s does not exist", t) + return "", fmt.Errorf("task %s is not defined", t) } for _, c := range commands { @@ -136,10 +139,18 @@ type LocalPipelineExecutor struct { func (l *LocalPipelineExecutor) Execute(pipeline string) (string, error) { var out bytes.Buffer - pl := l.Config.Pipelines[pipeline] + pl, exists := l.Config.Pipelines[pipeline] + if !exists { + return "", fmt.Errorf("pipeline %s is not defined", pipeline) + } for _, t := range pl.Tasks { - for _, c := range l.Config.Tasks[t] { + task, exists := l.Config.Tasks[t] + if !exists { + return "", fmt.Errorf("task %s is not defined", t) + } + + for _, c := range task { populatePlaceholders(&c, l.Config.Params) cmd := exec.Command("sh", "-c", c) cmd.Stdout = &out @@ -158,15 +169,3 @@ func (l *LocalPipelineExecutor) Execute(pipeline string) (string, error) { type Ploy struct { Config Config } - -func NewPloy(cfg Config) *Ploy { - return &Ploy{Config: cfg} -} - -func (p *Ploy) RunRollbackTask(task string) error { - for _, c := range p.Config.Tasks[fmt.Sprintf("rollback-%s", task)] { - fmt.Println("ROLLBACK TASK: ", c) - } - - return nil -} diff --git a/pkg/ploy/ploy_test.go b/pkg/ploy/ploy_test.go new file mode 100644 index 0000000..4d2a184 --- /dev/null +++ b/pkg/ploy/ploy_test.go @@ -0,0 +1,339 @@ +package ploy_test + +import ( + "fmt" + "github.com/davesavic/ploy/pkg/ploy" + "github.com/gliderlabs/ssh" + "io" + "os" + "path/filepath" + "strings" + "testing" +) + +type SSHTestServer struct { + server *ssh.Server +} + +func NewSSHTestServer(address string) *SSHTestServer { + return &SSHTestServer{ + server: &ssh.Server{ + Addr: address, + PublicKeyHandler: func(ctx ssh.Context, key ssh.PublicKey) bool { + return true + }, + }, + } +} + +func (s *SSHTestServer) ListenAndServe() error { + return s.server.ListenAndServe() +} + +func (s *SSHTestServer) Close() error { + return s.server.Close() +} + +func (s *SSHTestServer) SetOutputString(output string) { + s.server.Handler = func(s ssh.Session) { + _, _ = io.WriteString(s, output) + _ = s.Exit(0) + } +} + +func TestRemotePipelineExecutor_Execute2(t *testing.T) { + testCases := []struct { + name string + prepareFunc func() (*SSHTestServer, ploy.Config) + pipeline string + expectedOutput string + expectedError string + }{ + { + name: "valid execution", + pipeline: "test", + expectedOutput: "Hello, World!", + prepareFunc: func() (*SSHTestServer, ploy.Config) { + s := NewSSHTestServer("localhost:2222") + s.SetOutputString("Hello, World!") + go func() { + _ = s.ListenAndServe() + }() + + cwd, _ := os.Getwd() + testDataPath := filepath.Join(cwd, "testdata") + + cfg := ploy.Config{ + Servers: ploy.Servers{ + "test": ploy.Server{ + Host: "localhost", + Port: 2222, + User: "test", + PrivateKey: fmt.Sprintf("%s/id_rsa.test", testDataPath), + }, + }, + Pipelines: ploy.Pipelines{ + "test": ploy.Pipeline{ + Servers: []string{"test"}, + Tasks: []string{"echo"}, + }, + }, + Tasks: map[string][]string{ + "echo": {"echo '{{message}}'"}, + }, + Params: map[string]string{ + "message": "Hello, World!", + }, + } + + return s, cfg + }, + }, + { + name: "invalid server", + pipeline: "test", + expectedError: "server test does not exist", + prepareFunc: func() (*SSHTestServer, ploy.Config) { + cfg := ploy.Config{ + Pipelines: ploy.Pipelines{ + "test": ploy.Pipeline{ + Servers: []string{"test"}, + Tasks: []string{"echo"}, + }, + }, + Tasks: map[string][]string{ + "echo": {"echo '{{message}}'"}, + }, + Params: map[string]string{ + "message": "Hello, World!", + }, + } + + return nil, cfg + }, + }, + { + name: "missing pipeline server", + pipeline: "test", + expectedError: "pipeline test has no servers", + prepareFunc: func() (*SSHTestServer, ploy.Config) { + cfg := ploy.Config{ + Servers: map[string]ploy.Server{ + "test": { + Host: "localhost", + Port: 2222, + PrivateKey: "id_rsa.test", + User: "test", + }, + }, + Pipelines: ploy.Pipelines{ + "test": ploy.Pipeline{ + Tasks: []string{"echo"}, + }, + }, + Tasks: map[string][]string{ + "echo": {"echo '{{message}}'"}, + }, + Params: map[string]string{ + "message": "Hello, World!", + }, + } + + return nil, cfg + }, + }, + { + name: "invalid pipeline", + pipeline: "invalid", + expectedError: "pipeline invalid is not defined", + prepareFunc: func() (*SSHTestServer, ploy.Config) { + cfg := ploy.Config{ + Servers: map[string]ploy.Server{ + "test": { + Host: "localhost", + Port: 2222, + PrivateKey: "id_rsa.test", + User: "test", + }, + }, + Pipelines: ploy.Pipelines{ + "test": ploy.Pipeline{ + Servers: []string{"test"}, + Tasks: []string{"echo"}, + }, + }, + Tasks: map[string][]string{ + "echo": {"echo '{{message}}'"}, + }, + Params: map[string]string{ + "message": "Hello, World!", + }, + } + + return nil, cfg + }, + }, + { + name: "invalid task", + pipeline: "test", + expectedError: "task invalid is not defined", + prepareFunc: func() (*SSHTestServer, ploy.Config) { + s := NewSSHTestServer("localhost:2222") + s.SetOutputString("Hello, World!") + go func() { + _ = s.ListenAndServe() + }() + + cwd, _ := os.Getwd() + testDataPath := filepath.Join(cwd, "testdata") + + cfg := ploy.Config{ + Servers: ploy.Servers{ + "test": ploy.Server{ + Host: "localhost", + Port: 2222, + User: "test", + PrivateKey: fmt.Sprintf("%s/id_rsa.test", testDataPath), + }, + }, + Pipelines: ploy.Pipelines{ + "test": ploy.Pipeline{ + Servers: []string{"test"}, + Tasks: []string{"invalid"}, + }, + }, + Tasks: map[string][]string{ + "echo": {"echo '{{message}}'"}, + }, + Params: map[string]string{ + "message": "Hello, World!", + }, + } + + return s, cfg + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + server, cfg := tc.prepareFunc() + if server != nil { + defer func() { + _ = server.Close() + }() + } + + re := ploy.RemotePipelineExecutor{Config: cfg} + out, err := re.Execute(tc.pipeline) + + if tc.expectedError != "" { + if err == nil || !strings.Contains(err.Error(), tc.expectedError) { + t.Errorf("expected error to contain '%s', got '%s'", tc.expectedError, err.Error()) + } + + return + } + + if err != nil { + t.Errorf("error executing pipeline: %v", err) + } + + if !strings.Contains(out, tc.expectedOutput) { + t.Errorf("expected output to contain '%s', got '%s'", tc.expectedOutput, out) + } + }) + } +} + +func TestLocalPipelineExecutor_Execute(t *testing.T) { + testCases := []struct { + name string + prepareFunc func() ploy.Config + pipeline string + expectedOutput string + expectedError string + }{ + { + name: "valid execution", + pipeline: "test", + expectedOutput: "Hello, World!", + prepareFunc: func() ploy.Config { + cfg := ploy.Config{ + Pipelines: ploy.Pipelines{ + "test": ploy.Pipeline{ + Tasks: []string{"echo"}, + }, + }, + Tasks: map[string][]string{ + "echo": {fmt.Sprintf("echo '%s'", "Hello, World!")}, + }, + } + + return cfg + }, + }, + { + name: "invalid pipeline", + pipeline: "invalid", + expectedError: "pipeline invalid is not defined", + prepareFunc: func() ploy.Config { + cfg := ploy.Config{ + Pipelines: ploy.Pipelines{ + "test": ploy.Pipeline{ + Tasks: []string{"echo"}, + }, + }, + Tasks: map[string][]string{ + "echo": {fmt.Sprintf("echo '%s'", "Hello, World!")}, + }, + } + + return cfg + }, + }, + { + name: "invalid task", + pipeline: "test", + expectedError: "task invalid is not defined", + prepareFunc: func() ploy.Config { + cfg := ploy.Config{ + Pipelines: ploy.Pipelines{ + "test": ploy.Pipeline{ + Tasks: []string{"invalid"}, + }, + }, + Tasks: map[string][]string{ + "echo": {fmt.Sprintf("echo '%s'", "Hello, World!")}, + }, + } + + return cfg + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cfg := tc.prepareFunc() + le := ploy.LocalPipelineExecutor{Config: cfg} + out, err := le.Execute(tc.pipeline) + + if tc.expectedError != "" { + if err == nil || !strings.Contains(err.Error(), tc.expectedError) { + t.Errorf("expected error to contain '%s', got '%s'", tc.expectedError, err.Error()) + } + + return + } + + if err != nil { + t.Errorf("error executing pipeline: %v", err) + } + + if !strings.Contains(out, tc.expectedOutput) { + t.Errorf("expected output to contain '%s', got '%s'", tc.expectedOutput, out) + } + }) + } +} diff --git a/pkg/ploy/testdata/id_rsa.test b/pkg/ploy/testdata/id_rsa.test new file mode 100644 index 0000000..915656d --- /dev/null +++ b/pkg/ploy/testdata/id_rsa.test @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAv+dmdEuG/Gy/FdRUyoUJJz4/hgbYEu3+I2O/FJx+9cUhVaW9 +BOyu+UCcDR0VTEY5GDffrYAsRqm5Xqk/JHRzc9vcdAOTwGBsnWsLmNspW7gA9KBj +8q0wsWD7WOKbb4yGUFlqeM/eLfblOC5pwfWQuCkJY1ttlDdkZIVJqX59U1RJevJi +CTRNsoZCPW4Fc0F41NDRveSln+o3L3CLph0wGIU/BU7wVGDybxUVLWdMnZv1kmEC +cWOOczWWEtI62lHfGFPf2bBEZOa/kjo5IWqmwRu759DoX2vYhELTnWiLDXpgJcac +O3bqv4gj64eRZParVJ2CwI3xUcGWfcWXJgBAXQIDAQABAoIBAClKS7QYEBo997tl +rTzJ9Rc5gIeA73rbNEQ/EP0JUxPkb3CzMYFev6MnsKvtpwh7T4uTchAttNkbaaQh +fFGGsNSr6LoZju/kj1orjxo7haGTbLk1zWuIsiJoQIx2bYVJ0hh1tL/70c1IAzfc +XKr8AEBvq/Jx2Jj8diBewWOzsJl9+NPuvGd+2p7Bx0OtifVs33nrjHW3kg/9LytT +5Y9y4E9Xn96vNTka2dJUSnrUKWlNdeCfhyTWFHiEcyFCVXnDa4Ml68gN6o2ogNPJ +thD9bPpy4KQXdJphX3OlIxesZP2TAN7zkxxzhUAFW3P0+v7I0u8lS6czlKvkol0c +0UHPYG0CgYEA3bpmz4JCXpU2jGoOfao2BtYEccIUmxzK1IX/foQ3pBOqwRrop4LA +xXxLoLOaTWuhYH8NUTAbajuG/Ri3fPydnHJ0rYAYLmIwo9ll1VbzBKKDRUW9gQuG +fb5UEVWDROJzf1EMFQkbJ8u8vEgZXnXad0m/L+zEBfE7N6gSxJ8JluMCgYEA3ZDg +91YRW5icczCCs+bpjVu2vujzB30Eo/3S2ljqb1lBjW6sb6DFGolFAF/BVk+3+CT3 +Sfv2gx6hQp7CcRskRSSaLHM76+Y5vU/iriPVjF9WhhVWp4H5HCg62aZBTnvHffFj +Cg48uOvLodrd/yk1aDzmFEsY8wedlfBh+PxXL78CgYEAz7b254C80kRwpJwaVSkm +kcLeyP8rNKCFdxDM5+XPBjuSZHLj70EzfA5T/wkiDVM+C9saS6uIkz2O2P3VrxYs +RMqIeZ0dih5cOLLJjlF1OitQVI3f2MtGQ/gQY2i7n8WQs33mlrJAKUjY132nnnFD +pyqEG85vWK3DbwFaC659WkcCgYA5aLGxxJ5Iwnk/K4GiRaGcW/g07T0TYqRSLZF1 +u/Y6lcDzeYq6fci0gH7dgvIggBVl+YYNqHiOLuCP130AO40hUUOVYuJS1Ft/nvRY +NLa/YXCU23CRhI7cadwdywM+57mf+2yzDU9UhtxDeudsluvcr3LaLT8wsXd2g0uP +bSrWFwKBgCBGLpMFdjZvh2J0LFv6M4g0NXhwhgOHL0Nvj5JWUE8vJwrDLQIyRzik ++410rAMbG52mxEGRsDXcUd86vtqWZbFCutwuQ91j4/sUQikAcgz+qd1JVEHdoCxq +SEo2wEXBRdkTaIULcC2QrjHyFx2fI6a2kXdfG7hA4qiFhf0hRmhK +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/pkg/ploy/testdata/id_rsa.test.pub b/pkg/ploy/testdata/id_rsa.test.pub new file mode 100644 index 0000000..c25a6a0 --- /dev/null +++ b/pkg/ploy/testdata/id_rsa.test.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/52Z0S4b8bL8V1FTKhQknPj+GBtgS7f4jY78UnH71xSFVpb0E7K75QJwNHRVMRjkYN9+tgCxGqbleqT8kdHNz29x0A5PAYGydawuY2ylbuAD0oGPyrTCxYPtY4ptvjIZQWWp4z94t9uU4LmnB9ZC4KQljW22UN2RkhUmpfn1TVEl68mIJNE2yhkI9bgVzQXjU0NG95KWf6jcvcIumHTAYhT8FTvBUYPJvFRUtZ0ydm/WSYQJxY45zNZYS0jraUd8YU9/ZsERk5r+SOjkhaqbBG7vn0Ohfa9iEQtOdaIsNemAlxpw7duq/iCPrh5Fk9qtUnYLAjfFRwZZ9xZcmAEBd \ No newline at end of file