Documentation
¶
Overview ¶
Package plugin owns publication and the catalog lifecycle for the private Marketplace.
The server's half of publishing is deliberately independent of the client's: it hashes, extracts, and inspects the bytes it received rather than trusting what the publisher said about them. A client that validated is a convenience; this is the check that decides what a deployment's members can install.
Index ¶
- Variables
- func SelectRelease(releases []model.PluginRelease, opts SelectOptions) (*model.PluginRelease, error)
- type ActivateInput
- type CreateEntryInput
- type PublishInput
- type SelectOptions
- type Service
- func (s *Service) Activate(ctx context.Context, in ActivateInput) (*model.PluginActivation, error)
- func (s *Service) CreateEntry(ctx context.Context, in CreateEntryInput) (*model.Plugin, error)
- func (s *Service) GetEntry(ctx context.Context, name string) (*model.Plugin, error)
- func (s *Service) GetRelease(ctx context.Context, name, version string) (*model.PluginRelease, error)
- func (s *Service) ListActivations(ctx context.Context, teamID string) ([]model.PluginActivation, error)
- func (s *Service) ListEntries(ctx context.Context, includeArchived bool) ([]model.Plugin, error)
- func (s *Service) ListReleases(ctx context.Context, name string) ([]model.PluginRelease, error)
- func (s *Service) MovePin(ctx context.Context, in ActivateInput) (*model.PluginActivation, error)
- func (s *Service) OpenPackage(ctx context.Context, release model.PluginRelease) (io.ReadCloser, int64, error)
- func (s *Service) Publish(ctx context.Context, in PublishInput) (*model.PluginRelease, error)
- func (s *Service) ResolveSelection(ctx context.Context, teamID string, names []string, actorID string) ([]model.PluginActivation, error)
- func (s *Service) SetActivationEnabled(ctx context.Context, teamID, pluginName string, enabled bool, actorID string) (*model.PluginActivation, error)
- func (s *Service) SetArchived(ctx context.Context, name string, archived bool, actorID string) error
- func (s *Service) SetCuration(ctx context.Context, teamID string, mode model.PluginCuration, actorID string) error
- func (s *Service) UpdateEntry(ctx context.Context, name string, in model.UpdatePluginInput, actorID string) (*model.Plugin, error)
- func (s *Service) Yank(ctx context.Context, name, version, actorID, reason string) error
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoRelease means nothing published fits, which is different from the // plugin not existing. ErrNoRelease = errors.New("no release matches") // ErrReleaseYanked means the exact version asked for was withdrawn. Saying // so is the point: a recovery is allowed, but not by accident. ErrReleaseYanked = errors.New("that release was withdrawn") // ErrClientTooOld means the release states a lower bound this build does // not meet. ErrClientTooOld = errors.New("this build is older than the release requires") )
Reasons a release cannot be handed over.
var ErrExecutableContent = errors.New("this release contributes hooks or MCP servers, which cannot be activated for background runs yet")
ErrExecutableContent means the release contributes hooks or MCP servers.
Phase D1 refuses those unconditionally. Phase D2 replaces this with the operator's unattended-eligibility flag, which is the check that decides whether a program may run where nobody is present; until that flag exists there is nothing to check it against, and activating anyway would put a team's runs past a gate the deployment has not built.
var ErrInvalidCuration = errors.New("unknown plugin curation mode")
ErrInvalidCuration means the requested curation mode is not one of the two.
var ErrInvalidPackage = errors.New("invalid plugin package")
ErrInvalidPackage means the uploaded bytes are not a plugin this deployment would be able to load. It is a refusal of the request, not a server fault.
var ErrNameMismatch = errors.New("the package names a different plugin")
ErrNameMismatch means the manifest inside the package names a different plugin than the route it was published to.
var ErrNoActivatableRelease = errors.New("this plugin has no release that can be activated")
ErrNoActivatableRelease means the catalog has the plugin but nothing this team could be pinned to — every release is yanked, a prerelease, or refused for the reason ErrExecutableContent gives.
var ErrNotActivated = errors.New("this team has not activated this plugin")
ErrNotActivated means an agent named a plugin its team has not activated and the team curates its own list. In an open-mode team the same name activates the plugin instead; see docs/design/plugin-team-distribution.md §4.1.
Functions ¶
func SelectRelease ¶
func SelectRelease(releases []model.PluginRelease, opts SelectOptions) (*model.PluginRelease, error)
SelectRelease picks the release a caller should install.
The default is the newest release that is not a prerelease, not withdrawn, and whose lower bound this build meets. Every one of those exclusions is recoverable by naming a version exactly, which is what keeps the default safe without making it a wall.
Types ¶
type ActivateInput ¶
ActivateInput pins a release for a team. Version empty means the newest activatable release, which is what a curated activation from Portal sends when the admin did not pick one.
type CreateEntryInput ¶
CreateEntryInput reserves a catalog name.
type PublishInput ¶
type PublishInput struct {
// PluginName is the route's name. The manifest inside the package has to
// agree with it.
PluginName string
// Body is the archive, streamed rather than held.
Body io.Reader
// Source is the publisher's claim about the checkout the bytes came from.
// The server cannot verify it, so it is recorded as a claim beside a digest
// the server calculated itself.
Source model.PluginReleaseSource
ActorID string
}
PublishInput is one upload.
type SelectOptions ¶
type SelectOptions struct {
// Version asks for one exact release. Empty takes the default selection.
Version string
// ClientVersion is the build that will install it. An empty or unplaceable
// one satisfies every bound, because refusing to install on a version
// nobody can compare would break every contributor's checkout.
ClientVersion string
// AllowYanked permits a withdrawn release. It exists so a recovery has to
// say out loud what it is doing.
AllowYanked bool
// AllowPrerelease permits a prerelease in the default selection. Naming a
// prerelease version exactly always works without it.
AllowPrerelease bool
}
SelectOptions describes which release a caller wants.
type Service ¶
type Service struct {
Catalog model.PluginStore
// Activations and Teams carry the team half of distribution: which
// releases a team's background runs may use, and who fills that list.
// They are nil in a deployment that only publishes and installs locally.
Activations model.PluginActivationStore
Teams model.TeamStore
Packages objectstore.PluginPackageStorage
// KeyPrefix scopes package keys inside the object store.
KeyPrefix string
Audit *audit.Recorder
// Limits bound what one upload may cost. The zero value takes the defaults.
Limits archive.Limits
}
Service publishes releases and manages catalog entries.
func (*Service) Activate ¶
func (s *Service) Activate(ctx context.Context, in ActivateInput) (*model.PluginActivation, error)
Activate pins a release for a team's background runs.
It is the curated path: a person chose this plugin. The open-mode path is ResolveSelection, which activates as a side effect of an agent naming it and records that difference in the row's origin.
func (*Service) CreateEntry ¶
CreateEntry adds a catalog entry.
func (*Service) GetRelease ¶
func (s *Service) GetRelease(ctx context.Context, name, version string) (*model.PluginRelease, error)
GetRelease returns one release, or (nil, nil) when there is none.
func (*Service) ListActivations ¶
func (s *Service) ListActivations(ctx context.Context, teamID string) ([]model.PluginActivation, error)
ListActivations returns a team's activations, suspended ones included.
func (*Service) ListEntries ¶
ListEntries returns the catalog. Archived entries are included only when asked for: hiding a retired entry from the person who retired it would leave no way to restore it.
func (*Service) ListReleases ¶
ListReleases returns every release of one plugin, yanked ones included: which to install needs the version arithmetic, and an exact version can still be recovered by someone who acknowledges the state.
func (*Service) MovePin ¶
func (s *Service) MovePin(ctx context.Context, in ActivateInput) (*model.PluginActivation, error)
MovePin repoints a team's activation at another release.
It is separate from Activate because it is the action a capability report is read before: the bytes change, so what the team accepted changes with them. The new release passes the same content check a first activation does, which is what stops a plugin whose next version adds a hook from arriving as an update.
func (*Service) OpenPackage ¶
func (s *Service) OpenPackage(ctx context.Context, release model.PluginRelease) (io.ReadCloser, int64, error)
OpenPackage streams one release's bytes.
The stream is handed to the caller rather than read here: a download that buffered a package would size the server by its largest plugin.
func (*Service) Publish ¶
func (s *Service) Publish(ctx context.Context, in PublishInput) (*model.PluginRelease, error)
Publish stores one release.
The order matters. Bytes are stored before the release row, so a failure between the two leaves an orphan at a content-addressed key rather than a row pointing at nothing. An orphan costs disk; a dangling row costs an install.
func (*Service) ResolveSelection ¶
func (s *Service) ResolveSelection(ctx context.Context, teamID string, names []string, actorID string) ([]model.PluginActivation, error)
ResolveSelection turns the plugin names an agent definition carries into the activations that back them, activating what the team's mode allows.
It is the one seam the agent write path calls, because the answer to "may this agent name this plugin" is the team's curation mode and nothing the caller can work out for itself. In curated mode an unactivated name is refused; in open mode it activates the newest activatable release and attributes that to the person saving the agent.
A suspended activation is returned rather than refused: the write is not where that fails. A run resolving the same name is (§5.3), so refusing here would stop somebody editing an agent to remove the plugin that is failing it.
func (*Service) SetActivationEnabled ¶
func (s *Service) SetActivationEnabled(ctx context.Context, teamID, pluginName string, enabled bool, actorID string) (*model.PluginActivation, error)
SetActivationEnabled suspends or resumes an activation without losing the pin. Suspending fails the runs of the agents that name the plugin; that is intended, and it is why this is not a delete.
func (*Service) SetArchived ¶
func (s *Service) SetArchived(ctx context.Context, name string, archived bool, actorID string) error
SetArchived retires or restores a catalog entry.
It hides the entry and refuses new releases. It deletes nothing: a copy somebody already installed keeps working, and the record still explains where that copy came from.
func (*Service) SetCuration ¶
func (s *Service) SetCuration(ctx context.Context, teamID string, mode model.PluginCuration, actorID string) error
SetCuration records who fills a team's plugin activation list.