genkeys/testkeys: native-ZAP mnemonic via shared zapclient.LoadMnemonic

Switches both cmd/genkeys and cmd/testkeys from a bare MNEMONIC env-var
read to the canonical luxfi/kms zapclient.LoadMnemonic loader. Same path
luxd's keyutil (lux/node @ e1ecb6d) and lux/cli's ammcmd (lux/cli @ ad1e849b)
now use — every Lux-derived tool resolves mnemonics the same way.

Source order (handled inside the shared loader):
  1. MNEMONIC env var               local dev + CI test seam
  2. KMS_ADDR + KMS_ENV +           native ZAP fetch from Liquid KMS
     KMS_MNEMONIC_PATH

Backwards-compatible: setting MNEMONIC env still works exactly as before
(short-circuits the KMS call). New capability: setting KMS_* envs lets
netrunner tools fetch from KMS in CI / cluster contexts where the
mnemonic should not be a plaintext env var.

Dep:
  + github.com/luxfi/kms v1.9.12  (carries zapclient.LoadMnemonic)

Build clean.
This commit is contained in:
Hanzo AI
2026-05-31 14:32:19 -07:00
parent 1970f6efe0
commit 89888e6247
4 changed files with 56 additions and 10 deletions
+30 -4
View File
@@ -1,14 +1,26 @@
// genkeys generates mainnet validator keys from MNEMONIC
// genkeys generates mainnet validator keys from a BIP-39 mnemonic.
//
// Mnemonic source (priority order, handled inside the shared luxfi/kms
// zapclient.LoadMnemonic loader so every Lux-derived tool resolves keys
// the same way):
//
// 1. MNEMONIC env var — local dev + CI test seam
// 2. KMS_ADDR + KMS_ENV + — native ZAP from Liquid KMS
// KMS_MNEMONIC_PATH
package main
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/luxfi/keys"
"github.com/luxfi/kms/pkg/zapclient"
)
type ValidatorBackup struct {
@@ -22,9 +34,15 @@ type ValidatorBackup struct {
}
func main() {
mnemonic := os.Getenv("MNEMONIC")
if mnemonic == "" {
fmt.Println("ERROR: MNEMONIC not set")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
mnemonic, err := zapclient.LoadMnemonic(ctx,
os.Getenv("KMS_ADDR"),
os.Getenv("KMS_ENV"),
envOr("KMS_MNEMONIC_PATH", "/mnemonic"))
if err != nil {
fmt.Printf("ERROR: load mnemonic: %v\n", err)
fmt.Println("Set MNEMONIC env var, or KMS_ADDR + KMS_ENV + KMS_MNEMONIC_PATH for native ZAP.")
os.Exit(1)
}
@@ -126,3 +144,11 @@ func main() {
}())
}
}
// envOr returns the value of env var `name` if set + non-empty, else def.
func envOr(name, def string) string {
if v := strings.TrimSpace(os.Getenv(name)); v != "" {
return v
}
return def
}
+20 -3
View File
@@ -1,18 +1,27 @@
package main
import (
"context"
"fmt"
"os"
"sort"
"strings"
"time"
"github.com/luxfi/keys"
"github.com/luxfi/kms/pkg/zapclient"
)
func main() {
mnemonic := os.Getenv("MNEMONIC")
if mnemonic == "" {
fmt.Println("MNEMONIC not set")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
mnemonic, err := zapclient.LoadMnemonic(ctx,
os.Getenv("KMS_ADDR"),
os.Getenv("KMS_ENV"),
envOr("KMS_MNEMONIC_PATH", "/mnemonic"))
if err != nil {
fmt.Printf("ERROR: load mnemonic: %v\n", err)
fmt.Println("Set MNEMONIC env var, or KMS_ADDR + KMS_ENV + KMS_MNEMONIC_PATH for native ZAP.")
os.Exit(1)
}
@@ -75,3 +84,11 @@ func main() {
fmt.Printf(" %s\n", n)
}
}
// envOr returns the value of env var `name` if set + non-empty, else def.
func envOr(name, def string) string {
if v := strings.TrimSpace(os.Getenv(name)); v != "" {
return v
}
return def
}
+2 -1
View File
@@ -20,6 +20,7 @@ require (
github.com/luxfi/go-bip39 v1.1.2
github.com/luxfi/ids v1.2.10
github.com/luxfi/keys v1.0.8
github.com/luxfi/kms v1.9.12
github.com/luxfi/log v1.4.1
github.com/luxfi/math v1.4.1
github.com/luxfi/metric v1.5.5
@@ -102,7 +103,7 @@ require (
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.66 // indirect
github.com/miekg/dns v1.1.72 // indirect
github.com/minio/crc64nvme v1.1.1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.100 // indirect
+4 -2
View File
@@ -302,6 +302,8 @@ github.com/luxfi/keychain v1.0.2 h1:uQgmjs37/VBIALEiYrrszTpxvtqr07/YvS9TnmxGafs=
github.com/luxfi/keychain v1.0.2/go.mod h1:q/4ULgZBlstKkwzOzG/0T6y73BDPgnkrcibbJyTvmbU=
github.com/luxfi/keys v1.0.8 h1:fANl6qZInndyCcXHAWiHTQ50LHhU8pJlF0Ix3phTo4A=
github.com/luxfi/keys v1.0.8/go.mod h1:XbSCtgLyzEEVz2oZsYxnhRrNTGBxqrAm2Zu0uu06+qA=
github.com/luxfi/kms v1.9.12 h1:o+9Ssqln/24EDJJVmuLGm2q9ehqO08h/fGqjyyCEXVw=
github.com/luxfi/kms v1.9.12/go.mod h1:qGuK95av+MRUFsCr44FUuico4bX5lvO8pAq/lULeSas=
github.com/luxfi/lattice/v7 v7.1.0 h1:mr3HvN6olNTS2LT/xAW/JBhTqfvpsGmsopDMeR7BSJs=
github.com/luxfi/lattice/v7 v7.1.0/go.mod h1:IaaUN+3ysnBG4BA8ILRYG0j80+qtYDP4C5lkaDb2pDE=
github.com/luxfi/log v1.4.1 h1:rIfFRodb9jrD/w7KayaUk0Oc+37PaQQdKEEMJCjR8gw=
@@ -383,8 +385,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE=
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI=
github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=