This commit is contained in:
master
2026-02-04 19:59:20 +02:00
parent 557feefdc3
commit 5548cf83bf
1479 changed files with 53557 additions and 40339 deletions

View File

@@ -27,17 +27,21 @@ public static class BinaryIndexServiceExtensions
.GetSection("BinaryIndex")
.Get<BinaryIndexOptions>() ?? new BinaryIndexOptions();
services.AddSingleton(options);
if (!options.Enabled)
{
services.AddSingleton<IBinaryVulnerabilityService, NullBinaryVulnerabilityService>();
services.AddSingleton<IBinaryFeatureExtractor, NullBinaryFeatureExtractor>();
services.AddSingleton<BinaryVulnerabilityAnalyzer>();
services.AddSingleton<Processing.BinaryFindingMapper>();
return services;
}
services.AddSingleton(options);
services.AddScoped<IBinaryVulnerabilityService, BinaryVulnerabilityService>();
services.AddScoped<IBinaryFeatureExtractor, ElfFeatureExtractor>();
services.AddScoped<BinaryVulnerabilityAnalyzer>();
services.AddScoped<Processing.BinaryFindingMapper>();
services.AddSingleton<IBinaryVulnerabilityService, BinaryVulnerabilityService>();
services.AddSingleton<IBinaryFeatureExtractor, ElfFeatureExtractor>();
services.AddSingleton<BinaryVulnerabilityAnalyzer>();
services.AddSingleton<Processing.BinaryFindingMapper>();
return services;
}
@@ -51,7 +55,7 @@ public sealed class BinaryIndexOptions
/// <summary>
/// Whether binary vulnerability analysis is enabled.
/// </summary>
public bool Enabled { get; init; } = true;
public bool Enabled { get; init; } = false;
/// <summary>
/// Batch size for binary lookups.
@@ -159,3 +163,27 @@ internal sealed class NullBinaryVulnerabilityService : IBinaryVulnerabilityServi
return Task.FromResult(System.Collections.Immutable.ImmutableDictionary<string, System.Collections.Immutable.ImmutableArray<CorpusFunctionMatch>>.Empty);
}
}
/// <summary>
/// Null implementation of IBinaryFeatureExtractor for when binary analysis is disabled.
/// </summary>
internal sealed class NullBinaryFeatureExtractor : IBinaryFeatureExtractor
{
public bool CanExtract(Stream stream) => false;
public Task<StellaOps.BinaryIndex.Core.Models.BinaryIdentity> ExtractIdentityAsync(Stream stream, CancellationToken ct = default)
=> Task.FromResult(new StellaOps.BinaryIndex.Core.Models.BinaryIdentity
{
BinaryKey = "null",
FileSha256 = "",
Format = StellaOps.BinaryIndex.Core.Models.BinaryFormat.Elf,
Architecture = "unknown"
});
public Task<BinaryMetadata> ExtractMetadataAsync(Stream stream, CancellationToken ct = default)
=> Task.FromResult(new BinaryMetadata
{
Format = StellaOps.BinaryIndex.Core.Models.BinaryFormat.Elf,
Architecture = "unknown"
});
}

View File

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) StellaOps
using StellaOps.Scanner.Core.Epss;
namespace StellaOps.Scanner.Worker.Processing;
/// <summary>
/// Null implementation of IEpssProvider for when EPSS storage is not configured.
/// </summary>
internal sealed class NullEpssProvider : IEpssProvider
{
public Task<EpssEvidence?> GetCurrentAsync(string cveId, CancellationToken cancellationToken = default)
=> Task.FromResult<EpssEvidence?>(null);
public Task<EpssBatchResult> GetCurrentBatchAsync(IEnumerable<string> cveIds, CancellationToken cancellationToken = default)
=> Task.FromResult(new EpssBatchResult { Found = [], NotFound = cveIds.ToList(), ModelDate = DateOnly.MinValue });
public Task<EpssEvidence?> GetAsOfDateAsync(string cveId, DateOnly asOfDate, CancellationToken cancellationToken = default)
=> Task.FromResult<EpssEvidence?>(null);
public Task<IReadOnlyList<EpssEvidence>> GetHistoryAsync(string cveId, DateOnly startDate, DateOnly endDate, CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<EpssEvidence>>([]);
public Task<DateOnly?> GetLatestModelDateAsync(CancellationToken cancellationToken = default)
=> Task.FromResult<DateOnly?>(null);
public Task<bool> IsAvailableAsync(CancellationToken cancellationToken = default)
=> Task.FromResult(false);
}

View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) StellaOps
// Null implementations for PoE/Reachability infrastructure dependencies
using StellaOps.Scanner.Reachability;
using StellaOps.Scanner.Storage.ObjectStore;
namespace StellaOps.Scanner.Worker.Processing;
/// <summary>
/// Null implementation of IRichGraphStore for environments without richgraph infrastructure.
/// </summary>
internal sealed class NullRichGraphStore : IRichGraphStore
{
public Task<RichGraphV1?> FetchGraphAsync(string graphHash, CancellationToken cancellationToken)
=> Task.FromResult<RichGraphV1?>(null);
}
/// <summary>
/// Null implementation of IEntryPointResolver for environments without entry point resolution.
/// </summary>
internal sealed class NullEntryPointResolver : IEntryPointResolver
{
public Task<IReadOnlyList<EntryPoint>> ResolveAsync(RichGraphV1 graph, CancellationToken cancellationToken)
=> Task.FromResult<IReadOnlyList<EntryPoint>>([]);
}
/// <summary>
/// Null implementation of IVulnSurfaceService for environments without vulnerability surface data.
/// </summary>
internal sealed class NullVulnSurfaceService : IVulnSurfaceService
{
public Task<IReadOnlyList<AffectedSymbol>> GetAffectedSymbolsAsync(
string vulnId, string componentRef, CancellationToken cancellationToken)
=> Task.FromResult<IReadOnlyList<AffectedSymbol>>([]);
}
/// <summary>
/// Null implementation of IDsseSigningService for environments without signing infrastructure.
/// </summary>
internal sealed class NullDsseSigningService : StellaOps.Attestor.IDsseSigningService
{
public Task<byte[]> SignAsync(byte[] payload, string payloadType, string signingKeyId, CancellationToken cancellationToken = default)
=> Task.FromResult(Array.Empty<byte>());
public Task<bool> VerifyAsync(byte[] dsseEnvelope, IReadOnlyList<string> trustedKeyIds, CancellationToken cancellationToken = default)
=> Task.FromResult(false);
}
/// <summary>
/// Null implementation of IArtifactObjectStore for environments without object storage.
/// </summary>
internal sealed class NullArtifactObjectStore : IArtifactObjectStore
{
public Task PutAsync(ArtifactObjectDescriptor descriptor, Stream content, CancellationToken cancellationToken)
=> Task.CompletedTask;
public Task<Stream?> GetAsync(ArtifactObjectDescriptor descriptor, CancellationToken cancellationToken)
=> Task.FromResult<Stream?>(null);
public Task DeleteAsync(ArtifactObjectDescriptor descriptor, CancellationToken cancellationToken)
=> Task.CompletedTask;
}

View File

@@ -51,10 +51,11 @@ using StellaOps.Scanner.Worker.Processing.Entropy;
using StellaOps.Scanner.Worker.Processing.Secrets;
using StellaOps.Scanner.Worker.Processing.ServiceSecurity;
using StellaOps.Scanner.Worker.Processing.Surface;
using StellaOps.Worker.Health;
using System.Diagnostics;
using System.IO;
var builder = Host.CreateApplicationBuilder(args);
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddOptions<ScannerWorkerOptions>()
.BindConfiguration(ScannerWorkerOptions.SectionName)
@@ -92,6 +93,7 @@ builder.Services.AddSingleton(new DeterminismContext(
workerOptions.Determinism.FilterLogs,
workerOptions.Determinism.ConcurrencyLimit));
builder.Services.AddSingleton<IDeterministicRandomProvider>(_ => new DeterministicRandomProvider(workerOptions.Determinism.RngSeed));
builder.Services.AddSingleton<DeterministicRandomService>();
builder.Services.AddScannerCache(builder.Configuration);
builder.Services.AddSurfaceEnvironment(options =>
{
@@ -173,8 +175,21 @@ else
{
builder.Services.TryAddSingleton<IRubyPackageInventoryStore, NullRubyPackageInventoryStore>();
builder.Services.TryAddSingleton<IBunPackageInventoryStore, NullBunPackageInventoryStore>();
// Provide fallback registrations for services used by unconditionally-registered components
builder.Services.TryAddSingleton(new StellaOps.Scanner.Storage.ScannerStorageOptions());
builder.Services.TryAddSingleton<StellaOps.Scanner.Storage.ObjectStore.IArtifactObjectStore, NullArtifactObjectStore>();
}
// Unwrap IOptions<ScannerStorageOptions> to concrete type for classes that take it directly (e.g. ReplayBundleFetcher)
builder.Services.TryAddSingleton(sp =>
{
var opts = sp.GetService<Microsoft.Extensions.Options.IOptions<StellaOps.Scanner.Storage.ScannerStorageOptions>>();
return opts?.Value ?? new StellaOps.Scanner.Storage.ScannerStorageOptions();
});
// Ensure IEpssProvider is available even without storage (null fallback)
builder.Services.TryAddSingleton<StellaOps.Scanner.Core.Epss.IEpssProvider, NullEpssProvider>();
builder.Services.TryAddSingleton<IScanJobSource, NullScanJobSource>();
builder.Services.TryAddSingleton<IPluginCatalogGuard, RestartOnlyPluginGuard>();
builder.Services.AddSingleton<IOSAnalyzerPluginCatalog, OsAnalyzerPluginCatalog>();
@@ -260,9 +275,22 @@ if (workerOptions.Secrets.Enabled)
builder.Services.AddOptions<StellaOps.Scanner.Core.Configuration.PoEConfiguration>()
.BindConfiguration("PoE")
.ValidateOnStart();
// SubgraphExtractor dependencies (null defaults for environments without richgraph/vulnsurface infra)
builder.Services.TryAddSingleton<StellaOps.Scanner.Reachability.IRichGraphStore, NullRichGraphStore>();
builder.Services.TryAddSingleton<StellaOps.Scanner.Reachability.IEntryPointResolver, NullEntryPointResolver>();
builder.Services.TryAddSingleton<StellaOps.Scanner.Reachability.IVulnSurfaceService, NullVulnSurfaceService>();
builder.Services.AddSingleton<StellaOps.Scanner.Reachability.IReachabilityResolver, StellaOps.Scanner.Reachability.SubgraphExtractor>();
// PoEArtifactGenerator dependency (null default for environments without signing infra)
builder.Services.TryAddSingleton<StellaOps.Attestor.IDsseSigningService, NullDsseSigningService>();
// PoEEmissionOptions is a positional record without parameterless ctor - configure explicitly
builder.Services.AddSingleton(Microsoft.Extensions.Options.Options.Create(StellaOps.Attestor.PoEEmissionOptions.Default));
builder.Services.AddSingleton<StellaOps.Attestor.IProofEmitter, StellaOps.Attestor.PoEArtifactGenerator>();
builder.Services.AddSingleton<StellaOps.Signals.Storage.IPoECasStore, StellaOps.Signals.Storage.PoECasStore>();
// PoECasStore needs a string casRoot parameter - use factory
builder.Services.AddSingleton<StellaOps.Signals.Storage.IPoECasStore>(sp =>
new StellaOps.Signals.Storage.PoECasStore(
Environment.GetEnvironmentVariable("POE_CAS_ROOT") ?? "/tmp/poe-cas",
sp.GetRequiredService<ILogger<StellaOps.Signals.Storage.PoECasStore>>(),
sp.GetService<TimeProvider>()));
builder.Services.AddSingleton<StellaOps.Scanner.Worker.Orchestration.PoEOrchestrator>();
builder.Services.AddSingleton<IScanStageExecutor, StellaOps.Scanner.Worker.Processing.PoE.PoEGenerationStageExecutor>();
@@ -356,21 +384,25 @@ builder.Logging.Configure(options =>
| ActivityTrackingOptions.ParentId;
});
var host = builder.Build();
builder.Services.AddWorkerHealthChecks();
var app = builder.Build();
// Fail fast if surface configuration is invalid at startup.
using (var scope = host.Services.CreateScope())
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var env = services.GetRequiredService<ISurfaceEnvironment>();
var runner = services.GetRequiredService<ISurfaceValidatorRunner>();
await runner.EnsureAsync(
SurfaceValidationContext.Create(services, "Scanner.Worker.Startup", env.Settings),
host.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStopping)
app.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStopping)
.ConfigureAwait(false);
}
await host.RunAsync();
app.MapWorkerHealthEndpoints();
await app.RunAsync();
// Make Program class file-scoped to prevent it from being exposed to referencing assemblies
file sealed partial class Program;

View File

@@ -15,6 +15,10 @@
<PackageReference Include="OpenTelemetry.Instrumentation.Process" />
</ItemGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../__Libraries/StellaOps.Worker.Health/StellaOps.Worker.Health.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Canonical.Json/StellaOps.Canonical.Json.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Determinism.Abstractions/StellaOps.Determinism.Abstractions.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Cryptography/StellaOps.Cryptography.csproj" />