Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.
This commit is contained in:
@@ -137,11 +137,11 @@ internal static class MirrorRegistrationEndpoints
|
||||
record.Signature,
|
||||
record.PayloadUrl,
|
||||
record.TransparencyLog,
|
||||
record.PortableManifestHash);
|
||||
record.PortableManifestHash ?? string.Empty);
|
||||
|
||||
var paths = new MirrorBundlePaths(
|
||||
record.PortableManifestPath,
|
||||
record.EvidenceLockerPath);
|
||||
record.PortableManifestPath ?? string.Empty,
|
||||
record.EvidenceLockerPath ?? string.Empty);
|
||||
|
||||
var timeline = record.Timeline
|
||||
.OrderByDescending(e => e.CreatedAt)
|
||||
|
||||
@@ -13,8 +13,8 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Excititor.Attestation;
|
||||
using StellaOps.Excititor.Attestation.Dsse;
|
||||
using StellaOps.Excititor.Attestation.Signing;
|
||||
using StellaOps.Excititor.Core.Dsse;
|
||||
using StellaOps.Excititor.Core;
|
||||
using StellaOps.Excititor.Core.Lattice;
|
||||
using StellaOps.Excititor.Formats.OpenVEX;
|
||||
|
||||
@@ -23,12 +23,13 @@ using StellaOps.Excititor.Connectors.RedHat.CSAF.DependencyInjection;
|
||||
using StellaOps.Excititor.Core;
|
||||
using StellaOps.Excititor.Core.Evidence;
|
||||
using StellaOps.Excititor.Core.Observations;
|
||||
using StellaOps.Excititor.Core.Verification;
|
||||
using StellaOps.Excititor.Export;
|
||||
using StellaOps.Excititor.Formats.CSAF;
|
||||
using StellaOps.Excititor.Formats.CycloneDX;
|
||||
using StellaOps.Excititor.Formats.OpenVEX;
|
||||
using StellaOps.Excititor.Policy;
|
||||
using StellaOps.Excititor.Storage.Postgres;
|
||||
using StellaOps.Excititor.Persistence.Extensions;
|
||||
using StellaOps.Infrastructure.Postgres.Options;
|
||||
using StellaOps.Excititor.WebService.Endpoints;
|
||||
using StellaOps.Excititor.WebService.Extensions;
|
||||
@@ -41,6 +42,7 @@ using StellaOps.Excititor.WebService.Contracts;
|
||||
using System.Globalization;
|
||||
using StellaOps.Excititor.WebService.Graph;
|
||||
using StellaOps.Excititor.Core.Storage;
|
||||
using StellaOps.Excititor.Persistence.Postgres;
|
||||
using StellaOps.Router.AspNet;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
@@ -52,15 +54,36 @@ services.AddOptions<VexStorageOptions>()
|
||||
services.AddOptions<GraphOptions>()
|
||||
.Bind(configuration.GetSection("Excititor:Graph"));
|
||||
|
||||
services.AddExcititorPostgresStorage(configuration);
|
||||
services.AddExcititorPersistence(configuration);
|
||||
services.TryAddSingleton<IVexProviderStore, InMemoryVexProviderStore>();
|
||||
services.TryAddScoped<IVexConnectorStateRepository, InMemoryVexConnectorStateRepository>();
|
||||
services.TryAddSingleton<IVexClaimStore, InMemoryVexClaimStore>();
|
||||
services.AddCsafNormalizer();
|
||||
services.AddCycloneDxNormalizer();
|
||||
services.AddOpenVexNormalizer();
|
||||
services.AddSingleton<IVexSignatureVerifier, NoopVexSignatureVerifier>();
|
||||
// TODO: replace NoopVexSignatureVerifier with hardened verifier once portable bundle signatures are finalized.
|
||||
|
||||
// VEX Signature Verification (SPRINT_1227_0004_0001)
|
||||
// Feature flag controls whether production verification is active.
|
||||
// When VexSignatureVerification:Enabled is false, NoopVexSignatureVerifier is used.
|
||||
services.AddVexSignatureVerification(configuration);
|
||||
|
||||
// Legacy V1 interface - maintained for backward compatibility during migration
|
||||
if (configuration.GetValue<bool>("VexSignatureVerification:Enabled", false))
|
||||
{
|
||||
services.AddSingleton<IVexSignatureVerifier>(sp =>
|
||||
{
|
||||
// Adapter from V2 to V1 interface
|
||||
return new VexSignatureVerifierV1Adapter(
|
||||
sp.GetRequiredService<IVexSignatureVerifierV2>(),
|
||||
sp.GetRequiredService<IOptions<VexSignatureVerifierOptions>>(),
|
||||
sp.GetRequiredService<ILogger<VexSignatureVerifierV1Adapter>>());
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<IVexSignatureVerifier, NoopVexSignatureVerifier>();
|
||||
}
|
||||
|
||||
services.Configure<AirgapOptions>(configuration.GetSection(AirgapOptions.SectionName));
|
||||
services.AddSingleton<AirgapImportValidator>();
|
||||
services.AddSingleton<AirgapSignerTrustService>();
|
||||
@@ -2264,6 +2287,7 @@ internal sealed record ExcititorTimelineEvent(
|
||||
string? TraceId,
|
||||
string OccurredAt);
|
||||
|
||||
// Program class public for WebApplicationFactory<Program>
|
||||
public partial class Program;
|
||||
|
||||
internal sealed record StatusResponse(DateTimeOffset UtcNow, int InlineThreshold, string[] ArtifactStores);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"profiles": {
|
||||
"StellaOps.Excititor.WebService": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:62513;http://localhost:62514"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Text.Json.Serialization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Npgsql;
|
||||
using NpgsqlTypes;
|
||||
using StellaOps.Excititor.Storage.Postgres;
|
||||
using StellaOps.Excititor.Persistence.Postgres;
|
||||
using StellaOps.Excititor.WebService.Contracts;
|
||||
|
||||
namespace StellaOps.Excititor.WebService.Services;
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// VexSignatureVerifierV1Adapter - Adapts V2 interface to V1 for backward compatibility
|
||||
// Part of SPRINT_1227_0004_0001: Activate VEX Signature Verification Pipeline
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Excititor.Core;
|
||||
using StellaOps.Excititor.Core.Verification;
|
||||
|
||||
namespace StellaOps.Excititor.WebService.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Adapter that bridges the new IVexSignatureVerifierV2 interface to the legacy IVexSignatureVerifier interface.
|
||||
/// This allows gradual migration while maintaining backward compatibility.
|
||||
/// </summary>
|
||||
public sealed class VexSignatureVerifierV1Adapter : IVexSignatureVerifier
|
||||
{
|
||||
private readonly IVexSignatureVerifierV2 _v2Verifier;
|
||||
private readonly VexSignatureVerifierOptions _options;
|
||||
private readonly ILogger<VexSignatureVerifierV1Adapter> _logger;
|
||||
|
||||
public VexSignatureVerifierV1Adapter(
|
||||
IVexSignatureVerifierV2 v2Verifier,
|
||||
IOptions<VexSignatureVerifierOptions> options,
|
||||
ILogger<VexSignatureVerifierV1Adapter> logger)
|
||||
{
|
||||
_v2Verifier = v2Verifier ?? throw new ArgumentNullException(nameof(v2Verifier));
|
||||
_options = options?.Value ?? throw new ArgumentNullException(nameof(options));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask<VexSignatureMetadata?> VerifyAsync(
|
||||
VexRawDocument document,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(document);
|
||||
|
||||
try
|
||||
{
|
||||
// Create verification context from options
|
||||
var context = new VexVerificationContext
|
||||
{
|
||||
TenantId = ExtractTenantId(document),
|
||||
CryptoProfile = _options.DefaultProfile,
|
||||
AllowExpiredCerts = _options.AllowExpiredCerts,
|
||||
RequireSignature = _options.RequireSignature,
|
||||
ClockTolerance = _options.ClockTolerance
|
||||
};
|
||||
|
||||
// Call V2 verifier
|
||||
var result = await _v2Verifier.VerifyAsync(document, context, cancellationToken);
|
||||
|
||||
// Convert V2 result to V1 VexSignatureMetadata
|
||||
return ConvertToV1Metadata(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "V1 adapter verification failed for document {Digest}", document.Digest);
|
||||
|
||||
// Return null on error (V1 behavior - treat as unsigned)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ExtractTenantId(VexRawDocument document)
|
||||
{
|
||||
// Try to extract tenant from document metadata
|
||||
if (document.Metadata.TryGetValue("tenant-id", out var tenantId) &&
|
||||
!string.IsNullOrWhiteSpace(tenantId))
|
||||
{
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
if (document.Metadata.TryGetValue("x-stellaops-tenant", out tenantId) &&
|
||||
!string.IsNullOrWhiteSpace(tenantId))
|
||||
{
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
// Default to global tenant
|
||||
return "@global";
|
||||
}
|
||||
|
||||
private static VexSignatureMetadata? ConvertToV1Metadata(VexSignatureVerificationResult result)
|
||||
{
|
||||
// No signature case
|
||||
if (result.Method == VerificationMethod.None && !result.Verified)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Failed verification - still return metadata but with details
|
||||
// This allows the caller to see that verification was attempted
|
||||
|
||||
var type = result.Method switch
|
||||
{
|
||||
VerificationMethod.Dsse => "dsse",
|
||||
VerificationMethod.DsseKeyless => "dsse-keyless",
|
||||
VerificationMethod.Cosign => "cosign",
|
||||
VerificationMethod.CosignKeyless => "cosign-keyless",
|
||||
VerificationMethod.Pgp => "pgp",
|
||||
VerificationMethod.X509 => "x509",
|
||||
VerificationMethod.InToto => "in-toto",
|
||||
VerificationMethod.None => "none",
|
||||
_ => "unknown"
|
||||
};
|
||||
|
||||
// Build transparency log reference
|
||||
string? transparencyLogRef = null;
|
||||
if (result.RekorLogIndex.HasValue)
|
||||
{
|
||||
transparencyLogRef = result.RekorLogId != null
|
||||
? $"{result.RekorLogId}:{result.RekorLogIndex}"
|
||||
: $"rekor:{result.RekorLogIndex}";
|
||||
}
|
||||
|
||||
// Build trust metadata if issuer is known
|
||||
VexSignatureTrustMetadata? trust = null;
|
||||
if (!string.IsNullOrEmpty(result.IssuerId))
|
||||
{
|
||||
trust = new VexSignatureTrustMetadata(
|
||||
effectiveWeight: 1.0m, // Full trust for verified signatures
|
||||
tenantId: "@global",
|
||||
issuerId: result.IssuerId,
|
||||
tenantOverrideApplied: false,
|
||||
retrievedAtUtc: result.VerifiedAt);
|
||||
}
|
||||
|
||||
return new VexSignatureMetadata(
|
||||
type: type,
|
||||
subject: result.CertSubject,
|
||||
issuer: result.IssuerName,
|
||||
keyId: result.KeyId,
|
||||
verifiedAt: result.Verified ? result.VerifiedAt : null,
|
||||
transparencyLogReference: transparencyLogRef,
|
||||
trust: trust);
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,17 @@
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Console" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Core/StellaOps.Excititor.Core.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Messaging/StellaOps.Messaging.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Storage.Postgres/StellaOps.Excititor.Storage.Postgres.csproj" />
|
||||
<ProjectReference Include="../../Router/__Libraries/StellaOps.Messaging/StellaOps.Messaging.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Persistence/StellaOps.Excititor.Persistence.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Export/StellaOps.Excititor.Export.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Connectors.Abstractions/StellaOps.Excititor.Connectors.Abstractions.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Policy/StellaOps.Excititor.Policy.csproj" />
|
||||
@@ -30,6 +30,6 @@
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Excititor.Formats.OpenVEX/StellaOps.Excititor.Formats.OpenVEX.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Ingestion.Telemetry/StellaOps.Ingestion.Telemetry.csproj" />
|
||||
<ProjectReference Include="../../Aoc/__Libraries/StellaOps.Aoc/StellaOps.Aoc.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj" />
|
||||
<ProjectReference Include="../../Router/__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user