github.com/drycc/workflow-cli@v1.5.3-0.20240322092846-d4ee25983af9/cmd/keys_test.go (about) 1 package cmd 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "net/http" 8 "os" 9 "path/filepath" 10 "strings" 11 "testing" 12 13 "github.com/drycc/controller-sdk-go/api" 14 "github.com/drycc/workflow-cli/pkg/testutil" 15 "github.com/drycc/workflow-cli/settings" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 func TestGetKey(t *testing.T) { 20 t.Parallel() 21 22 file, err := os.CreateTemp("", "drycc-key") 23 assert.NoError(t, err) 24 25 toWrite := []byte("ssh-rsa abc test@example.com") 26 27 expected := api.KeyCreateRequest{ 28 ID: "test@example.com", 29 Public: string(toWrite), 30 Name: file.Name(), 31 } 32 33 _, err = file.Write(toWrite) 34 assert.NoError(t, err) 35 file.Close() 36 37 key, err := getKey(file.Name()) 38 assert.NoError(t, err) 39 assert.Equal(t, key, expected, "key") 40 41 _, err = getKey("notarealkey") 42 assert.NotEqual(t, err, nil, "file error") 43 } 44 45 func TestGetKeyNoComment(t *testing.T) { 46 t.Parallel() 47 48 file, err := os.CreateTemp("", "drycc-key") 49 assert.NoError(t, err) 50 51 toWrite := []byte("ssh-rsa abc") 52 53 expected := api.KeyCreateRequest{ 54 ID: filepath.Base(file.Name()), 55 Public: string(toWrite), 56 Name: file.Name(), 57 } 58 59 _, err = file.Write(toWrite) 60 assert.NoError(t, err) 61 62 key, err := getKey(file.Name()) 63 assert.NoError(t, err) 64 65 assert.Equal(t, key, expected, "key") 66 } 67 68 func TestGetInvalidKey(t *testing.T) { 69 t.Parallel() 70 71 file, err := os.CreateTemp("", "drycc-key") 72 assert.NoError(t, err) 73 74 toWrite := []byte("not a key") 75 _, err = file.Write(toWrite) 76 assert.NoError(t, err) 77 78 expected := fmt.Sprintf("%s is not a valid ssh key", file.Name()) 79 80 _, err = getKey(file.Name()) 81 assert.Equal(t, err.Error(), expected, "error") 82 } 83 84 func TestListKeys(t *testing.T) { 85 name, err := os.MkdirTemp("", "drycc-key") 86 assert.NoError(t, err) 87 settings.SetHome(name) 88 89 folder := filepath.Join(name, ".ssh") 90 91 err = os.Mkdir(folder, 0755) 92 assert.NoError(t, err) 93 94 toWrite := []byte("ssh-rsa abc test@example.com") 95 fileNames := []string{"test1.pub", "test2.pub"} 96 97 expected := []api.KeyCreateRequest{ 98 { 99 ID: "test@example.com", 100 Public: string(toWrite), 101 Name: filepath.Join(folder, fileNames[0]), 102 }, 103 { 104 ID: "test@example.com", 105 Public: string(toWrite), 106 Name: filepath.Join(folder, fileNames[1]), 107 }, 108 } 109 110 for _, file := range fileNames { 111 os.WriteFile(filepath.Join(folder, file), toWrite, 0775) 112 assert.NoError(t, err) 113 } 114 115 keys, err := listKeys(io.Discard) 116 assert.NoError(t, err) 117 118 assert.Equal(t, keys, expected, "key") 119 120 var b bytes.Buffer 121 // Write bad ssh key 122 filename := filepath.Join(folder, "test3.pub") 123 os.WriteFile(filename, []byte("ssh-rsa"), 0775) 124 _, err = listKeys(&b) 125 assert.Equal(t, b.String(), filename+" is not a valid ssh key\n", "output") 126 assert.NoError(t, err) 127 128 } 129 130 type chooseKeyCases struct { 131 Reader io.Reader 132 Err bool 133 ExpectedErr string 134 ExpectedKey *api.KeyCreateRequest 135 LoadKey bool 136 } 137 138 func TestChooseKey(t *testing.T) { 139 t.Parallel() 140 141 file, err := os.CreateTemp("", "drycc-key") 142 assert.NoError(t, err) 143 toWrite := []byte("ssh-rsa abc test@example.com") 144 _, err = file.Write(toWrite) 145 assert.NoError(t, err) 146 file.Close() 147 148 testKeys := []api.KeyCreateRequest{ 149 { 150 ID: "test@example.com", 151 Public: "ssh-rsa 123 abc@example.com", 152 Name: ".ssh/public/id_rsa.pub", 153 }, 154 { 155 ID: "example@example.com", 156 Public: "ssh-rsa abc123 example@example.com", 157 Name: ".ssh/public/id_rsa.pub", 158 }, 159 } 160 161 expectedWrittenKey := api.KeyCreateRequest{ 162 ID: "test@example.com", 163 Public: string(toWrite), 164 Name: file.Name(), 165 } 166 167 checks := []chooseKeyCases{ 168 {strings.NewReader("-1"), true, "-1 is not a valid option", nil, false}, 169 {strings.NewReader("3"), true, "3 is not a valid option", nil, false}, 170 {strings.NewReader("a"), true, "a is not a valid integer", nil, false}, 171 {strings.NewReader("1"), false, "", &testKeys[0], false}, 172 {strings.NewReader("0\n" + file.Name()), false, "", &expectedWrittenKey, true}, 173 } 174 175 var b bytes.Buffer 176 for _, check := range checks { 177 b.Reset() 178 key, err := chooseKey(testKeys, check.Reader, &b) 179 expectedOut := `Found the following SSH public keys: 180 1) id_rsa.pub test@example.com 181 2) id_rsa.pub example@example.com 182 0) Enter path to pubfile (or use keys:add <key_path>) 183 Which would you like to use with Drycc? ` 184 185 if check.LoadKey { 186 expectedOut += "Enter the path to the pubkey file: " 187 } 188 assert.Equal(t, b.String(), expectedOut, "output") 189 190 if check.Err { 191 assert.Equal(t, err.Error(), check.ExpectedErr, "error") 192 } else { 193 assert.Equal(t, key, *check.ExpectedKey, "key") 194 } 195 } 196 } 197 198 func TestKeysList(t *testing.T) { 199 t.Parallel() 200 cf, server, err := testutil.NewTestServerAndClient() 201 if err != nil { 202 t.Fatal(err) 203 } 204 defer server.Close() 205 var b bytes.Buffer 206 cmdr := DryccCmd{WOut: &b, ConfigFile: cf} 207 208 server.Mux.HandleFunc("/v2/keys/", func(w http.ResponseWriter, _ *http.Request) { 209 testutil.SetHeaders(w) 210 fmt.Fprintf(w, `{ 211 "count": 2, 212 "next": null, 213 "previous": null, 214 "results": [ 215 { 216 "created": "2014-01-01T00:00:00UTC", 217 "id": "cpike@starfleet.ufp", 218 "owner": "cpike", 219 "public": "ssh-rsa abc cpike@starfleet.ufp", 220 "updated": "2014-01-01T00:00:00UTC", 221 "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75" 222 }, 223 { 224 "created": "2014-01-01T00:00:00UTC", 225 "id": "cpike@1701.ncc.starfleet.ufp", 226 "owner": "cpike", 227 "public": "ssh-rsa 123 cpike@1701.ncc.starfleet.ufp", 228 "updated": "2014-01-01T00:00:00UTC", 229 "uuid": "le19f5b5-4a72-4f94-a10c-d2a374jcd075" 230 } 231 ] 232 }`) 233 }) 234 235 err = cmdr.KeysList(-1) 236 assert.NoError(t, err) 237 assert.Equal(t, b.String(), `ID OWNER KEY 238 cpike@starfleet.ufp cpike ssh-rsa abc cpik...rfleet.ufp 239 cpike@1701.ncc.starfleet.ufp cpike ssh-rsa 123 cpik...rfleet.ufp 240 `, "output") 241 } 242 243 func TestKeysListLimit(t *testing.T) { 244 t.Parallel() 245 cf, server, err := testutil.NewTestServerAndClient() 246 if err != nil { 247 t.Fatal(err) 248 } 249 defer server.Close() 250 var b bytes.Buffer 251 cmdr := DryccCmd{WOut: &b, ConfigFile: cf} 252 253 server.Mux.HandleFunc("/v2/keys/", func(w http.ResponseWriter, _ *http.Request) { 254 testutil.SetHeaders(w) 255 fmt.Fprintf(w, `{ 256 "count": 2, 257 "next": null, 258 "previous": null, 259 "results": [ 260 { 261 "created": "2014-01-01T00:00:00UTC", 262 "id": "cpike@starfleet.ufp", 263 "owner": "cpike", 264 "public": "ssh-rsa abc cpike@starfleet.ufp", 265 "updated": "2014-01-01T00:00:00UTC", 266 "uuid": "de1bf5b5-4a72-4f94-a10c-d2a3741cdf75" 267 } 268 ] 269 }`) 270 }) 271 272 err = cmdr.KeysList(1) 273 assert.NoError(t, err) 274 assert.Equal(t, b.String(), `ID OWNER KEY 275 cpike@starfleet.ufp cpike ssh-rsa abc cpik...rfleet.ufp 276 `, "output") 277 } 278 279 func TestKeyRemove(t *testing.T) { 280 t.Parallel() 281 cf, server, err := testutil.NewTestServerAndClient() 282 if err != nil { 283 t.Fatal(err) 284 } 285 defer server.Close() 286 var b bytes.Buffer 287 cmdr := DryccCmd{WOut: &b, ConfigFile: cf} 288 289 server.Mux.HandleFunc("/v2/keys/cpike@starfleet.ufp", func(w http.ResponseWriter, _ *http.Request) { 290 testutil.SetHeaders(w) 291 w.WriteHeader(http.StatusNoContent) 292 }) 293 294 err = cmdr.KeyRemove("cpike@starfleet.ufp") 295 assert.NoError(t, err) 296 assert.Equal(t, testutil.StripProgress(b.String()), "Removing cpike@starfleet.ufp SSH Key... done\n", "output") 297 } 298 299 func TestKeyAdd(t *testing.T) { 300 // Set temp home dir so no unknown files are listed. 301 name, err := os.MkdirTemp("", "drycc-key") 302 assert.NoError(t, err) 303 settings.SetHome(name) 304 folder := filepath.Join(name, ".ssh") 305 err = os.Mkdir(folder, 0755) 306 assert.NoError(t, err) 307 308 cf, server, err := testutil.NewTestServerAndClient() 309 if err != nil { 310 t.Fatal(err) 311 } 312 defer server.Close() 313 var b bytes.Buffer 314 cmdr := DryccCmd{WOut: &b, ConfigFile: cf} 315 316 keyFile, err := os.CreateTemp("", "drycc-cli-unit-test-ssh-key") 317 assert.NoError(t, err) 318 toWrite := []byte("ssh-rsa abc test@example.com") 319 _, err = keyFile.Write(toWrite) 320 assert.NoError(t, err) 321 keyFile.Close() 322 323 server.Mux.HandleFunc("/v2/keys/", func(w http.ResponseWriter, r *http.Request) { 324 testutil.SetHeaders(w) 325 testutil.AssertBody(t, api.KeyCreateRequest{ID: "test@example.com", Public: string(toWrite)}, r) 326 w.WriteHeader(http.StatusCreated) 327 fmt.Fprintf(w, "{}") 328 }) 329 330 out := fmt.Sprintf("Uploading %s to drycc... done\n", filepath.Base(keyFile.Name())) 331 332 err = cmdr.KeyAdd("", keyFile.Name()) 333 assert.NoError(t, err) 334 assert.Equal(t, testutil.StripProgress(b.String()), out, "output") 335 336 b.Reset() 337 cmdr.WIn = strings.NewReader("0\n" + keyFile.Name()) 338 err = cmdr.KeyAdd("", "") 339 assert.NoError(t, err) 340 assert.Equal(t, testutil.StripProgress(b.String()), `Found the following SSH public keys: 341 0) Enter path to pubfile (or use keys:add <key_path>) 342 Which would you like to use with Drycc? Enter the path to the pubkey file: `+out, "output") 343 } 344 345 func TestKeyAddName(t *testing.T) { 346 // Set temp home dir so no unknown files are listed. 347 name, err := os.MkdirTemp("", "drycc-key") 348 assert.NoError(t, err) 349 settings.SetHome(name) 350 folder := filepath.Join(name, ".ssh") 351 err = os.Mkdir(folder, 0755) 352 assert.NoError(t, err) 353 354 cf, server, err := testutil.NewTestServerAndClient() 355 if err != nil { 356 t.Fatal(err) 357 } 358 defer server.Close() 359 var b bytes.Buffer 360 cmdr := DryccCmd{WOut: &b, ConfigFile: cf} 361 362 keyFile, err := os.CreateTemp("", "drycc-cli-unit-test-ssh-key") 363 assert.NoError(t, err) 364 // generate with one name but used another in the add 365 toWrite := []byte("ssh-rsa abc test@example.com") 366 _, err = keyFile.Write(toWrite) 367 assert.NoError(t, err) 368 keyFile.Close() 369 370 server.Mux.HandleFunc("/v2/keys/", func(w http.ResponseWriter, r *http.Request) { 371 testutil.SetHeaders(w) 372 testutil.AssertBody(t, api.KeyCreateRequest{ID: "drycc-test-key", Public: string(toWrite)}, r) 373 w.WriteHeader(http.StatusCreated) 374 fmt.Fprintf(w, "{}") 375 }) 376 377 out := fmt.Sprintf("Uploading %s to drycc... done\n", filepath.Base(keyFile.Name())) 378 379 err = cmdr.KeyAdd("drycc-test-key", keyFile.Name()) 380 assert.NoError(t, err) 381 assert.Equal(t, testutil.StripProgress(b.String()), out, "output") 382 }