This commit is contained in:
StellaOps Bot
2025-12-14 23:20:14 +02:00
parent 3411e825cd
commit b058dbe031
356 changed files with 68310 additions and 1108 deletions

View File

@@ -0,0 +1,54 @@
{
"$schema": "http://json.schemastore.org/template",
"author": "StellaOps",
"classifications": ["StellaOps", "Plugin", "Connector"],
"identity": "StellaOps.Plugin.Connector",
"name": "StellaOps Connector Plugin",
"shortName": "stellaops-plugin-connector",
"description": "A template for creating StellaOps connector plugins (e.g., VEX, advisory, or feed connectors)",
"tags": {
"language": "C#",
"type": "project"
},
"sourceName": "MyConnector",
"preferNameDirectory": true,
"symbols": {
"connectorName": {
"type": "parameter",
"datatype": "text",
"description": "The name of the connector (e.g., 'Acme' for AcmeConnector)",
"defaultValue": "MyConnector",
"replaces": "MyConnector",
"fileRename": "MyConnector"
},
"connectorId": {
"type": "parameter",
"datatype": "text",
"description": "The unique connector identifier (e.g., 'acme-vex')",
"defaultValue": "my-connector",
"replaces": "my-connector"
},
"namespace": {
"type": "parameter",
"datatype": "text",
"description": "The root namespace for the plugin",
"defaultValue": "StellaOps.Plugin.MyConnector",
"replaces": "StellaOps.Plugin.MyConnector"
},
"pluginVersion": {
"type": "parameter",
"datatype": "text",
"description": "The initial plugin version",
"defaultValue": "1.0.0",
"replaces": "1.0.0-template"
}
},
"postActions": [
{
"description": "Restore NuGet packages required by this project",
"manualInstructions": [{ "text": "Run 'dotnet restore'" }],
"actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
"continueOnError": true
}
]
}

View File

@@ -0,0 +1,26 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using StellaOps.DependencyInjection;
using StellaOps.DependencyInjection.Validation;
namespace StellaOps.Plugin.MyConnector;
/// <summary>
/// Registers MyConnector services with the dependency injection container.
/// </summary>
public sealed class MyConnectorDependencyInjectionRoutine : IDependencyInjectionRoutine
{
/// <inheritdoc />
public IServiceCollection Register(IServiceCollection services, IConfiguration configuration)
{
// Register options with fail-fast validation
services.AddOptionsWithValidation<MyConnectorOptions, MyConnectorOptionsValidator>(
MyConnectorOptions.SectionName);
// Register the connector plugin
services.AddSingleton<IConnectorPlugin, MyConnectorPlugin>();
return services;
}
}

View File

@@ -0,0 +1,105 @@
using Microsoft.Extensions.Logging;
using StellaOps.Plugin;
namespace StellaOps.Plugin.MyConnector;
/// <summary>
/// Connector implementation for MyConnector.
/// </summary>
public sealed class MyConnector : IFeedConnector
{
private readonly ILogger<MyConnector> _logger;
private readonly MyConnectorOptions _options;
public MyConnector(ILogger<MyConnector> logger, MyConnectorOptions options)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_options = options ?? throw new ArgumentNullException(nameof(options));
}
/// <summary>
/// Gets the unique identifier for this connector.
/// </summary>
public string Id => "my-connector";
/// <summary>
/// Gets the display name for this connector.
/// </summary>
public string DisplayName => "My Connector";
/// <inheritdoc />
public async Task<FetchResult> FetchAsync(FetchContext context, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Fetching data from {ConnectorId}...", Id);
// TODO: Implement your fetch logic here
// Example: Download data from an external source
await Task.Delay(100, cancellationToken); // Placeholder
return new FetchResult(
Success: true,
Data: Array.Empty<byte>(),
ContentType: "application/json",
ETag: null);
}
/// <inheritdoc />
public async Task<ParseResult> ParseAsync(byte[] data, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Parsing data from {ConnectorId}...", Id);
// TODO: Implement your parsing logic here
await Task.Yield();
return new ParseResult(
Success: true,
Items: Array.Empty<object>(),
Errors: Array.Empty<string>());
}
/// <inheritdoc />
public async Task<MapResult> MapAsync(object item, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Mapping item from {ConnectorId}...", Id);
// TODO: Implement your mapping logic here
await Task.Yield();
return new MapResult(
Success: true,
MappedItem: item,
Errors: Array.Empty<string>());
}
}
/// <summary>
/// Result of a fetch operation.
/// </summary>
public sealed record FetchResult(
bool Success,
byte[] Data,
string? ContentType,
string? ETag);
/// <summary>
/// Result of a parse operation.
/// </summary>
public sealed record ParseResult(
bool Success,
IReadOnlyList<object> Items,
IReadOnlyList<string> Errors);
/// <summary>
/// Result of a map operation.
/// </summary>
public sealed record MapResult(
bool Success,
object? MappedItem,
IReadOnlyList<string> Errors);
/// <summary>
/// Context for fetch operations.
/// </summary>
public sealed record FetchContext(
string? LastETag = null,
DateTimeOffset? LastFetchTime = null);

View File

@@ -0,0 +1,42 @@
using System.ComponentModel.DataAnnotations;
namespace StellaOps.Plugin.MyConnector;
/// <summary>
/// Configuration options for the MyConnector plugin.
/// </summary>
public sealed class MyConnectorOptions
{
/// <summary>
/// The configuration section name.
/// </summary>
public const string SectionName = "Plugins:MyConnector";
/// <summary>
/// Gets or sets the base URL for the connector's data source.
/// </summary>
[Required]
public required string BaseUrl { get; set; }
/// <summary>
/// Gets or sets the API key for authentication.
/// </summary>
public string? ApiKey { get; set; }
/// <summary>
/// Gets or sets the request timeout in seconds. Default is 30.
/// </summary>
[Range(1, 300)]
public int TimeoutSeconds { get; set; } = 30;
/// <summary>
/// Gets or sets the maximum number of retry attempts. Default is 3.
/// </summary>
[Range(0, 10)]
public int MaxRetries { get; set; } = 3;
/// <summary>
/// Gets or sets whether to enable verbose logging.
/// </summary>
public bool EnableVerboseLogging { get; set; }
}

View File

@@ -0,0 +1,27 @@
using Microsoft.Extensions.Options;
using StellaOps.DependencyInjection.Validation;
namespace StellaOps.Plugin.MyConnector;
/// <summary>
/// Validates <see cref="MyConnectorOptions"/> configuration.
/// </summary>
public sealed class MyConnectorOptionsValidator : OptionsValidatorBase<MyConnectorOptions>
{
protected override string SectionPrefix => MyConnectorOptions.SectionName;
protected override void ValidateOptions(MyConnectorOptions options, ValidationContext context)
{
context
.RequireNotEmpty(options.BaseUrl, nameof(options.BaseUrl))
.RequirePositive(options.TimeoutSeconds, nameof(options.TimeoutSeconds))
.RequireInRange(options.MaxRetries, nameof(options.MaxRetries), 0, 10);
// Validate URL format
if (!string.IsNullOrWhiteSpace(options.BaseUrl) &&
!Uri.TryCreate(options.BaseUrl, UriKind.Absolute, out _))
{
context.AddError(nameof(options.BaseUrl), "must be a valid absolute URL.");
}
}
}

View File

@@ -0,0 +1,33 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StellaOps.Plugin;
using StellaOps.Plugin.Versioning;
// Declare plugin version for compatibility checking
[assembly: StellaPluginVersion("1.0.0-template", MinimumHostVersion = "1.0.0")]
namespace StellaOps.Plugin.MyConnector;
/// <summary>
/// Plugin entry point for the MyConnector connector.
/// </summary>
public sealed class MyConnectorPlugin : IConnectorPlugin
{
/// <inheritdoc />
public string Name => "MyConnector";
/// <inheritdoc />
public bool IsAvailable(IServiceProvider services)
{
// Add availability checks here (e.g., required configuration present)
return true;
}
/// <inheritdoc />
public IFeedConnector Create(IServiceProvider services)
{
var logger = services.GetRequiredService<ILogger<MyConnector>>();
var options = services.GetRequiredService<Microsoft.Extensions.Options.IOptions<MyConnectorOptions>>();
return new MyConnector(logger, options.Value);
}
}

View File

@@ -0,0 +1,47 @@
# MyConnector Plugin
A StellaOps connector plugin template.
## Getting Started
1. Update the `MyConnectorOptions.cs` with your connector-specific configuration
2. Implement the fetch, parse, and map logic in `MyConnector.cs`
3. Update the plugin metadata in `MyConnectorPlugin.cs`
4. Build and sign your plugin
## Configuration
Add the following to your `appsettings.json`:
```json
{
"Plugins": {
"MyConnector": {
"BaseUrl": "https://api.example.com",
"ApiKey": "your-api-key",
"TimeoutSeconds": 30,
"MaxRetries": 3
}
}
}
```
## Building
```bash
dotnet build -c Release
```
## Signing
For production use, sign your plugin with Cosign:
```bash
cosign sign --key $COSIGN_KEY bin/Release/net10.0/StellaOps.Plugin.MyConnector.dll
```
## Testing
```bash
dotnet test
```

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>1.0.0-template</Version>
<Description>StellaOps MyConnector Plugin</Description>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0" />
</ItemGroup>
<!-- Reference StellaOps plugin infrastructure -->
<!-- Adjust paths based on your repository structure -->
<ItemGroup>
<ProjectReference Include="..\..\src\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj" />
<ProjectReference Include="..\..\src\__Libraries\StellaOps.DependencyInjection\StellaOps.DependencyInjection.csproj" />
</ItemGroup>
</Project>