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:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user