mirror of https://github.com/docker/docs.git
255 lines
8.6 KiB
Go
255 lines
8.6 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/docker/notary/client"
|
|
"github.com/docker/notary/passphrase"
|
|
"github.com/docker/notary/trustmanager"
|
|
"github.com/docker/notary/tuf/data"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// --- tests for pretty printing keys ---
|
|
|
|
func TestTruncateWithEllipsis(t *testing.T) {
|
|
digits := "1234567890"
|
|
// do not truncate
|
|
require.Equal(t, truncateWithEllipsis(digits, 10, true), digits)
|
|
require.Equal(t, truncateWithEllipsis(digits, 10, false), digits)
|
|
require.Equal(t, truncateWithEllipsis(digits, 11, true), digits)
|
|
require.Equal(t, truncateWithEllipsis(digits, 11, false), digits)
|
|
|
|
// left and right truncate
|
|
require.Equal(t, truncateWithEllipsis(digits, 8, true), "...67890")
|
|
require.Equal(t, truncateWithEllipsis(digits, 8, false), "12345...")
|
|
}
|
|
|
|
func TestKeyInfoSorter(t *testing.T) {
|
|
expected := []keyInfo{
|
|
{role: data.CanonicalRootRole, gun: "", keyID: "a", location: "i"},
|
|
{role: data.CanonicalRootRole, gun: "", keyID: "a", location: "j"},
|
|
{role: data.CanonicalRootRole, gun: "", keyID: "z", location: "z"},
|
|
{role: "a", gun: "a", keyID: "a", location: "y"},
|
|
{role: "b", gun: "a", keyID: "a", location: "y"},
|
|
{role: "b", gun: "a", keyID: "b", location: "y"},
|
|
{role: "b", gun: "a", keyID: "b", location: "z"},
|
|
{role: "a", gun: "b", keyID: "a", location: "z"},
|
|
}
|
|
jumbled := make([]keyInfo, len(expected))
|
|
// randomish indices
|
|
for j, e := range []int{3, 6, 1, 4, 0, 7, 5, 2} {
|
|
jumbled[j] = expected[e]
|
|
}
|
|
|
|
sort.Sort(keyInfoSorter(jumbled))
|
|
require.True(t, reflect.DeepEqual(expected, jumbled),
|
|
fmt.Sprintf("Expected %v, Got %v", expected, jumbled))
|
|
}
|
|
|
|
type otherMemoryStore struct {
|
|
trustmanager.KeyMemoryStore
|
|
}
|
|
|
|
func (l *otherMemoryStore) Name() string {
|
|
return strings.Repeat("z", 70)
|
|
}
|
|
|
|
// If there are no keys in any of the key stores, a message that there are no
|
|
// signing keys should be displayed.
|
|
func TestPrettyPrintZeroKeys(t *testing.T) {
|
|
ret := passphrase.ConstantRetriever("pass")
|
|
emptyKeyStore := trustmanager.NewKeyMemoryStore(ret)
|
|
|
|
var b bytes.Buffer
|
|
prettyPrintKeys([]trustmanager.KeyStore{emptyKeyStore}, &b)
|
|
text, err := ioutil.ReadAll(&b)
|
|
require.NoError(t, err)
|
|
|
|
lines := strings.Split(strings.TrimSpace(string(text)), "\n")
|
|
require.Len(t, lines, 1)
|
|
require.Equal(t, "No signing keys found.", lines[0])
|
|
}
|
|
|
|
// Given a list of key stores, the keys should be pretty-printed with their
|
|
// roles, locations, IDs, and guns first in sorted order in the key store
|
|
func TestPrettyPrintRootAndSigningKeys(t *testing.T) {
|
|
ret := passphrase.ConstantRetriever("pass")
|
|
keyStores := []trustmanager.KeyStore{
|
|
trustmanager.NewKeyMemoryStore(ret),
|
|
&otherMemoryStore{KeyMemoryStore: *trustmanager.NewKeyMemoryStore(ret)},
|
|
}
|
|
|
|
longNameShortened := "..." + strings.Repeat("z", 37)
|
|
|
|
keys := make([]data.PrivateKey, 4)
|
|
for i := 0; i < 4; i++ {
|
|
key, err := trustmanager.GenerateED25519Key(rand.Reader)
|
|
require.NoError(t, err)
|
|
keys[i] = key
|
|
}
|
|
|
|
root := data.CanonicalRootRole
|
|
|
|
// add keys to the key stores
|
|
require.NoError(t, keyStores[0].AddKey(trustmanager.KeyInfo{Role: root, Gun: ""}, keys[0]))
|
|
require.NoError(t, keyStores[1].AddKey(trustmanager.KeyInfo{Role: root, Gun: ""}, keys[0]))
|
|
require.NoError(t, keyStores[0].AddKey(trustmanager.KeyInfo{Role: data.CanonicalTargetsRole, Gun: strings.Repeat("/a", 30)}, keys[1]))
|
|
require.NoError(t, keyStores[1].AddKey(trustmanager.KeyInfo{Role: data.CanonicalSnapshotRole, Gun: "short/gun"}, keys[1]))
|
|
require.NoError(t, keyStores[0].AddKey(trustmanager.KeyInfo{Role: "targets/a", Gun: ""}, keys[3]))
|
|
require.NoError(t, keyStores[0].AddKey(trustmanager.KeyInfo{Role: "invalidRole", Gun: ""}, keys[2]))
|
|
|
|
expected := [][]string{
|
|
// root always comes first
|
|
{root, keys[0].ID(), keyStores[0].Name()},
|
|
{root, keys[0].ID(), longNameShortened},
|
|
// these have no gun, so they come first
|
|
{"invalidRole", keys[2].ID(), keyStores[0].Name()},
|
|
{"targets/a", keys[3].ID(), keyStores[0].Name()},
|
|
// these have guns, and are sorted then by guns
|
|
{data.CanonicalTargetsRole, "..." + strings.Repeat("/a", 11), keys[1].ID(), keyStores[0].Name()},
|
|
{data.CanonicalSnapshotRole, "short/gun", keys[1].ID(), longNameShortened},
|
|
}
|
|
|
|
var b bytes.Buffer
|
|
prettyPrintKeys(keyStores, &b)
|
|
text, err := ioutil.ReadAll(&b)
|
|
require.NoError(t, err)
|
|
|
|
lines := strings.Split(strings.TrimSpace(string(text)), "\n")
|
|
require.Len(t, lines, len(expected)+2)
|
|
|
|
// starts with headers
|
|
require.True(t, reflect.DeepEqual(strings.Fields(lines[0]),
|
|
[]string{"ROLE", "GUN", "KEY", "ID", "LOCATION"}))
|
|
require.Equal(t, "----", lines[1][:4])
|
|
|
|
for i, line := range lines[2:] {
|
|
// we are purposely not putting spaces in test data so easier to split
|
|
splitted := strings.Fields(line)
|
|
for j, v := range splitted {
|
|
require.Equal(t, expected[i][j], strings.TrimSpace(v))
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- tests for pretty printing targets ---
|
|
|
|
// If there are no targets, no table is printed, only a line saying that there
|
|
// are no targets.
|
|
func TestPrettyPrintZeroTargets(t *testing.T) {
|
|
var b bytes.Buffer
|
|
prettyPrintTargets([]*client.TargetWithRole{}, &b)
|
|
text, err := ioutil.ReadAll(&b)
|
|
require.NoError(t, err)
|
|
|
|
lines := strings.Split(strings.TrimSpace(string(text)), "\n")
|
|
require.Len(t, lines, 1)
|
|
require.Equal(t, "No targets present in this repository.", lines[0])
|
|
|
|
}
|
|
|
|
// Targets are sorted by name, and the name, SHA256 digest, size, and role are
|
|
// printed.
|
|
func TestPrettyPrintSortedTargets(t *testing.T) {
|
|
hashes := make([][]byte, 3)
|
|
var err error
|
|
for i, letter := range []string{"a012", "b012", "c012"} {
|
|
hashes[i], err = hex.DecodeString(letter)
|
|
require.NoError(t, err)
|
|
}
|
|
unsorted := []*client.TargetWithRole{
|
|
{Target: client.Target{Name: "zebra", Hashes: data.Hashes{"sha256": hashes[0]}, Length: 8}, Role: "targets/b"},
|
|
{Target: client.Target{Name: "aardvark", Hashes: data.Hashes{"sha256": hashes[1]}, Length: 1},
|
|
Role: "targets"},
|
|
{Target: client.Target{Name: "bee", Hashes: data.Hashes{"sha256": hashes[2]}, Length: 5}, Role: "targets/a"},
|
|
}
|
|
|
|
var b bytes.Buffer
|
|
prettyPrintTargets(unsorted, &b)
|
|
text, err := ioutil.ReadAll(&b)
|
|
require.NoError(t, err)
|
|
|
|
expected := [][]string{
|
|
{"aardvark", "b012", "1", "targets"},
|
|
{"bee", "c012", "5", "targets/a"},
|
|
{"zebra", "a012", "8", "targets/b"},
|
|
}
|
|
|
|
lines := strings.Split(strings.TrimSpace(string(text)), "\n")
|
|
require.Len(t, lines, len(expected)+2)
|
|
|
|
// starts with headers
|
|
require.True(t, reflect.DeepEqual(strings.Fields(lines[0]), strings.Fields(
|
|
"NAME DIGEST SIZE (BYTES) ROLE")))
|
|
require.Equal(t, "----", lines[1][:4])
|
|
|
|
for i, line := range lines[2:] {
|
|
splitted := strings.Fields(line)
|
|
require.Equal(t, expected[i], splitted)
|
|
}
|
|
}
|
|
|
|
// --- tests for pretty printing roles ---
|
|
|
|
// If there are no roles, no table is printed, only a line saying that there
|
|
// are no roles.
|
|
func TestPrettyPrintZeroRoles(t *testing.T) {
|
|
var b bytes.Buffer
|
|
prettyPrintRoles([]*data.Role{}, &b, "delegations")
|
|
text, err := ioutil.ReadAll(&b)
|
|
require.NoError(t, err)
|
|
|
|
lines := strings.Split(strings.TrimSpace(string(text)), "\n")
|
|
require.Len(t, lines, 1)
|
|
require.Equal(t, "No delegations present in this repository.", lines[0])
|
|
}
|
|
|
|
// Roles are sorted by name, and the name, paths, and KeyIDs are printed.
|
|
func TestPrettyPrintSortedRoles(t *testing.T) {
|
|
var err error
|
|
|
|
unsorted := []*data.Role{
|
|
{Name: "targets/zebra", Paths: []string{"stripes", "black", "white"}, RootRole: data.RootRole{KeyIDs: []string{"101"}, Threshold: 1}},
|
|
{Name: "targets/aardvark/unicorn/pony", Paths: []string{"rainbows"}, RootRole: data.RootRole{KeyIDs: []string{"135"}, Threshold: 1}},
|
|
{Name: "targets/bee", Paths: []string{"honey"}, RootRole: data.RootRole{KeyIDs: []string{"246"}, Threshold: 1}},
|
|
{Name: "targets/bee/wasp", Paths: []string{"honey/sting", "stuff"}, RootRole: data.RootRole{KeyIDs: []string{"246", "468"}, Threshold: 1}},
|
|
}
|
|
|
|
var b bytes.Buffer
|
|
prettyPrintRoles(unsorted, &b, "delegations")
|
|
text, err := ioutil.ReadAll(&b)
|
|
require.NoError(t, err)
|
|
|
|
expected := [][]string{
|
|
{"targets/aardvark/unicorn/pony", "rainbows", "135", "1"},
|
|
{"targets/bee", "honey", "246", "1"},
|
|
{"targets/bee/wasp", "honey/sting", "246", "1"},
|
|
{"stuff", "468"}, // Extra keys and paths are printed to extra rows
|
|
{"targets/zebra", "black", "101", "1"},
|
|
{"stripes"},
|
|
{"white"},
|
|
}
|
|
|
|
lines := strings.Split(strings.TrimSpace(string(text)), "\n")
|
|
require.Len(t, lines, len(expected)+2)
|
|
|
|
// starts with headers
|
|
require.True(t, reflect.DeepEqual(strings.Fields(lines[0]), strings.Fields(
|
|
"ROLE PATHS KEY IDS THRESHOLD")))
|
|
require.Equal(t, "----", lines[1][:4])
|
|
|
|
for i, line := range lines[2:] {
|
|
splitted := strings.Fields(line)
|
|
require.Equal(t, expected[i], splitted)
|
|
}
|
|
}
|