release orchestrator v1 draft and build fixes

This commit is contained in:
master
2026-01-12 12:24:17 +02:00
parent f3de858c59
commit 9873f80830
1598 changed files with 240385 additions and 5944 deletions

View File

@@ -0,0 +1,220 @@
namespace StellaOps.Authority.Plugin.Unified;
using StellaOps.Authority.Plugins.Abstractions;
using StellaOps.Plugin.Abstractions;
using StellaOps.Plugin.Abstractions.Capabilities;
using StellaOps.Plugin.Abstractions.Context;
using StellaOps.Plugin.Abstractions.Health;
using StellaOps.Plugin.Abstractions.Lifecycle;
/// <summary>
/// Adapts an existing IIdentityProviderPlugin to the unified IPlugin and IAuthCapability interfaces.
/// This enables gradual migration of Authority plugins to the unified plugin architecture.
/// </summary>
public sealed class AuthPluginAdapter : IPlugin, IAuthCapability
{
private readonly IIdentityProviderPlugin _inner;
private IPluginContext? _context;
private PluginLifecycleState _state = PluginLifecycleState.Discovered;
/// <summary>
/// Creates a new adapter for an existing identity provider plugin.
/// </summary>
/// <param name="inner">The existing identity provider plugin to wrap.</param>
public AuthPluginAdapter(IIdentityProviderPlugin inner)
{
_inner = inner ?? throw new ArgumentNullException(nameof(inner));
}
/// <inheritdoc />
public PluginInfo Info => new(
Id: $"com.stellaops.auth.{_inner.Type}",
Name: _inner.Name,
Version: "1.0.0",
Vendor: "Stella Ops",
Description: $"Authority {_inner.Type} identity provider plugin");
/// <inheritdoc />
public PluginTrustLevel TrustLevel => PluginTrustLevel.BuiltIn;
/// <inheritdoc />
public PluginCapabilities Capabilities => PluginCapabilities.Auth | PluginCapabilities.Network;
/// <inheritdoc />
public PluginLifecycleState State => _state;
#region IAuthCapability
/// <inheritdoc />
public string ProviderType => _inner.Type;
/// <inheritdoc />
public IReadOnlyList<string> SupportedMethods
{
get
{
var methods = new List<string>();
if (_inner.Capabilities.SupportsPassword)
methods.Add("password");
if (_inner.Capabilities.SupportsMfa)
methods.Add("mfa");
return methods;
}
}
/// <inheritdoc />
public async Task<AuthResult> AuthenticateAsync(AuthRequest request, CancellationToken ct)
{
if (request.Method != "password" || string.IsNullOrEmpty(request.Username) || string.IsNullOrEmpty(request.Password))
{
return AuthResult.Failed("Invalid authentication method or missing credentials");
}
try
{
var result = await _inner.Credentials.VerifyPasswordAsync(
request.Username,
request.Password,
ct);
if (result.Succeeded && result.User != null)
{
return AuthResult.Succeeded(
userId: result.User.SubjectId,
roles: result.User.Roles?.ToList());
}
return AuthResult.Failed(result.Message ?? "Authentication failed");
}
catch (Exception ex)
{
return AuthResult.Failed(ex.Message);
}
}
/// <inheritdoc />
public Task<TokenValidationResult> ValidateTokenAsync(string token, CancellationToken ct)
{
// Authority plugins don't typically handle token validation directly
// This is handled by the Authority web service
return Task.FromResult(TokenValidationResult.Invalid("Token validation not supported by this provider"));
}
/// <inheritdoc />
public async Task<AuthUserInfo?> GetUserInfoAsync(string userId, CancellationToken ct)
{
try
{
var user = await _inner.Credentials.FindBySubjectAsync(userId, ct);
if (user == null)
return null;
return new AuthUserInfo(
Id: user.SubjectId,
Username: user.Username,
Email: user.Attributes?.GetValueOrDefault("email"),
DisplayName: user.DisplayName,
Attributes: user.Attributes?.Where(kv => kv.Value != null)
.ToDictionary(kv => kv.Key, kv => kv.Value!));
}
catch
{
return null;
}
}
/// <inheritdoc />
public async Task<IReadOnlyList<AuthGroupInfo>> GetUserGroupsAsync(string userId, CancellationToken ct)
{
try
{
// Get user and extract roles as groups
var user = await _inner.Credentials.FindBySubjectAsync(userId, ct);
if (user == null)
return Array.Empty<AuthGroupInfo>();
return user.Roles.Select(role => new AuthGroupInfo(role, role, null)).ToList();
}
catch
{
return Array.Empty<AuthGroupInfo>();
}
}
/// <inheritdoc />
public async Task<bool> HasPermissionAsync(string userId, string permission, CancellationToken ct)
{
var groups = await GetUserGroupsAsync(userId, ct);
return groups.Any(g => g.Name.Equals(permission, StringComparison.OrdinalIgnoreCase));
}
/// <inheritdoc />
public Task<SsoInitiation?> InitiateSsoAsync(SsoRequest request, CancellationToken ct)
{
// SSO is type-specific - LDAP doesn't support it, OIDC/SAML do
// This base adapter doesn't support SSO; specialized adapters should override
return Task.FromResult<SsoInitiation?>(null);
}
/// <inheritdoc />
public Task<AuthResult> CompleteSsoAsync(SsoCallback callback, CancellationToken ct)
{
return Task.FromResult(AuthResult.Failed("SSO not supported by this provider"));
}
#endregion
#region IPlugin
/// <inheritdoc />
public async Task InitializeAsync(IPluginContext context, CancellationToken ct)
{
_context = context;
_state = PluginLifecycleState.Initializing;
// The inner plugin is already initialized via the Authority plugin loader
// We just need to verify it's working
var health = await _inner.CheckHealthAsync(ct);
if (health.Status == AuthorityPluginHealthStatus.Unavailable)
{
_state = PluginLifecycleState.Failed;
throw new InvalidOperationException($"Authority plugin health check failed: {health.Message}");
}
_state = PluginLifecycleState.Active;
context.Logger.Info("Authority plugin adapter initialized for {PluginName}", _inner.Name);
}
/// <inheritdoc />
public async Task<HealthCheckResult> HealthCheckAsync(CancellationToken ct)
{
try
{
var result = await _inner.CheckHealthAsync(ct);
return result.Status switch
{
AuthorityPluginHealthStatus.Healthy => HealthCheckResult.Healthy()
.WithDetails(result.Details?.Where(kv => kv.Value != null)
.ToDictionary(kv => kv.Key, kv => (object)kv.Value!) ?? new Dictionary<string, object>()),
AuthorityPluginHealthStatus.Degraded => HealthCheckResult.Degraded(result.Message ?? "Degraded")
.WithDetails(result.Details?.Where(kv => kv.Value != null)
.ToDictionary(kv => kv.Key, kv => (object)kv.Value!) ?? new Dictionary<string, object>()),
_ => HealthCheckResult.Unhealthy(result.Message ?? "Unhealthy")
};
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy(ex);
}
}
/// <inheritdoc />
public ValueTask DisposeAsync()
{
_state = PluginLifecycleState.Stopped;
return ValueTask.CompletedTask;
}
#endregion
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Description>Unified plugin adapter for Authority identity provider plugins</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Authority.Plugins.Abstractions\StellaOps.Authority.Plugins.Abstractions.csproj" />
<ProjectReference Include="..\..\..\Plugin\StellaOps.Plugin.Abstractions\StellaOps.Plugin.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,5 @@
using StellaOps.Determinism;
namespace StellaOps.Authority.Persistence.InMemory.Stores;
public interface IAuthorityInMemoryIdGenerator
@@ -7,5 +9,12 @@ public interface IAuthorityInMemoryIdGenerator
public sealed class GuidAuthorityInMemoryIdGenerator : IAuthorityInMemoryIdGenerator
{
public string NextId() => Guid.NewGuid().ToString("N");
private readonly IGuidProvider _guidProvider;
public GuidAuthorityInMemoryIdGenerator(IGuidProvider? guidProvider = null)
{
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
}
public string NextId() => _guidProvider.NewGuid().ToString("N");
}

View File

@@ -28,6 +28,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.Postgres\StellaOps.Infrastructure.Postgres.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.EfCore\StellaOps.Infrastructure.EfCore.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Determinism.Abstractions\StellaOps.Determinism.Abstractions.csproj" />
<ProjectReference Include="..\StellaOps.Authority.Core\StellaOps.Authority.Core.csproj" />
</ItemGroup>