check / check (push) Successful in 52s
REPO_POLICIES.md sets the Go module root to sneak.berlin/go/<name>. go.mod, every import of the old path and the -X path in the Makefile LDFLAGS now use sneak.berlin/go/keyfunc; make fmt moved those imports to their new place in the sort order. The old path keeps no alias. The README gives the go install line next to the build from a clone and drops this issue from its TODO list, which now names the open 1.0 issues. Model: opus-5-5
129 lines
2.9 KiB
Go
129 lines
2.9 KiB
Go
package sshkey_test
|
|
|
|
import (
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/crypto/ssh"
|
|
"golang.org/x/crypto/ssh/agent"
|
|
"sneak.berlin/go/keyfunc/internal/derive"
|
|
"sneak.berlin/go/keyfunc/internal/sshkey"
|
|
)
|
|
|
|
// agentDirectoryMode is what the directory holding the agent socket
|
|
// has to be: nobody but its owner may enter it.
|
|
const agentDirectoryMode = 0o700
|
|
|
|
// exampleIndex is the key index every test here derives at.
|
|
const exampleIndex = 0
|
|
|
|
// example returns the mnemonic every BIP-39 document uses to show its
|
|
// test vectors: eleven abandons and about.
|
|
func example() string {
|
|
return strings.Repeat("abandon ", 11) + "about"
|
|
}
|
|
|
|
func TestTooFewBytesAreRefused(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := sshkey.New([]byte("short"))
|
|
require.ErrorIs(t, err, sshkey.ErrSize)
|
|
}
|
|
|
|
func TestTheCommentIsPutAtTheEndOfTheLine(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
key := exampleKey(t)
|
|
|
|
line, err := key.Line("hello")
|
|
require.NoError(t, err)
|
|
require.True(t, strings.HasPrefix(line, "ssh-ed25519 "))
|
|
require.True(t, strings.HasSuffix(line, " hello"))
|
|
}
|
|
|
|
func TestThePrivateKeyCarriesTheSamePublicKey(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
key := exampleKey(t)
|
|
|
|
line, err := key.Line("")
|
|
require.NoError(t, err)
|
|
|
|
block, err := key.Block("a comment")
|
|
require.NoError(t, err)
|
|
|
|
parsed, err := ssh.ParsePrivateKey([]byte(block))
|
|
require.NoError(t, err)
|
|
|
|
back := strings.TrimSpace(
|
|
string(ssh.MarshalAuthorizedKey(parsed.PublicKey())),
|
|
)
|
|
require.Equal(t, line, back)
|
|
}
|
|
|
|
func TestTheAgentServesTheOneKeyAndNothingElse(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
key := exampleKey(t)
|
|
|
|
served, err := key.Serve(t.Context(), "a comment")
|
|
require.NoError(t, err)
|
|
t.Cleanup(served.Stop)
|
|
|
|
directory, err := os.Stat(filepath.Dir(served.Socket()))
|
|
require.NoError(t, err)
|
|
require.Equal(t,
|
|
os.FileMode(agentDirectoryMode), directory.Mode().Perm(),
|
|
)
|
|
|
|
var dialer net.Dialer
|
|
|
|
connection, err := dialer.DialContext(t.Context(), "unix", served.Socket())
|
|
require.NoError(t, err)
|
|
|
|
defer func() { _ = connection.Close() }()
|
|
|
|
held, err := agent.NewClient(connection).List()
|
|
require.NoError(t, err)
|
|
require.Len(t, held, 1)
|
|
|
|
line, err := key.Line("a comment")
|
|
require.NoError(t, err)
|
|
require.Equal(t, line, held[0].String())
|
|
}
|
|
|
|
func TestStoppingTheAgentLeavesNothingBehind(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
served, err := exampleKey(t).Serve(t.Context(), "a comment")
|
|
require.NoError(t, err)
|
|
|
|
directory := filepath.Dir(served.Socket())
|
|
require.DirExists(t, directory)
|
|
|
|
served.Stop()
|
|
require.NoDirExists(t, directory)
|
|
|
|
var dialer net.Dialer
|
|
|
|
_, err = dialer.DialContext(t.Context(), "unix", served.Socket())
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// exampleKey derives the key the example mnemonic gives.
|
|
func exampleKey(t *testing.T) *sshkey.Key {
|
|
t.Helper()
|
|
|
|
material, err := derive.Bytes(example(), sshkey.Application, exampleIndex)
|
|
require.NoError(t, err)
|
|
|
|
key, err := sshkey.New(material)
|
|
require.NoError(t, err)
|
|
|
|
return key
|
|
}
|