Plugin Framework
Verified against commit
942a18727c(2026-09-26). Re-verify with:ls src/Plugin src/Plugin/StellaOps.Plugin.Registry.Persistence/Migrations && rg -n "FromTrust" src/Plugin/StellaOps.Plugin.Sandbox/SandboxMode.cs src/Plugin/StellaOps.Plugin.Host/PluginHost.cs
Universal extensibility framework providing deterministic plugin discovery, admission checks, registry models, and SDK support for building Stella Ops plugins.
Audience: plugin authors building connectors, analyzers, or gate/step providers, and module owners who load plugins into their service hosts.
Purpose
The Plugin Framework is a foundational library that provides a consistent plugin lifecycle, deterministic discovery, signature/version admission checks, process/in-process sandboxing, and a persistent registry for Stella Ops modules. It is consumed as a library by other modules and exposes no HTTP endpoints.
The src/Plugin/ host derives a runtime SandboxMode from each plugin’s verified trust level via SandboxModeMatrix.FromTrust (StellaOps.Plugin.Sandbox/SandboxMode.cs). Today BuiltIn plugins load in-process with policy-interposed filesystem and process-spawn calls; Trusted plugins run out of process through ProcessSandbox behind a SandboxedPluginProxy; Untrusted plugins (valid signature, signer not allowlisted) still load in-process in an isolated, collectible AssemblyLoadContext, because the confined process runner is not yet wired into the host. See architecture.md.
Two distinct hosts exist. This dossier (
src/Plugin/) documents the sandbox-capable host used by Release Orchestrator. A separate, older library atsrc/__Libraries/StellaOps.Plugin/(PluginHost/PluginManifestLoader/NullPluginVerifier) is a lightweight shared host with admission checks and no process sandboxing; Integrations, Scanner and the JobEngine Scheduler use it. Integrations adds its ownstellaops.pluginhost.process.v1child-runner path for production admission, allowlistedintegration:test-connection/integration:health-check/integration:discoveryexecution, deterministic dead-runner evidence and brokered single-authref secret materialization.
Quick Links
- Architecture - Technical design and implementation details
- Sandbox confinement events - Stable
plugin.sandbox.*event-name contract (StellaOps.Plugin.Sandbox/Diagnostics/PluginSandboxEventName.cs)
Status
| Attribute | Value |
|---|---|
| Maturity | Production |
| Source | src/Plugin/ |
Key Features
- IPlugin interface and lifecycle:
IPlugin(extendsIAsyncDisposable) is the contract for all plugins. ThePluginLifecycleStateenum (StellaOps.Plugin.Abstractions/Lifecycle/PluginLifecycleState.cs) defines nine states:Discovered (0),Loading (1),Initializing (2),Active (3),Degraded (4),Stopping (5),Stopped (6),Failed (7),Unloading (8). There is noStartAsync/StopAsyncon the plugin itself — the host drives start/stop; the plugin exposesInitializeAsync, a periodicHealthCheckAsync, and disposal-based shutdown. - Trust levels and sandbox modes:
PluginTrustLevel(BuiltIn = 0,Trusted = 1,Untrusted = 2) is the cryptographic pre-load verdict (“who is the plugin?”);SandboxModeMatrix.FromTrustmaps it to the intendedSandboxMode(“what may it do at runtime?”) per PSB-01:BuiltIn → InProcessHardened,Trusted → OutOfProcessOverlay,Untrusted → OutOfProcessConfined. The first two are wired into the host;Untrustedcurrently loads in-process in an isolated load context, not in a confined process. - Process sandboxing:
StellaOps.Plugin.SandboxshipsProcessSandbox(ISandbox/ISandboxFactory, registered byAddPluginHost) for out-of-process plugins:IPluginProcessManagerprocess management,OverlayFilesystemPolicywrite redirection,NetworkPolicyEnforcer, Linux/WindowsIResourceLimiter(the Windows limiter uses a Job Object),LinuxAppArmorAttacher/ApparmorAuditLogScraper(SELinux has event names only, no attacher), and anIGrpcPluginBridgeover aplugin_bridge.protoclient. The host wires this viaSandboxedPluginProxy, which preserves theIPluginlifecycle without loading the plugin assembly into the host process.AssemblyPluginLoaderrejectsTrustedplugins (they must launch throughProcessSandbox). - Sandbox confinement diagnostics: Stable
plugin.sandbox.*event names (PluginSandboxEventName) form a binding contract for workspace, OS-confinement, resource-limiter, and lifecycle-denial events — e.g.plugin.sandbox.confinement.profile_attached,plugin.sandbox.confinement.fail_closed,plugin.sandbox.resource_limiter.exceeded,plugin.sandbox.lifecycle.start_denied. See sandbox-confinement-events.md. - Signature & trust admission:
PluginTrustDecisionMakerplusX509PinnedSignatureValidatorandPemDirectoryPluginTrustRootverify aplugin.signature.jsonagainst a PEM trust bundle. Trust is promoted only by leaf-certificate thumbprint allowlists (BuiltInSignerThumbprints/TrustedSignerThumbprintsonPluginHostOptions); a valid signature from any other signer yieldsUntrusted, and an invalid one is rejected.AllowUnsignedPluginsInDevelopment(honoured only in Development) andAllowMissingTrustRootBundle(boot escape hatch, defaultfalse) gate the fail-closed posture. - License (SPDX) admission:
DefaultLicenseValidator/SpdxExpression/LicensePolicyOptionsenforce the manifestinfo.licensefield against allow/deny lists during discovery. - Plugin registry: Persistent catalog with version tracking —
InMemoryPluginRegistryfor tests andPostgresPluginRegistryfor production (IPluginRegistry). Tablesplugins,plugin_capabilitiesandplugin_instances(multi-tenant) live in the registering host’s database underPluginRegistryOptions.SchemaName(defaultplatform), created by the embedded migrations insrc/Plugin/StellaOps.Plugin.Registry.Persistence/Migrations/and applied byPluginRegistryMigrationRunner. Migration003_retire_plugin_health_history.sql(RFC-19) removes the unusedplugin_health_historytable; health is kept only as the current status on the plugin row. - Capability declarations: The
PluginCapabilities[Flags]enum (long-backed) declares what a plugin provides — core (Crypto,Auth,Llm,Secrets), connector (Scm,Registry,Ci,Vault,Notification,IssueTracker), analysis (Analysis,Feed,Sbom), infrastructure (Network,FilesystemRead,FilesystemWrite,Process,Transport), and orchestrator (StepProvider,GateProvider,TargetProvider,EvidenceProvider,Execution) bits, withAllConnectors/AllOrchestrator/AllInfrastructurecomposites. Plugin manifests additionally carry typedCapabilityDeclarationentries and (Pattern Z, ADR-011) arequireslist ofPluginRequirementservice contracts. - SDK and test utilities:
StellaOps.Plugin.Sdk(PluginBase,PluginInfoBuilder, options/config helpers) for plugin authors;StellaOps.Plugin.Testing(PluginTestHost, fake services/logger, deterministicTimeProvider/GUID) for deterministic harnesses;StellaOps.Plugin.Host.Toolprovides a CLI host;Samples/StellaOps.Plugin.Samples.HelloWorlddemonstrates the SDK.
Testing
Tests live under src/Plugin/__Tests/ (Abstractions, Host, Registry, Sandbox, Sdk). The sandbox suites also run in the platform-specific CI lanes .gitea/workflows/plugin-linux-os-confinement.yml, plugin-linux-overlay-sandbox.yml, plugin-windows-filesystem-sandbox.yml and plugin-windows-os-confinement.yml. StellaOps.Plugin.Sandbox.Tests references Microsoft.Extensions.Logging directly (it previously received logging only through a removed transitive test reference). Lane status is tracked in the active sprint, not here.
Dependencies
Upstream (this module depends on)
- Cryptography (
StellaOps.Cryptography) -StellaOps.Plugin.Hostroutes asymmetric signature verification through the canonical crypto assembly (PSV-01…03). Otherwise foundational with no module-level upstream dependencies.
Downstream (modules that depend on this)
Consumers of the src/Plugin/host/abstractions/registry/sandbox/SDK projects documented here:
- Release Orchestrator - Primary consumer of the host: agent hosts (
Agent.Host,Agent.DeployNative/Compose,Agent.Build*), WebApi (which also registersPostgresPluginRegistry), and the orchestrator plugin SDK/IntegrationHub - Platform -
Platform.WebServiceandPlatform.Database - Router / Gateway -
Router.Common,Gateway.WebService, and*.Plugin.Unifiedpacks - Cryptography -
StellaOps.Cryptography.Plugin/.Plugin.Hsm - AdvisoryAI / Authority / Notify / Doctor / Signer / CLI / OfflineKit (export adapters) - reference
src/Plugin/projects (re-verify withrg -l "StellaOps.Plugin.(Abstractions|Host|Sandbox|Sdk)" src --glob "*.csproj")
Note: Integrations, Scanner and JobEngine (Scheduler job plugins) load plugins through the older
src/__Libraries/StellaOps.Plugin/shared host (sandbox-free) and reference onlyStellaOps.Plugin.Abstractionsfromsrc/Plugin/.
Related Documentation
- Architecture - Full component and contract reference, including the two-host distinction
- Sandbox confinement events - Binding
plugin.sandbox.*event-name contract - Release Orchestrator - Primary consumer of the
src/Plugin/host (agents, gates, deploy) - Integrations - Consumer of the older
__Libraries/StellaOps.Pluginshared host (connector plugins) - Scanner - Consumer of the older
__Libraries/StellaOps.Pluginshared host (analysis extensibility) - Plugin system architecture - Authoritative dossier covering signature verification (SPRINT_20260501_001) and SPDX license enforcement (SPRINT_20260501_002). Plugin authors: see the “License declaration (SPDX)” section for the required
info.licensefield and the default allow / deny lists.
