- Implemented PathViewerComponent for visualizing reachability call paths. - Added RiskDriftCardComponent to display reachability drift results. - Created corresponding HTML templates and SCSS styles for both components. - Introduced test fixtures for reachability analysis in JSON format. - Enhanced user interaction with collapsible and expandable features in PathViewer. - Included risk trend visualization and summary metrics in RiskDriftCard.
147 lines
6.1 KiB
C#
147 lines
6.1 KiB
C#
// -----------------------------------------------------------------------------
|
|
// AttestingRichGraphWriter.cs
|
|
// Sprint: SPRINT_3620_0001_0001_reachability_witness_dsse
|
|
// Description: RichGraphWriter wrapper that produces DSSE attestation alongside graph.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace StellaOps.Scanner.Reachability.Attestation;
|
|
|
|
/// <summary>
|
|
/// Result of writing a rich graph with attestation.
|
|
/// </summary>
|
|
/// <param name="GraphPath">Path to the richgraph-v1.json file.</param>
|
|
/// <param name="MetaPath">Path to the meta.json file.</param>
|
|
/// <param name="GraphHash">Content-addressed hash of the graph.</param>
|
|
/// <param name="NodeCount">Number of nodes in the graph.</param>
|
|
/// <param name="EdgeCount">Number of edges in the graph.</param>
|
|
/// <param name="AttestationPath">Path to the attestation DSSE envelope (if produced).</param>
|
|
/// <param name="WitnessResult">Detailed witness publication result (if attestation enabled).</param>
|
|
public sealed record AttestingRichGraphWriteResult(
|
|
string GraphPath,
|
|
string MetaPath,
|
|
string GraphHash,
|
|
int NodeCount,
|
|
int EdgeCount,
|
|
string? AttestationPath,
|
|
ReachabilityWitnessPublishResult? WitnessResult);
|
|
|
|
/// <summary>
|
|
/// Writes richgraph-v1 documents with optional DSSE attestation.
|
|
/// Wraps <see cref="RichGraphWriter"/> and integrates with <see cref="IReachabilityWitnessPublisher"/>.
|
|
/// </summary>
|
|
public sealed class AttestingRichGraphWriter
|
|
{
|
|
private readonly RichGraphWriter _graphWriter;
|
|
private readonly IReachabilityWitnessPublisher _witnessPublisher;
|
|
private readonly ReachabilityWitnessOptions _options;
|
|
private readonly ILogger<AttestingRichGraphWriter> _logger;
|
|
|
|
/// <summary>
|
|
/// Creates a new attesting rich graph writer.
|
|
/// </summary>
|
|
public AttestingRichGraphWriter(
|
|
RichGraphWriter graphWriter,
|
|
IReachabilityWitnessPublisher witnessPublisher,
|
|
IOptions<ReachabilityWitnessOptions> options,
|
|
ILogger<AttestingRichGraphWriter> logger)
|
|
{
|
|
_graphWriter = graphWriter ?? throw new ArgumentNullException(nameof(graphWriter));
|
|
_witnessPublisher = witnessPublisher ?? throw new ArgumentNullException(nameof(witnessPublisher));
|
|
_options = options?.Value ?? throw new ArgumentNullException(nameof(options));
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the rich graph and produces attestation if enabled.
|
|
/// </summary>
|
|
/// <param name="graph">The rich graph to write.</param>
|
|
/// <param name="outputRoot">Root output directory.</param>
|
|
/// <param name="analysisId">Analysis identifier.</param>
|
|
/// <param name="subjectDigest">Subject artifact digest for attestation.</param>
|
|
/// <param name="policyHash">Optional policy hash for attestation.</param>
|
|
/// <param name="sourceCommit">Optional source commit for attestation.</param>
|
|
/// <param name="cancellationToken">Cancellation token.</param>
|
|
/// <returns>Write result including attestation details.</returns>
|
|
public async Task<AttestingRichGraphWriteResult> WriteWithAttestationAsync(
|
|
RichGraph graph,
|
|
string outputRoot,
|
|
string analysisId,
|
|
string subjectDigest,
|
|
string? policyHash = null,
|
|
string? sourceCommit = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(graph);
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(outputRoot);
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(analysisId);
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(subjectDigest);
|
|
|
|
// Step 1: Write the graph using the standard writer
|
|
var writeResult = await _graphWriter.WriteAsync(graph, outputRoot, analysisId, cancellationToken)
|
|
.ConfigureAwait(false);
|
|
|
|
_logger.LogDebug(
|
|
"Wrote rich graph: {GraphPath}, hash={GraphHash}, nodes={NodeCount}, edges={EdgeCount}",
|
|
writeResult.GraphPath,
|
|
writeResult.GraphHash,
|
|
writeResult.NodeCount,
|
|
writeResult.EdgeCount);
|
|
|
|
// Step 2: Produce attestation if enabled
|
|
string? attestationPath = null;
|
|
ReachabilityWitnessPublishResult? witnessResult = null;
|
|
|
|
if (_options.Enabled)
|
|
{
|
|
// Read the graph bytes for attestation
|
|
var graphBytes = await File.ReadAllBytesAsync(writeResult.GraphPath, cancellationToken)
|
|
.ConfigureAwait(false);
|
|
|
|
// Publish witness attestation
|
|
witnessResult = await _witnessPublisher.PublishAsync(
|
|
graph,
|
|
graphBytes,
|
|
writeResult.GraphHash,
|
|
subjectDigest,
|
|
policyHash,
|
|
sourceCommit,
|
|
cancellationToken).ConfigureAwait(false);
|
|
|
|
// Write DSSE envelope to disk alongside the graph
|
|
if (witnessResult.DsseEnvelopeBytes.Length > 0)
|
|
{
|
|
var graphDir = Path.GetDirectoryName(writeResult.GraphPath)!;
|
|
attestationPath = Path.Combine(graphDir, "richgraph-v1.dsse.json");
|
|
|
|
await File.WriteAllBytesAsync(attestationPath, witnessResult.DsseEnvelopeBytes, cancellationToken)
|
|
.ConfigureAwait(false);
|
|
|
|
_logger.LogInformation(
|
|
"Wrote reachability witness attestation: {AttestationPath}, statementHash={StatementHash}",
|
|
attestationPath,
|
|
witnessResult.StatementHash);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_logger.LogDebug("Reachability witness attestation is disabled");
|
|
}
|
|
|
|
return new AttestingRichGraphWriteResult(
|
|
GraphPath: writeResult.GraphPath,
|
|
MetaPath: writeResult.MetaPath,
|
|
GraphHash: writeResult.GraphHash,
|
|
NodeCount: writeResult.NodeCount,
|
|
EdgeCount: writeResult.EdgeCount,
|
|
AttestationPath: attestationPath,
|
|
WitnessResult: witnessResult);
|
|
}
|
|
}
|