github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/trust/key_generate_test.go (about)

     1  package trust
     2  
     3  import (
     4  	"encoding/pem"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"github.com/docker/cli/cli/config"
    12  	"github.com/docker/cli/internal/test"
    13  	"github.com/theupdateframework/notary"
    14  	"github.com/theupdateframework/notary/passphrase"
    15  	"github.com/theupdateframework/notary/trustmanager"
    16  	tufutils "github.com/theupdateframework/notary/tuf/utils"
    17  	"gotest.tools/v3/assert"
    18  	is "gotest.tools/v3/assert/cmp"
    19  )
    20  
    21  func TestTrustKeyGenerateErrors(t *testing.T) {
    22  	testCases := []struct {
    23  		name          string
    24  		args          []string
    25  		expectedError string
    26  	}{
    27  		{
    28  			name:          "not-enough-args",
    29  			expectedError: "requires exactly 1 argument",
    30  		},
    31  		{
    32  			name:          "too-many-args",
    33  			args:          []string{"key-1", "key-2"},
    34  			expectedError: "requires exactly 1 argument",
    35  		},
    36  	}
    37  
    38  	config.SetDir(t.TempDir())
    39  
    40  	for _, tc := range testCases {
    41  		cli := test.NewFakeCli(&fakeClient{})
    42  		cmd := newKeyGenerateCommand(cli)
    43  		cmd.SetArgs(tc.args)
    44  		cmd.SetOut(io.Discard)
    45  		assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
    46  	}
    47  }
    48  
    49  func TestGenerateKeySuccess(t *testing.T) {
    50  	pubKeyCWD := t.TempDir()
    51  	privKeyStorageDir := t.TempDir()
    52  
    53  	passwd := "password"
    54  	cannedPasswordRetriever := passphrase.ConstantRetriever(passwd)
    55  	// generate a single key
    56  	keyName := "alice"
    57  	privKeyFileStore, err := trustmanager.NewKeyFileStore(privKeyStorageDir, cannedPasswordRetriever)
    58  	assert.NilError(t, err)
    59  
    60  	pubKeyPEM, err := generateKeyAndOutputPubPEM(keyName, privKeyFileStore)
    61  	assert.NilError(t, err)
    62  
    63  	assert.Check(t, is.Equal(keyName, pubKeyPEM.Headers["role"]))
    64  	// the default GUN is empty
    65  	assert.Check(t, is.Equal("", pubKeyPEM.Headers["gun"]))
    66  	// assert public key header
    67  	assert.Check(t, is.Equal("PUBLIC KEY", pubKeyPEM.Type))
    68  
    69  	// check that an appropriate ~/<trust_dir>/private/<key_id>.key file exists
    70  	expectedPrivKeyDir := filepath.Join(privKeyStorageDir, notary.PrivDir)
    71  	_, err = os.Stat(expectedPrivKeyDir)
    72  	assert.NilError(t, err)
    73  
    74  	keyFiles, err := os.ReadDir(expectedPrivKeyDir)
    75  	assert.NilError(t, err)
    76  	assert.Check(t, is.Len(keyFiles, 1))
    77  	privKeyFilePath := filepath.Join(expectedPrivKeyDir, keyFiles[0].Name())
    78  
    79  	// verify the key content
    80  	privFrom, _ := os.OpenFile(privKeyFilePath, os.O_RDONLY, notary.PrivExecPerms)
    81  	defer privFrom.Close()
    82  	fromBytes, _ := io.ReadAll(privFrom)
    83  	privKeyPEM, _ := pem.Decode(fromBytes)
    84  	assert.Check(t, is.Equal(keyName, privKeyPEM.Headers["role"]))
    85  	// the default GUN is empty
    86  	assert.Check(t, is.Equal("", privKeyPEM.Headers["gun"]))
    87  	// assert encrypted header
    88  	assert.Check(t, is.Equal("ENCRYPTED PRIVATE KEY", privKeyPEM.Type))
    89  	// check that the passphrase matches
    90  	_, err = tufutils.ParsePKCS8ToTufKey(privKeyPEM.Bytes, []byte(passwd))
    91  	assert.NilError(t, err)
    92  
    93  	// check that the public key exists at the correct path if we use the helper:
    94  	returnedPath, err := writePubKeyPEMToDir(pubKeyPEM, keyName, pubKeyCWD)
    95  	assert.NilError(t, err)
    96  	expectedPubKeyPath := filepath.Join(pubKeyCWD, keyName+".pub")
    97  	assert.Check(t, is.Equal(returnedPath, expectedPubKeyPath))
    98  	_, err = os.Stat(expectedPubKeyPath)
    99  	assert.NilError(t, err)
   100  	// check that the public key is the only file output in CWD
   101  	cwdKeyFiles, err := os.ReadDir(pubKeyCWD)
   102  	assert.NilError(t, err)
   103  	assert.Check(t, is.Len(cwdKeyFiles, 1))
   104  }
   105  
   106  func TestValidateKeyArgs(t *testing.T) {
   107  	pubKeyCWD := t.TempDir()
   108  
   109  	err := validateKeyArgs("a", pubKeyCWD)
   110  	assert.NilError(t, err)
   111  
   112  	err = validateKeyArgs("a/b", pubKeyCWD)
   113  	assert.Error(t, err, "key name \"a/b\" must start with lowercase alphanumeric characters and can include \"-\" or \"_\" after the first character")
   114  
   115  	err = validateKeyArgs("-", pubKeyCWD)
   116  	assert.Error(t, err, "key name \"-\" must start with lowercase alphanumeric characters and can include \"-\" or \"_\" after the first character")
   117  
   118  	assert.NilError(t, os.WriteFile(filepath.Join(pubKeyCWD, "a.pub"), []byte("abc"), notary.PrivExecPerms))
   119  	err = validateKeyArgs("a", pubKeyCWD)
   120  	assert.Error(t, err, fmt.Sprintf("public key file already exists: \"%s\"", filepath.Join(pubKeyCWD, "a.pub")))
   121  
   122  	err = validateKeyArgs("a", "/random/dir/")
   123  	assert.Error(t, err, "public key path does not exist: \"/random/dir/\"")
   124  }