up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
sdk-generator-smoke / sdk-smoke (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-27 08:51:10 +02:00
parent ea970ead2a
commit c34fb7256d
126 changed files with 18553 additions and 693 deletions

View File

@@ -7,12 +7,13 @@ namespace StellaOps.Scanner.Worker.Determinism;
/// </summary>
public sealed class DeterminismContext
{
public DeterminismContext(bool fixedClock, DateTimeOffset fixedInstantUtc, int? rngSeed, bool filterLogs)
public DeterminismContext(bool fixedClock, DateTimeOffset fixedInstantUtc, int? rngSeed, bool filterLogs, int? concurrencyLimit)
{
FixedClock = fixedClock;
FixedInstantUtc = fixedInstantUtc.ToUniversalTime();
RngSeed = rngSeed;
FilterLogs = filterLogs;
ConcurrencyLimit = concurrencyLimit;
}
public bool FixedClock { get; }
@@ -22,4 +23,6 @@ public sealed class DeterminismContext
public int? RngSeed { get; }
public bool FilterLogs { get; }
public int? ConcurrencyLimit { get; }
}

View File

@@ -42,6 +42,7 @@ internal sealed class SurfaceManifestStageExecutor : IScanStageExecutor
private readonly ILogger<SurfaceManifestStageExecutor> _logger;
private readonly ICryptoHash _hash;
private readonly IRubyPackageInventoryStore _rubyPackageStore;
private readonly Determinism.DeterminismContext _determinism;
private readonly string _componentVersion;
public SurfaceManifestStageExecutor(
@@ -51,7 +52,8 @@ internal sealed class SurfaceManifestStageExecutor : IScanStageExecutor
ScannerWorkerMetrics metrics,
ILogger<SurfaceManifestStageExecutor> logger,
ICryptoHash hash,
IRubyPackageInventoryStore rubyPackageStore)
IRubyPackageInventoryStore rubyPackageStore,
Determinism.DeterminismContext determinism)
{
_publisher = publisher ?? throw new ArgumentNullException(nameof(publisher));
_surfaceCache = surfaceCache ?? throw new ArgumentNullException(nameof(surfaceCache));
@@ -60,6 +62,7 @@ internal sealed class SurfaceManifestStageExecutor : IScanStageExecutor
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_hash = hash ?? throw new ArgumentNullException(nameof(hash));
_rubyPackageStore = rubyPackageStore ?? throw new ArgumentNullException(nameof(rubyPackageStore));
_determinism = determinism ?? throw new ArgumentNullException(nameof(determinism));
_componentVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown";
}
@@ -221,9 +224,56 @@ internal sealed class SurfaceManifestStageExecutor : IScanStageExecutor
}));
}
var determinismPayload = BuildDeterminismPayload(context, payloads);
if (determinismPayload is not null)
{
payloads.Add(determinismPayload);
}
return payloads;
}
private SurfaceManifestPayload? BuildDeterminismPayload(ScanJobContext context, IEnumerable<SurfaceManifestPayload> payloads)
{
var pins = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (context.Lease.Metadata.TryGetValue("determinism.feed", out var feed) && !string.IsNullOrWhiteSpace(feed))
{
pins["feed"] = feed;
}
if (context.Lease.Metadata.TryGetValue("determinism.policy", out var policy) && !string.IsNullOrWhiteSpace(policy))
{
pins["policy"] = policy;
}
var artifactHashes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var payload in payloads)
{
var digest = ComputeDigest(payload.Content.Span);
artifactHashes[payload.Kind] = digest;
}
var report = new
{
fixedClock = _determinism.FixedClock,
fixedInstantUtc = _determinism.FixedInstantUtc,
rngSeed = _determinism.RngSeed,
filterLogs = _determinism.FilterLogs,
concurrencyLimit = _determinism.ConcurrencyLimit,
pins = pins,
artifacts = artifactHashes
};
var json = JsonSerializer.Serialize(report, JsonOptions);
return new SurfaceManifestPayload(
ArtifactDocumentType.SurfaceObservation,
ArtifactDocumentFormat.ObservationJson,
Kind: "determinism.json",
MediaType: "application/json",
Content: Encoding.UTF8.GetBytes(json),
View: "replay");
}
private async Task PersistRubyPackagesAsync(ScanJobContext context, CancellationToken cancellationToken)
{
if (!context.Analysis.TryGet<ReadOnlyDictionary<string, LanguageAnalyzerResult>>(ScanAnalysisKeys.LanguageAnalyzerResults, out var results))

View File

@@ -58,7 +58,8 @@ builder.Services.AddSingleton(new DeterminismContext(
workerOptions.Determinism.FixedClock,
workerOptions.Determinism.FixedInstantUtc,
workerOptions.Determinism.RngSeed,
workerOptions.Determinism.FilterLogs));
workerOptions.Determinism.FilterLogs,
workerOptions.Determinism.ConcurrencyLimit));
builder.Services.AddSingleton<IDeterministicRandomProvider>(_ => new DeterministicRandomProvider(workerOptions.Determinism.RngSeed));
builder.Services.AddScannerCache(builder.Configuration);
builder.Services.AddSurfaceEnvironment(options =>