Skeleton, mnemonic input, derivation, and the ssh pub and priv commands (closes #1)
All checks were successful
check / check (push) Successful in 5s
All checks were successful
check / check (push) Successful in 5s
The module, the script entrypoints and Makefile, Docker-only linting, the mnemonic sources in the specified order with their refusals, the BIP-85 derivation, and keyfunc ssh pub and priv with the README test vectors as tests. Two review rounds; the second passed with no findings. Model: opus-5 (implementation and review); fable-5-1 (landing)
This commit was merged in pull request #5.
This commit is contained in:
110
internal/cli/cli_test.go
Normal file
110
internal/cli/cli_test.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.eeqj.de/sneak/keyfunc/internal/cli"
|
||||
"git.eeqj.de/sneak/keyfunc/internal/derive"
|
||||
"git.eeqj.de/sneak/keyfunc/internal/mnemonic"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// The two lines the README says the example mnemonic produces.
|
||||
const (
|
||||
vectorZero = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJZOtOczrc/7CQytc" +
|
||||
"uFwt7s4r8KjkZWkwjLZWBaFKD+7"
|
||||
vectorOne = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOEWY8+/gmHYVC4u0Y" +
|
||||
"0I4FKs+eVUulTPHfk9VtXw1tMF"
|
||||
)
|
||||
|
||||
// example returns the mnemonic the README gives its test vectors for:
|
||||
// eleven abandons and about.
|
||||
func example() string {
|
||||
return strings.Repeat("abandon ", 11) + "about"
|
||||
}
|
||||
|
||||
func TestTheReadmeTestVectors(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, example())
|
||||
|
||||
require.Equal(t,
|
||||
vectorZero+" keyfunc/ssh/0",
|
||||
strings.TrimSpace(run(t, "ssh", "pub", "-n", "0")),
|
||||
)
|
||||
require.Equal(t,
|
||||
vectorOne+" keyfunc/ssh/1",
|
||||
strings.TrimSpace(run(t, "ssh", "pub", "-n", "1")),
|
||||
)
|
||||
}
|
||||
|
||||
func TestTheCommentCanBeChosen(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, example())
|
||||
|
||||
line := strings.TrimSpace(run(t, "ssh", "pub", "--comment", "mine"))
|
||||
require.Equal(t, vectorZero+" mine", line)
|
||||
}
|
||||
|
||||
func TestThePrivateKeyMatchesThePublicOne(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, example())
|
||||
|
||||
block := run(t, "ssh", "priv", "-n", "1")
|
||||
require.True(t,
|
||||
strings.HasPrefix(block, "-----BEGIN OPENSSH PRIVATE KEY-----"),
|
||||
)
|
||||
|
||||
parsed, err := ssh.ParsePrivateKey([]byte(block))
|
||||
require.NoError(t, err)
|
||||
|
||||
back := strings.TrimSpace(
|
||||
string(ssh.MarshalAuthorizedKey(parsed.PublicKey())),
|
||||
)
|
||||
require.Equal(t, vectorOne, back)
|
||||
}
|
||||
|
||||
func TestAnIndexWithNoHardenedChildIsRefused(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, example())
|
||||
|
||||
out, err := execute(t, "ssh", "pub", "-n", "2147483648")
|
||||
require.ErrorIs(t, err, derive.ErrIndexTooLarge)
|
||||
require.Empty(t, out)
|
||||
}
|
||||
|
||||
func TestTheMnemonicCommandIsUsed(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, "")
|
||||
|
||||
line := strings.TrimSpace(run(t,
|
||||
"ssh", "pub",
|
||||
"--mnemonic-command", "printf '%s\\n' '"+example()+"'",
|
||||
))
|
||||
require.Equal(t, vectorZero+" keyfunc/ssh/0", line)
|
||||
}
|
||||
|
||||
// run executes the tool with the given arguments and returns what it
|
||||
// wrote to standard output.
|
||||
func run(t *testing.T, args ...string) string {
|
||||
t.Helper()
|
||||
|
||||
out, err := execute(t, args...)
|
||||
require.NoError(t, err)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// execute runs the tool and returns both what it wrote and how it
|
||||
// ended.
|
||||
func execute(t *testing.T, args ...string) (string, error) {
|
||||
t.Helper()
|
||||
|
||||
var out bytes.Buffer
|
||||
|
||||
root := cli.Root()
|
||||
root.SetOut(&out)
|
||||
root.SetErr(&out)
|
||||
root.SetArgs(args)
|
||||
|
||||
err := root.ExecuteContext(t.Context())
|
||||
|
||||
return out.String(), err
|
||||
}
|
||||
Reference in New Issue
Block a user