// Package engine defines the Engine interface and mount registry. // Phase 1: interface and registry only, no concrete implementations. package engine import ( "context" "errors" "fmt" "sync" "git.wntrmute.dev/kyle/metacrypt/internal/barrier" ) // EngineType identifies a cryptographic engine type. type EngineType string const ( EngineTypeCA EngineType = "ca" EngineTypeSSHCA EngineType = "sshca" EngineTypeTransit EngineType = "transit" EngineTypeUser EngineType = "user" ) var ( ErrMountExists = errors.New("engine: mount already exists") ErrMountNotFound = errors.New("engine: mount not found") ErrUnknownType = errors.New("engine: unknown engine type") ) // Request is a request to an engine. type Request struct { Operation string Path string Data map[string]interface{} } // Response is a response from an engine. type Response struct { Data map[string]interface{} } // Engine is the interface that all cryptographic engines must implement. type Engine interface { // Type returns the engine type. Type() EngineType // Initialize sets up the engine for first use. Initialize(ctx context.Context, b barrier.Barrier, mountPath string) error // Unseal opens the engine using state from the barrier. Unseal(ctx context.Context, b barrier.Barrier, mountPath string) error // Seal closes the engine and zeroizes key material. Seal() error // HandleRequest processes a request. HandleRequest(ctx context.Context, req *Request) (*Response, error) } // Factory creates a new engine instance of a given type. type Factory func() Engine // Mount represents a mounted engine instance. type Mount struct { Name string `json:"name"` Type EngineType `json:"type"` MountPath string `json:"mount_path"` engine Engine } // Registry manages mounted engine instances. type Registry struct { mu sync.RWMutex mounts map[string]*Mount factories map[EngineType]Factory barrier barrier.Barrier } // NewRegistry creates a new engine registry. func NewRegistry(b barrier.Barrier) *Registry { return &Registry{ mounts: make(map[string]*Mount), factories: make(map[EngineType]Factory), barrier: b, } } // RegisterFactory registers a factory for the given engine type. func (r *Registry) RegisterFactory(t EngineType, f Factory) { r.mu.Lock() defer r.mu.Unlock() r.factories[t] = f } // Mount creates and initializes a new engine mount. func (r *Registry) Mount(ctx context.Context, name string, engineType EngineType) error { r.mu.Lock() defer r.mu.Unlock() if _, exists := r.mounts[name]; exists { return ErrMountExists } factory, ok := r.factories[engineType] if !ok { return fmt.Errorf("%w: %s", ErrUnknownType, engineType) } eng := factory() mountPath := fmt.Sprintf("engine/%s/%s/", engineType, name) if err := eng.Initialize(ctx, r.barrier, mountPath); err != nil { return fmt.Errorf("engine: initialize %q: %w", name, err) } r.mounts[name] = &Mount{ Name: name, Type: engineType, MountPath: mountPath, engine: eng, } return nil } // Unmount removes and seals an engine mount. func (r *Registry) Unmount(name string) error { r.mu.Lock() defer r.mu.Unlock() mount, exists := r.mounts[name] if !exists { return ErrMountNotFound } if err := mount.engine.Seal(); err != nil { return fmt.Errorf("engine: seal %q: %w", name, err) } delete(r.mounts, name) return nil } // ListMounts returns all current mounts. func (r *Registry) ListMounts() []Mount { r.mu.RLock() defer r.mu.RUnlock() mounts := make([]Mount, 0, len(r.mounts)) for _, m := range r.mounts { mounts = append(mounts, Mount{ Name: m.Name, Type: m.Type, MountPath: m.MountPath, }) } return mounts } // HandleRequest routes a request to the appropriate engine. func (r *Registry) HandleRequest(ctx context.Context, mountName string, req *Request) (*Response, error) { r.mu.RLock() mount, exists := r.mounts[mountName] r.mu.RUnlock() if !exists { return nil, ErrMountNotFound } return mount.engine.HandleRequest(ctx, req) } // SealAll seals all mounted engines. func (r *Registry) SealAll() error { r.mu.Lock() defer r.mu.Unlock() for name, mount := range r.mounts { if err := mount.engine.Seal(); err != nil { return fmt.Errorf("engine: seal %q: %w", name, err) } } return nil }