up
Some checks failed
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
This commit is contained in:
@@ -2,31 +2,31 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using StellaOps.Configuration;
|
||||
using StellaOps.Scanner.Storage;
|
||||
|
||||
namespace StellaOps.Scanner.WebService.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed configuration for the Scanner WebService host.
|
||||
/// </summary>
|
||||
public sealed class ScannerWebServiceOptions
|
||||
{
|
||||
public const string SectionName = "scanner";
|
||||
|
||||
/// <summary>
|
||||
/// Schema version for configuration consumers to coordinate breaking changes.
|
||||
/// </summary>
|
||||
public int SchemaVersion { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Mongo storage configuration used for catalog and job state.
|
||||
/// </summary>
|
||||
public StorageOptions Storage { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Queue configuration used to enqueue scan jobs.
|
||||
/// </summary>
|
||||
public QueueOptions Queue { get; set; } = new();
|
||||
|
||||
|
||||
namespace StellaOps.Scanner.WebService.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed configuration for the Scanner WebService host.
|
||||
/// </summary>
|
||||
public sealed class ScannerWebServiceOptions
|
||||
{
|
||||
public const string SectionName = "scanner";
|
||||
|
||||
/// <summary>
|
||||
/// Schema version for configuration consumers to coordinate breaking changes.
|
||||
/// </summary>
|
||||
public int SchemaVersion { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// PostgreSQL storage configuration used for catalog and job state.
|
||||
/// </summary>
|
||||
public StorageOptions Storage { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Queue configuration used to enqueue scan jobs.
|
||||
/// </summary>
|
||||
public QueueOptions Queue { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Object store configuration for SBOM artefacts.
|
||||
/// </summary>
|
||||
@@ -36,32 +36,32 @@ public sealed class ScannerWebServiceOptions
|
||||
/// Registry credential configuration for report/export operations.
|
||||
/// </summary>
|
||||
public RegistryOptions Registry { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Feature flags toggling optional behaviours.
|
||||
/// </summary>
|
||||
public FeatureFlagOptions Features { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Plug-in loader configuration.
|
||||
/// </summary>
|
||||
public PluginOptions Plugins { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Telemetry configuration for logs, metrics, traces.
|
||||
/// </summary>
|
||||
public TelemetryOptions Telemetry { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Authority / authentication configuration.
|
||||
/// </summary>
|
||||
public AuthorityOptions Authority { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Signing configuration for report envelopes and attestations.
|
||||
/// </summary>
|
||||
public SigningOptions Signing { get; set; } = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Feature flags toggling optional behaviours.
|
||||
/// </summary>
|
||||
public FeatureFlagOptions Features { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Plug-in loader configuration.
|
||||
/// </summary>
|
||||
public PluginOptions Plugins { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Telemetry configuration for logs, metrics, traces.
|
||||
/// </summary>
|
||||
public TelemetryOptions Telemetry { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Authority / authentication configuration.
|
||||
/// </summary>
|
||||
public AuthorityOptions Authority { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Signing configuration for report envelopes and attestations.
|
||||
/// </summary>
|
||||
public SigningOptions Signing { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// API-specific settings such as base path.
|
||||
/// </summary>
|
||||
@@ -91,39 +91,42 @@ public sealed class ScannerWebServiceOptions
|
||||
/// Deterministic execution switches for tests and replay.
|
||||
/// </summary>
|
||||
public DeterminismOptions Determinism { get; set; } = new();
|
||||
|
||||
public sealed class StorageOptions
|
||||
{
|
||||
public string Driver { get; set; } = "mongo";
|
||||
|
||||
public string Dsn { get; set; } = string.Empty;
|
||||
|
||||
public string? Database { get; set; }
|
||||
|
||||
public int CommandTimeoutSeconds { get; set; } = 30;
|
||||
|
||||
public int HealthCheckTimeoutSeconds { get; set; } = 5;
|
||||
|
||||
public IList<string> Migrations { get; set; } = new List<string>();
|
||||
}
|
||||
|
||||
public sealed class QueueOptions
|
||||
{
|
||||
public string Driver { get; set; } = "redis";
|
||||
|
||||
public string Dsn { get; set; } = string.Empty;
|
||||
|
||||
public string Namespace { get; set; } = "scanner";
|
||||
|
||||
public int VisibilityTimeoutSeconds { get; set; } = 300;
|
||||
|
||||
public int LeaseHeartbeatSeconds { get; set; } = 30;
|
||||
|
||||
public int MaxDeliveryAttempts { get; set; } = 5;
|
||||
|
||||
public IDictionary<string, string> DriverSettings { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
|
||||
public sealed class StorageOptions
|
||||
{
|
||||
public string Driver { get; set; } = "postgres";
|
||||
|
||||
public string Dsn { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Optional schema name for scanner tables. Defaults to <c>scanner</c> when not provided.
|
||||
/// </summary>
|
||||
public string? Database { get; set; }
|
||||
|
||||
public int CommandTimeoutSeconds { get; set; } = 30;
|
||||
|
||||
public int HealthCheckTimeoutSeconds { get; set; } = 5;
|
||||
|
||||
public IList<string> Migrations { get; set; } = new List<string>();
|
||||
}
|
||||
|
||||
public sealed class QueueOptions
|
||||
{
|
||||
public string Driver { get; set; } = "redis";
|
||||
|
||||
public string Dsn { get; set; } = string.Empty;
|
||||
|
||||
public string Namespace { get; set; } = "scanner";
|
||||
|
||||
public int VisibilityTimeoutSeconds { get; set; } = 300;
|
||||
|
||||
public int LeaseHeartbeatSeconds { get; set; } = 30;
|
||||
|
||||
public int MaxDeliveryAttempts { get; set; } = 5;
|
||||
|
||||
public IDictionary<string, string> DriverSettings { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public sealed class ArtifactStoreOptions
|
||||
{
|
||||
public string Driver { get; set; } = "rustfs";
|
||||
@@ -159,114 +162,114 @@ public sealed class ScannerWebServiceOptions
|
||||
|
||||
public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
|
||||
public sealed class FeatureFlagOptions
|
||||
{
|
||||
public bool AllowAnonymousScanSubmission { get; set; }
|
||||
|
||||
public bool EnableSignedReports { get; set; } = true;
|
||||
|
||||
public bool EnablePolicyPreview { get; set; } = true;
|
||||
|
||||
public IDictionary<string, bool> Experimental { get; set; } = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public sealed class PluginOptions
|
||||
{
|
||||
public string? BaseDirectory { get; set; }
|
||||
|
||||
public string? Directory { get; set; }
|
||||
|
||||
public IList<string> SearchPatterns { get; set; } = new List<string>();
|
||||
|
||||
public IList<string> OrderedPlugins { get; set; } = new List<string>();
|
||||
}
|
||||
|
||||
public sealed class TelemetryOptions
|
||||
{
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
public bool EnableTracing { get; set; } = true;
|
||||
|
||||
public bool EnableMetrics { get; set; } = true;
|
||||
|
||||
public bool EnableLogging { get; set; } = true;
|
||||
|
||||
public bool EnableRequestLogging { get; set; } = true;
|
||||
|
||||
public string MinimumLogLevel { get; set; } = "Information";
|
||||
|
||||
public string? ServiceName { get; set; }
|
||||
|
||||
public string? OtlpEndpoint { get; set; }
|
||||
|
||||
public IDictionary<string, string> OtlpHeaders { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public IDictionary<string, string> ResourceAttributes { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public sealed class AuthorityOptions
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public bool AllowAnonymousFallback { get; set; } = true;
|
||||
|
||||
public string Issuer { get; set; } = string.Empty;
|
||||
|
||||
public string? MetadataAddress { get; set; }
|
||||
|
||||
public bool RequireHttpsMetadata { get; set; } = true;
|
||||
|
||||
public int BackchannelTimeoutSeconds { get; set; } = 30;
|
||||
|
||||
public int TokenClockSkewSeconds { get; set; } = 60;
|
||||
|
||||
public IList<string> Audiences { get; set; } = new List<string>();
|
||||
|
||||
public IList<string> RequiredScopes { get; set; } = new List<string>();
|
||||
|
||||
public IList<string> BypassNetworks { get; set; } = new List<string>();
|
||||
|
||||
public string? ClientId { get; set; }
|
||||
|
||||
public string? ClientSecret { get; set; }
|
||||
|
||||
public string? ClientSecretFile { get; set; }
|
||||
|
||||
public IList<string> ClientScopes { get; set; } = new List<string>();
|
||||
|
||||
public ResilienceOptions Resilience { get; set; } = new();
|
||||
|
||||
public sealed class ResilienceOptions
|
||||
{
|
||||
public bool? EnableRetries { get; set; }
|
||||
|
||||
public IList<TimeSpan> RetryDelays { get; set; } = new List<TimeSpan>();
|
||||
|
||||
public bool? AllowOfflineCacheFallback { get; set; }
|
||||
|
||||
public TimeSpan? OfflineCacheTolerance { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool EnablePolicyPreview { get; set; } = true;
|
||||
|
||||
public IDictionary<string, bool> Experimental { get; set; } = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public sealed class PluginOptions
|
||||
{
|
||||
public string? BaseDirectory { get; set; }
|
||||
|
||||
public string? Directory { get; set; }
|
||||
|
||||
public IList<string> SearchPatterns { get; set; } = new List<string>();
|
||||
|
||||
public IList<string> OrderedPlugins { get; set; } = new List<string>();
|
||||
}
|
||||
|
||||
public sealed class TelemetryOptions
|
||||
{
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
public bool EnableTracing { get; set; } = true;
|
||||
|
||||
public bool EnableMetrics { get; set; } = true;
|
||||
|
||||
public bool EnableLogging { get; set; } = true;
|
||||
|
||||
public bool EnableRequestLogging { get; set; } = true;
|
||||
|
||||
public string MinimumLogLevel { get; set; } = "Information";
|
||||
|
||||
public string? ServiceName { get; set; }
|
||||
|
||||
public string? OtlpEndpoint { get; set; }
|
||||
|
||||
public IDictionary<string, string> OtlpHeaders { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public IDictionary<string, string> ResourceAttributes { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public sealed class AuthorityOptions
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public bool AllowAnonymousFallback { get; set; } = true;
|
||||
|
||||
public string Issuer { get; set; } = string.Empty;
|
||||
|
||||
public string? MetadataAddress { get; set; }
|
||||
|
||||
public bool RequireHttpsMetadata { get; set; } = true;
|
||||
|
||||
public int BackchannelTimeoutSeconds { get; set; } = 30;
|
||||
|
||||
public int TokenClockSkewSeconds { get; set; } = 60;
|
||||
|
||||
public IList<string> Audiences { get; set; } = new List<string>();
|
||||
|
||||
public IList<string> RequiredScopes { get; set; } = new List<string>();
|
||||
|
||||
public IList<string> BypassNetworks { get; set; } = new List<string>();
|
||||
|
||||
public string? ClientId { get; set; }
|
||||
|
||||
public string? ClientSecret { get; set; }
|
||||
|
||||
public string? ClientSecretFile { get; set; }
|
||||
|
||||
public IList<string> ClientScopes { get; set; } = new List<string>();
|
||||
|
||||
public ResilienceOptions Resilience { get; set; } = new();
|
||||
|
||||
public sealed class ResilienceOptions
|
||||
{
|
||||
public bool? EnableRetries { get; set; }
|
||||
|
||||
public IList<TimeSpan> RetryDelays { get; set; } = new List<TimeSpan>();
|
||||
|
||||
public bool? AllowOfflineCacheFallback { get; set; }
|
||||
|
||||
public TimeSpan? OfflineCacheTolerance { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SigningOptions
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
public string KeyId { get; set; } = string.Empty;
|
||||
|
||||
public string Algorithm { get; set; } = "ed25519";
|
||||
|
||||
public string? Provider { get; set; }
|
||||
|
||||
public string? KeyPem { get; set; }
|
||||
|
||||
public string? KeyPemFile { get; set; }
|
||||
|
||||
public string? CertificatePem { get; set; }
|
||||
|
||||
public string? CertificatePemFile { get; set; }
|
||||
|
||||
|
||||
public string Algorithm { get; set; } = "ed25519";
|
||||
|
||||
public string? Provider { get; set; }
|
||||
|
||||
public string? KeyPem { get; set; }
|
||||
|
||||
public string? KeyPemFile { get; set; }
|
||||
|
||||
public string? CertificatePem { get; set; }
|
||||
|
||||
public string? CertificatePemFile { get; set; }
|
||||
|
||||
public string? CertificateChainPem { get; set; }
|
||||
|
||||
public string? CertificateChainPemFile { get; set; }
|
||||
@@ -305,7 +308,7 @@ public sealed class ScannerWebServiceOptions
|
||||
|
||||
public string? Email { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public sealed class ApiOptions
|
||||
{
|
||||
public string BasePath { get; set; } = "/api/v1";
|
||||
@@ -333,13 +336,13 @@ public sealed class ScannerWebServiceOptions
|
||||
public sealed class EventsOptions
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public string Driver { get; set; } = "redis";
|
||||
|
||||
public string Dsn { get; set; } = string.Empty;
|
||||
|
||||
public string Stream { get; set; } = "stella.events";
|
||||
|
||||
|
||||
public string Driver { get; set; } = "redis";
|
||||
|
||||
public string Dsn { get; set; } = string.Empty;
|
||||
|
||||
public string Stream { get; set; } = "stella.events";
|
||||
|
||||
public double PublishTimeoutSeconds { get; set; } = 5;
|
||||
|
||||
public long MaxStreamLength { get; set; } = 10000;
|
||||
|
||||
@@ -38,7 +38,6 @@ using StellaOps.Scanner.WebService.Security;
|
||||
using StellaOps.Scanner.WebService.Replay;
|
||||
using StellaOps.Scanner.Storage;
|
||||
using StellaOps.Scanner.Storage.Extensions;
|
||||
using StellaOps.Scanner.Storage.Mongo;
|
||||
using StellaOps.Scanner.WebService.Endpoints;
|
||||
using StellaOps.Scanner.WebService.Options;
|
||||
|
||||
@@ -138,15 +137,12 @@ else
|
||||
builder.Services.AddSingleton<IReportEventDispatcher, ReportEventDispatcher>();
|
||||
builder.Services.AddScannerStorage(storageOptions =>
|
||||
{
|
||||
storageOptions.Mongo.ConnectionString = bootstrapOptions.Storage.Dsn;
|
||||
if (!string.IsNullOrWhiteSpace(bootstrapOptions.Storage.Database))
|
||||
{
|
||||
storageOptions.Mongo.DatabaseName = bootstrapOptions.Storage.Database;
|
||||
}
|
||||
|
||||
storageOptions.Mongo.CommandTimeout = TimeSpan.FromSeconds(bootstrapOptions.Storage.CommandTimeoutSeconds);
|
||||
storageOptions.Mongo.UseMajorityReadConcern = true;
|
||||
storageOptions.Mongo.UseMajorityWriteConcern = true;
|
||||
storageOptions.Postgres.ConnectionString = bootstrapOptions.Storage.Dsn;
|
||||
storageOptions.Postgres.SchemaName = string.IsNullOrWhiteSpace(bootstrapOptions.Storage.Database)
|
||||
? ScannerStorageDefaults.DefaultSchemaName
|
||||
: bootstrapOptions.Storage.Database!.Trim();
|
||||
storageOptions.Postgres.CommandTimeoutSeconds = bootstrapOptions.Storage.CommandTimeoutSeconds;
|
||||
storageOptions.Postgres.AutoMigrate = true;
|
||||
|
||||
storageOptions.ObjectStore.Headers.Clear();
|
||||
foreach (var header in bootstrapOptions.ArtifactStore.Headers)
|
||||
@@ -335,12 +331,6 @@ if (authorityConfigured && resolvedOptions.Authority.AllowAnonymousFallback)
|
||||
"Scanner authority authentication is enabled but anonymous fallback remains allowed. Disable fallback before production rollout.");
|
||||
}
|
||||
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var bootstrapper = scope.ServiceProvider.GetRequiredService<MongoBootstrapper>();
|
||||
await bootstrapper.InitializeAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (resolvedOptions.Telemetry.EnableLogging && resolvedOptions.Telemetry.EnableRequestLogging)
|
||||
{
|
||||
app.UseSerilogRequestLogging(options =>
|
||||
|
||||
@@ -184,7 +184,7 @@ internal sealed class RecordModeService : IRecordModeService
|
||||
{
|
||||
var manifest = new ReplayManifest
|
||||
{
|
||||
SchemaVersion = ReplayManifestVersions.V1,
|
||||
SchemaVersion = ReplayManifestVersions.V2,
|
||||
Scan = new ReplayScanMetadata
|
||||
{
|
||||
Id = request.ScanId,
|
||||
|
||||
@@ -2,7 +2,6 @@ using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Text;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Scanner.Storage.Catalog;
|
||||
using StellaOps.Scanner.Storage.Repositories;
|
||||
using StellaOps.Scanner.WebService.Options;
|
||||
@@ -85,7 +84,7 @@ internal sealed class RuntimeEventIngestionService : IRuntimeEventIngestionServi
|
||||
return RuntimeEventIngestionResult.PayloadTooLarge(totalPayloadBytes, options.MaxPayloadBytes);
|
||||
}
|
||||
|
||||
var payloadDocument = BsonDocument.Parse(Encoding.UTF8.GetString(payloadBytes));
|
||||
var payloadJson = Encoding.UTF8.GetString(payloadBytes);
|
||||
var runtimeEvent = envelope.Event;
|
||||
var normalizedDigest = ExtractImageDigest(runtimeEvent);
|
||||
var normalizedBuildId = NormalizeBuildId(runtimeEvent.Process?.BuildId);
|
||||
@@ -113,7 +112,7 @@ internal sealed class RuntimeEventIngestionService : IRuntimeEventIngestionServi
|
||||
ImageSigned = runtimeEvent.Posture?.ImageSigned,
|
||||
SbomReferrer = runtimeEvent.Posture?.SbomReferrer,
|
||||
BuildId = normalizedBuildId,
|
||||
Payload = payloadDocument
|
||||
PayloadJson = payloadJson
|
||||
};
|
||||
|
||||
documents.Add(document);
|
||||
|
||||
Reference in New Issue
Block a user