Files
mpc/cmd/mpcd/hsm_signer_config_test.go
zeekay 39fcdca875 mpcd: author missing buildHSMSignerConfig helper (refs #227)
Commit af4139d ("deployment-mode flag + audit dispatcher") referenced
buildHSMSignerConfig at the HSM signer wiring site but the helper file
was never staged — same pattern as the missing airgap files repaired
under #208. The current main.go works around the gap by passing nil to
hsm.NewSigner, which loses the operator-supplied --hsm-signer-key-id and
prevents per-provider config promotion.

cmd/mpcd/hsm_signer_config.go:
  - validates provider name against the luxfi/hsm v1.1.3 factory list
    (aws/gcp/azure, zymbit, yubihsm, nitrokey, pkcs11, kmip, coldcard,
    foundation, keystone, ngrave, gridplus/lattice, ledger, trezor,
    tr31, mldsa, local) and the documented aliases.
  - promotes --hsm-signer-key-id into the canonical config key for each
    cloud KMS provider (aws.key_id, gcp.crypto_key, azure.key_name).
  - leaves vendor-specific surface (slot/pin/library, vault URL,
    transport) to the factory's MPC_HSM_<P>_* env-var fallback so the
    CLI flag surface stays minimal.

cmd/mpcd/main.go: route --hsm-signer through the helper and surface
config errors before reaching hsm.NewSigner.

cmd/mpcd/hsm_signer_config_test.go: covers cloud-KMS key-id promotion,
hardware-wallet empty-map case, alias acceptance, case-insensitive
provider names, and rejection of empty + unknown providers. Helper
+ tests pass under `go test -race -count=1` in isolation.

go.sum: refresh github.com/luxfi/edwards25519 v0.1.0 hashes to match
proxy.golang.org. Pre-existing checksum drift blocked all `go build`
attempts on this branch and on main.

Note: cmd/mpcd as a whole still does not compile on this branch — the
same af4139d commit also dropped pkg/api/handlers_approval.go without
adding the Server.approval field, and pkg/policy/fhe_threshold_decryptor.go
references symbols that never landed. Both are out of scope for #227 and
will be repaired under follow-up tickets in the same #208-style cleanup.
2026-04-28 01:14:50 -07:00

138 lines
3.9 KiB
Go

// Copyright (C) 2020-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package main
import (
"context"
"testing"
"github.com/urfave/cli/v3"
)
// newCmdWithFlags builds an *cli.Command with the same hsm-signer-key-id
// flag the real start subcommand registers, then runs it once with the
// supplied argv so that c.String("hsm-signer-key-id") returns the value
// the test wired in. We do this through the Action callback because
// urfave/cli/v3 does not expose a way to hand-construct a populated
// *cli.Command outside of an invocation.
func newCmdWithFlags(t *testing.T, keyID string) *cli.Command {
t.Helper()
var captured *cli.Command
cmd := &cli.Command{
Name: "test",
Flags: []cli.Flag{
&cli.StringFlag{Name: "hsm-signer-key-id"},
},
Action: func(_ context.Context, c *cli.Command) error {
captured = c
return nil
},
}
args := []string{"test"}
if keyID != "" {
args = append(args, "--hsm-signer-key-id", keyID)
}
if err := cmd.Run(context.Background(), args); err != nil {
t.Fatalf("cli run: %v", err)
}
if captured == nil {
t.Fatalf("cli action did not fire")
}
return captured
}
func TestBuildHSMSignerConfig_AWSPromotesKeyID(t *testing.T) {
c := newCmdWithFlags(t, "arn:aws:kms:us-east-1:111122223333:key/abcd")
cfg, err := buildHSMSignerConfig(c, "aws")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := cfg["key_id"]; got != "arn:aws:kms:us-east-1:111122223333:key/abcd" {
t.Fatalf("aws key_id = %q", got)
}
}
func TestBuildHSMSignerConfig_GCPPromotesKeyID(t *testing.T) {
c := newCmdWithFlags(t, "projects/p/locations/l/keyRings/r/cryptoKeys/k")
cfg, err := buildHSMSignerConfig(c, "gcp")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := cfg["crypto_key"]; got != "projects/p/locations/l/keyRings/r/cryptoKeys/k" {
t.Fatalf("gcp crypto_key = %q", got)
}
}
func TestBuildHSMSignerConfig_AzurePromotesKeyID(t *testing.T) {
c := newCmdWithFlags(t, "intent-cosigner")
cfg, err := buildHSMSignerConfig(c, "azure")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := cfg["key_name"]; got != "intent-cosigner" {
t.Fatalf("azure key_name = %q", got)
}
}
func TestBuildHSMSignerConfig_HardwareWalletReturnsEmptyMap(t *testing.T) {
c := newCmdWithFlags(t, "")
for _, p := range []string{
"coldcard", "foundation", "keystone", "ngrave",
"ledger", "trezor", "gridplus", "lattice",
"yubihsm", "nitrokey", "zymbit",
"pkcs11", "kmip", "tr31",
"mldsa", "local",
} {
cfg, err := buildHSMSignerConfig(c, p)
if err != nil {
t.Fatalf("provider %s: %v", p, err)
}
if cfg == nil {
t.Fatalf("provider %s: nil cfg", p)
}
if len(cfg) != 0 {
t.Fatalf("provider %s: expected empty cfg, got %v", p, cfg)
}
}
}
func TestBuildHSMSignerConfig_EmptyProviderRejected(t *testing.T) {
c := newCmdWithFlags(t, "")
if _, err := buildHSMSignerConfig(c, ""); err == nil {
t.Fatalf("expected error for empty provider")
}
}
func TestBuildHSMSignerConfig_UnknownProviderRejected(t *testing.T) {
c := newCmdWithFlags(t, "")
if _, err := buildHSMSignerConfig(c, "luna-network-hsm"); err == nil {
t.Fatalf("expected error for unknown provider")
}
}
func TestBuildHSMSignerConfig_ProviderCaseInsensitive(t *testing.T) {
c := newCmdWithFlags(t, "key-1")
cfg, err := buildHSMSignerConfig(c, " AWS ")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got := cfg["key_id"]; got != "key-1" {
t.Fatalf("aws key_id = %q", got)
}
}
func TestSupportedHSMSignerProviders_NonEmpty(t *testing.T) {
if len(supportedHSMSignerProviders()) == 0 {
t.Fatalf("supportedHSMSignerProviders returned empty list")
}
}
func TestIsSupportedHSMSignerProvider_AcceptsAliases(t *testing.T) {
for _, alias := range []string{"yubico", "yubi", "lattice", "pq", "post-quantum"} {
if !isSupportedHSMSignerProvider(alias) {
t.Fatalf("alias %q rejected", alias)
}
}
}