Files
zeekay 9b9b26dccd chore: bump deps (lattice v7.1.0, hsm v1.1.3, sqlite3 v1.14.42)
- lattice v7.0.2 -> v7.1.0: types package (ComputeTrustMode,
  ConfidentialIOLevel, WorkloadPrivacyClass) used by pkg/registry +
  pkg/attestation. Was on feat/lp-137-types branch; merged + tagged.
- luxfi/hsm v1.1.2 -> v1.1.3: airgap factory cases (coldcard,
  foundation, keystone, ngrave, gridplus, ledger, trezor, yubihsm,
  nitrokey, pkcs11). Unblocks TestAirgapProvidersRoundTripFactory.
- mattn/go-sqlite3 v2.0.3+incompatible -> v1.14.42: json1 default-on,
  fixes pkg/custody json_extract failures (no build-tag dance needed).
- pkg/approval/factory_test.go: yubihsm now wantError=false (v1.1.3
  exposes it), removes the v1.1.2 workaround comment.
- cc/attest/verifier_test.go + pkg/hsm/hsm_test.go: pre-existing minor
  test cleanups bundled in (stub-panic and gcp/azure-stub assertions).

Build + 36/36 packages pass. Standalone integration smoke
(cmd/mpcd TestStandaloneSelfQuorum, -tags integration): PASS.
2026-04-29 00:19:15 -07:00

238 lines
5.3 KiB
Go

package hsm
import (
"context"
"crypto/ed25519"
"encoding/hex"
"os"
"path/filepath"
"testing"
)
func TestFileProvider_RoundTrip(t *testing.T) {
dir := t.TempDir()
ctx := context.Background()
p, err := NewFileProvider(&FileConfig{
BasePath: dir,
HexEncoded: true,
})
if err != nil {
t.Fatalf("NewFileProvider: %v", err)
}
if p.Name() != "file" {
t.Fatalf("Name() = %q, want %q", p.Name(), "file")
}
// Generate a deterministic Ed25519 seed.
seed := make([]byte, ed25519.SeedSize)
for i := range seed {
seed[i] = byte(i)
}
keyID := "test-key-01"
// Store.
if err := p.StoreKey(ctx, keyID, seed); err != nil {
t.Fatalf("StoreKey: %v", err)
}
// Verify file exists and contains hex.
data, err := os.ReadFile(filepath.Join(dir, keyID))
if err != nil {
t.Fatalf("read file: %v", err)
}
if string(data) != hex.EncodeToString(seed) {
t.Fatalf("file content = %q, want %q", data, hex.EncodeToString(seed))
}
// Get.
got, err := p.GetKey(ctx, keyID)
if err != nil {
t.Fatalf("GetKey: %v", err)
}
if hex.EncodeToString(got) != hex.EncodeToString(seed) {
t.Fatalf("GetKey returned %x, want %x", got, seed)
}
// List.
keys, err := p.ListKeys(ctx)
if err != nil {
t.Fatalf("ListKeys: %v", err)
}
if len(keys) != 1 || keys[0] != keyID {
t.Fatalf("ListKeys = %v, want [%q]", keys, keyID)
}
// Delete.
if err := p.DeleteKey(ctx, keyID); err != nil {
t.Fatalf("DeleteKey: %v", err)
}
keys, err = p.ListKeys(ctx)
if err != nil {
t.Fatalf("ListKeys after delete: %v", err)
}
if len(keys) != 0 {
t.Fatalf("ListKeys after delete = %v, want empty", keys)
}
}
func TestFileProvider_Sign(t *testing.T) {
dir := t.TempDir()
ctx := context.Background()
p, err := NewFileProvider(&FileConfig{
BasePath: dir,
HexEncoded: true,
})
if err != nil {
t.Fatalf("NewFileProvider: %v", err)
}
// Use a real Ed25519 keypair.
pub, priv, err := ed25519.GenerateKey(nil)
if err != nil {
t.Fatalf("GenerateKey: %v", err)
}
seed := priv.Seed()
keyID := "sign-test"
if err := p.StoreKey(ctx, keyID, seed); err != nil {
t.Fatalf("StoreKey: %v", err)
}
message := []byte("threshold signing test message")
sig, err := p.Sign(ctx, keyID, message)
if err != nil {
t.Fatalf("Sign: %v", err)
}
if !ed25519.Verify(pub, message, sig) {
t.Fatal("signature verification failed")
}
}
func TestFileProvider_Healthy(t *testing.T) {
dir := t.TempDir()
p, err := NewFileProvider(&FileConfig{BasePath: dir})
if err != nil {
t.Fatalf("NewFileProvider: %v", err)
}
if err := p.Healthy(context.Background()); err != nil {
t.Fatalf("Healthy: %v", err)
}
// Non-existent path should fail.
p2, err := NewFileProvider(&FileConfig{BasePath: filepath.Join(dir, "nonexistent")})
if err != nil {
// NewFileProvider creates the directory, so it should succeed.
t.Fatalf("NewFileProvider: %v", err)
}
// But it exists now because we created it.
if err := p2.Healthy(context.Background()); err != nil {
t.Fatalf("Healthy after create: %v", err)
}
}
func TestFileProvider_RawBytes(t *testing.T) {
dir := t.TempDir()
ctx := context.Background()
// Test non-hex mode.
p, err := NewFileProvider(&FileConfig{
BasePath: dir,
HexEncoded: false,
})
if err != nil {
t.Fatalf("NewFileProvider: %v", err)
}
seed := make([]byte, ed25519.SeedSize)
for i := range seed {
seed[i] = byte(i + 100)
}
keyID := "raw-key"
if err := p.StoreKey(ctx, keyID, seed); err != nil {
t.Fatalf("StoreKey: %v", err)
}
got, err := p.GetKey(ctx, keyID)
if err != nil {
t.Fatalf("GetKey: %v", err)
}
if hex.EncodeToString(got) != hex.EncodeToString(seed) {
t.Fatalf("raw GetKey returned %x, want %x", got, seed)
}
}
func TestNewProvider_File(t *testing.T) {
dir := t.TempDir()
p, err := NewProvider(Config{
Provider: "file",
File: &FileConfig{BasePath: dir},
})
if err != nil {
t.Fatalf("NewProvider(file): %v", err)
}
if p.Name() != "file" {
t.Fatalf("Name() = %q, want %q", p.Name(), "file")
}
if err := p.Close(); err != nil {
t.Fatalf("Close: %v", err)
}
}
func TestNewProvider_Default(t *testing.T) {
dir := t.TempDir()
// Empty provider string should default to file.
p, err := NewProvider(Config{
File: &FileConfig{BasePath: dir},
})
if err != nil {
t.Fatalf("NewProvider(default): %v", err)
}
if p.Name() != "file" {
t.Fatalf("Name() = %q, want %q", p.Name(), "file")
}
}
func TestNewProvider_Unknown(t *testing.T) {
_, err := NewProvider(Config{Provider: "quantum"})
if err == nil {
t.Fatal("expected error for unknown provider")
}
}
// The stub tests below run only without the gcp/azure/zymbit build tag.
// Each stub MUST return a non-nil error; the test asserts that contract
// rather than skipping silently.
func TestNewProvider_GCP_Stub(t *testing.T) {
_, err := NewGCPProvider(&GCPConfig{Project: "test"})
if err == nil {
t.Fatal("NewGCPProvider stub returned nil error; expected \"not compiled\"")
}
}
func TestNewProvider_Azure_Stub(t *testing.T) {
_, err := NewAzureProvider(&AzureConfig{VaultURL: "https://test"})
if err == nil {
t.Fatal("NewAzureProvider stub returned nil error; expected \"not compiled\"")
}
}
func TestNewProvider_Zymbit_Stub(t *testing.T) {
_, err := NewZymbitProvider(&ZymbitConfig{APIEndpoint: "http://localhost"})
if err == nil {
t.Fatal("NewZymbitProvider stub returned nil error; expected \"not compiled\"")
}
}