up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Findings Ledger CI / build-test (push) Has been cancelled
Findings Ledger CI / migration-validation (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
cryptopro-linux-csp / build-and-test (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
sm-remote-ci / build-and-test (push) Has been cancelled
Findings Ledger CI / generate-manifest (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-09 09:38:09 +02:00
parent bc0762e97d
commit 108d1c64b3
193 changed files with 7265 additions and 13029 deletions

View File

@@ -30,7 +30,7 @@ Run Excititor background jobs (ingestion, linkset extraction, dedup/idempotency
- Keep timestamps UTC ISO-8601; inject clock/GUID providers for tests.
## Boundaries
- Delegate domain logic to Core and persistence to Storage.Mongo; avoid embedding policy or UI concerns.
- Delegate domain logic to Core and persistence to Storage.Postgres; avoid embedding policy or UI concerns.
- Configuration via appsettings/environment; no hard-coded secrets.
## Ready-to-Start Checklist

View File

@@ -12,7 +12,6 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Excititor.Core;
using StellaOps.Excititor.Core.Orchestration;
using StellaOps.Excititor.Storage.Mongo;
using StellaOps.Excititor.Worker.Options;
namespace StellaOps.Excititor.Worker.Orchestration;

View File

@@ -8,11 +8,12 @@ using StellaOps.Plugin;
using StellaOps.Excititor.Connectors.RedHat.CSAF.DependencyInjection;
using StellaOps.Excititor.Core;
using StellaOps.Excititor.Core.Aoc;
using StellaOps.Excititor.Core.Storage;
using StellaOps.Excititor.Core.Orchestration;
using StellaOps.Excititor.Formats.CSAF;
using StellaOps.Excititor.Formats.CycloneDX;
using StellaOps.Excititor.Formats.OpenVEX;
using StellaOps.Excititor.Storage.Mongo;
using StellaOps.Excititor.Storage.Postgres;
using StellaOps.Excititor.Worker.Auth;
using StellaOps.Excititor.Worker.Options;
using StellaOps.Excititor.Worker.Orchestration;
@@ -43,11 +44,14 @@ services.PostConfigure<VexWorkerOptions>(options =>
});
services.AddRedHatCsafConnector();
services.AddOptions<VexMongoStorageOptions>()
.Bind(configuration.GetSection("Excititor:Storage:Mongo"))
services.AddOptions<VexStorageOptions>()
.Bind(configuration.GetSection("Excititor:Storage"))
.ValidateOnStart();
services.AddExcititorMongoStorage();
services.AddExcititorPostgresStorage(configuration);
services.AddSingleton<IVexProviderStore, InMemoryVexProviderStore>();
services.AddSingleton<IVexConnectorStateRepository, InMemoryVexConnectorStateRepository>();
services.AddSingleton<IVexClaimStore, InMemoryVexClaimStore>();
services.AddCsafNormalizer();
services.AddCycloneDxNormalizer();
services.AddOpenVexNormalizer();

View File

@@ -5,12 +5,10 @@ using System.Security.Cryptography;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using StellaOps.Plugin;
using StellaOps.Excititor.Connectors.Abstractions;
using StellaOps.Excititor.Core;
using StellaOps.Excititor.Core.Orchestration;
using StellaOps.Excititor.Storage.Mongo;
using StellaOps.Excititor.Worker.Options;
using StellaOps.Excititor.Worker.Orchestration;
using StellaOps.Excititor.Worker.Signature;
@@ -95,12 +93,6 @@ internal sealed class DefaultVexProviderRunner : IVexProviderRunner
var stateRepository = scopeProvider.GetRequiredService<IVexConnectorStateRepository>();
var normalizerRouter = scopeProvider.GetRequiredService<IVexNormalizerRouter>();
var signatureVerifier = scopeProvider.GetRequiredService<IVexSignatureVerifier>();
var sessionProvider = scopeProvider.GetService<IVexMongoSessionProvider>();
IClientSessionHandle? session = null;
if (sessionProvider is not null)
{
session = await sessionProvider.StartSessionAsync(cancellationToken).ConfigureAwait(false);
}
var descriptor = connector switch
{
@@ -108,12 +100,12 @@ internal sealed class DefaultVexProviderRunner : IVexProviderRunner
_ => new VexConnectorDescriptor(connector.Id, VexProviderKind.Vendor, connector.Id)
};
var provider = await providerStore.FindAsync(descriptor.Id, cancellationToken, session).ConfigureAwait(false)
var provider = await providerStore.FindAsync(descriptor.Id, cancellationToken).ConfigureAwait(false)
?? new VexProvider(descriptor.Id, descriptor.DisplayName, descriptor.Kind);
await providerStore.SaveAsync(provider, cancellationToken, session).ConfigureAwait(false);
await providerStore.SaveAsync(provider, cancellationToken).ConfigureAwait(false);
var stateBeforeRun = await stateRepository.GetAsync(descriptor.Id, cancellationToken, session).ConfigureAwait(false);
var stateBeforeRun = await stateRepository.GetAsync(descriptor.Id, cancellationToken).ConfigureAwait(false);
var now = _timeProvider.GetUtcNow();
if (stateBeforeRun?.NextEligibleRun is { } nextEligible && nextEligible > now)

View File

@@ -1,65 +1,64 @@
using System.Collections.Immutable;
using System.Globalization;
using StellaOps.Excititor.Core;
using StellaOps.Excititor.Storage.Mongo;
namespace StellaOps.Excititor.Worker.Signature;
internal sealed class VerifyingVexRawDocumentSink : IVexRawDocumentSink
{
private readonly IVexRawStore _inner;
private readonly IVexSignatureVerifier _signatureVerifier;
public VerifyingVexRawDocumentSink(IVexRawStore inner, IVexSignatureVerifier signatureVerifier)
{
_inner = inner ?? throw new ArgumentNullException(nameof(inner));
_signatureVerifier = signatureVerifier ?? throw new ArgumentNullException(nameof(signatureVerifier));
}
public async ValueTask StoreAsync(VexRawDocument document, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(document);
var signatureMetadata = await _signatureVerifier.VerifyAsync(document, cancellationToken).ConfigureAwait(false);
var enrichedDocument = signatureMetadata is null
? document
: document with { Metadata = EnrichMetadata(document.Metadata, signatureMetadata) };
await _inner.StoreAsync(enrichedDocument, cancellationToken).ConfigureAwait(false);
}
private static ImmutableDictionary<string, string> EnrichMetadata(
ImmutableDictionary<string, string> metadata,
VexSignatureMetadata signature)
{
var builder = metadata is null
? ImmutableDictionary.CreateBuilder<string, string>(StringComparer.Ordinal)
: metadata.ToBuilder();
builder["signature.present"] = "true";
builder["signature.verified"] = "true";
builder["vex.signature.type"] = signature.Type;
if (!string.IsNullOrWhiteSpace(signature.Subject))
{
builder["vex.signature.subject"] = signature.Subject!;
}
if (!string.IsNullOrWhiteSpace(signature.Issuer))
{
builder["vex.signature.issuer"] = signature.Issuer!;
}
if (!string.IsNullOrWhiteSpace(signature.KeyId))
{
builder["vex.signature.keyId"] = signature.KeyId!;
}
if (signature.VerifiedAt is not null)
{
builder["vex.signature.verifiedAt"] = signature.VerifiedAt.Value.ToString("O");
}
internal sealed class VerifyingVexRawDocumentSink : IVexRawDocumentSink
{
private readonly IVexRawStore _inner;
private readonly IVexSignatureVerifier _signatureVerifier;
public VerifyingVexRawDocumentSink(IVexRawStore inner, IVexSignatureVerifier signatureVerifier)
{
_inner = inner ?? throw new ArgumentNullException(nameof(inner));
_signatureVerifier = signatureVerifier ?? throw new ArgumentNullException(nameof(signatureVerifier));
}
public async ValueTask StoreAsync(VexRawDocument document, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(document);
var signatureMetadata = await _signatureVerifier.VerifyAsync(document, cancellationToken).ConfigureAwait(false);
var enrichedDocument = signatureMetadata is null
? document
: document with { Metadata = EnrichMetadata(document.Metadata, signatureMetadata) };
await _inner.StoreAsync(enrichedDocument, cancellationToken).ConfigureAwait(false);
}
private static ImmutableDictionary<string, string> EnrichMetadata(
ImmutableDictionary<string, string> metadata,
VexSignatureMetadata signature)
{
var builder = metadata is null
? ImmutableDictionary.CreateBuilder<string, string>(StringComparer.Ordinal)
: metadata.ToBuilder();
builder["signature.present"] = "true";
builder["signature.verified"] = "true";
builder["vex.signature.type"] = signature.Type;
if (!string.IsNullOrWhiteSpace(signature.Subject))
{
builder["vex.signature.subject"] = signature.Subject!;
}
if (!string.IsNullOrWhiteSpace(signature.Issuer))
{
builder["vex.signature.issuer"] = signature.Issuer!;
}
if (!string.IsNullOrWhiteSpace(signature.KeyId))
{
builder["vex.signature.keyId"] = signature.KeyId!;
}
if (signature.VerifiedAt is not null)
{
builder["vex.signature.verifiedAt"] = signature.VerifiedAt.Value.ToString("O");
}
if (!string.IsNullOrWhiteSpace(signature.TransparencyLogReference))
{
builder["vex.signature.transparencyLogReference"] = signature.TransparencyLogReference!;

View File

@@ -14,12 +14,10 @@
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
<ProjectReference Include="../../Concelier/__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj" />
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Connectors.Abstractions/StellaOps.Excititor.Connectors.Abstractions.csproj" />
<!-- Temporarily commented out: RedHat CSAF connector blocked by missing Storage.Mongo project -->
<!-- <ProjectReference Include="../__Libraries/StellaOps.Excititor.Connectors.RedHat.CSAF/StellaOps.Excititor.Connectors.RedHat.CSAF.csproj" /> -->
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Core/StellaOps.Excititor.Core.csproj" />
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Policy/StellaOps.Excititor.Policy.csproj" />
<!-- Temporarily commented out: Storage.Mongo project not found -->
<!-- <ProjectReference Include="../__Libraries/StellaOps.Excititor.Storage.Mongo/StellaOps.Excititor.Storage.Mongo.csproj" /> -->
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Storage.Postgres/StellaOps.Excititor.Storage.Postgres.csproj" />
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Formats.CSAF/StellaOps.Excititor.Formats.CSAF.csproj" />
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Formats.CycloneDX/StellaOps.Excititor.Formats.CycloneDX.csproj" />
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Formats.OpenVEX/StellaOps.Excititor.Formats.OpenVEX.csproj" />