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  }