keystore

package
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 31, 2025 License: Apache-2.0 Imports: 26 Imported by: 0

README

Keystore Overview

The keystore package owns credential persistence, secure refresh, and the reuse of provider‑specific SDK clients and operations. It is built from a handful of composable building blocks that each focus on a single responsibility.

Data & Credential Flow

  1. Store (store.go) persists provider credentials for an org inside integrations + hush secrets (Ent).
  2. Broker (broker.go) wraps the store, fetching cached payloads or minting fresh ones through the provider registry. It implements the CredentialSource interface consumed by higher layers.
  3. ClientPool (client_pool.go) uses eddy’s caching primitives to build/reuse short‑lived provider SDK clients for a single provider/client pairing.
  4. ClientPoolManager (client_manager.go) maintains a registry of pools driven by provider‑published ClientDescriptors so integrations can self‑describe which clients they expose.
  5. OperationManager (operations_manager.go) executes provider operations described by OperationDescriptors, resolving credentials via the broker and optional clients via the manager.

Components

Store
  • Validates org/provider inputs, ensures an integration record exists, and persists credential payloads as hush secrets (SaveCredential, LoadCredential, DeleteIntegration).
  • Converts between types.CredentialPayload and the models.CredentialSet envelope for storage, cloning timestamps and provider metadata.
  • Acts as the durable source of truth for all credentials referenced by the broker.
Broker (CredentialSource)
  • Implements Get by checking an in‑memory cache keyed by org + provider, falling back to the store when missing or expired.
  • Implements Mint by calling the registered provider’s Mint handler with the current stored payload, persisting the result back through the store, and refreshing the cache.
  • Provides the CredentialSource interface that ClientPool, ClientPoolManager, and OperationManager depend on so they can stay agnostic of storage details.
ClientPool
  • Parameterized by concrete client (T) and config (Config) types to preserve compile‑time safety inside first‑party packages.
  • Accepts a ClientBuilder (usually an integration SDK adapter) and reuses instances via eddy.ClientService, deduplicating builds per org/provider/version.
  • Handles credential refresh logic: force refresh, automatic refresh when token expiry nears (refreshSkew), and eviction when new credentials are minted.
  • Exposes ClientRequestOptions so callers can inject per‑call config or force a refresh of cached credentials/clients.
ClientPoolManager
  • Lets providers publish ClientDescriptors (provider, logical client name, build func). Each descriptor gets its own underlying ClientPool[any, map[string]any].
  • Performs descriptor validation (descriptorKey), clones config maps defensively, and keeps a copy of descriptors for discovery via Descriptors().
  • Gives dynamic consumers a single entry point (Get) where they specify org, provider, and client name without wiring concrete builders ahead of time.
OperationManager
  • Registers OperationDescriptors (provider + operation name + run func) and exposes Run for callers.
  • Resolves credentials through the shared CredentialSource (typically the broker) and, if the descriptor declares a client dependency, asks the injected ClientPoolManager to supply it.
  • Supports per‑operation config maps, force‑mint (req.Force), and optional client force refresh (req.ClientForce).
  • Returns structured types.OperationResult objects so integrations/CLI surfaces can report status and payloads consistently.

Descriptor Types

  • types.ClientDescriptor: provider identifier, logical client name, and a build function func(context.Context, types.CredentialPayload, map[string]any) (any, error). Used by ClientPoolManager.
  • types.OperationDescriptor: provider identifier, operation name, optional client name dependency, and a run function that receives types.OperationInput. Used by OperationManager.
  • Helper constructors such as FlattenDescriptors / FlattenOperationDescriptors convert provider‑keyed maps into the slices accepted by the managers.

Extending the System

  1. Add credential persistence: ensure the provider’s onboarding flow calls Store.SaveCredential (usually via the broker).
  2. Register provider with the integrations registry so the broker can look it up for minting.
  3. Expose clients by returning types.ClientDescriptors from the provider package; wire them into a ClientPoolManager via NewClientPoolManager.
  4. Expose operations by returning types.OperationDescriptors; pass them to NewOperationManager, supplying WithOperationClients if an operation needs reusable clients.
  5. Callers use the manager APIs (ClientPoolManager.Get, OperationManager.Run) without needing to understand how credentials are persisted or clients are cached.

Together these components keep the keystore boundary clean: persistence lives in the store, refresh/caching in the broker and eddy pools, and dynamic runtime behaviors (clients + operations) hanging off descriptors so new providers can plug in without changing core code.

Documentation

Overview

Package keystore manages credential persistence, token refresh, client pooling, and operation execution for integration providers

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrProviderRequired indicates a credential operation lacked a provider identifier
	ErrProviderRequired = errors.New("keystore: provider required")
	// ErrOrgIDRequired indicates the caller did not provide an organization identifier
	ErrOrgIDRequired = errors.New("keystore: org id required")
	// ErrCredentialNotFound indicates no credential exists for the supplied org/provider
	ErrCredentialNotFound = errors.New("keystore: credential not found")
	// ErrProviderNotRegistered indicates the registry does not have a provider implementation for the requested type
	ErrProviderNotRegistered = errors.New("keystore: provider not registered")
	// ErrBrokerRequired indicates a client pool was constructed without a credential broker/source
	ErrBrokerRequired = errors.New("keystore: credential broker required")
	// ErrClientBuilderRequired indicates a client pool was constructed without a builder
	ErrClientBuilderRequired = errors.New("keystore: client builder required")
	// ErrClientUnavailable indicates the requested client could not be created
	ErrClientUnavailable = errors.New("keystore: client unavailable")
	// ErrClientNotRegistered indicates no client descriptor/pool exists for the requested provider+client pair
	ErrClientNotRegistered = errors.New("keystore: client not registered")
	// ErrClientDescriptorInvalid indicates a provider published an invalid client descriptor
	ErrClientDescriptorInvalid = errors.New("keystore: client descriptor invalid")
	// ErrOperationNameRequired indicates the caller omitted an operation identifier
	ErrOperationNameRequired = errors.New("keystore: operation name required")
	// ErrOperationNotRegistered indicates no operation exists for the requested provider/name pair
	ErrOperationNotRegistered = errors.New("keystore: operation not registered")
	// ErrOperationDescriptorInvalid indicates a provider published an invalid operation descriptor
	ErrOperationDescriptorInvalid = errors.New("keystore: operation descriptor invalid")
	// ErrOperationClientManagerRequired indicates an operation requires a client pool but none was provided
	ErrOperationClientManagerRequired = errors.New("keystore: client manager required for operation")
	// ErrStoreNotInitialized indicates the store instance is nil
	ErrStoreNotInitialized = errors.New("keystore: store not initialized")
)

Functions

func FlattenDescriptors

func FlattenDescriptors(entries map[types.ProviderType][]types.ClientDescriptor) []types.ClientDescriptor

FlattenDescriptors converts a map of provider descriptors into a single slice for manager construction

func FlattenOperationDescriptors

func FlattenOperationDescriptors(entries map[types.ProviderType][]types.OperationDescriptor) []types.OperationDescriptor

FlattenOperationDescriptors converts a map of provider operations into a single slice for manager construction

func Schema

func Schema() *jsonschema.Schema

Schema returns the JSON schema for integration provider specifications.

Types

type AuthType

type AuthType = types.AuthKind

type Broker

type Broker struct {
	// contains filtered or unexported fields
}

Broker exchanges persisted credentials for short-lived tokens via registered providers

func NewBroker

func NewBroker(store *Store, reg *registry.Registry) *Broker

NewBroker constructs a broker backed by the supplied store and provider registry

func (*Broker) Get

func (b *Broker) Get(ctx context.Context, orgID string, provider types.ProviderType) (types.CredentialPayload, error)

Get returns the latest credential payload for the given org/provider pair (using cache when valid)

func (*Broker) Mint

func (b *Broker) Mint(ctx context.Context, orgID string, provider types.ProviderType) (types.CredentialPayload, error)

Mint refreshes the stored credential via the provider and returns the updated payload

type ClientBuilder

type ClientBuilder[T any, Config any] interface {
	// Build constructs a new client instance using the supplied credential payload and configuration
	Build(ctx context.Context, payload types.CredentialPayload, config Config) (T, error)
	// ProviderType returns the provider identifier handled by this builder
	ProviderType() types.ProviderType
}

ClientBuilder constructs provider SDK clients from credential payloads

type ClientBuilderFunc

type ClientBuilderFunc[T any, Config any] struct {
	// Provider identifies which provider this builder handles
	Provider types.ProviderType
	// BuildFn is the function that constructs the client
	BuildFn func(context.Context, types.CredentialPayload, Config) (T, error)
}

ClientBuilderFunc adapts a function to the ClientBuilder interface

func (ClientBuilderFunc[T, Config]) Build

func (f ClientBuilderFunc[T, Config]) Build(ctx context.Context, payload types.CredentialPayload, config Config) (T, error)

Build constructs the client using the configured function

func (ClientBuilderFunc[T, Config]) ProviderType

func (f ClientBuilderFunc[T, Config]) ProviderType() types.ProviderType

ProviderType returns the provider identifier for the builder

type ClientDescriptor

type ClientDescriptor = types.ClientDescriptor

type ClientName

type ClientName = types.ClientName

type ClientPool

type ClientPool[T any, Config any] struct {
	// contains filtered or unexported fields
}

ClientPool orchestrates credential retrieval and client caching for a specific provider type

func NewClientPool

func NewClientPool[T any, Config any](source CredentialSource, builder ClientBuilder[T, Config], opts ...ClientPoolOption[T, Config]) (*ClientPool[T, Config], error)

NewClientPool builds a client pool that reuses provider SDK clients using eddy's caching primitives

func (*ClientPool[T, Config]) Get

func (p *ClientPool[T, Config]) Get(ctx context.Context, orgID string, opts ...ClientRequestOption[Config]) (T, error)

Get returns a provider-specific client for the supplied organization, reusing cached instances when possible

func (*ClientPool[T, Config]) Provider

func (p *ClientPool[T, Config]) Provider() types.ProviderType

Provider returns the provider type handled by this pool

type ClientPoolManager

type ClientPoolManager struct {
	// contains filtered or unexported fields
}

ClientPoolManager manages client pools constructed from provider-published descriptors

func NewClientPoolManager

func NewClientPoolManager(source CredentialSource, descriptors []types.ClientDescriptor) (*ClientPoolManager, error)

NewClientPoolManager builds a manager from the supplied credential source and descriptors

func (*ClientPoolManager) Descriptors

Descriptors returns a copy of all registered descriptors keyed by provider

func (*ClientPoolManager) Get

func (m *ClientPoolManager) Get(ctx context.Context, orgID string, provider types.ProviderType, client types.ClientName, opts ...ClientRequestOption[map[string]any]) (any, error)

Get retrieves a client for the given provider/client name pair

func (*ClientPoolManager) RegisterDescriptor

func (m *ClientPoolManager) RegisterDescriptor(descriptor types.ClientDescriptor) error

RegisterDescriptor registers a single client descriptor and lazily constructs its pool

type ClientPoolOption

type ClientPoolOption[T any, Config any] func(*ClientPool[T, Config], *clientPoolSettings[Config])

ClientPoolOption customizes client pool construction

func WithClientConfigClone

func WithClientConfigClone[T any, Config any](clone func(Config) Config) ClientPoolOption[T, Config]

WithClientConfigClone configures how per-request config structs are cloned before invoking the builder

func WithClientPoolTTL

func WithClientPoolTTL[T any, Config any](ttl time.Duration) ClientPoolOption[T, Config]

WithClientPoolTTL overrides the default client cache TTL

type ClientRequestOption

type ClientRequestOption[Config any] func(*clientRequest[Config])

ClientRequestOption customizes Get requests

func WithClientConfig

func WithClientConfig[Config any](config Config) ClientRequestOption[Config]

WithClientConfig supplies provider-specific builder configuration

func WithClientForceRefresh

func WithClientForceRefresh[Config any]() ClientRequestOption[Config]

WithClientForceRefresh bypasses cached credentials and forces a mint operation

type CredentialSource

type CredentialSource interface {
	// Get retrieves the latest credential payload for the given org/provider pair
	Get(ctx context.Context, orgID string, provider types.ProviderType) (types.CredentialPayload, error)
	// Mint obtains a fresh credential payload for the given org/provider pair
	Mint(ctx context.Context, orgID string, provider types.ProviderType) (types.CredentialPayload, error)
}

CredentialSource exposes the subset of broker operations required by the client pool

type GitHubAppSpec

type GitHubAppSpec = config.GitHubAppSpec

type GoogleWorkloadIdentitySpec

type GoogleWorkloadIdentitySpec = config.GoogleWorkloadIdentitySpec

type OperationDescriptor

type OperationDescriptor = types.OperationDescriptor

type OperationManager

type OperationManager struct {
	// contains filtered or unexported fields
}

OperationManager executes provider-published operations using stored credentials and optional client pools

func NewOperationManager

func NewOperationManager(source CredentialSource, descriptors []types.OperationDescriptor, opts ...OperationManagerOption) (*OperationManager, error)

NewOperationManager builds an OperationManager from the supplied credential source and descriptors

func (*OperationManager) Descriptors

Descriptors returns a copy of all registered operations keyed by provider

func (*OperationManager) RegisterDescriptor

func (m *OperationManager) RegisterDescriptor(descriptor types.OperationDescriptor) error

RegisterDescriptor registers an operation descriptor and makes it available to callers

func (*OperationManager) Run

Run executes the requested provider operation using stored credentials and optional clients

type OperationManagerOption

type OperationManagerOption func(*OperationManager)

OperationManagerOption customizes manager construction

func WithOperationClients

func WithOperationClients(clients *ClientPoolManager) OperationManagerOption

WithOperationClients registers the client pool manager used to satisfy operation client dependencies

type OperationName

type OperationName = types.OperationName

type OperationRequest

type OperationRequest = types.OperationRequest

type OperationResult

type OperationResult = types.OperationResult

type PersistenceSpec

type PersistenceSpec = config.PersistenceSpec

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store persists credential payloads using Ent-backed integrations and hush secrets

func NewStore

func NewStore(db *ent.Client) *Store

NewStore returns a Store backed by the supplied Ent client

func (*Store) DeleteIntegration

func (s *Store) DeleteIntegration(ctx context.Context, orgID string, integrationID string) (types.ProviderType, string, error)

DeleteIntegration removes the integration and associated secrets for the given org

func (*Store) EnsureIntegration

func (s *Store) EnsureIntegration(ctx context.Context, orgID string, provider types.ProviderType) (*ent.Integration, error)

EnsureIntegration guarantees an integration record exists for the given org/provider pair

func (*Store) LoadCredential

func (s *Store) LoadCredential(ctx context.Context, orgID string, provider types.ProviderType) (types.CredentialPayload, error)

LoadCredential retrieves the credential payload for the given org/provider pair

func (*Store) SaveCredential

func (s *Store) SaveCredential(ctx context.Context, orgID string, payload types.CredentialPayload) (types.CredentialPayload, error)

SaveCredential upserts the credential payload for the given org/provider pair

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL