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

This commit is contained in:
StellaOps Bot
2025-12-12 09:35:37 +02:00
parent ce5ec9c158
commit efaf3cb789
238 changed files with 146274 additions and 5767 deletions

View File

@@ -46,7 +46,9 @@ public sealed class ReachabilityGraphBuilder
int? sourceLine = null,
IReadOnlyDictionary<string, string>? attributes = null,
string? purl = null,
string? symbolDigest = null)
string? symbolDigest = null,
ReachabilitySymbol? symbol = null,
string? codeBlockHash = null)
{
if (string.IsNullOrWhiteSpace(symbolId))
{
@@ -63,7 +65,9 @@ public sealed class ReachabilityGraphBuilder
sourceLine,
attributes?.ToImmutableSortedDictionary(StringComparer.Ordinal) ?? ImmutableSortedDictionary<string, string>.Empty,
purl?.Trim(),
symbolDigest?.Trim());
symbolDigest?.Trim(),
symbol?.Trimmed(),
codeBlockHash?.Trim());
_richNodes[id] = node;
nodes.Add(id);
@@ -184,6 +188,8 @@ public sealed class ReachabilityGraphBuilder
rich.Lang,
rich.Kind,
rich.Display,
rich.CodeBlockHash,
rich.Symbol,
source,
rich.Attributes.Count > 0 ? rich.Attributes : null,
rich.Purl,
@@ -337,7 +343,9 @@ public sealed class ReachabilityGraphBuilder
int? SourceLine,
ImmutableSortedDictionary<string, string> Attributes,
string? Purl = null,
string? SymbolDigest = null);
string? SymbolDigest = null,
ReachabilitySymbol? Symbol = null,
string? CodeBlockHash = null);
private sealed record RichEdge(
string From,

View File

@@ -48,6 +48,7 @@ public sealed class ReachabilityReplayWriter
Kind = graph.Kind,
CasUri = graph.CasUri,
Sha256 = graph.Sha256,
HashAlgorithm = string.IsNullOrWhiteSpace(graph.Sha256) ? "sha256" : "blake3-256",
Analyzer = graph.Analyzer,
Version = graph.Version
});
@@ -81,6 +82,7 @@ public sealed class ReachabilityReplayWriter
Source = trace.Source,
CasUri = trace.CasUri,
Sha256 = trace.Sha256,
HashAlgorithm = string.IsNullOrWhiteSpace(trace.Sha256) ? "sha256" : "sha256",
RecordedAt = trace.RecordedAt
});
}

View File

@@ -0,0 +1,37 @@
using System;
namespace StellaOps.Scanner.Reachability;
/// <summary>
/// Represents optional symbol metadata (mangled/demangled names, source, confidence).
/// Used to enrich reachability evidence without altering canonical IDs.
/// </summary>
public sealed record ReachabilitySymbol(
string? Mangled,
string? Demangled,
string? Source,
double? Confidence)
{
public ReachabilitySymbol Trimmed()
=> new(
TrimOrNull(Mangled),
TrimOrNull(Demangled),
NormalizeSource(Source),
Confidence is null ? null : ClampConfidence(Confidence.Value));
private static string? TrimOrNull(string? value)
=> string.IsNullOrWhiteSpace(value) ? null : value.Trim();
private static string? NormalizeSource(string? source)
{
if (string.IsNullOrWhiteSpace(source))
{
return null;
}
return source.Trim().ToUpperInvariant();
}
private static double ClampConfidence(double value)
=> Math.Max(0.0, Math.Min(1.0, value));
}

View File

@@ -72,6 +72,8 @@ public sealed class ReachabilityUnionWriter
Lang = Trim(n.Lang) ?? string.Empty,
Kind = Trim(n.Kind) ?? string.Empty,
Display = Trim(n.Display),
CodeBlockHash = Trim(n.CodeBlockHash),
Symbol = n.Symbol?.Trimmed(),
Source = n.Source?.Trimmed(),
Attributes = (n.Attributes ?? ImmutableDictionary<string, string>.Empty)
.Where(kv => !string.IsNullOrWhiteSpace(kv.Key) && kv.Value is not null)
@@ -173,6 +175,17 @@ public sealed class ReachabilityUnionWriter
jw.WriteString("purl", node.Purl);
}
if (!string.IsNullOrWhiteSpace(node.CodeBlockHash))
{
jw.WriteString("code_block_hash", node.CodeBlockHash);
}
if (node.Symbol is not null)
{
jw.WritePropertyName("symbol");
WriteSymbol(jw, node.Symbol);
}
if (!string.IsNullOrWhiteSpace(node.SymbolDigest))
{
jw.WriteString("symbol_digest", node.SymbolDigest);
@@ -309,6 +322,31 @@ public sealed class ReachabilityUnionWriter
await writer.WriteAsync(Encoding.UTF8.GetString(json.ToArray())).ConfigureAwait(false);
}
private static void WriteSymbol(Utf8JsonWriter jw, ReachabilitySymbol symbol)
{
jw.WriteStartObject();
if (!string.IsNullOrWhiteSpace(symbol.Mangled))
{
jw.WriteString("mangled", symbol.Mangled);
}
if (!string.IsNullOrWhiteSpace(symbol.Demangled))
{
jw.WriteString("demangled", symbol.Demangled);
}
if (!string.IsNullOrWhiteSpace(symbol.Source))
{
jw.WriteString("source", symbol.Source);
}
if (symbol.Confidence is not null)
{
jw.WriteNumber("confidence", symbol.Confidence.Value);
}
jw.WriteEndObject();
}
private static void WriteSource(Utf8JsonWriter jw, ReachabilitySource source)
{
jw.WriteStartObject();
@@ -390,6 +428,8 @@ public sealed record ReachabilityUnionNode(
string Lang,
string Kind,
string? Display = null,
string? CodeBlockHash = null,
ReachabilitySymbol? Symbol = null,
ReachabilitySource? Source = null,
IReadOnlyDictionary<string, string>? Attributes = null,
string? Purl = null,

View File

@@ -52,7 +52,9 @@ public sealed record RichGraphNode(
string? BuildId,
IReadOnlyList<string>? Evidence,
IReadOnlyDictionary<string, string>? Attributes,
string? SymbolDigest)
string? SymbolDigest,
ReachabilitySymbol? Symbol = null,
string? CodeBlockHash = null)
{
public RichGraphNode Trimmed()
{
@@ -66,7 +68,9 @@ public sealed record RichGraphNode(
Kind = Kind.Trim(),
Display = string.IsNullOrWhiteSpace(Display) ? null : Display.Trim(),
BuildId = string.IsNullOrWhiteSpace(BuildId) ? null : BuildId.Trim(),
CodeBlockHash = string.IsNullOrWhiteSpace(CodeBlockHash) ? null : CodeBlockHash.Trim(),
SymbolDigest = string.IsNullOrWhiteSpace(SymbolDigest) ? null : SymbolDigest.Trim(),
Symbol = Symbol?.Trimmed(),
Evidence = Evidence is null
? Array.Empty<string>()
: Evidence.Where(e => !string.IsNullOrWhiteSpace(e)).Select(e => e.Trim()).OrderBy(e => e, StringComparer.Ordinal).ToArray(),
@@ -155,6 +159,21 @@ public static class RichGraphBuilder
var symbolDigest = ComputeSymbolDigest(symbolId);
nodeDigests[symbolId] = symbolDigest;
var codeBlockHash = node.CodeBlockHash;
if (string.IsNullOrWhiteSpace(codeBlockHash) && node.Attributes is not null && node.Attributes.TryGetValue("code_block_hash", out var cbh))
{
codeBlockHash = cbh;
}
var symbol = node.Symbol;
if (symbol is null && !string.IsNullOrWhiteSpace(node.Display))
{
var symbolSource = node.Attributes is not null && node.Attributes.TryGetValue("symbol_source", out var sourceHint)
? sourceHint
: null;
symbol = new ReachabilitySymbol(null, node.Display, symbolSource, null);
}
var codeId = node.Attributes is not null && node.Attributes.TryGetValue("code_id", out var cid)
? cid
: CodeId.FromSymbolId(symbolId);
@@ -170,7 +189,9 @@ public static class RichGraphBuilder
BuildId: node.Attributes is not null && node.Attributes.TryGetValue("build_id", out var bid) ? bid : null,
Evidence: node.Source?.Evidence is null ? Array.Empty<string>() : new[] { node.Source.Evidence },
Attributes: node.Attributes,
SymbolDigest: symbolDigest));
SymbolDigest: symbolDigest,
Symbol: symbol?.Trimmed(),
CodeBlockHash: string.IsNullOrWhiteSpace(codeBlockHash) ? null : codeBlockHash.Trim()));
}
var edges = new List<RichGraphEdge>();

View File

@@ -110,7 +110,13 @@ public sealed class RichGraphWriter
if (!string.IsNullOrWhiteSpace(node.CodeId)) writer.WriteString("code_id", node.CodeId);
if (!string.IsNullOrWhiteSpace(node.Purl)) writer.WriteString("purl", node.Purl);
if (!string.IsNullOrWhiteSpace(node.BuildId)) writer.WriteString("build_id", node.BuildId);
if (!string.IsNullOrWhiteSpace(node.CodeBlockHash)) writer.WriteString("code_block_hash", node.CodeBlockHash);
if (!string.IsNullOrWhiteSpace(node.SymbolDigest)) writer.WriteString("symbol_digest", node.SymbolDigest);
if (node.Symbol is not null)
{
writer.WritePropertyName("symbol");
WriteSymbol(writer, node.Symbol);
}
if (node.Evidence is { Count: > 0 })
{
@@ -182,6 +188,30 @@ public sealed class RichGraphWriter
writer.WriteEndObject();
}
private static void WriteSymbol(Utf8JsonWriter writer, ReachabilitySymbol symbol)
{
writer.WriteStartObject();
if (!string.IsNullOrWhiteSpace(symbol.Mangled))
{
writer.WriteString("mangled", symbol.Mangled);
}
if (!string.IsNullOrWhiteSpace(symbol.Demangled))
{
writer.WriteString("demangled", symbol.Demangled);
}
if (!string.IsNullOrWhiteSpace(symbol.Source))
{
writer.WriteString("source", symbol.Source);
}
if (symbol.Confidence is not null)
{
writer.WriteNumber("confidence", symbol.Confidence.Value);
}
writer.WriteEndObject();
}
}
public sealed record RichGraphWriteResult(