Files
secret/internal/secret/seunlocker_test.go
T
sneak 4a6e30f9bf
check / check (push) Failing after 3s
Check errors by identity, not by message text, in tests (closes #49)
Tests that asserted a failure by a fragment of its message now use
errors.Is: a refactor returning the wrong error, or wrapping with %v
instead of %w, now fails them. New tests return each exported error of
internal/vault and pkg/bip85 that no test returned, and check wrapped
causes (os.ErrNotExist, ErrMnemonicMismatch through GetSecret,
ErrInvalidPathComponent through DeriveBIP85Entropy). The 999-versions
test moves into package secret to name its unexported error. Checks of
errors no test can name keep their text; they are listed on the issue.

Model: opus-5-5
2026-10-04 20:04:59 +00:00

112 lines
2.9 KiB
Go

//go:build darwin
//nolint:testpackage // white-box test of unexported Secure Enclave helpers
package secret
import (
"os"
"testing"
"time"
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewSecureEnclaveUnlocker(t *testing.T) {
t.Parallel()
fs := afero.NewMemMapFs()
dir := "/tmp/test-se-unlocker"
metadata := UnlockerMetadata{
Type: seUnlockerType,
CreatedAt: time.Date(2026, 1, 15, 10, 30, 0, 0, time.UTC),
Flags: []string{seUnlockerType, "macos"},
}
unlocker := NewSecureEnclaveUnlocker(fs, dir, metadata)
require.NotNil(t, unlocker, "NewSecureEnclaveUnlocker should return a valid instance")
// Test GetType returns correct type
assert.Equal(t, seUnlockerType, unlocker.GetType())
// Test GetMetadata returns the metadata we passed in
assert.Equal(t, metadata, unlocker.GetMetadata())
// Test GetDirectory returns the directory we passed in
assert.Equal(t, dir, unlocker.GetDirectory())
}
func TestSecureEnclaveUnlockerImplementsInterface(t *testing.T) {
t.Parallel()
fs := afero.NewMemMapFs()
metadata := UnlockerMetadata{
Type: seUnlockerType,
CreatedAt: time.Now().UTC(),
}
unlocker := NewSecureEnclaveUnlocker(fs, "/tmp/test", metadata)
// Verify the darwin implementation implements the Unlocker interface
var _ Unlocker = unlocker
}
func TestSecureEnclaveUnlockerGetIDFormat(t *testing.T) {
t.Parallel()
fs := afero.NewMemMapFs()
metadata := UnlockerMetadata{
Type: seUnlockerType,
CreatedAt: time.Date(2026, 3, 10, 14, 30, 0, 0, time.UTC),
}
unlocker := NewSecureEnclaveUnlocker(fs, "/tmp/test", metadata)
// The ID is the name of the unlocker's directory
assert.Equal(t, "test", unlocker.GetID())
}
func TestGenerateSEKeyLabel(t *testing.T) {
t.Parallel()
label, err := generateSEKeyLabel("test-vault")
require.NoError(t, err)
// Label should contain the prefix and vault name
assert.Contains(t, label, seKeyLabelPrefix)
assert.Contains(t, label, "test-vault")
}
func TestSecureEnclaveUnlockerGetIdentityMissingFile(t *testing.T) {
t.Parallel()
fs := afero.NewMemMapFs()
dir := "/tmp/test-se-unlocker-missing"
// Create unlocker directory with metadata but no encrypted key file
require.NoError(t, fs.MkdirAll(dir, DirPerms))
metadataJSON := `{
"type": "secure-enclave",
"createdAt": "2026-01-15T10:30:00Z",
"seKeyLabel": "berlin.sneak.app.secret.se.test",
"seKeyHash": "abc123"
}`
require.NoError(t, afero.WriteFile(
fs, dir+"/unlocker-metadata.json", []byte(metadataJSON), FilePerms,
))
metadata := UnlockerMetadata{
Type: seUnlockerType,
CreatedAt: time.Date(2026, 1, 15, 10, 30, 0, 0, time.UTC),
}
unlocker := NewSecureEnclaveUnlocker(fs, dir, metadata)
// GetIdentity should fail because the encrypted longterm key file is missing
identity, err := unlocker.GetIdentity()
assert.Nil(t, identity)
require.ErrorIs(t, err, os.ErrNotExist)
}