# Writing Plug‑ins for Stella Ops SDK *Preview 3*

> **SDK status:** *Preview 3* is compatible with the **v0.1 α** runtime.  
> Interfaces freeze at **v0.2 β**; binary‑breaking changes are still possible
> until then.

| SDK NuGet | Runtime compat | Notes |
|-----------|---------------|-------|
| `StellaOps.SDK 0.2.0-preview3` | `stella-ops >= 0.1.0-alpha` | Current preview |
| `StellaOps.SDK 0.2.x‑beta` | v0.2 β (Q1 2026) | Interface **freeze** |
| `StellaOps.SDK 1.0.0` | v1.0 GA (Q4 2026) | Semantic Ver from here |

---

## 0 · Extension points

| Area | Interface / format | Example |
|------|--------------------|---------|
| SBOM mutator | `ISbomMutator` | Inject SPDX licences |
| Additional scanner | `IVulnerabilityProvider` | Rust Crates ecosystem |
| Policy engine | **OPA Rego** file | Custom pass/fail rule |
| Result exporter | `IResultSink` | Slack webhook notifier |

*Hot‑plugging (live reload) is **post‑1.0**; modules are discovered once
during service start‑up.*

---

## 1 · Five‑minute quick‑start (C# /.NET {{ dotnet }})

```bash
dotnet new classlib -n SlackExporter
cd SlackExporter
dotnet add package StellaOps.SDK --version 0.2.0-preview3
````

```csharp
using System.Net.Http.Json;
using StellaOps.Plugin;

public sealed class SlackSink : IResultSink
{
    private readonly string _webhook =
        Environment.GetEnvironmentVariable("SLACK_WEBHOOK")
        ?? throw new InvalidOperationException("Missing SLACK_WEBHOOK");

    public string Name => "Slack Notifier";

    public async Task ExportAsync(ScanResult result, CancellationToken ct)
    {
        var payload = new
        {
            text = $":rotating_light: *{result.Image}* " +
                   $"→ {result.Findings.Count} findings (max {result.MaxSeverity})"
        };

        using var client = new HttpClient();
        await client.PostAsJsonAsync(_webhook, payload, ct);
    }
}
```

```bash
dotnet publish -c Release -o out
sudo mkdir -p /opt/stella/plugins/Slack
sudo cp out/SlackExporter.dll /opt/stella/plugins/Slack/
sudo systemctl restart stella-ops
```

Start‑up log:

```
[PluginLoader] Loaded 1 plug‑in:
  • Slack Notifier
```

---

## 2 · Packaging rules

| Item   | Rule                                      |
| ------ | ----------------------------------------- |
| Folder | `/opt/stella/plugins/<NiceName>/`         |
| DLLs   | Your plug‑in + non‑GAC deps               |
| Config | Env‑vars or `settings.yaml`               |
| SBOM   | Optional `addon.spdx.json` for provenance |

---

## 3 · Security sandbox

* Runs as Linux user **`stella‑plugin` (UID 1001)**.
* SELinux/AppArmor profile blocks inbound traffic; outbound :80/443 only.
* cgroup default: **1 CPU / 256 MiB** (adjustable).
* SHA‑256 of every DLL is embedded in the run report.

---

## 4 · Debugging

| Technique         | Command                            |
| ----------------- | ---------------------------------- |
| Verbose core log  | `STELLA_LOG=debug`                 |
| Per‑plug‑in log   | Inject `ILogger<YourClass>`        |
| Dry‑run (no fail) | `--plugin-mode warn`               |
| Hot reload        | *Not supported* (planned post‑1.0) |

Logs: `/var/log/stella-ops/plugins/YYYY‑MM‑DD.log`.

---

## 5 · Interface reference (Preview 3)

```csharp
namespace StellaOps.Plugin
{
    public interface ISbomMutator
    {
        string Name { get; }
        Task<SoftwareBillOfMaterials> MutateAsync(
            SoftwareBillOfMaterials sbom,
            CancellationToken ct = default);
    }

    public interface IVulnerabilityProvider
    {
        string Ecosystem { get; }
        Task<IReadOnlyList<Vulnerability>> QueryAsync(
            PackageReference p, CancellationToken ct = default);
    }

    public interface IResultSink
    {
        string Name { get; }
        Task ExportAsync(
            ScanResult result, CancellationToken ct = default);
    }
}
```

Full POCO docs: [https://git.stella-ops.org/stella-ops/sdk/-/tree/main/docs/api](https://git.stella-ops.org/stella-ops/sdk/-/tree/main/docs/api).

---

*Last updated {{ "now" | date: "%Y‑%m‑%d" }} – constants auto‑injected.*

