feat: Implement approvals workflow and notifications integration
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Added approvals orchestration with persistence and workflow scaffolding.
- Integrated notifications insights and staged resume hooks.
- Introduced approval coordinator and policy notification bridge with unit tests.
- Added approval decision API with resume requeue and persisted plan snapshots.
- Documented the Excitor consensus API beta and provided JSON sample payload.
- Created analyzers to flag usage of deprecated merge service APIs.
- Implemented logging for artifact uploads and approval decision service.
- Added tests for PackRunApprovalDecisionService and related components.
This commit is contained in:
master
2025-11-06 08:48:13 +02:00
parent 21a2759412
commit dd217b4546
98 changed files with 3883 additions and 2381 deletions

View File

@@ -52,9 +52,11 @@ internal static class JobRegistrationExtensions
new("source:vndr-oracle:parse", "StellaOps.Concelier.Connector.Vndr.Oracle.OracleParseJob", "StellaOps.Concelier.Connector.Vndr.Oracle", TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(5)),
new("source:vndr-oracle:map", "StellaOps.Concelier.Connector.Vndr.Oracle.OracleMapJob", "StellaOps.Concelier.Connector.Vndr.Oracle", TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(5)),
new("export:json", "StellaOps.Concelier.Exporter.Json.JsonExportJob", "StellaOps.Concelier.Exporter.Json", TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(5)),
new("export:json", "StellaOps.Concelier.Exporter.Json.JsonExportJob", "StellaOps.Concelier.Exporter.Json", TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(5)),
new("export:trivy-db", "StellaOps.Concelier.Exporter.TrivyDb.TrivyDbExportJob", "StellaOps.Concelier.Exporter.TrivyDb", TimeSpan.FromMinutes(20), TimeSpan.FromMinutes(10)),
#pragma warning disable CS0618, CONCELIER0001 // Legacy merge job remains available until MERGE-LNM-21-002 completes.
new("merge:reconcile", "StellaOps.Concelier.Merge.Jobs.MergeReconcileJob", "StellaOps.Concelier.Merge", TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(5))
#pragma warning restore CS0618, CONCELIER0001
};
public static IServiceCollection AddBuiltInConcelierJobs(this IServiceCollection services)

View File

@@ -15,6 +15,8 @@ public sealed class ConcelierOptions
public AuthorityOptions Authority { get; set; } = new();
public MirrorOptions Mirror { get; set; } = new();
public FeaturesOptions Features { get; set; } = new();
public sealed class StorageOptions
{
@@ -135,4 +137,13 @@ public sealed class ConcelierOptions
public int MaxDownloadRequestsPerHour { get; set; } = 1200;
}
public sealed class FeaturesOptions
{
public bool NoMergeEnabled { get; set; }
public bool LnmShadowWrites { get; set; } = true;
public IList<string> MergeJobAllowlist { get; } = new List<string>();
}
}

View File

@@ -17,7 +17,8 @@ public static class ConcelierOptionsPostConfigure
{
ArgumentNullException.ThrowIfNull(options);
options.Authority ??= new ConcelierOptions.AuthorityOptions();
options.Authority ??= new ConcelierOptions.AuthorityOptions();
options.Features ??= new ConcelierOptions.FeaturesOptions();
var authority = options.Authority;
if (string.IsNullOrWhiteSpace(authority.ClientSecret)

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
@@ -98,9 +99,36 @@ builder.Services.AddConcelierLinksetMappers();
builder.Services.AddAdvisoryRawServices();
builder.Services.AddSingleton<IAdvisoryObservationQueryService, AdvisoryObservationQueryService>();
builder.Services.AddMergeModule(builder.Configuration);
var features = concelierOptions.Features ?? new ConcelierOptions.FeaturesOptions();
if (!features.NoMergeEnabled)
{
#pragma warning disable CS0618, CONCELIER0001, CONCELIER0002 // Legacy merge service is intentionally supported behind a feature toggle.
builder.Services.AddMergeModule(builder.Configuration);
#pragma warning restore CS0618, CONCELIER0001, CONCELIER0002
}
builder.Services.AddJobScheduler();
builder.Services.AddBuiltInConcelierJobs();
builder.Services.PostConfigure<JobSchedulerOptions>(options =>
{
if (features.NoMergeEnabled)
{
options.Definitions.Remove("merge:reconcile");
return;
}
if (features.MergeJobAllowlist is { Count: > 0 })
{
var allowMergeJob = features.MergeJobAllowlist.Any(value =>
string.Equals(value, "merge:reconcile", StringComparison.OrdinalIgnoreCase));
if (!allowMergeJob)
{
options.Definitions.Remove("merge:reconcile");
}
}
});
builder.Services.AddSingleton<OpenApiDiscoveryDocumentProvider>();
builder.Services.AddSingleton<ServiceStatus>(sp => new ServiceStatus(sp.GetRequiredService<TimeProvider>()));
@@ -183,7 +211,7 @@ if (authorityConfigured)
builder.Services.AddAuthorization(options =>
{
options.AddStellaOpsScopePolicy(JobsPolicyName, concelierOptions.Authority.RequiredScopes.ToArray());
options.AddStellaOpsScopePolicy(ObservationsPolicyName, StellaOpsScopes.VulnRead);
options.AddStellaOpsScopePolicy(ObservationsPolicyName, StellaOpsScopes.VulnView);
options.AddStellaOpsScopePolicy(AdvisoryIngestPolicyName, StellaOpsScopes.AdvisoryIngest);
options.AddStellaOpsScopePolicy(AdvisoryReadPolicyName, StellaOpsScopes.AdvisoryRead);
options.AddStellaOpsScopePolicy(AocVerifyPolicyName, StellaOpsScopes.AdvisoryRead, StellaOpsScopes.AocVerify);
@@ -197,6 +225,11 @@ builder.Services.AddEndpointsApiExplorer();
var app = builder.Build();
if (features.NoMergeEnabled)
{
app.Logger.LogWarning("Legacy merge module disabled via concelier:features:noMergeEnabled; Link-Not-Merge mode active.");
}
var resolvedConcelierOptions = app.Services.GetRequiredService<IOptions<ConcelierOptions>>().Value;
var resolvedAuthority = resolvedConcelierOptions.Authority ?? new ConcelierOptions.AuthorityOptions();
authorityConfigured = resolvedAuthority.Enabled;

View File

@@ -35,5 +35,8 @@
<ProjectReference Include="../../Authority/StellaOps.Authority/StellaOps.Auth.ServerIntegration/StellaOps.Auth.ServerIntegration.csproj" />
<ProjectReference Include="../../Aoc/__Libraries/StellaOps.Aoc/StellaOps.Aoc.csproj" />
<ProjectReference Include="../../Aoc/__Libraries/StellaOps.Aoc.AspNetCore/StellaOps.Aoc.AspNetCore.csproj" />
<ProjectReference Include="../__Analyzers/StellaOps.Concelier.Analyzers/StellaOps.Concelier.Analyzers.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>