Some checks failed
		
		
	
	Build Test Deploy / authority-container (push) Has been cancelled
				
			Build Test Deploy / docs (push) Has been cancelled
				
			Build Test Deploy / deploy (push) Has been cancelled
				
			Build Test Deploy / build-test (push) Has been cancelled
				
			Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
			
				
	
	
		
			194 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Markdown
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Markdown
		
	
	
		
			Executable File
		
	
	
	
	
| # 10 · Plug‑in SDK Guide — **Stella Ops**
 | ||
| *(v 1.5 — 11 Jul 2025 · template install, no reload, IoC)*  
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## 0 Audience & Scope  
 | ||
| Guidance for developers who extend Stella Ops with schedule jobs, scanner adapters, TLS providers, notification channels, etc.  Everything here is OSS; commercial variants simply ship additional signed plug‑ins.
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## 1 Prerequisites  
 | ||
| 
 | ||
| | Tool                    | Min Version                                                       |
 | ||
| | ----------------------- | ----------------------------------------------------------------- |
 | ||
| | .NET SDK                | {{ dotnet }}                                                      |
 | ||
| | **StellaOps templates** | install once via `bash dotnet new install StellaOps.Templates::*` |
 | ||
| | **Cosign**              | 2.3 + — used to sign DLLs                                         |
 | ||
| | xUnit                   | 2.6                                                               |
 | ||
| | Docker CLI              | only if your plug‑in shells out to containers                     |
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## 2 Repository & Build Output  
 | ||
| 
 | ||
| Every plug‑in is hosted in **`git.stella‑ops.org`**.  
 | ||
| At publish time it must copy its signed artefacts to:
 | ||
| 
 | ||
| ~~~text
 | ||
| src/backend/Stella.Ops.Plugin.Binaries/<MyPlugin>/
 | ||
|         ├── MyPlugin.dll
 | ||
|         └── MyPlugin.dll.sig
 | ||
| ~~~
 | ||
| 
 | ||
| The back‑end scans this folder on start‑up, verifies the **Cosign** signature, confirms the `[StellaPluginVersion]` gate, then loads the DLL inside an **isolated AssemblyLoadContext** to avoid dependency clashes
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## 3 Project Scaffold  
 | ||
| 
 | ||
| Generate with the installed template:
 | ||
| 
 | ||
| ~~~bash
 | ||
| dotnet new stellaops-plugin-schedule \
 | ||
|        -n MyPlugin.Schedule \
 | ||
|        --output src
 | ||
| ~~~
 | ||
| 
 | ||
| Result:
 | ||
| 
 | ||
| ~~~text
 | ||
| src/
 | ||
|  ├─ MyPlugin.Schedule/
 | ||
|  │    ├─ MyJob.cs
 | ||
|  │    └─ MyPlugin.Schedule.csproj
 | ||
|  └─ tests/
 | ||
|       └─ MyPlugin.Schedule.Tests/
 | ||
| ~~~
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## 4 MSBuild Wiring  
 | ||
| 
 | ||
| Add this to **`MyPlugin.Schedule.csproj`** so the signed DLL + `.sig` land in the canonical plug‑in folder:
 | ||
| 
 | ||
| ~~~xml
 | ||
| <PropertyGroup>
 | ||
|   <StellaPluginOut>$(SolutionDir)src/backend/Stella.Ops.Plugin.Binaries/$(MSBuildProjectName)</StellaPluginOut>
 | ||
| </PropertyGroup>
 | ||
| 
 | ||
| <ItemGroup>
 | ||
|   
 | ||
|   <ProjectReference Include="..\..\StellaOps.Common\StellaOps.Common.csproj"
 | ||
|                     PrivateAssets="all" /> 
 | ||
| </ItemGroup>
 | ||
| 
 | ||
| <Target Name="CopyStellaPlugin" AfterTargets="Publish">
 | ||
|   <MakeDir Directories="$(StellaPluginOut)" />
 | ||
|   <Copy SourceFiles="$(PublishDir)$(AssemblyName).dll;$(PublishDir)$(AssemblyName).dll.sig"
 | ||
|         DestinationFolder="$(StellaPluginOut)" />
 | ||
| </Target>
 | ||
| ~~~
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## 5 Dependency‑Injection Entry‑point  
 | ||
| 
 | ||
| Back‑end auto‑discovers the static method below:
 | ||
| 
 | ||
| ~~~csharp
 | ||
| namespace StellaOps.DependencyInjection;
 | ||
| 
 | ||
| public static class IoCConfigurator
 | ||
| {
 | ||
|     public static IServiceCollection Configure(this IServiceCollection services,
 | ||
|                                                IConfiguration cfg)
 | ||
|     {
 | ||
|         services.AddSingleton<IJob, MyJob>();        // schedule job
 | ||
|         services.Configure<MyPluginOptions>(cfg.GetSection("Plugins:MyPlugin"));
 | ||
|         return services;
 | ||
|     }
 | ||
| }
 | ||
| ~~~
 | ||
| 
 | ||
| ---
 | ||
| 
 | ||
| ## 6 Schedule Plug‑ins  
 | ||
| 
 | ||
| ### 6.1 Minimal Job  
 | ||
| 
 | ||
| ~~~csharp
 | ||
| using StellaOps.Scheduling;             // contract
 | ||
| 
 | ||
| [StellaPluginVersion("2.0.0")]
 | ||
| public sealed class MyJob : IJob
 | ||
| {
 | ||
|     public async Task ExecuteAsync(CancellationToken ct)
 | ||
|     {
 | ||
|         Console.WriteLine("Hello from plug‑in!");
 | ||
|         await Task.Delay(500, ct);
 | ||
|     }
 | ||
| }
 | ||
| ~~~
 | ||
| 
 | ||
| ### 6.2 Cron Registration  
 | ||
| 
 | ||
| ```csharp
 | ||
| services.AddCronJob<MyJob>("0 15 * * *"); // everyday 
 | ||
| ```
 | ||
| 
 | ||
| 15:00
 | ||
| Cron syntax follows Hangfire rules 
 | ||
| 
 | ||
| ## 7 Scanner Adapters
 | ||
| 
 | ||
| Implement IScannerRunner.
 | ||
| Register inside Configure:
 | ||
| ```csharp
 | ||
| services.AddScanner<MyAltScanner>("alt"); // backend 
 | ||
| ```
 | ||
| 
 | ||
| selects by --engine alt
 | ||
| If the engine needs a side‑car container, include a Dockerfile in your repo and document resource expectations.
 | ||
| ## 8 Packaging & Signing
 | ||
| 
 | ||
| ```bash
 | ||
| dotnet publish -c Release -p:PublishSingleFile=true -o out
 | ||
| cosign sign --key $COSIGN_KEY out/MyPlugin.Schedule.dll   # sign binary only
 | ||
| sha256sum out/MyPlugin.Schedule.dll > out/.sha256          # optional checksum
 | ||
| zip MyPlugin.zip out/* README.md
 | ||
| ```
 | ||
| 
 | ||
| Unsigned DLLs are refused when StellaOps:Security:DisableUnsigned=false.
 | ||
| 
 | ||
| ## 9 Deployment
 | ||
| 
 | ||
| ```bash
 | ||
| docker cp MyPlugin.zip <backend>:/opt/plugins/ && docker restart <backend>
 | ||
| ```
 | ||
| 
 | ||
| Check /health – "plugins":["MyPlugin.Schedule@2.0.0"].
 | ||
| (Hot‑reload was removed to keep the core process simple and memory‑safe.)
 | ||
| 
 | ||
| ## 10 Configuration Patterns
 | ||
| 
 | ||
| | Need         | Pattern                                                   |
 | ||
| | ------------ | --------------------------------------------------------- |
 | ||
| | Settings     | Plugins:MyPlugin:* in appsettings.json.                   |
 | ||
| | Secrets      | Redis secure:<plugin>:<key> (encrypted per TLS provider). |
 | ||
| | Dynamic cron | Implement ICronConfigurable; UI exposes editor.           |
 | ||
| 
 | ||
| ## 11 Testing & CI
 | ||
| 
 | ||
| | Layer       | Tool                       | Gate                |
 | ||
| | ----------- | -------------------------- | ------------------- |
 | ||
| | Unit        | xUnit + Moq                | ≥ 50 % lines        |
 | ||
| | Integration | Testcontainers ‑ run in CI | Job completes < 5 s |
 | ||
| | Style       | dotnet                     | format	0 warnings   |
 | ||
| 
 | ||
| Use the pre‑baked workflow in StellaOps.Templates as starting point.
 | ||
| 
 | ||
| ## 12 Publishing to the Community Marketplace
 | ||
| 
 | ||
| Tag Git release plugin‑vX.Y.Z and attach the signed ZIP.
 | ||
| Submit a PR to stellaops/community-plugins.json with metadata & git URL.
 | ||
| On merge, the plug‑in shows up in the UI Marketplace.
 | ||
| 
 | ||
| ## 13 Common Pitfalls
 | ||
| 
 | ||
| | Symptom             | Root cause                 | Fix                                         |
 | ||
| | ------------------- | -------------------------- | ------------------------------------------- |
 | ||
| | NotDetected         | .sig missing               | cosign sign …                               |
 | ||
| | VersionGateMismatch | Backend 2.1 vs plug‑in 2.0 | Re‑compile / bump attribute                 |
 | ||
| | FileLoadException   | Duplicate                  | StellaOps.Common	Ensure PrivateAssets="all" |
 | ||
| | Redis               | timeouts	Large writes      | Batch or use Mongo                          | |