mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
- 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.
238 lines
5.3 KiB
Go
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\"")
|
|
}
|
|
}
|