Files
zeekay cc986c328d lux/kms: orphan history at f2e793bf8 (was: kms: wire luxfi/mpc as REK backend)
Squashes all pre-rewrite history into a single root commit. Previous tree:
- 14506 commits including upstream Infisical fork history
- Multiple merge chains carrying pre-purge content

Force-rewrite per disk-space reclamation discipline. GHCR images
(1.9.9, 1.9.11) remain immutable; their git lineage is no longer
materialized.
2026-06-07 14:28:09 -07:00

149 lines
3.4 KiB
Go

// Package store provides key metadata and secret persistence via ZapDB.
// ZapDB is an embedded LSM key-value store with built-in S3 replication.
// No SQLite, no PostgreSQL, no Base dependency.
package store
import (
"encoding/json"
"errors"
"fmt"
"sync"
"github.com/luxfi/kms/pkg/keys"
badger "github.com/luxfi/zapdb"
)
var (
ErrNotFound = errors.New("store: key set not found")
ErrAlreadyExists = errors.New("store: key set already exists")
)
// Key prefix for validator key sets in ZapDB.
var keyPrefix = []byte("kms/keys/")
// Store persists validator key set metadata in ZapDB.
type Store struct {
db *badger.DB
mu sync.RWMutex
data map[string]*keys.ValidatorKeySet
}
// New creates a Store backed by a ZapDB instance.
func New(db *badger.DB) (*Store, error) {
s := &Store{
db: db,
data: make(map[string]*keys.ValidatorKeySet),
}
if err := s.load(); err != nil {
return nil, err
}
return s, nil
}
// load reads all validator key sets from ZapDB into memory.
func (s *Store) load() error {
return s.db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.Prefix = keyPrefix
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
err := item.Value(func(val []byte) error {
var ks keys.ValidatorKeySet
if err := json.Unmarshal(val, &ks); err != nil {
return fmt.Errorf("store: corrupt record key=%s: %w", item.Key(), err)
}
s.data[ks.ValidatorID] = &ks
return nil
})
if err != nil {
return err
}
}
return nil
})
}
// dbKey returns the ZapDB key for a validator ID.
func dbKey(validatorID string) []byte {
return append(keyPrefix, []byte(validatorID)...)
}
// Put saves a validator key set. Returns ErrAlreadyExists if the validator ID is taken.
func (s *Store) Put(ks *keys.ValidatorKeySet) error {
s.mu.Lock()
defer s.mu.Unlock()
if _, exists := s.data[ks.ValidatorID]; exists {
return ErrAlreadyExists
}
s.data[ks.ValidatorID] = ks
return s.persist(ks)
}
// Update replaces an existing validator key set.
func (s *Store) Update(ks *keys.ValidatorKeySet) error {
s.mu.Lock()
defer s.mu.Unlock()
if _, exists := s.data[ks.ValidatorID]; !exists {
return ErrNotFound
}
s.data[ks.ValidatorID] = ks
return s.persist(ks)
}
// Get retrieves a validator key set by validator ID.
func (s *Store) Get(validatorID string) (*keys.ValidatorKeySet, error) {
s.mu.RLock()
defer s.mu.RUnlock()
ks, ok := s.data[validatorID]
if !ok {
return nil, ErrNotFound
}
cp := *ks
return &cp, nil
}
// List returns all validator key sets.
func (s *Store) List() []*keys.ValidatorKeySet {
s.mu.RLock()
defer s.mu.RUnlock()
result := make([]*keys.ValidatorKeySet, 0, len(s.data))
for _, ks := range s.data {
cp := *ks
result = append(result, &cp)
}
return result
}
// Delete removes a validator key set by validator ID.
func (s *Store) Delete(validatorID string) error {
s.mu.Lock()
defer s.mu.Unlock()
if _, exists := s.data[validatorID]; !exists {
return ErrNotFound
}
delete(s.data, validatorID)
return s.db.Update(func(txn *badger.Txn) error {
return txn.Delete(dbKey(validatorID))
})
}
// persist writes a key set to ZapDB.
func (s *Store) persist(ks *keys.ValidatorKeySet) error {
raw, err := json.Marshal(ks)
if err != nil {
return err
}
return s.db.Update(func(txn *badger.Txn) error {
return txn.Set(dbKey(ks.ValidatorID), raw)
})
}