controlplane

package
v0.60.0 Latest Latest
Warning

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

Go to latest
Published: Jul 19, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package controlplane owns Stella's deployment control-plane resources: LLM providers, deployment settings (embedding, CLI-tool registry, OAuth provider config), plugins (registered + manifest), and channels.

These resources are administered, not user-owned. Authorization is a single admin gate at Begin (see access.go): an Access is minted only for an admin authority, so a non-admin actor is denied before any durable read or external action — identical to the legacy requireAdmin gate this service replaces. There is no per-user ownership and no per-method authorization.

The service also owns the persistence and live-reload orchestration each control-plane mutation performs (store writes plus pool/plugin-host hot reloads), so the HTTP transport keeps only request decoding and response shaping. It never reads request-supplied identity: the caller passes a trusted authz.Authority derived from verified session claims.

Index

Constants

View Source
const ChannelPluginConfigError = "channel instance config lives on /channels, not plugin config"

ChannelPluginConfigError is the client message returned when an admin tries to read or write a channel plugin's config through the plugin API; channel instance config lives on the /channels surface instead.

Variables

View Source
var ErrUnavailable = errors.New("controlplane: authorization unavailable")

ErrUnavailable is returned when the service itself is not configured (a nil receiver); the transport maps it to a fail-closed 503.

Functions

This section is empty.

Types

type Access

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

Access is one authorized control-plane use case. Every control-plane resource (providers, settings, plugins, channels) is admin-only, so authorization is a single gate at Begin: an Access exists only for an admin authority. Each method then performs the durable write and hot-reload the legacy handler did, with no further per-method authorization.

func (*Access) CliToolLatest

func (a *Access) CliToolLatest(ctx context.Context, tool string) (string, error)

CliToolLatest resolves the latest installable version for a mise tool key.

func (*Access) CreateProvider

func (a *Access) CreateProvider(ctx context.Context, p config.Provider) error

CreateProvider persists a new provider and hot-reloads the pool.

func (*Access) DeleteChannel

func (a *Access) DeleteChannel(ctx context.Context, id string) error

DeleteChannel stops a channel's runtime and removes it.

func (*Access) DeleteOAuthProviderConfig

func (a *Access) DeleteOAuthProviderConfig(ctx context.Context, id string) error

DeleteOAuthProviderConfig removes an OAuth provider client configuration.

func (*Access) DeleteProvider

func (a *Access) DeleteProvider(ctx context.Context, id string) error

DeleteProvider removes a provider and hot-reloads the pool.

func (*Access) FetchProviderModels

func (a *Access) FetchProviderModels(ctx context.Context, id, apiKey, baseURL string) ([]ProviderModelItem, error)

FetchProviderModels lists the provider's models from its live API, refreshes the cached set, and returns the merged list. Credentials fall back to the stored provider when the caller omits them. It preserves the legacy status split: a missing provider during the credential fallback is a 400 "api_key is required", while the authoritative load is a 404.

func (*Access) GetChannel

func (a *Access) GetChannel(ctx context.Context, id string) (config.Channel, error)

GetChannel returns one channel by id (opaque 404 when missing).

func (*Access) GetEmbeddingSettings

func (a *Access) GetEmbeddingSettings(ctx context.Context) (config.EmbeddingSettings, error)

GetEmbeddingSettings returns the deployment-wide embedding configuration.

func (*Access) GetOAuthProviderConfig

func (a *Access) GetOAuthProviderConfig(ctx context.Context, id string) (connections.OAuthProviderConfig, error)

GetOAuthProviderConfig returns the stored OAuth provider client configuration.

func (*Access) GetPluginConfig

func (a *Access) GetPluginConfig(ctx context.Context, kind, name string) (map[string]any, error)

GetPluginConfig returns a plugin's stored config. Channel plugins are rejected: their instance config lives on /channels.

func (*Access) GetPluginConfigSchema

func (a *Access) GetPluginConfigSchema(ctx context.Context, kind, name string) (map[string]any, error)

GetPluginConfigSchema returns a plugin's admin config schema.

func (*Access) GetPluginStatus

func (a *Access) GetPluginStatus(ctx context.Context, kind, name string) (any, error)

GetPluginStatus returns a plugin's admin status payload.

func (*Access) GetProvider

func (a *Access) GetProvider(ctx context.Context, id string) (config.Provider, error)

GetProvider returns one provider by id (opaque 404 when missing).

func (*Access) ListChannels

func (a *Access) ListChannels(ctx context.Context) ([]config.Channel, error)

func (*Access) ListManifestPlugins

func (a *Access) ListManifestPlugins(ctx context.Context) (*manifestplugins.Manifest, error)

ListManifestPlugins returns the builtin manifest overlaid with DB overrides.

func (*Access) ListPlugins

func (a *Access) ListPlugins(ctx context.Context) ([]pkgplugins.RegisteredPlugin, error)

ListPlugins returns the admin-visible registered plugins. The transport shapes each into its admin view.

func (*Access) ListProviderModels

func (a *Access) ListProviderModels(ctx context.Context, id string) ([]ProviderModelItem, error)

ListProviderModels returns the merged custom+fetched model list for a provider.

func (*Access) ListProviderTypes

func (a *Access) ListProviderTypes() ([]pluginhost.ProviderType, error)

ListProviderTypes returns the provider plugin types the deployment can add.

func (*Access) ListProviders

func (a *Access) ListProviders(ctx context.Context) ([]config.Provider, error)

ListProviders returns every configured LLM provider.

func (*Access) LookupAgent

func (a *Access) LookupAgent(ctx context.Context, id string) (config.Agent, error)

LookupAgent reads an agent for a channel-binding precondition: a registration flow binds a channel to an agent that must exist and be enabled. It is an admin-gated read (the Access already passed Begin), so a non-admin never reaches it; the caller inspects the returned agent's Enabled flag.

func (*Access) ManageChannel

func (a *Access) ManageChannel(id string) (*ChannelManagement, error)

ManageChannel opens a channel-management operation. The admin gate already ran at Begin, so this only hands back the operation handle; id is retained for call-site symmetry (registration flows keep this handle across their platform handshake, then call Save after credentials arrive).

func (*Access) SaveChannel

func (a *Access) SaveChannel(ctx context.Context, ch config.Channel, cfgMap map[string]any, create bool) (config.Channel, error)

SaveChannel validates and persists a channel, ensures its plugin is enabled, and applies its runtime. create=true rejects an id that already exists (the create-only POST contract). It returns the reloaded channel.

func (*Access) SaveManifestPlugins

func (a *Access) SaveManifestPlugins(ctx context.Context, plugins []manifestplugins.ManifestPlugin) (*manifestplugins.Manifest, error)

SaveManifestPlugins persists per-plugin overrides (definition and/or enabled toggle), re-registers the merged manifest, hot-reloads plugin tools/hooks, and returns the merged manifest.

func (*Access) SearchCliToolRegistry

func (a *Access) SearchCliToolRegistry(ctx context.Context, query string, limit int) ([]manifestplugins.RegistryTool, error)

SearchCliToolRegistry searches the mise tool registry so the UI can add a CLI tool by name instead of a hand-written backend key.

func (*Access) SetEmbeddingSettings

func (a *Access) SetEmbeddingSettings(ctx context.Context, upd EmbeddingUpdate) (config.EmbeddingSettings, error)

SetEmbeddingSettings persists the embedding configuration. The api_key is write-only: an omitted or empty key keeps the stored one. Enabling the lane without a key is rejected (it would silently no-op).

func (*Access) SetOAuthProviderConfig

SetOAuthProviderConfig persists an OAuth provider client configuration and returns the refreshed stored value.

func (*Access) SyncManifestPlugins

func (a *Access) SyncManifestPlugins(ctx context.Context) (manifestplugins.ReconcileResult, error)

SyncManifestPlugins reconciles the merged manifest against the filesystem (installs binaries/skills) and returns the reconcile result.

func (*Access) TogglePlugin

func (a *Access) TogglePlugin(ctx context.Context, kind, name string, enabled bool) (config.Plugin, error)

TogglePlugin enables/disables a plugin and hot-reloads its runtime. A sandbox backend pinned by STELLA_SANDBOX_BACKEND cannot be toggled.

func (*Access) UpdatePluginConfig

func (a *Access) UpdatePluginConfig(ctx context.Context, kind, name string, cfg map[string]any) (config.Plugin, error)

UpdatePluginConfig validates and persists a plugin's config, then hot-reloads its runtime. Channel plugins are rejected (config lives on /channels).

func (*Access) UpdateProvider

func (a *Access) UpdateProvider(ctx context.Context, id string, p config.Provider) (config.Provider, error)

UpdateProvider merges the request over the stored provider (preserving Type and defaulting Name), persists it, and hot-reloads the pool. It returns the merged provider so the transport can echo it.

type ChannelManagement

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

ChannelManagement is one channel-management operation. Its Save method owns the channel row plus the required channel plugin enable/apply as a single unit, so callers never need a second plugin call.

func (*ChannelManagement) Channel

func (m *ChannelManagement) Channel(ctx context.Context, id string) (config.Channel, error)

Channel reads the current row for this operation's channel so a caller can merge a partial update onto it. It is an admin-gated read (Begin already ran); a missing channel returns an error the caller treats as "start from a fresh row" rather than a hard failure.

func (*ChannelManagement) Save

func (m *ChannelManagement) Save(ctx context.Context, ch config.Channel, cfgMap map[string]any, create bool) (config.Channel, error)

Save persists the already-authorized channel and applies its plugin as one control-plane operation. It intentionally makes no further authorization call.

func (*ChannelManagement) ValidateBinding

func (m *ChannelManagement) ValidateBinding(ctx context.Context, ch config.Channel) error

ListChannels returns every configured channel. ValidateBinding checks the durable channel-binding invariant before an enrollment flow performs an external handshake. Save repeats the check and the database unique index closes the concurrent-write race.

type ConflictError

type ConflictError struct{ Msg string }

ConflictError reports a create that collides with an existing resource, mapped to 409 by the transport. It is returned only after authorization succeeds.

func (*ConflictError) Error

func (e *ConflictError) Error() string

type EmbeddingUpdate

type EmbeddingUpdate struct {
	Enabled   bool
	Model     string
	Dim       int
	BaseURL   string
	Normalize bool
	APIKey    *string
}

EmbeddingUpdate carries a validated embedding-settings write. APIKey is nil to keep the stored key (the GET never echoes it) or non-nil to replace it.

type ForbiddenError

type ForbiddenError struct{ Msg string }

ForbiddenError reports a control-plane precondition that forbids an operation for a reason other than the admin gate (e.g. a resource locked by an environment override). It maps to 403 with Msg, distinct from the opaque authz.ErrForbidden denial, and is only ever returned after authorization succeeds so it never leaks to an unauthorized caller.

func (*ForbiddenError) Error

func (e *ForbiddenError) Error() string

type NotFoundError

type NotFoundError struct{ Msg string }

NotFoundError reports a control-plane resource that does not exist. Msg carries the historical per-resource client message so the transport preserves the 404 body byte-for-byte.

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

type ProviderModelItem

type ProviderModelItem struct {
	ID      string               `json:"id"`
	Name    string               `json:"name,omitempty"`
	Source  string               `json:"source"`
	Enabled bool                 `json:"enabled"`
	Config  config.ProviderModel `json:"config,omitzero"`
}

ProviderModelItem is one merged model entry for a provider: custom (config-declared) models plus fetched (cached) models, unioned. Kept here with the persistence it derives from; the transport writes it directly.

type PublicChannel

type PublicChannel struct {
	ID      string
	Type    string // effective type: the configured type, or the id when unset
	AgentID string
	Enabled bool
}

PublicChannel is the config-secret-free projection of a channel for the user-facing channel list. It deliberately omits the raw Config JSON that config.Channel carries (channel credentials), exposing only the fields the public list renders.

type Service

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

Service owns the control-plane resources: the persistence and runtime handles a control-plane mutation needs to apply and hot-reload changes. Authorization is the admin gate in Begin (see access.go); a nil receiver fails closed.

func NewService

func NewService(store config.Store, plugins *pluginhost.Host, pools *agent.PoolManager, conns *connections.Service, log *slog.Logger) *Service

NewService builds the control-plane service from its fully-wired dependencies. The composition root constructs it once and shares the same instance behind the HTTP endpoints. log defaults to slog.Default() when nil.

func (*Service) Begin

func (s *Service) Begin(_ context.Context, authority authz.Authority) (*Access, error)

Begin authorizes one control-plane use case. The control plane is administered, not user-owned: it validates the Authority and requires IsAdmin exactly once, so a non-admin or invalid authority fails closed here, before any durable read or external action — identical to the legacy requireAdmin gate this replaces. The handler never inspects identity beyond passing the trusted Authority.

func (*Service) EnabledChannelTypes

func (s *Service) EnabledChannelTypes(ctx context.Context, authority authz.Authority) (map[string]bool, error)

EnabledChannelTypes returns the set of enabled channel-plugin names, used by the transport to hide channels whose plugin is disabled.

func (*Service) ListEnabledModels

func (s *Service) ListEnabledModels(ctx context.Context, authority authz.Authority) ([]config.CachedModel, error)

ListEnabledModels returns the models available for selection: enabled models from enabled providers, plus fetched-cache models whose provider is enabled, deduplicated by provider/model and sorted. It performs no provider API calls.

func (*Service) PublicChannels

func (s *Service) PublicChannels(ctx context.Context, authority authz.Authority) ([]PublicChannel, error)

PublicChannels returns the secret-free projection of every configured channel for the user-facing channel list. The transport filters visibility by the caller's agent access and the enabled plugin types; this only supplies the projected rows.

type UpstreamError

type UpstreamError struct{ Err error }

UpstreamError reports a failed call to an external control-plane dependency (e.g. a provider's model-listing endpoint), mapped to 502 by the transport.

func (*UpstreamError) Error

func (e *UpstreamError) Error() string

func (*UpstreamError) Unwrap

func (e *UpstreamError) Unwrap() error

type ValidationError

type ValidationError struct{ Msg string }

ValidationError reports a rejected control-plane input (the legacy 400 path). Msg carries the exact historical client message.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Jump to

Keyboard shortcuts

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