plugin

package
v0.2.3 Latest Latest
Warning

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

Go to latest
Published: Sep 8, 2026 License: MIT Imports: 33 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// BackingRuntime: the plugin's own artifact serves the method. The default.
	BackingRuntime = "runtime"
	// BackingCore: a core-registered provider owned by this plugin serves the method.
	// Host-risk by nature — only a system plugin may declare it, and every v2 manifest
	// already requires a trusted-publisher signature.
	BackingCore = "core"
)

Backing names who actually serves an interface's methods.

A plugin is not required to carry its own engine. Some domain engines — the nftables renderer, the WireGuard key/config engine — deliberately stay in core so the trust base stays small (ADR-001 D5). What the plugin owns in that case is the UI, the validation, and the workflow intent; core owns the engine.

That arrangement is legitimate. What is not legitimate is leaving it implicit: a manifest that declares a method core secretly answers is a contract that lies, and no operator or auditor can see the difference. Backing makes the split an explicit, signed, per-service declaration.

View Source
const (
	DefaultInvokeTimeoutMS   = 10_000
	DefaultInvokeStdoutBytes = 1 << 20
	DefaultInvokeStderrBytes = 1 << 20
	DefaultInvokeHostCalls   = 64

	HostMaxInvokeTimeoutMS   = 30_000
	HostMaxInvokeStdoutBytes = 8 << 20
	HostMaxInvokeStderrBytes = 1 << 20
	// HostMaxInvokeHostCalls bounds what a signed manifest may declare per
	// method. 64 was sized for CRUD shapes; the sub-store plugin's real shapes
	// run past it — an export reattaches one program key per script file and
	// the store caps at 256 records (2 + 256 = 258), and a migration is that
	// plus three upstream fetches (263). 512 covers the store-bounded worst
	// cases with headroom while still killing a runaway plugin.
	HostMaxInvokeHostCalls = 512
)
View Source
const (
	ManifestSchemaV2           = "lattice.plugin.manifest.v2"
	BundleFormatTarGzip        = "tar+gzip"
	RuntimeProtocolStdioJSONV1 = "stdio-json-v1"
	RuntimeProtocolStdioJSONV2 = "stdio-json-v2"
	UIRuntimeModeSandbox       = "sandbox"
	UIBridgeVersion1           = "1"

	InterfaceEffectRead  = "read"
	InterfaceEffectWrite = "write"
	InterfaceEffectPlan  = "plan"
)
View Source
const (
	TypeSystem = "system"
	TypeWasm   = "wasm"
	TypeWorker = "worker"

	RiskRead  = "read"
	RiskWrite = "write"
	RiskHost  = "host"
)
View Source
const (
	RuntimeStateArmed    = "armed"
	RuntimeStateStopping = "stopping"
	RuntimeStateStopped  = "stopped"
	RuntimeStateDegraded = "degraded"
	RuntimeStateFailed   = "failed"
)

Variables

View Source
var (
	// ErrCapabilityDenied is returned when a plugin calls a host API without
	// declaring the matching capability in its verified manifest.
	ErrCapabilityDenied = errors.New("plugin capability denied")
	// ErrHostServiceUnavailable is returned when the capability is granted but
	// the server did not wire the corresponding host service into the broker.
	ErrHostServiceUnavailable = errors.New("plugin host service unavailable")
)
View Source
var (
	// ErrRPCNoService is returned when no plugin has registered the target service.
	ErrRPCNoService = errors.New("rpc service not found")
	// ErrRPCNoMethod is returned when the target service does not expose the method.
	ErrRPCNoMethod = errors.New("rpc method not found")
	// ErrRPCDenied is returned when the caller is not on the service's directed
	// allow-list (and is not the service owner). Distinct from "not found" so the
	// broker can record it as a security deny event.
	ErrRPCDenied = errors.New("rpc call denied")
	// ErrRPCInvalid is returned for a malformed service registration.
	ErrRPCInvalid = errors.New("invalid rpc registration")
	// ErrRPCOwnerInactive is returned when the plugin owning a service is not active.
	// Disable must stop the backend, not merely hide the UI: core-registered providers
	// are wired at boot and never unregistered, so without this gate a disabled plugin
	// kept serving — to the gateway, and to any consumer still holding a granted edge.
	ErrRPCOwnerInactive = errors.New("rpc service owner is not active")
)

Inter-plugin RPC (design-09 §F). The registry is the server-owned bus that makes one first-party plugin's logic callable from another without exposing raw handles: a plugin with rpc:expose registers a service; a plugin with rpc:call invokes it through the broker. Every call is capability-gated at the broker, authorized here by a directed caller->callee allow-list, and audited.

View Source
var ErrCircuitOpen = errors.New("plugin circuit breaker open")

ErrCircuitOpen is returned once a plugin has failed CrashThreshold times in a row. The operator must disable+re-enable (restart) the plugin to reset it; a flapping plugin cannot keep consuming resources.

Functions

func BindOperation added in v0.2.3

func BindOperation(ctx context.Context, grant *OperationGrant) (context.Context, error)

BindOperation attaches an approved operation's one-time authority to a single invocation. Only the approval executor calls this; an ordinary /api/plugins/call invocation binds nothing, so a plugin reached any other way holds no grant and its task.enqueue is refused.

func BindOperatorTargets added in v0.2.3

func BindOperatorTargets(ctx context.Context, targets []string) (context.Context, error)

BindOperatorTargets attaches server-authorized base URLs to one invocation. Only the system runner and server tests should mint this context value.

func CanonicalOperationPlan added in v0.2.3

func CanonicalOperationPlan(plan PluginOperationPlan) (string, error)

CanonicalOperationPlan renders the reviewable plan deterministically. This string is stored in Approval.Plan and hashed by the approval plan-hash gate, so the operator approves exactly these bytes; any ambiguity in the encoding would be an ambiguity in what was approved.

func CapabilityList

func CapabilityList() []string

func CapabilityRisk added in v0.2.0

func CapabilityRisk(cap string) (string, bool)

func DigestSHA256 added in v0.2.0

func DigestSHA256(artifact []byte) string

func SHA256Hex added in v0.2.3

func SHA256Hex(data []byte) string

SHA256Hex is the one hashing helper the operation protocol uses, so plan hashes and request hashes are computed the same way.

func SigningPayload added in v0.2.0

func SigningPayload(m Manifest) []byte

func ValidateInvokeBudgetSpec added in v0.2.3

func ValidateInvokeBudgetSpec(b InvokeBudgetSpec) error

func ValidateManifest

func ValidateManifest(m Manifest) error

func ValidateOperationPlan added in v0.2.3

func ValidateOperationPlan(plan PluginOperationPlan) error

ValidateOperationPlan bounds what a plugin may propose. A plan is plugin-authored input crossing into the operator's review surface, so it is checked like any other untrusted input — before a human is asked to read it.

func ValidateSystemPoolConfig added in v0.2.3

func ValidateSystemPoolConfig(cfg SystemPoolConfig) error

ValidateSystemPoolConfig checks the host-side resource bounds without creating runtime directories or starting plugin processes.

func VerifyManifest added in v0.2.0

func VerifyManifest(m Manifest, artifact []byte, policy TrustPolicy) error

func VersionInRange added in v0.2.3

func VersionInRange(version, rangeExpr string) bool

VersionInRange reports whether version satisfies the comparator set — exported for the server-side activation gate (plugin load uses the same evaluator internally).

Types

type Broker added in v0.2.0

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

Broker is the capability-scoped facade a verified plugin uses to call back into server-owned host services.

func NewBroker added in v0.2.0

func NewBroker(loaded Loaded, services HostServices) (*Broker, error)

NewBroker binds a verified plugin registry entry to server-owned host services.

func (*Broker) CanExposeRPC added in v0.2.0

func (b *Broker) CanExposeRPC() bool

CanExposeRPC reports whether the verified plugin declared rpc:expose, i.e. may register a callable service in the inter-plugin RPC registry. The server checks this before registering a plugin's handlers (design-09 §F).

func (*Broker) HTTPDo added in v0.2.0

HTTPDo performs guarded outbound HTTP and requires http:egress. The broker itself runs the SSRF/egress guard on req.URL BEFORE delegating to the HTTPHost, so egress filtering is structural at this boundary and every HTTPHost (including future ones) is guarded regardless of its own behavior.

func (*Broker) HTTPOperatorDo added in v0.2.3

func (b *Broker) HTTPOperatorDo(ctx context.Context, req HostHTTPRequest) (HostHTTPResponse, error)

HTTPOperatorDo reaches an explicitly operator-selected endpoint and requires the distinct system-only http:operator-target capability. It never weakens HTTPDo or its SSRF boundary.

func (*Broker) HasCapability added in v0.2.0

func (b *Broker) HasCapability(cap string) bool

HasCapability reports whether the verified plugin declared cap.

func (*Broker) KVGet added in v0.2.0

func (b *Broker) KVGet(ctx context.Context, key string) ([]byte, bool, error)

KVGet reads a KV value and requires kv:read. The plugin-supplied key names only the entry within the plugin's own namespace; the broker pins the bucket so a plugin can never read another plugin's or the operator's keys.

func (*Broker) KVPut added in v0.2.0

func (b *Broker) KVPut(ctx context.Context, key string, value []byte) error

KVPut writes a KV value and requires kv:write. As with KVGet, the bucket is fixed to the plugin's own namespace; the plugin only chooses the entry key.

func (*Broker) Log added in v0.2.0

func (b *Broker) Log(ctx context.Context, level, message string, fields map[string]string) error

Log writes a plugin-authored log entry and requires log:write. The plugin controls the level/message/fields, so the broker bounds them before they reach the sink: the level is mapped to a known set, an oversize message is truncated, and the field count is capped. This prevents a plugin from flooding or poisoning the operator log through unbounded input.

func (*Broker) Notify added in v0.2.0

func (b *Broker) Notify(ctx context.Context, title, body string) error

Notify sends an operator notification and requires notify:send.

func (*Broker) PluginID added in v0.2.0

func (b *Broker) PluginID() string

PluginID returns the verified plugin id attached to this broker.

func (*Broker) RPCCall added in v0.2.0

func (b *Broker) RPCCall(ctx context.Context, service, method string, request []byte) ([]byte, error)

RPCCall invokes method on another plugin's exposed service and requires rpc:call. The broker stamps the VERIFIED caller id (b.pluginID) so the registry can authorize the directed edge; a plugin cannot impersonate another caller. Registry-level denials (ErrRPCDenied) are additionally recorded as a deny event for audit visibility (the capability check itself already recorded an allow). Service/method-not-found are client errors once the directed edge is authorized, so they are returned without an extra deny event.

func (*Broker) SecretDelete added in v0.2.3

func (b *Broker) SecretDelete(ctx context.Context, key string) error

SecretDelete removes an encrypted secret and requires secret:write.

func (*Broker) SecretGet added in v0.2.3

func (b *Broker) SecretGet(ctx context.Context, key string) (string, bool, error)

SecretGet reads an encrypted secret and requires secret:read. As with KV, the bucket is pinned by the broker, so a plugin can only read secrets it wrote itself.

The value is returned to the PLUGIN BACKEND only. It never crosses the browser bridge: the bridge can invoke a plugin's declared interface methods, and what a method chooses to return is the plugin's own business, but the host never places a secret into a plan, an error, an audit record, or a log line.

func (*Broker) SecretPut added in v0.2.3

func (b *Broker) SecretPut(ctx context.Context, key, value string) error

SecretPut writes an encrypted secret and requires secret:write.

func (*Broker) TaskEnqueue added in v0.2.3

func (b *Broker) TaskEnqueue(ctx context.Context, req HostTaskRequest) (string, error)

TaskEnqueue queues agent work for an APPROVED operation and requires task:run.

The capability alone grants nothing. task:run says a plugin is *eligible* to run work; the operation grant says which work, on which nodes, under which approval — and it exists only inside an invocation the approval executor started. So the ways a plugin might try to reach a node all fail here:

  • called through the ordinary gateway, there is no grant at all;
  • holding a grant, it cannot aim at a node the operator did not approve;
  • it cannot enqueue against a plan other than the one that was approved;
  • it cannot enqueue more times than the approval allowed.

The script itself is arbitrary — `sh` on a node is full execution by design. That is exactly why the grant binds the target set: the blast radius is the reviewed one.

type BundleFile added in v0.2.3

type BundleFile struct {
	Size   int64  `json:"size"`
	SHA256 string `json:"sha256"`
	Mode   uint32 `json:"mode"`
}

func ReadVerifiedBundleFile added in v0.2.3

func ReadVerifiedBundleFile(loaded Loaded, rel string) ([]byte, BundleFile, error)

ReadVerifiedBundleFile reads one inventory-pinned file from an extracted v2 tree after rechecking path components, type, mode, size, and digest. Callers serve the returned immutable bytes rather than reopening a mutable path.

type BundleLimits added in v0.2.3

type BundleLimits struct {
	MaxCompressedBytes int64
	MaxExpandedBytes   int64
	MaxFileBytes       int64
	MaxFiles           int
	MaxPathBytes       int
	MaxDepth           int
}

func DefaultBundleLimits added in v0.2.3

func DefaultBundleLimits() BundleLimits

type BundleSpec added in v0.2.3

type BundleSpec struct {
	Format       string `json:"format"`
	DigestSHA256 string `json:"digest_sha256"`
}

type CapabilityError added in v0.2.0

type CapabilityError struct {
	PluginID   string
	Capability string
}

CapabilityError describes the exact capability a plugin lacked.

func (*CapabilityError) Error added in v0.2.0

func (e *CapabilityError) Error() string

func (*CapabilityError) Unwrap added in v0.2.0

func (e *CapabilityError) Unwrap() error

type CompatibilitySpec added in v0.2.3

type CompatibilitySpec struct {
	Server          string `json:"server"`
	DashboardHost   string `json:"dashboard_host"`
	RuntimeProtocol string `json:"runtime_protocol"`
}

type DependencySpec added in v0.2.3

type DependencySpec struct {
	ID       string `json:"id"`
	Version  string `json:"version,omitempty"`
	Optional bool   `json:"optional,omitempty"`
}

DependencySpec names one required or optional plugin dependency. Version is a comparator set (">=0.8.0-alpha.5, <0.9"); empty means any installed version. A missing required dependency refuses load; a present-but-inactive one refuses activation.

type ExtractedBundle added in v0.2.3

type ExtractedBundle struct {
	Root        string
	RuntimePath string
	UIRoot      string
	UIEntry     string
	Digest      string
	Inventory   map[string]BundleFile
}

func ExtractBundleV2 added in v0.2.3

func ExtractBundleV2(cacheDir string, manifest Manifest, artifact []byte, platform string, limits BundleLimits, policy TrustPolicy) (ExtractedBundle, error)

ExtractBundleV2 verifies the signed compressed bytes before parsing, expands into a fresh cache-local staging directory, and publishes a content-addressed immutable tree. Existing cache entries are reused only after byte-for-byte hash, size, type, mode, and tree membership validation against this extraction.

type GenerationCleanupError added in v0.2.3

type GenerationCleanupError struct {
	PluginID      string
	Generation    uint64
	Stage         string
	PendingStages []string
	ResidualPGIDs []int
	Transport     error
	Authority     error
	RemoveAll     error
	Err           error
}

GenerationCleanupError preserves every residual from one generation's teardown instead of collapsing transport, authority, and filesystem failure into an apparently successful retirement.

func (*GenerationCleanupError) Error added in v0.2.3

func (e *GenerationCleanupError) Error() string

func (*GenerationCleanupError) Unwrap added in v0.2.3

func (e *GenerationCleanupError) Unwrap() error

type GenerationCleanupResult added in v0.2.3

type GenerationCleanupResult struct {
	PluginID      string
	Generation    uint64
	Stage         string
	PendingStages []string
	ResidualPGIDs []int
	Transport     error
	Authority     error
	RemoveAll     error
	Err           error
}

GenerationCleanupResult is the stable, caller-bounded view of one physical generation teardown. Pending snapshots and the immutable terminal result use the same shape so callers never lose ownership detail on timeout.

type GenerationLeasingRunner added in v0.2.3

type GenerationLeasingRunner interface {
	AcquireInvocation(pluginID string, generation uint64) (InvocationGenerationLease, error)
}

type HTTPHost added in v0.2.0

type HTTPHost interface {
	Do(ctx context.Context, req HostHTTPRequest) (HostHTTPResponse, error)
}

HTTPHost performs guarded outbound HTTP. Implementations must enforce the server's SSRF/egress policy before dialing.

type HostAccessSpec added in v0.2.3

type HostAccessSpec struct {
	RPC []RPCDependency `json:"rpc,omitempty"`
}

HostAccessSpec declares host-mediated dependencies owned by another plugin. It is signed manifest data; the server grants it only while this plugin is active and revokes it on disable. UI code never receives this structure.

type HostAudit added in v0.2.0

type HostAudit interface {
	RecordHostCall(ctx context.Context, event HostCallEvent)
}

HostAudit records broker allow/deny decisions for host API calls.

type HostCallEvent added in v0.2.0

type HostCallEvent struct {
	PluginID   string
	Action     string
	Capability string
	Decision   string
	Reason     string
}

HostCallEvent records one broker authorization decision.

type HostHTTPRequest added in v0.2.0

type HostHTTPRequest struct {
	Method string
	URL    string
	Header map[string]string
	Body   []byte
}

HostHTTPRequest is the broker's stable outbound HTTP request shape.

type HostHTTPResponse added in v0.2.0

type HostHTTPResponse struct {
	StatusCode int
	Header     map[string]string
	Body       []byte
}

HostHTTPResponse is the broker's stable outbound HTTP response shape.

type HostLogEntry added in v0.2.0

type HostLogEntry struct {
	PluginID string
	Level    string
	Message  string
	Fields   map[string]string
}

HostLogEntry is a plugin-authored structured log entry.

type HostServices added in v0.2.0

type HostServices struct {
	KV KVHost
	// Secret is the encrypted namespaced store (spec §9.4). When nil, a plugin
	// holding secret:read/secret:write gets ErrHostServiceUnavailable rather than
	// silently falling back to plaintext KV.
	Secret SecretHost
	// Task enqueues agent work for an APPROVED operation (spec §9.3). Reachable only
	// with task:run AND a context-bound operation grant, so a plugin cannot touch a
	// node outside a plan an operator read and approved.
	Task         TaskHost
	Notify       NotifyHost
	HTTP         HTTPHost
	OperatorHTTP OperatorHTTPHost
	Log          LogHost
	Audit        HostAudit
	// RPC dispatches inter-plugin calls (design-09 §F). When nil, a plugin with
	// rpc:call gets ErrHostServiceUnavailable rather than a panic.
	RPC RPCHost
	// GuardURL, when set, validates an outbound HTTP target's URL/host BEFORE the
	// broker delegates to HTTP.Do. It makes SSRF/egress guarding structural at the
	// broker boundary rather than relying on every HTTPHost implementation to
	// remember to guard. A non-nil error rejects the request before any dial. When
	// nil, the broker falls back to a built-in guard (see defaultGuardURL) so an
	// HTTPHost is never trusted by convention alone.
	GuardURL         func(url string) error
	GuardOperatorURL func(url string) error
}

HostServices are the real server-owned handles exposed through the broker. The broker keeps these handles behind per-call capability checks.

type HostTaskRequest added in v0.2.3

type HostTaskRequest struct {
	PluginID    string
	ApprovalID  string
	NodeID      string
	Interpreter string
	Script      string
	TimeoutSec  int
}

HostTaskRequest is the broker's stable task-enqueue shape.

type InterfaceContract added in v0.2.0

type InterfaceContract struct {
	Service string `json:"service"`
	// Methods remains the normalized name list so v1 callers keep their source
	// contract. MethodSpecs carries the signed v2 effect and method-level scopes.
	Methods     []string          `json:"-"`
	MethodSpecs []InterfaceMethod `json:"-"`
	Scopes      []string          `json:"scopes,omitempty"`
	// Backing is empty on manifests signed before the field existed. Empty stays
	// omitted from the signing payload, so those signatures remain byte-identical
	// and valid; the gateway resolves them through a logged legacy path until they
	// are re-signed with an explicit declaration.
	Backing string `json:"backing,omitempty"`
	// contains filtered or unexported fields
}

InterfaceContract declares an interface the plugin exposes (service + methods), callable through the dashboard->plugin gateway under the given scopes.

func (InterfaceContract) EffectiveBacking added in v0.2.3

func (c InterfaceContract) EffectiveBacking() string

EffectiveBacking resolves the declared backing, defaulting to runtime.

func (InterfaceContract) EffectiveMethodScopes added in v0.2.3

func (c InterfaceContract) EffectiveMethodScopes(name string) ([]string, bool)

func (InterfaceContract) MarshalJSON added in v0.2.3

func (c InterfaceContract) MarshalJSON() ([]byte, error)

func (InterfaceContract) MethodContract added in v0.2.3

func (c InterfaceContract) MethodContract(name string) (InterfaceMethod, bool)

func (InterfaceContract) MethodContracts added in v0.2.3

func (c InterfaceContract) MethodContracts() []InterfaceMethod

func (InterfaceContract) TypedMethods added in v0.2.3

func (c InterfaceContract) TypedMethods() bool

func (*InterfaceContract) UnmarshalJSON added in v0.2.3

func (c *InterfaceContract) UnmarshalJSON(data []byte) error

type InterfaceMethod added in v0.2.3

type InterfaceMethod struct {
	Name                 string            `json:"name"`
	Effect               string            `json:"effect"`
	Scopes               []string          `json:"scopes,omitempty"`
	OperatorTargetFields []string          `json:"operator_target_fields,omitempty"`
	Budget               *InvokeBudgetSpec `json:"budget,omitempty"`
}

type InvocationGenerationLease added in v0.2.3

type InvocationGenerationLease interface {
	Invoke(ctx context.Context, req InvokeRequest) (InvokeResponse, error)
	Release()
}

type InvokeBudgetSpec added in v0.2.3

type InvokeBudgetSpec struct {
	TimeoutMS   int `json:"timeout_ms"`
	StdoutBytes int `json:"stdout_bytes"`
	StderrBytes int `json:"stderr_bytes"`
	HostCalls   int `json:"host_calls"`
}

InvokeBudgetSpec is signed method-level runtime data. An absent budget stays additive and resolves to the old global defaults; a present budget must be complete so host_calls:0 can be used intentionally to forbid host calls.

func DefaultInvokeBudgetSpec added in v0.2.3

func DefaultInvokeBudgetSpec() InvokeBudgetSpec

func (*InvokeBudgetSpec) UnmarshalJSON added in v0.2.3

func (b *InvokeBudgetSpec) UnmarshalJSON(data []byte) error

type InvokeConstraints added in v0.2.3

type InvokeConstraints struct {
	OperatorTargets []string
	// Budget is the signed method-level runtime budget resolved by the host. Nil
	// is the additive compatibility path for already-signed manifests and resolves
	// to the old global defaults with a host warning.
	Budget *InvokeBudgetSpec
	// BudgetLabel is a stable service/method label used only for host logs.
	BudgetLabel string
	// Operation is the one-time authority for an approved host-risk operation (§9.3).
	// Like OperatorTargets it stays on the host side of the boundary: the plugin never
	// receives it, so it cannot forge or widen one — it can only make a host call that
	// the broker then checks against it.
	Operation *OperationGrant
}

InvokeConstraints are host-owned, invocation-scoped grants. They are never serialized to the child process and therefore cannot be expanded by plugin code after the operator call has been authorized.

type InvokeRequest added in v0.2.0

type InvokeRequest struct {
	PluginID    string
	Generation  uint64
	Action      string
	Payload     json.RawMessage
	Constraints InvokeConstraints
}

InvokeRequest asks an armed plugin to perform one action. Payload is the raw JSON body handed to the plugin; the runner frames {action,payload} as a single stdin line and reads the reply from stdout.

type InvokeResponse added in v0.2.0

type InvokeResponse struct {
	OK       bool            `json:"ok"`
	Message  string          `json:"message,omitempty"`
	Result   json.RawMessage `json:"result,omitempty"`
	Warnings []string        `json:"warnings,omitempty"`
}

InvokeResponse is the decoded plugin reply. Result carries the plugin's body (e.g. a rendered plan) for the host to act on under its own privileges.

type Invoker added in v0.2.0

type Invoker interface {
	Invoke(ctx context.Context, req InvokeRequest) (InvokeResponse, error)
}

Invoker is an optional runner capability: a request/response action protocol with the plugin. The system runner implements it; the noop runner does not.

type KVHost added in v0.2.0

type KVHost interface {
	Get(ctx context.Context, key string) ([]byte, bool, error)
	Put(ctx context.Context, key string, value []byte) error
}

KVHost is the plugin-facing KV subset. The implementation remains server-owned.

type LoadOutcome added in v0.2.0

type LoadOutcome struct {
	BundlePath string
	PluginID   string
	Loaded     bool
	Reason     string // failure reason when Loaded is false
}

LoadOutcome records the result of attempting to load one bundle so the caller can audit every accept and reject.

type Loaded added in v0.2.0

type Loaded struct {
	Manifest       Manifest
	Capabilities   []string
	BundlePath     string
	ArtifactPath   string
	ArtifactDigest string
	ExtractedRoot  string
	RuntimeEntry   string
	RuntimePath    string
	UIRoot         string
	UIEntry        string
	Inventory      map[string]BundleFile
	BundleLimits   BundleLimits
}

Loaded is a verified, registered plugin: the decoded manifest plus the capabilities the trust policy granted at load time. Execution (host-API binding and invocation) is a later milestone; loading establishes the verified registry and is the point at which signature/digest/capability trust is enforced.

type Loader added in v0.2.0

type Loader struct {
	Dir      string
	CacheDir string
	Platform string
	Limits   BundleLimits
	Policy   TrustPolicy
}

Loader discovers and verifies plugin bundles under Dir against an operator TrustPolicy. It never executes anything; it only decides what is trusted enough to register.

func (Loader) Load added in v0.2.0

func (l Loader) Load() ([]Loaded, []LoadOutcome, error)

Load scans the plugin directory and verifies each bundle. It returns the verified plugins (sorted by id) and a per-bundle outcome log. A bundle that fails verification is skipped and recorded as a failure — one bad bundle never aborts the scan or blocks startup. A missing/empty directory loads nothing.

type LogHost added in v0.2.0

type LogHost interface {
	Write(ctx context.Context, entry HostLogEntry) error
}

LogHost records a plugin-authored log entry after the broker stamps plugin id.

type Manifest

type Manifest struct {
	Schema           string             `json:"schema,omitempty"`
	ID               string             `json:"id"`
	Name             string             `json:"name"`
	Type             string             `json:"type"`
	Capabilities     []string           `json:"capabilities"`
	Version          string             `json:"version,omitempty"`
	Entrypoint       string             `json:"entrypoint,omitempty"`
	Publisher        string             `json:"publisher,omitempty"`
	DigestSHA256     string             `json:"digest_sha256,omitempty"`
	SignatureEd25519 string             `json:"signature_ed25519,omitempty"`
	Bundle           *BundleSpec        `json:"bundle,omitempty"`
	Runtime          *RuntimeSpec       `json:"runtime,omitempty"`
	UIRuntime        *UIRuntimeSpec     `json:"ui_runtime,omitempty"`
	Compatibility    *CompatibilitySpec `json:"compatibility,omitempty"`
	MinServer        string             `json:"min_server,omitempty"`
	HostAccess       *HostAccessSpec    `json:"host_access,omitempty"`
	// UI + Interfaces are the design-10 dashboard contributions: declarative data
	// (nav/views) + the interfaces the plugin exposes. They are covered by the
	// signature (see SigningPayload) so a tampered contribution fails verification.
	UI         *ManifestUI         `json:"ui,omitempty"`
	Interfaces []InterfaceContract `json:"interfaces,omitempty"`
	// Dependencies declares plugin-to-plugin requirements (design-18 D3/E1).
	// Required dependencies gate both load and activation; optional ones are
	// advisory. Covered by the v2 signing payload like every other field.
	Dependencies []DependencySpec `json:"dependencies,omitempty"`
}

func DecodeManifest added in v0.2.3

func DecodeManifest(manifestBytes []byte) (Manifest, error)

func VerifyInstallManifest added in v0.2.0

func VerifyInstallManifest(manifestBytes, artifact []byte, policy TrustPolicy) (Manifest, error)

func (Manifest) InterfaceFor added in v0.2.3

func (m Manifest) InterfaceFor(service string) (InterfaceContract, bool)

InterfaceFor returns the contract the manifest declares for a service.

type ManifestUI added in v0.2.0

type ManifestUI struct {
	Nav   []NavContribution  `json:"nav,omitempty"`
	Views []ViewContribution `json:"views,omitempty"`
}

ManifestUI is a plugin's dashboard contribution set.

type NavContribution struct {
	Section      string   `json:"section"`
	SectionTitle string   `json:"section_title,omitempty"`
	Title        string   `json:"title"`
	Route        string   `json:"route"`
	Icon         string   `json:"icon,omitempty"`
	Scopes       []string `json:"scopes,omitempty"`
}

NavContribution is a sidebar entry a plugin adds. Route is plugin-relative and mounted at /plugins/<id>/<route>.

type NotifyHost added in v0.2.0

type NotifyHost interface {
	Send(ctx context.Context, title, body string) error
}

NotifyHost sends an operator notification through server-owned channels.

type OperationExecuteRequest added in v0.2.3

type OperationExecuteRequest struct {
	ApprovalID string          `json:"approval_id"`
	Targets    []string        `json:"targets"`
	Data       json.RawMessage `json:"data,omitempty"`
}

OperationExecuteRequest is what the approval executor hands the plugin's `execute` action: the approved plan's opaque data and the approved targets. The plugin acts on this, but every task it then tries to enqueue is checked by the broker against the grant — so this payload is a convenience, not an authority.

type OperationGrant added in v0.2.3

type OperationGrant struct {
	ApprovalID string
	PluginID   string
	// PlanSHA256 is the hash of the exact approved plan text. Carried for audit so a
	// task can be tied back to the approval it ran under.
	PlanSHA256 string
	// Targets is the approved node set. The broker refuses any task aimed elsewhere, so
	// a plugin holding a legitimate grant still cannot reach an unapproved node.
	Targets []string
	// Remaining bounds how many tasks this single approved operation may enqueue.
	Remaining int
}

OperationGrant is the one-time, invocation-scoped authority handed to a plugin when the approval executor invokes it. It is bound into the invocation's context and is NEVER serialized to the child process: the plugin cannot read it, forge it, or widen it — it can only cause the broker to consult it by making a host call.

This mirrors how operator targets are bound (InvokeConstraints.OperatorTargets): the grant lives on the host side of the boundary, and the plugin's only interaction with it is that the broker checks a request against it.

func (*OperationGrant) AllowsTarget added in v0.2.3

func (g *OperationGrant) AllowsTarget(nodeID string) bool

AllowsTarget reports whether a node was in the approved set.

type OperatorHTTPHost added in v0.2.3

type OperatorHTTPHost interface {
	DoOperator(ctx context.Context, req HostHTTPRequest) (HostHTTPResponse, error)
}

OperatorHTTPHost performs HTTP to an explicitly operator-selected endpoint. It is separate from ordinary egress so private-network access cannot be enabled by a caller-controlled flag on http.do.

type OwnerActiveFunc added in v0.2.3

type OwnerActiveFunc func(pluginID string) bool

OwnerActiveFunc reports whether the plugin owning a service is currently active.

type PluginOperationPlan added in v0.2.3

type PluginOperationPlan struct {
	// Summary is the one-line intent an operator sees first.
	Summary string `json:"summary"`
	// Targets are the node IDs this operation would touch. The server authorizes each
	// one against the approving principal and records them as Approval.Targets; a plugin
	// cannot widen its own blast radius by naming extra nodes.
	Targets []string `json:"targets"`
	// Preview is the redacted, human-reviewable body of the change. It is what the
	// operator actually reads, so it must not contain secrets — the plugin redacts it,
	// and the server never reconstructs the unredacted form (§9.4).
	Preview string `json:"preview,omitempty"`
	// Steps are the ordered actions the plugin intends to take.
	Steps []string `json:"steps,omitempty"`
	// Rollback states what undoing this looks like. A plan that cannot say how it is
	// undone is a plan an operator cannot safely approve.
	Rollback string `json:"rollback,omitempty"`
	// Data is opaque plugin-owned state carried through approval back into execute. The
	// server does not interpret it; it hands back exactly what was approved.
	Data json.RawMessage `json:"data,omitempty"`
}

PluginOperationPlan is what a plugin's `plan`-effect method returns: a deterministic, reviewable description of what an apply would do. It is authored by the plugin and never trusted as authorization — only as a proposal. It is what the server stores in Approval.Plan and what the operator reads.

func ParseOperationPlan added in v0.2.3

func ParseOperationPlan(plan string) (PluginOperationPlan, error)

ParseOperationPlan reads back a stored plan.

type PoolCleanupResult added in v0.2.3

type PoolCleanupResult struct {
	Generation    uint64
	Err           error
	ResidualPGIDs []int
	Stage         string
	PendingStages []string
}

PoolCleanupResult is the owned, generation-scoped teardown ledger. A future is returned so callers can broadcast abort requests first and join all transports under their own deadline.

type RPCDependency added in v0.2.3

type RPCDependency struct {
	Service string   `json:"service"`
	Methods []string `json:"methods"`
}

type RPCGrant added in v0.2.3

type RPCGrant map[string]map[string]struct{}

type RPCGrantedHost added in v0.2.3

type RPCGrantedHost interface {
	CallGranted(ctx context.Context, caller string, grant RPCGrant, service, method string, request []byte) ([]byte, error)
}

type RPCHandler added in v0.2.0

type RPCHandler func(ctx context.Context, method string, request []byte) ([]byte, error)

RPCHandler serves one inter-plugin RPC method: it receives the method name and raw request bytes and returns raw response bytes. Implementations must be safe for concurrent use; the registry invokes them WITHOUT holding its lock.

type RPCHost added in v0.2.0

type RPCHost interface {
	Call(ctx context.Context, caller, service, method string, request []byte) ([]byte, error)
}

RPCHost dispatches an inter-plugin RPC call to a server-owned registry that resolves the target service, enforces the directed caller->callee allow-list, and invokes the callee's handler. caller is the VERIFIED id of the calling plugin, supplied by the broker; a plugin cannot spoof it.

type RPCRegistry added in v0.2.0

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

RPCRegistry is the server-owned inter-plugin RPC bus. It is safe for concurrent use and implements the broker's RPCHost interface.

func NewRPCRegistry added in v0.2.0

func NewRPCRegistry() *RPCRegistry

NewRPCRegistry returns an empty registry.

func (*RPCRegistry) Allow added in v0.2.0

func (r *RPCRegistry) Allow(callerPluginID, service string)

Allow grants callerPluginID permission to call service. Grants are directed and additive; a service owner can always call its own service.

func (*RPCRegistry) AllowMethods added in v0.2.3

func (r *RPCRegistry) AllowMethods(callerPluginID, service string, methods []string)

AllowMethods grants only the named methods. This prevents a plugin from inheriting future methods added to a dependency service.

func (*RPCRegistry) Call added in v0.2.0

func (r *RPCRegistry) Call(ctx context.Context, caller, service, method string, request []byte) ([]byte, error)

Call implements RPCHost: enforce the directed allow-list (the owner may always self-call), then reveal service/lifecycle/method details only to authorized callers. The handler runs OUTSIDE the lock so a slow or re-entrant handler cannot block the bus.

func (*RPCRegistry) CallGranted added in v0.2.3

func (r *RPCRegistry) CallGranted(ctx context.Context, caller string, grant RPCGrant, service, method string, request []byte) ([]byte, error)

func (*RPCRegistry) CallOperator added in v0.2.0

func (r *RPCRegistry) CallOperator(ctx context.Context, service, method string, request []byte) ([]byte, error)

CallOperator dispatches a service method on behalf of the OPERATOR (the dashboard gateway), bypassing the plugin->plugin directed allow-list — the HTTP layer has already enforced the interface's declared RBAC scopes + audit. Service/method-not-found are still errors. The handler runs OUTSIDE the lock.

func (*RPCRegistry) Owns added in v0.2.3

func (r *RPCRegistry) Owns(ownerPluginID, service string) bool

Owns reports whether service is registered by ownerPluginID. The dashboard gateway uses this exact owner check before dispatching a v2 plugin call to an in-core implementation; a manifest cannot claim another plugin's service.

func (*RPCRegistry) Register added in v0.2.0

func (r *RPCRegistry) Register(ownerPluginID, service, version string, methods []string, handler RPCHandler) error

Register adds (or replaces) a service exposed by ownerPluginID. service is the fully-qualified id (e.g. "latticenet.vpn-core/nodes"); it must carry >=1 non-empty method and a non-nil handler. Re-registering the same id replaces it (used on plugin restart). The caller (server) is responsible for verifying the owner declared rpc:expose before registering.

func (*RPCRegistry) Revoke added in v0.2.0

func (r *RPCRegistry) Revoke(callerPluginID, service string)

Revoke removes a previously granted directed edge.

func (*RPCRegistry) Services added in v0.2.0

func (r *RPCRegistry) Services() []RPCServiceDescriptor

Services returns descriptors for every registered service, sorted by id, for discovery (e.g. an rpc.List host call). Handlers are not exposed.

func (*RPCRegistry) SetOwnerActive added in v0.2.3

func (r *RPCRegistry) SetOwnerActive(fn OwnerActiveFunc)

SetOwnerActive installs the lifecycle predicate consulted before every dispatch. Until it is set the registry serves any registered service, which is the correct default for a bus with no lifecycle to consult (tests, boot).

func (*RPCRegistry) Unregister added in v0.2.0

func (r *RPCRegistry) Unregister(service string)

Unregister removes a service and any grants targeting it (e.g. on disable).

type RPCServiceDescriptor added in v0.2.0

type RPCServiceDescriptor struct {
	Service string   `json:"service"`
	Owner   string   `json:"owner"`
	Version string   `json:"version"`
	Methods []string `json:"methods"`
}

RPCServiceDescriptor is the discovery shape returned by RPCRegistry.Services. Handlers are never exposed.

type ResolvedInvokeBudget added in v0.2.3

type ResolvedInvokeBudget struct {
	Timeout     time.Duration
	StdoutBytes int
	StderrBytes int
	HostCalls   int
	Declared    bool
}

func ResolveInvokeBudget added in v0.2.3

func ResolveInvokeBudget(spec *InvokeBudgetSpec, defaults InvokeBudgetSpec) ResolvedInvokeBudget

type Runner added in v0.2.0

type Runner interface {
	Name() string
	Start(ctx context.Context, req RunnerStartRequest) (RunnerStartResult, error)
	Stop(ctx context.Context, req RunnerStopRequest) error
}

Runner is the narrow runtime contract concrete plugin runtimes must satisfy. It receives a verified plugin and a capability-scoped broker, never raw server handles. Implementations must honor ctx cancellation and deadlines.

type RunnerCloser added in v0.2.3

type RunnerCloser interface {
	StopAll(ctx context.Context) error
}

type RunnerStartRequest added in v0.2.0

type RunnerStartRequest struct {
	PluginID   string
	Generation uint64
	Loaded     Loaded
	Broker     *Broker
}

type RunnerStartResult added in v0.2.0

type RunnerStartResult struct {
	Message string
}

type RunnerStopRequest added in v0.2.0

type RunnerStopRequest struct {
	PluginID   string
	Reason     string
	Generation uint64
}

type RuntimeManager added in v0.2.0

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

RuntimeManager binds verified plugins to capability-scoped brokers and tracks runtime health. The current implementation is an execution-safe skeleton: it arms host-API access for a verified plugin but does not spawn processes, load wasm, or invoke artifact code.

func NewRuntimeManager added in v0.2.0

func NewRuntimeManager(services HostServices) *RuntimeManager

func NewRuntimeManagerWithOptions added in v0.2.0

func NewRuntimeManagerWithOptions(opts RuntimeManagerOptions) *RuntimeManager

func (*RuntimeManager) Close added in v0.2.3

func (m *RuntimeManager) Close(ctx context.Context) error

Close atomically closes runtime admission, invalidates every pending start, and joins runner-owned generations before returning.

func (*RuntimeManager) Invoke added in v0.2.0

func (m *RuntimeManager) Invoke(ctx context.Context, pluginID, action string, payload json.RawMessage) (InvokeResponse, error)

Invoke dispatches one action to an armed plugin whose runner supports the request/response protocol. It fails closed if the plugin is not armed or its runner is not an Invoker (e.g. the noop runner), so a disabled or execution-disabled plugin can never be invoked.

func (*RuntimeManager) InvokeConstrained added in v0.2.3

func (m *RuntimeManager) InvokeConstrained(ctx context.Context, pluginID, action string, payload json.RawMessage, constraints InvokeConstraints) (InvokeResponse, error)

func (*RuntimeManager) IsArmed added in v0.2.0

func (m *RuntimeManager) IsArmed(pluginID string) bool

func (*RuntimeManager) Snapshot added in v0.2.0

func (m *RuntimeManager) Snapshot() map[string]RuntimeStatus

func (*RuntimeManager) Start added in v0.2.0

func (m *RuntimeManager) Start(ctx context.Context, loaded Loaded) (RuntimeStatus, error)

Start validates the loaded plugin, creates its broker, and marks it armed. The context is accepted now so future runners can honor cancellation without changing the call site.

func (*RuntimeManager) Status added in v0.2.0

func (m *RuntimeManager) Status(pluginID string) (RuntimeStatus, bool)

func (*RuntimeManager) Stop added in v0.2.0

func (m *RuntimeManager) Stop(pluginID, message string) (RuntimeStatus, error)

type RuntimeManagerOptions added in v0.2.0

type RuntimeManagerOptions struct {
	Services     HostServices
	Runners      map[string]Runner
	StartTimeout time.Duration
}

type RuntimeShutdownError added in v0.2.3

type RuntimeShutdownError struct {
	PluginID      string
	Stage         string
	PendingStages []string
	Err           error
}

RuntimeShutdownError reports a caller-bounded observation of physical shutdown without transferring or abandoning manager ownership.

func (*RuntimeShutdownError) Error added in v0.2.3

func (e *RuntimeShutdownError) Error() string

func (*RuntimeShutdownError) Unwrap added in v0.2.3

func (e *RuntimeShutdownError) Unwrap() error

type RuntimeSpec added in v0.2.3

type RuntimeSpec struct {
	Protocol    string            `json:"protocol"`
	Entrypoints map[string]string `json:"entrypoints"`
}

type RuntimeStatus added in v0.2.0

type RuntimeStatus struct {
	PluginID  string    `json:"plugin_id"`
	State     string    `json:"state"`
	Runner    string    `json:"runner,omitempty"`
	Message   string    `json:"message,omitempty"`
	StartedAt time.Time `json:"started_at,omitempty"`
	StoppedAt time.Time `json:"stopped_at,omitempty"`
	UpdatedAt time.Time `json:"updated_at"`
}

RuntimeStatus is the public, non-secret health view for one plugin runtime. It deliberately excludes local bundle paths and the broker itself.

type SecretHost added in v0.2.3

type SecretHost interface {
	Get(ctx context.Context, key string) (string, bool, error)
	Put(ctx context.Context, key, value string) error
	Delete(ctx context.Context, key string) error
}

SecretHost is the plugin-facing encrypted-secret subset (spec §9.4). It is shaped like KVHost on purpose, but the implementation stores values through the server's at-rest cipher. The distinction is not a naming convention: a value written here is encrypted in the persisted state, and a value written through KVHost is not.

There is no List. A plugin reads back a key it chose to write; it cannot enumerate its own vault, so a read-only compromise cannot sweep for secrets whose names it does not already know.

type SystemPoolCircuitTransition added in v0.2.3

type SystemPoolCircuitTransition int

SystemPoolCircuitTransition names a circuit-breaker state change.

const SystemPoolCircuitOpened SystemPoolCircuitTransition = 1

SystemPoolCircuitOpened is the closed-to-open transition. Re-arming is not observed here: the pool opens the circuit at a decision point, but closing arrives from operator recovery flows whose truth lives elsewhere.

type SystemPoolConfig added in v0.2.3

type SystemPoolConfig struct {
	Size         int
	MaxOverflow  int
	StartTimeout time.Duration
	MaxUses      int
	MaxAge       time.Duration
}

SystemPoolConfig configures the persistent stdio-json-v2 worker pool.

type SystemPoolDurationPhase added in v0.2.3

type SystemPoolDurationPhase int

SystemPoolDurationPhase names one measured span of a pooled invocation or worker start. The zero value is deliberately invalid so an unset phase can never masquerade as a real one.

const (
	// SystemPoolDurationQueue is the wait for a pooled worker, successful or
	// not: the time an invocation spent owning no worker.
	SystemPoolDurationQueue SystemPoolDurationPhase = iota + 1
	// SystemPoolDurationStart is one worker start attempt, from spawn to
	// readiness or failure.
	SystemPoolDurationStart
	// SystemPoolDurationHandler is the span the invocation actually held the
	// worker's transport.
	SystemPoolDurationHandler
	// SystemPoolDurationTotal is the whole pooled invocation as the caller
	// experienced it, queue included.
	SystemPoolDurationTotal
)

type SystemPoolLifecycleEvent added in v0.2.3

type SystemPoolLifecycleEvent int

SystemPoolLifecycleEvent names one countable pool outcome.

const (
	// SystemPoolLifecycleWorkerStartSuccess is a worker that reached readiness.
	SystemPoolLifecycleWorkerStartSuccess SystemPoolLifecycleEvent = iota + 1
	// SystemPoolLifecycleWorkerStartFailure is a start attempt that did not,
	// canceled shutdown attempts excluded.
	SystemPoolLifecycleWorkerStartFailure
	// SystemPoolLifecycleInvocationReusable is an invocation whose worker came
	// back reusable.
	SystemPoolLifecycleInvocationReusable
	// SystemPoolLifecycleInvocationFailure is an invocation that poisoned its
	// worker.
	SystemPoolLifecycleInvocationFailure
)

type SystemPoolObserver added in v0.2.3

type SystemPoolObserver interface {
	ObserveSystemPoolDuration(phase SystemPoolDurationPhase, d time.Duration)
	ObserveSystemPoolLifecycle(event SystemPoolLifecycleEvent)
	ObserveSystemPoolCircuit(transition SystemPoolCircuitTransition)
	ObserveSystemPoolRetirement(reason SystemPoolRetirementReason)
}

SystemPoolObserver receives warm-pool observations at the exact points where the pool decides a worker's or invocation's fate. Implementations must be cheap and must not call back into the runner or pool; a nil observer is valid and observes nothing.

type SystemPoolRetirementReason added in v0.2.3

type SystemPoolRetirementReason int

SystemPoolRetirementReason names why exactly one worker left the pool.

const (
	// SystemPoolRetirementPoisoned is an invocation-declared terminal failure.
	SystemPoolRetirementPoisoned SystemPoolRetirementReason = iota + 1
	// SystemPoolRetirementMaxUses is the configured use ceiling.
	SystemPoolRetirementMaxUses
	// SystemPoolRetirementMaxAge is the configured age ceiling.
	SystemPoolRetirementMaxAge
	// SystemPoolRetirementCircuitOpen is a worker dropped because the circuit
	// opened, at lease end or from the idle set.
	SystemPoolRetirementCircuitOpen
	// SystemPoolRetirementShutdown is a worker dropped by drain or close.
	SystemPoolRetirementShutdown
	// SystemPoolRetirementRejected is a worker the pool refused to keep: built
	// for a superseded generation, arriving past capacity, or otherwise valid
	// work the pool's current state has no place for.
	SystemPoolRetirementRejected
)

type SystemRunner added in v0.2.0

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

SystemRunner implements Runner and Invoker.

func NewSystemRunner added in v0.2.0

func NewSystemRunner(opts SystemRunnerOptions) (*SystemRunner, error)

NewSystemRunner returns a checked system runner with the given options and safe defaults for any zero-valued legacy invocation bound.

func (*SystemRunner) AbortGeneration added in v0.2.3

func (r *SystemRunner) AbortGeneration(ctx context.Context, pluginID string, generation uint64) error

func (*SystemRunner) AcquireInvocation added in v0.2.3

func (r *SystemRunner) AcquireInvocation(pluginID string, generation uint64) (InvocationGenerationLease, error)

func (*SystemRunner) ActivateGeneration added in v0.2.3

func (r *SystemRunner) ActivateGeneration(pluginID string, generation uint64) error

func (*SystemRunner) Invoke added in v0.2.0

func (*SystemRunner) Name added in v0.2.0

func (r *SystemRunner) Name() string

func (*SystemRunner) Prepare added in v0.2.3

Prepare stages and starts an exact generation without admitting invocations.

func (*SystemRunner) RetireGeneration added in v0.2.3

func (r *SystemRunner) RetireGeneration(ctx context.Context, pluginID string, generation uint64) error

func (*SystemRunner) Start added in v0.2.0

Start re-verifies the manifest-pinned digest of the artifact at the FIXED bundle path (TOCTOU defense in case the bundle changed after load), copies the bytes into a confined per-plugin 0700 working dir, and arms the runner. It always executes the staged 0700 copy, never the (possibly read-only or swapped) bundle file, and never resolves a manifest-controlled path.

func (*SystemRunner) Stop added in v0.2.0

Stop clears the plugin's staged state and removes its runtime dir. In-flight invocations are bound to their own context and terminate independently.

func (*SystemRunner) StopAll added in v0.2.3

func (r *SystemRunner) StopAll(ctx context.Context) error

StopAll drains every generation and reaps all persistent workers during graceful server shutdown.

type SystemRunnerOptions added in v0.2.0

type SystemRunnerOptions struct {
	// RuntimeDir is the root under which each plugin gets a confined 0700 working
	// directory (RuntimeDir/<pluginID>) holding a 0700 copy of its verified
	// artifact. Required.
	RuntimeDir string
	// EnvAllowlist names the environment variables forwarded to the plugin. Every
	// other variable is stripped; a fixed safe PATH is always provided.
	EnvAllowlist []string
	// InvokeTimeout bounds one invocation (default 10s).
	InvokeTimeout time.Duration
	// StopGrace is the SIGTERM->SIGKILL window for a timed-out/cancelled process
	// (default 3s).
	StopGrace time.Duration
	// MaxOutputBytes caps captured stdout and (separately) stderr per invocation
	// (default 1 MiB), so a plugin cannot exhaust host memory by flooding output.
	MaxOutputBytes int
	// CrashThreshold trips the circuit breaker after this many consecutive failed
	// invocations (default 5).
	CrashThreshold int
	// MaxHostCalls caps broker calls during one invocation (default 64).
	MaxHostCalls int
	// Logf receives host-visible runtime warnings. Nil disables warning logs.
	Logf func(format string, args ...any)
	// Pool controls stdio-json-v2 worker capacity and retirement. Nil uses safe
	// host defaults; a non-nil value is validated exactly, including zero overflow.
	Pool *SystemPoolConfig
	// PoolObserver receives warm-pool telemetry at the pool's decision points.
	// Nil observes nothing. The observer must be cheap and must not call back
	// into the runner.
	PoolObserver SystemPoolObserver
}

SystemRunnerOptions configures the trusted-subprocess runner.

type TaskHost added in v0.2.3

type TaskHost interface {
	Enqueue(ctx context.Context, req HostTaskRequest) (string, error)
}

TaskHost enqueues bounded agent work. The implementation remains server-owned and applies the operator's own task validation, so a plugin can never reach a wider interpreter set, a longer timeout, or a bigger script than an operator could.

type TransactionalRunner added in v0.2.3

type TransactionalRunner interface {
	Runner
	Prepare(ctx context.Context, req RunnerStartRequest) (RunnerStartResult, error)
	ActivateGeneration(pluginID string, generation uint64) error
	AbortGeneration(ctx context.Context, pluginID string, generation uint64) error
	RetireGeneration(ctx context.Context, pluginID string, generation uint64) error
}

TransactionalRunner separates candidate preparation from admission. A prepared generation must not be invokable until ActivateGeneration succeeds; failed/stale candidates are removed with AbortGeneration, while an old committed generation is retired only after the manager publishes its replacement.

type TrustPolicy added in v0.2.0

type TrustPolicy struct {
	TrustedPublishers map[string]ed25519.PublicKey
	// AllowUnsignedHostRisk opts OUT of signature enforcement for host-risk
	// plugins. The zero value is fail-closed: host-risk plugins require a trusted
	// publisher signature unless an operator explicitly sets this true (dev only).
	AllowUnsignedHostRisk bool
}

func ParseTrustPolicyJSON added in v0.2.0

func ParseTrustPolicyJSON(data []byte) (TrustPolicy, error)

type UIRuntimeSpec added in v0.2.3

type UIRuntimeSpec struct {
	Mode          string `json:"mode"`
	Entrypoint    string `json:"entrypoint"`
	BridgeVersion string `json:"bridge_version"`
}

type ViewAction added in v0.2.0

type ViewAction struct {
	Label     string          `json:"label"`
	Interface string          `json:"interface"`
	Method    string          `json:"method"`
	Form      []ViewFormField `json:"form,omitempty"`
	Scopes    []string        `json:"scopes,omitempty"`
}

ViewAction is a button that calls an interface method (optionally with a form).

type ViewColumn added in v0.2.0

type ViewColumn struct {
	Key    string `json:"key"`
	Label  string `json:"label"`
	Render string `json:"render,omitempty"`
}

ViewColumn is one table column. Render selects a safe dashboard formatter.

type ViewContribution added in v0.2.0

type ViewContribution struct {
	Route   string       `json:"route"`
	Title   string       `json:"title"`
	Kind    string       `json:"kind"`
	Source  *ViewSource  `json:"source,omitempty"`
	Columns []ViewColumn `json:"columns,omitempty"`
	Actions []ViewAction `json:"actions,omitempty"`
}

ViewContribution is one declarative view rendered by a fixed dashboard primitive.

type ViewFormField added in v0.2.0

type ViewFormField struct {
	Key     string   `json:"key"`
	Label   string   `json:"label,omitempty"`
	Kind    string   `json:"kind"`
	Options []string `json:"options,omitempty"`
}

ViewFormField is one input in an action form.

type ViewSource added in v0.2.0

type ViewSource struct {
	Interface string `json:"interface"`
	Method    string `json:"method"`
}

ViewSource binds a view's data to a plugin interface method.

Jump to

Keyboard shortcuts

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