up
This commit is contained in:
@@ -82,53 +82,53 @@ Add this to **`MyPlugin.Schedule.csproj`** so the signed DLL + `.sig` land in th
|
||||
|
||||
---
|
||||
|
||||
## 5 Dependency‑Injection Entry‑point
|
||||
|
||||
Back‑end auto‑discovers restart‑time bindings through two mechanisms:
|
||||
|
||||
1. **Service binding metadata** for simple contracts.
|
||||
2. **`IDependencyInjectionRoutine`** implementations when you need full control.
|
||||
|
||||
### 5.1 Service binding metadata
|
||||
|
||||
Annotate implementations with `[ServiceBinding]` to declare their lifetime and service contract.
|
||||
The loader honours scoped lifetimes and will register the service before executing any custom DI routines.
|
||||
|
||||
~~~csharp
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.DependencyInjection;
|
||||
|
||||
[ServiceBinding(typeof(IJob), ServiceLifetime.Scoped, RegisterAsSelf = true)]
|
||||
public sealed class MyJob : IJob
|
||||
{
|
||||
// IJob dependencies can now use scoped services (Mongo sessions, etc.)
|
||||
}
|
||||
~~~
|
||||
|
||||
Use `RegisterAsSelf = true` when you also want to resolve the concrete type.
|
||||
Set `ReplaceExisting = true` to override default descriptors if the host already provides one.
|
||||
|
||||
### 5.2 Dependency injection routines
|
||||
|
||||
For advanced scenarios continue to expose a routine:
|
||||
|
||||
~~~csharp
|
||||
namespace StellaOps.DependencyInjection;
|
||||
|
||||
public sealed class IoCConfigurator : IDependencyInjectionRoutine
|
||||
{
|
||||
public IServiceCollection Register(IServiceCollection services, IConfiguration cfg)
|
||||
{
|
||||
services.AddSingleton<IJob, MyJob>(); // schedule job
|
||||
services.Configure<MyPluginOptions>(cfg.GetSection("Plugins:MyPlugin"));
|
||||
return services;
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
---
|
||||
|
||||
## 6 Schedule Plug‑ins
|
||||
## 5 Dependency‑Injection Entry‑point
|
||||
|
||||
Back‑end auto‑discovers restart‑time bindings through two mechanisms:
|
||||
|
||||
1. **Service binding metadata** for simple contracts.
|
||||
2. **`IDependencyInjectionRoutine`** implementations when you need full control.
|
||||
|
||||
### 5.1 Service binding metadata
|
||||
|
||||
Annotate implementations with `[ServiceBinding]` to declare their lifetime and service contract.
|
||||
The loader honours scoped lifetimes and will register the service before executing any custom DI routines.
|
||||
|
||||
~~~csharp
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.DependencyInjection;
|
||||
|
||||
[ServiceBinding(typeof(IJob), ServiceLifetime.Scoped, RegisterAsSelf = true)]
|
||||
public sealed class MyJob : IJob
|
||||
{
|
||||
// IJob dependencies can now use scoped services (Mongo sessions, etc.)
|
||||
}
|
||||
~~~
|
||||
|
||||
Use `RegisterAsSelf = true` when you also want to resolve the concrete type.
|
||||
Set `ReplaceExisting = true` to override default descriptors if the host already provides one.
|
||||
|
||||
### 5.2 Dependency injection routines
|
||||
|
||||
For advanced scenarios continue to expose a routine:
|
||||
|
||||
~~~csharp
|
||||
namespace StellaOps.DependencyInjection;
|
||||
|
||||
public sealed class IoCConfigurator : IDependencyInjectionRoutine
|
||||
{
|
||||
public IServiceCollection Register(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
|
||||
|
||||
@@ -216,4 +216,213 @@ On merge, the plug‑in shows up in the UI Marketplace.
|
||||
| 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 |
|
||||
| Redis | timeouts Large writes | Batch or use Mongo |
|
||||
|
||||
---
|
||||
|
||||
## 14 Plugin Version Compatibility (v2.0)
|
||||
|
||||
**IMPORTANT:** All plugins **must** declare a `[StellaPluginVersion]` attribute. Plugins without this attribute will be rejected by the host loader.
|
||||
|
||||
Declare your plugin's version and host compatibility requirements:
|
||||
|
||||
```csharp
|
||||
using StellaOps.Plugin.Versioning;
|
||||
|
||||
// In AssemblyInfo.cs or any file at assembly level
|
||||
[assembly: StellaPluginVersion("1.2.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "2.0.0")]
|
||||
```
|
||||
|
||||
| Property | Purpose | Required |
|
||||
|----------|---------|----------|
|
||||
| `pluginVersion` (constructor) | Your plugin's semantic version | **Yes** |
|
||||
| `MinimumHostVersion` | Lowest host version that can load this plugin | Recommended |
|
||||
| `MaximumHostVersion` | Highest host version supported | Recommended for cross-major compatibility |
|
||||
| `RequiresSignature` | Whether signature verification is mandatory (default: true) | No |
|
||||
|
||||
### Version Compatibility Rules
|
||||
|
||||
1. **Attribute Required:** Plugins without `[StellaPluginVersion]` are rejected
|
||||
2. **Minimum Version:** Host version must be ≥ `MinimumHostVersion`
|
||||
3. **Maximum Version:** Host version must be ≤ `MaximumHostVersion` (if specified)
|
||||
4. **Strict Major Version:** If `MaximumHostVersion` is not specified, the plugin is assumed to only support the same major version as `MinimumHostVersion`
|
||||
|
||||
### Examples
|
||||
|
||||
```csharp
|
||||
// Plugin works with host 1.0.0 through 2.x (explicit range)
|
||||
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "2.99.99")]
|
||||
|
||||
// Plugin works with host 2.x only (strict - no MaximumHostVersion means same major version)
|
||||
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "2.0.0")]
|
||||
|
||||
// Plugin version 3.0.0 with no host constraints (uses plugin major version as reference)
|
||||
[assembly: StellaPluginVersion("3.0.0")]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 15 Plugin Host Configuration (v2.0)
|
||||
|
||||
Configure the plugin loader with security-first defaults in `PluginHostOptions`:
|
||||
|
||||
```csharp
|
||||
var options = new PluginHostOptions
|
||||
{
|
||||
// Version enforcement (all default to true for security)
|
||||
HostVersion = new Version(2, 0, 0),
|
||||
EnforceVersionCompatibility = true, // Reject incompatible plugins
|
||||
RequireVersionAttribute = true, // Reject plugins without [StellaPluginVersion]
|
||||
StrictMajorVersionCheck = true, // Reject plugins crossing major version boundaries
|
||||
|
||||
// Signature verification (opt-in, requires infrastructure)
|
||||
EnforceSignatureVerification = true,
|
||||
SignatureVerifier = new CosignPluginVerifier(new CosignVerifierOptions
|
||||
{
|
||||
PublicKeyPath = "/keys/cosign.pub",
|
||||
UseRekorTransparencyLog = true,
|
||||
AllowUnsigned = false
|
||||
})
|
||||
};
|
||||
|
||||
var result = await PluginHost.LoadPluginsAsync(options, logger);
|
||||
|
||||
// Check for failures
|
||||
if (result.HasFailures)
|
||||
{
|
||||
foreach (var failure in result.Failures)
|
||||
{
|
||||
logger.LogError("Plugin {Path} failed: {Reason} - {Message}",
|
||||
failure.AssemblyPath, failure.Reason, failure.Message);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Host Options Reference
|
||||
|
||||
| Option | Default | Purpose |
|
||||
|--------|---------|---------|
|
||||
| `HostVersion` | null | The host application version for compatibility checking |
|
||||
| `EnforceVersionCompatibility` | **true** | Reject plugins that fail version checks |
|
||||
| `RequireVersionAttribute` | **true** | Reject plugins without `[StellaPluginVersion]` |
|
||||
| `StrictMajorVersionCheck` | **true** | Reject plugins that don't explicitly support the host's major version |
|
||||
| `EnforceSignatureVerification` | false | Reject plugins without valid signatures |
|
||||
| `SignatureVerifier` | null | The verifier implementation (e.g., `CosignPluginVerifier`) |
|
||||
|
||||
### Failure Reasons
|
||||
|
||||
| Reason | Description |
|
||||
|--------|-------------|
|
||||
| `LoadError` | Assembly could not be loaded (missing dependencies, corrupt file) |
|
||||
| `SignatureInvalid` | Signature verification failed |
|
||||
| `IncompatibleVersion` | Plugin version constraints not satisfied |
|
||||
| `MissingVersionAttribute` | Plugin lacks required `[StellaPluginVersion]` attribute |
|
||||
|
||||
---
|
||||
|
||||
## 16 Fail-Fast Options Validation (v2.0)
|
||||
|
||||
Use the fail-fast validation pattern to catch configuration errors at startup:
|
||||
|
||||
```csharp
|
||||
using StellaOps.DependencyInjection.Validation;
|
||||
|
||||
// Register options with automatic startup validation
|
||||
services.AddOptionsWithValidation<MyPluginOptions, MyPluginOptionsValidator>(
|
||||
MyPluginOptions.SectionName);
|
||||
|
||||
// Or with data annotations
|
||||
services.AddOptionsWithDataAnnotations<MyPluginOptions>(
|
||||
MyPluginOptions.SectionName);
|
||||
```
|
||||
|
||||
Create validators using the base class:
|
||||
|
||||
```csharp
|
||||
public sealed class MyPluginOptionsValidator : OptionsValidatorBase<MyPluginOptions>
|
||||
{
|
||||
protected override string SectionPrefix => "Plugins:MyPlugin";
|
||||
|
||||
protected override void ValidateOptions(MyPluginOptions options, ValidationContext context)
|
||||
{
|
||||
context
|
||||
.RequireNotEmpty(options.BaseUrl, nameof(options.BaseUrl))
|
||||
.RequirePositive(options.TimeoutSeconds, nameof(options.TimeoutSeconds))
|
||||
.RequireInRange(options.MaxRetries, nameof(options.MaxRetries), 0, 10);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 17 Available Templates (v2.0)
|
||||
|
||||
Install and use the official plugin templates:
|
||||
|
||||
```bash
|
||||
# Install from local templates directory
|
||||
dotnet new install ./templates
|
||||
|
||||
# Or install from NuGet
|
||||
dotnet new install StellaOps.Templates
|
||||
|
||||
# Create a connector plugin
|
||||
dotnet new stellaops-plugin-connector -n MyCompany.AcmeConnector
|
||||
|
||||
# Create a scheduled job plugin
|
||||
dotnet new stellaops-plugin-scheduler -n MyCompany.CleanupJob
|
||||
```
|
||||
|
||||
Templates include:
|
||||
- Plugin entry point with version attribute
|
||||
- Options class with data annotations
|
||||
- Options validator with fail-fast pattern
|
||||
- DI routine registration
|
||||
- README with build/sign instructions
|
||||
|
||||
---
|
||||
|
||||
## 18 Migration Guide: v2.0 to v2.1
|
||||
|
||||
### Breaking Change: Version Attribute Required
|
||||
|
||||
As of v2.1, all plugins **must** include a `[StellaPluginVersion]` attribute. Plugins without this attribute will be rejected with `MissingVersionAttribute` failure.
|
||||
|
||||
**Before (v2.0):** Optional, plugins without attribute loaded with warning.
|
||||
**After (v2.1):** Required, plugins without attribute are rejected.
|
||||
|
||||
### Migration Steps
|
||||
|
||||
1. Add the version attribute to your plugin's AssemblyInfo.cs:
|
||||
```csharp
|
||||
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "2.0.0", MaximumHostVersion = "2.99.99")]
|
||||
```
|
||||
|
||||
2. If your plugin must support multiple major host versions, explicitly set `MaximumHostVersion`:
|
||||
```csharp
|
||||
// Supports host 1.x through 3.x
|
||||
[assembly: StellaPluginVersion("1.0.0", MinimumHostVersion = "1.0.0", MaximumHostVersion = "3.99.99")]
|
||||
```
|
||||
|
||||
3. Rebuild and re-sign your plugin.
|
||||
|
||||
### Opt-out (Not Recommended)
|
||||
|
||||
If you must load legacy plugins without version attributes:
|
||||
```csharp
|
||||
var options = new PluginHostOptions
|
||||
{
|
||||
RequireVersionAttribute = false, // Allow unversioned plugins (NOT recommended)
|
||||
StrictMajorVersionCheck = false // Allow cross-major version loading
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Change Log
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| v2.1 | 2025-12-14 | **Breaking:** `[StellaPluginVersion]` attribute now required by default. Added `RequireVersionAttribute`, `StrictMajorVersionCheck` options. Added `MissingVersionAttribute` failure reason. |
|
||||
| v2.0 | 2025-12-14 | Added StellaPluginVersion attribute, Cosign verification options, fail-fast validation, new templates |
|
||||
| v1.5 | 2025-07-11 | Template install, no hot-reload, IoC conventions |
|
||||
|
||||
Reference in New Issue
Block a user