Files
git.stella-ops.org/docs/10_PLUGIN_SDK_GUIDE.md
2025-12-24 12:38:14 +02:00

5.1 KiB
Executable File

Plugin SDK Guide

This guide explains how StellaOps 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 StellaOps

StellaOps uses plugins to extend behavior without losing:

  • Determinism (stable ordering, stable identifiers, replayable outputs).
  • Offline posture (no hidden outbound calls; explicit trust roots and caches).
  • Security boundaries (no client-controlled identity injection; signed artifacts where enforced).

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:

  • Discovery occurs in a configured plugin directory.
  • Assemblies are loaded in an isolated AssemblyLoadContext.
  • A compatibility gate runs before DI registration:
    • version attribute presence and host compatibility
    • optional signature verification

2.1 Plugin directory and discovery patterns

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

  • Base directory: AppContext.BaseDirectory (unless overridden).
  • Plugin directory:
    • <PrimaryPrefix>.PluginBinaries when PrimaryPrefix is set, otherwise PluginBinaries.
  • Discovery glob(s):
    • <prefix>.Plugin.*.dll for each configured prefix.

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:

  • When no explicit order is configured, discovered plugin assemblies are sorted by filename (case-insensitive).
  • When an explicit order is configured, that order is applied first and the remainder stays sorted.

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:

  • Required attribute presence (RequireVersionAttribute).
  • Compatibility bounds (MinimumHostVersion / MaximumHostVersion).
  • Strict major compatibility when MaximumHostVersion is not set (StrictMajorVersionCheck).

4) Dependency injection wiring

StellaOps 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:

  • MyPlugin.dll
  • MyPlugin.dll.sig

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):

  • src/StellaOps.Authority.PluginBinaries/
  • src/Concelier/StellaOps.Concelier.PluginBinaries/

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:

  • Stable ordering of outputs and collections.
  • Stable timestamps (UTC ISO-8601).
  • Fixture-backed inputs for offline operation.
  • Compatibility checks for host version boundaries.

Reference tests for the generic plugin host live under:

  • src/__Libraries/__Tests/StellaOps.Plugin.Tests/

8) Where to go next

  • Authority plugins and operations: docs/modules/authority/
  • Concelier connectors and operations: docs/modules/concelier/
  • Scanner analyzers and operations: docs/modules/scanner/
  • CLI command modules: docs/modules/cli/