Plugin SDK Guide

Audience: developers extending Stella Ops with custom plugins (identity providers, connectors, analyzers, transports, CLI command modules, and the like).

This guide explains how Stella Ops loads, validates, and wires restart-time plugins. It is intentionally cross-cutting: module-specific plugin contracts (Authority identity providers, Concelier connectors, Scanner analyzers, CLI command modules, etc.) live in the corresponding module dossiers under docs/modules/.

1) What a “plugin” means in Stella Ops

Stella Ops uses plugins to extend behavior without losing:

Most services load plugins at process start (restart-time). Hot reload is not a goal: restart-time loading keeps memory and dependency isolation predictable.

2) Service plugin loading model (restart-time)

Service plugins are loaded by the StellaOps.Plugin library:

2.1 Plugin directory and discovery patterns

Default behavior (from StellaOps.Plugin.Hosting.PluginHostOptions):

Hosts may override the directory and/or add explicit searchPatterns in their config. Use module operations docs to see the authoritative configuration for a given service.

2.2 Deterministic ordering

The loader is deterministic:

3) Version compatibility requirements

Plugins should declare the assembly-level attribute:

using StellaOps.Plugin.Versioning;

[assembly: StellaPluginVersion("1.2.3", MinimumHostVersion = "1.0.0")]

The host can enforce:

4) Dependency injection wiring

Stella Ops supports two DI registration mechanisms.

4.1 Simple bindings via ServiceBindingAttribute

Annotate implementations with ServiceBindingAttribute:

using Microsoft.Extensions.DependencyInjection;
using StellaOps.DependencyInjection;

[ServiceBinding(typeof(IMyContract), ServiceLifetime.Singleton, RegisterAsSelf = true)]
public sealed class MyPluginService : IMyContract
{
}

4.2 Advanced wiring via IDependencyInjectionRoutine

For full control, include a concrete IDependencyInjectionRoutine implementation. The host discovers and runs all routines in loaded plugin assemblies:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.DependencyInjection;

public sealed class MyPluginDi : IDependencyInjectionRoutine
{
    public IServiceCollection Register(IServiceCollection services, IConfiguration configuration)
    {
        services.AddSingleton<IMyContract, MyPluginService>();
        return services;
    }
}

5) Signing and verification (Cosign)

When enabled, the host can verify plugin assemblies using Cosign (cosign verify-blob). The signature file is expected adjacent to the assembly:

Verification is performed by StellaOps.Plugin.Security.CosignPluginVerifier and controlled by host configuration (for example EnforceSignatureVerification plus verifier options).

Offline note: verification can be performed without transparency log access when the host is configured accordingly (for example by ignoring tlog or using an offline receipt flow).

6) Repo layout (this monorepo)

In this repository, plugin binaries are typically staged under module-specific *.PluginBinaries directories (examples):

The authoritative loader configuration is owned by the host module and documented in its operations/architecture docs.

7) Testing expectations

Plugins should ship tests that protect determinism and compatibility:

Reference tests for the generic plugin host live under:

8) Where to go next