Files
git.stella-ops.org/src/Scanner/__Libraries/StellaOps.Scanner.Reachability/ReachabilityReplayWriter.cs
StellaOps Bot efaf3cb789
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
up
2025-12-12 09:35:37 +02:00

160 lines
5.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using StellaOps.Replay.Core;
namespace StellaOps.Scanner.Reachability;
/// <summary>
/// Helper that projects reachability artifacts into the replay manifest.
/// </summary>
public sealed class ReachabilityReplayWriter
{
/// <summary>
/// Attaches reachability graphs and runtime traces to the supplied replay manifest.
/// </summary>
public void AttachEvidence(
ReplayManifest manifest,
IEnumerable<ReachabilityReplayGraph>? graphs,
IEnumerable<ReachabilityReplayTrace>? traces)
{
ArgumentNullException.ThrowIfNull(manifest);
WriteGraphs(manifest, graphs);
WriteTraces(manifest, traces);
}
private static void WriteGraphs(ReplayManifest manifest, IEnumerable<ReachabilityReplayGraph>? graphs)
{
if (graphs is null)
{
return;
}
var sanitized = graphs
.Where(graph => graph is not null)
.Select(graph => NormalizeGraph(graph!))
.Where(graph => graph is not null)
.Select(graph => graph!)
.DistinctBy(graph => (graph.Kind, graph.CasUri, graph.Sha256, graph.Analyzer, graph.Version))
.OrderBy(graph => graph.CasUri, StringComparer.Ordinal)
.ThenBy(graph => graph.Kind, StringComparer.Ordinal)
.ToList();
foreach (var graph in sanitized)
{
manifest.AddReachabilityGraph(new ReplayReachabilityGraphReference
{
Kind = graph.Kind,
CasUri = graph.CasUri,
Sha256 = graph.Sha256,
HashAlgorithm = string.IsNullOrWhiteSpace(graph.Sha256) ? "sha256" : "blake3-256",
Analyzer = graph.Analyzer,
Version = graph.Version
});
}
}
private static void WriteTraces(ReplayManifest manifest, IEnumerable<ReachabilityReplayTrace>? traces)
{
if (traces is null)
{
return;
}
var normalized = traces
.Where(trace => trace is not null)
.Select(trace => NormalizeTrace(trace!))
.Where(trace => trace is not null)
.Select(trace => trace!)
.ToList();
var collapsed = normalized
.GroupBy(trace => (trace.Source, trace.CasUri, trace.Sha256))
.Select(group => group.OrderBy(t => t.RecordedAt).First())
.OrderBy(trace => trace.RecordedAt)
.ThenBy(trace => trace.CasUri, StringComparer.Ordinal)
.ToList();
foreach (var trace in collapsed)
{
manifest.AddReachabilityTrace(new ReplayReachabilityTraceReference
{
Source = trace.Source,
CasUri = trace.CasUri,
Sha256 = trace.Sha256,
HashAlgorithm = string.IsNullOrWhiteSpace(trace.Sha256) ? "sha256" : "sha256",
RecordedAt = trace.RecordedAt
});
}
}
private static NormalizedGraph? NormalizeGraph(ReachabilityReplayGraph graph)
{
var casUri = Normalize(graph.CasUri);
if (string.IsNullOrEmpty(casUri))
{
return null;
}
return new NormalizedGraph(
Kind: Normalize(graph.Kind) ?? "static",
CasUri: casUri,
Sha256: NormalizeHash(graph.Sha256),
Analyzer: Normalize(graph.Analyzer) ?? string.Empty,
Version: Normalize(graph.Version) ?? string.Empty);
}
private static NormalizedTrace? NormalizeTrace(ReachabilityReplayTrace trace)
{
var casUri = Normalize(trace.CasUri);
if (string.IsNullOrEmpty(casUri))
{
return null;
}
return new NormalizedTrace(
Source: Normalize(trace.Source) ?? string.Empty,
CasUri: casUri,
Sha256: NormalizeHash(trace.Sha256),
RecordedAt: trace.RecordedAt.ToUniversalTime());
}
private static string? Normalize(string? value)
=> string.IsNullOrWhiteSpace(value) ? null : value.Trim();
private static string NormalizeHash(string? hash)
=> string.IsNullOrWhiteSpace(hash) ? string.Empty : hash.Trim().ToLowerInvariant();
private sealed record NormalizedGraph(
string Kind,
string CasUri,
string Sha256,
string Analyzer,
string Version);
private sealed record NormalizedTrace(
string Source,
string CasUri,
string Sha256,
DateTimeOffset RecordedAt);
}
/// <summary>
/// Describes a CAS-backed reachability graph emitted by Scanner.
/// </summary>
public sealed record ReachabilityReplayGraph(
string? Kind,
string? CasUri,
string? Sha256,
string? Analyzer,
string? Version);
/// <summary>
/// Describes a runtime trace artifact emitted by Scanner/Zastava.
/// </summary>
public sealed record ReachabilityReplayTrace(
string? Source,
string? CasUri,
string? Sha256,
DateTimeOffset RecordedAt);