up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
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
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-13 18:08:55 +02:00
parent 6e45066e37
commit f1a39c4ce3
234 changed files with 24038 additions and 6910 deletions

View File

@@ -0,0 +1,264 @@
using System.Collections.Immutable;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace StellaOps.Scanner.Reachability;
/// <summary>
/// Semantic attribute keys for richgraph-v1 nodes.
/// </summary>
/// <remarks>
/// Part of Sprint 0411 - Semantic Entrypoint Engine (Task 19).
/// These attributes extend RichGraphNode to include semantic analysis data.
/// </remarks>
public static class RichGraphSemanticAttributes
{
/// <summary>Application intent (WebServer, Worker, CliTool, etc.).</summary>
public const string Intent = "semantic_intent";
/// <summary>Comma-separated capability flags.</summary>
public const string Capabilities = "semantic_capabilities";
/// <summary>Threat vector types (comma-separated).</summary>
public const string ThreatVectors = "semantic_threats";
/// <summary>Risk score (0.0-1.0).</summary>
public const string RiskScore = "semantic_risk_score";
/// <summary>Confidence score (0.0-1.0).</summary>
public const string Confidence = "semantic_confidence";
/// <summary>Confidence tier (Unknown, Low, Medium, High, Definitive).</summary>
public const string ConfidenceTier = "semantic_confidence_tier";
/// <summary>Framework name.</summary>
public const string Framework = "semantic_framework";
/// <summary>Framework version.</summary>
public const string FrameworkVersion = "semantic_framework_version";
/// <summary>Whether this is an entrypoint node.</summary>
public const string IsEntrypoint = "is_entrypoint";
/// <summary>Data flow boundaries (JSON array).</summary>
public const string DataBoundaries = "semantic_boundaries";
/// <summary>OWASP category if applicable.</summary>
public const string OwaspCategory = "owasp_category";
/// <summary>CWE ID if applicable.</summary>
public const string CweId = "cwe_id";
}
/// <summary>
/// Extension methods for accessing semantic data on RichGraph nodes.
/// </summary>
public static class RichGraphSemanticExtensions
{
/// <summary>Gets the application intent from node attributes.</summary>
public static string? GetIntent(this RichGraphNode node)
{
return node.Attributes?.TryGetValue(RichGraphSemanticAttributes.Intent, out var value) == true ? value : null;
}
/// <summary>Gets the capabilities as a list.</summary>
public static IReadOnlyList<string> GetCapabilities(this RichGraphNode node)
{
if (node.Attributes?.TryGetValue(RichGraphSemanticAttributes.Capabilities, out var value) != true ||
string.IsNullOrWhiteSpace(value))
{
return Array.Empty<string>();
}
return value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
}
/// <summary>Gets the threat vectors as a list.</summary>
public static IReadOnlyList<string> GetThreatVectors(this RichGraphNode node)
{
if (node.Attributes?.TryGetValue(RichGraphSemanticAttributes.ThreatVectors, out var value) != true ||
string.IsNullOrWhiteSpace(value))
{
return Array.Empty<string>();
}
return value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
}
/// <summary>Gets the risk score.</summary>
public static double? GetRiskScore(this RichGraphNode node)
{
if (node.Attributes?.TryGetValue(RichGraphSemanticAttributes.RiskScore, out var value) != true ||
string.IsNullOrWhiteSpace(value))
{
return null;
}
return double.TryParse(value, out var score) ? score : null;
}
/// <summary>Gets the confidence score.</summary>
public static double? GetConfidence(this RichGraphNode node)
{
if (node.Attributes?.TryGetValue(RichGraphSemanticAttributes.Confidence, out var value) != true ||
string.IsNullOrWhiteSpace(value))
{
return null;
}
return double.TryParse(value, out var score) ? score : null;
}
/// <summary>Checks if this node is an entrypoint.</summary>
public static bool IsEntrypoint(this RichGraphNode node)
{
if (node.Attributes?.TryGetValue(RichGraphSemanticAttributes.IsEntrypoint, out var value) != true ||
string.IsNullOrWhiteSpace(value))
{
return false;
}
return bool.TryParse(value, out var result) && result;
}
/// <summary>Checks if node has semantic data.</summary>
public static bool HasSemanticData(this RichGraphNode node)
{
return node.Attributes?.ContainsKey(RichGraphSemanticAttributes.Intent) == true ||
node.Attributes?.ContainsKey(RichGraphSemanticAttributes.Capabilities) == true;
}
/// <summary>Gets the framework name.</summary>
public static string? GetFramework(this RichGraphNode node)
{
return node.Attributes?.TryGetValue(RichGraphSemanticAttributes.Framework, out var value) == true ? value : null;
}
/// <summary>Gets all entrypoint nodes from the graph.</summary>
public static IReadOnlyList<RichGraphNode> GetEntrypointNodes(this RichGraph graph)
{
return graph.Nodes.Where(n => n.IsEntrypoint()).ToList();
}
/// <summary>Gets all nodes with semantic data.</summary>
public static IReadOnlyList<RichGraphNode> GetNodesWithSemantics(this RichGraph graph)
{
return graph.Nodes.Where(n => n.HasSemanticData()).ToList();
}
/// <summary>Calculates overall risk score for the graph.</summary>
public static double CalculateOverallRiskScore(this RichGraph graph)
{
var riskScores = graph.Nodes
.Select(n => n.GetRiskScore())
.Where(s => s.HasValue)
.Select(s => s!.Value)
.ToList();
if (riskScores.Count == 0)
return 0.0;
// Use max risk score as overall
return riskScores.Max();
}
}
/// <summary>
/// Builder for creating RichGraphNode with semantic attributes.
/// </summary>
public sealed class RichGraphNodeSemanticBuilder
{
private readonly Dictionary<string, string> _attributes = new(StringComparer.Ordinal);
public RichGraphNodeSemanticBuilder WithIntent(string intent)
{
_attributes[RichGraphSemanticAttributes.Intent] = intent;
return this;
}
public RichGraphNodeSemanticBuilder WithCapabilities(IEnumerable<string> capabilities)
{
_attributes[RichGraphSemanticAttributes.Capabilities] = string.Join(",", capabilities);
return this;
}
public RichGraphNodeSemanticBuilder WithThreatVectors(IEnumerable<string> threats)
{
_attributes[RichGraphSemanticAttributes.ThreatVectors] = string.Join(",", threats);
return this;
}
public RichGraphNodeSemanticBuilder WithRiskScore(double score)
{
_attributes[RichGraphSemanticAttributes.RiskScore] = score.ToString("F3");
return this;
}
public RichGraphNodeSemanticBuilder WithConfidence(double score, string tier)
{
_attributes[RichGraphSemanticAttributes.Confidence] = score.ToString("F3");
_attributes[RichGraphSemanticAttributes.ConfidenceTier] = tier;
return this;
}
public RichGraphNodeSemanticBuilder WithFramework(string framework, string? version = null)
{
_attributes[RichGraphSemanticAttributes.Framework] = framework;
if (version is not null)
{
_attributes[RichGraphSemanticAttributes.FrameworkVersion] = version;
}
return this;
}
public RichGraphNodeSemanticBuilder AsEntrypoint()
{
_attributes[RichGraphSemanticAttributes.IsEntrypoint] = "true";
return this;
}
public RichGraphNodeSemanticBuilder WithOwaspCategory(string category)
{
_attributes[RichGraphSemanticAttributes.OwaspCategory] = category;
return this;
}
public RichGraphNodeSemanticBuilder WithCweId(int cweId)
{
_attributes[RichGraphSemanticAttributes.CweId] = cweId.ToString();
return this;
}
/// <summary>Builds the attributes dictionary.</summary>
public IReadOnlyDictionary<string, string> Build()
{
return _attributes.ToImmutableDictionary();
}
/// <summary>Merges semantic attributes with existing node attributes.</summary>
public IReadOnlyDictionary<string, string> MergeWith(IReadOnlyDictionary<string, string>? existing)
{
var merged = new Dictionary<string, string>(StringComparer.Ordinal);
if (existing is not null)
{
foreach (var pair in existing)
{
merged[pair.Key] = pair.Value;
}
}
foreach (var pair in _attributes)
{
merged[pair.Key] = pair.Value;
}
return merged.ToImmutableDictionary();
}
/// <summary>Creates a new RichGraphNode with semantic attributes.</summary>
public RichGraphNode ApplyTo(RichGraphNode node)
{
return node with { Attributes = MergeWith(node.Attributes) };
}
}