Plugin Framework
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/ projects ship a trust-driven sandbox: StellaOps.Plugin.Host derives a runtime SandboxMode from each plugin’s verified trust level via SandboxModeMatrix.FromTrust (StellaOps.Plugin.Sandbox/SandboxMode.cs) — BuiltIn → InProcessHardened, Trusted → OutOfProcessOverlay, Untrusted → OutOfProcessConfined. OutOfProcess* modes run the plugin in a separate OS process (ProcessSandbox) with an overlay filesystem, network-policy enforcement, resource limits, and a gRPC bridge; OutOfProcessConfined additionally attaches an OS-level confinement profile (AppArmor/SELinux on Linux, Job Object on Windows) and fails closed if it cannot be attached.
Two distinct hosts exist. This dossier (
Source: src/Plugin/) documents the sandbox-capable host. A separate, older library atsrc/__Libraries/StellaOps.Plugin/(PluginHost/PluginManifestLoader/NullPluginVerifier) is a simpler shared host that does not ship process sandboxing; consumers of that host must provide their own isolation. Integrations runs a narrowstellaops.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. See architecture.md for the full distinction.
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 aSandboxMode(“what may it do at runtime?”) per PSB-01:BuiltIn → InProcessHardened(loads in the host’s defaultAssemblyLoadContextbut filesystem/process-spawn calls are interposed throughIFilesystemPolicy/IProcessSpawnPolicy);Trusted → OutOfProcessOverlay(process sandbox + overlay filesystem, no OS confinement profile);Untrusted → OutOfProcessConfined(process sandbox + overlay filesystem + AppArmor/SELinux/Job Object, fail-closed on attach failure). - Process sandboxing:
StellaOps.Plugin.SandboxshipsProcessSandbox(ISandbox/ISandboxFactory) for out-of-process plugins:IPluginProcessManagerprocess management,OverlayFilesystemPolicywrite redirection,NetworkPolicyEnforcer, Linux/WindowsIResourceLimiter(CPU/memory/process/file-handle limits),LinuxAppArmorAttacher/ApparmorAuditLogScraper, 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 by leaf-certificate thumbprint allowlists (BuiltInSignerThumbprints/TrustedSignerThumbprintsonPluginHostOptions); the pre-PSV-04 plain-text id/vendor allowlists are retained as[Obsolete]properties.AllowUnsignedPluginsInDevelopment(Development-only) andAllowMissingTrustRootBundle(boot escape hatch) 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). The PostgreSQL schema isplatformwith tablesplugins,plugin_capabilities,plugin_instances(multi-tenant), andplugin_health_history(migration001_CreatePluginTables.sql, applied byPluginRegistryMigrationRunner). - 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.
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: agent hosts (
Agent.Host,Agent.DeployNative/Compose,Agent.Build*), WebApi, 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 - Concelier / AdvisoryAI / Authority -
*.Plugin.Unifiedplugin packs
Note: Integrations and Scanner consume the older
src/__Libraries/StellaOps.Plugin/shared host (sandbox-free), not thesrc/Plugin/projects above. Treat their connector/analyzer plugins as consumers of that separate library.
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.
