Files
base/plugins/kms/plugin.go
zeekay 344fcd1d51 logger: app.Logger() returns the shim interface, default to luxfi/log
core.App.Logger() now returns logger.Logger (the new shim interface)
instead of *slog.Logger, so every consumer talks to the same
backend-agnostic surface and stops pinning itself to log/slog. The raw
*slog.Logger is still reachable as App.SlogLogger() for the in-app
BatchHandler reload hook and the two tests that type-assert the
underlying handler — that's the only sanctioned escape hatch.

Plugins and network code that previously held *slog.Logger fields move
to luxlog.Logger (kms, vault, zap-transport, base-network/transport_zap,
network/archive_writer, tools/tasks/client). luxfi/zap's Logger field
was a pure transit dependency; we drop it from base call sites since
zaplib has its own default.

Remaining "log/slog" imports — 11 files — are confined to the
adapter/handler bridge (tools/logger and core/log_printer/base/app) and
to two tests that exercise the slog.Handler contract directly. Those
are the irreducible boundary where slog is the language of the
interface.
2026-05-15 04:04:26 -07:00

142 lines
3.6 KiB
Go

// Copyright (C) 2020-2026, Hanzo AI Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package kms
import (
"github.com/hanzoai/base/core"
"github.com/hanzoai/base/tools/hook"
sdk "github.com/hanzoai/kms/sdk/go"
luxlog "github.com/luxfi/log"
)
// MustRegister registers the KMS plugin with a Base app and panics on error.
//
// Usage:
//
// kms.MustRegister(app, kms.Config{
// Nodes: []string{"https://kms-mpc-0:9999", "https://kms-mpc-1:9999", "https://kms-mpc-2:9999"},
// OrgSlug: "my-org",
// Threshold: 2,
// EncryptedCollections: map[string][]string{
// "credentials": {"api_key", "api_secret"},
// },
// FHESearchable: map[string][]string{
// "credentials": {"name"},
// },
// })
func MustRegister(app core.App, config Config) {
if err := Register(app, config); err != nil {
panic(err)
}
}
// Register registers the KMS plugin with a Base app. The plugin provides:
// - Zero-knowledge encrypted secret management via REST API
// - Transparent field-level encryption on configured collections
// - FHE-encrypted indexes for querying encrypted fields without decryption
func Register(app core.App, config Config) error {
if !config.Enabled {
return nil
}
if err := config.validate(); err != nil {
return err
}
client, err := sdk.NewClient(sdk.Config{
Nodes: config.Nodes,
OrgSlug: config.OrgSlug,
Threshold: config.Threshold,
})
if err != nil {
return err
}
p := &plugin{
app: app,
config: config,
client: client,
logger: luxlog.New("component", "kms"),
}
// Build lookup maps for fast hook checks.
p.encFieldSet = make(map[string]map[string]struct{}, len(config.EncryptedCollections))
for col, fields := range config.EncryptedCollections {
m := make(map[string]struct{}, len(fields))
for _, f := range fields {
m[f] = struct{}{}
}
p.encFieldSet[col] = m
}
p.fheFieldSet = make(map[string]map[string]struct{}, len(config.FHESearchable))
for col, fields := range config.FHESearchable {
m := make(map[string]struct{}, len(fields))
for _, f := range fields {
m[f] = struct{}{}
}
p.fheFieldSet[col] = m
}
// Bootstrap: auto-unlock if configured.
app.OnBootstrap().Bind(&hook.Handler[*core.BootstrapEvent]{
Id: "__kmsBootstrap__",
Func: func(e *core.BootstrapEvent) error {
if err := e.Next(); err != nil {
return err
}
if config.AutoUnlock {
passphrase := config.resolvePassphrase()
if passphrase != "" {
if unlockErr := client.Unlock(passphrase); unlockErr != nil {
p.logger.Warn("kms: auto-unlock failed", "error", unlockErr)
} else {
p.logger.Info("kms: auto-unlock succeeded")
}
}
}
return nil
},
})
// Serve: register routes and record hooks.
app.OnServe().Bind(&hook.Handler[*core.ServeEvent]{
Id: "__kmsServe__",
Func: func(e *core.ServeEvent) error {
// Store reference for programmatic access.
app.Store().Set("kms", p)
p.registerRoutes(e.Router)
p.registerHooks()
return e.Next()
},
})
// Terminate: lock CEK on shutdown.
app.OnTerminate().Bind(&hook.Handler[*core.TerminateEvent]{
Id: "__kmsTerminate__",
Func: func(e *core.TerminateEvent) error {
p.logger.Info("kms: locking CEK on shutdown")
client.Lock()
return e.Next()
},
})
return nil
}
type plugin struct {
app core.App
config Config
client *sdk.Client
logger luxlog.Logger
// Pre-computed field sets for O(1) lookup in hooks.
encFieldSet map[string]map[string]struct{} // collection -> field -> struct{}
fheFieldSet map[string]map[string]struct{} // collection -> field -> struct{}
}