Refactor code structure for improved readability and maintainability; optimize performance in key functions.

This commit is contained in:
master
2025-12-22 19:06:31 +02:00
parent dfaa2079aa
commit 4602ccc3a3
1444 changed files with 109919 additions and 8058 deletions

View File

@@ -0,0 +1,19 @@
# Attestor __Libraries AGENTS
## Purpose & Scope
- Working directory: `src/Attestor/__Libraries/` (shared attestation libraries).
- Roles: backend engineer, QA automation.
## Required Reading (treat as read before DOING)
- `docs/README.md`
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
- `docs/modules/attestor/architecture.md`
- Relevant sprint files.
## Working Agreements
- Preserve DSSE/in-toto compatibility and deterministic serialization.
- Avoid network dependencies in libraries and tests.
- Record schema changes in attestor docs and sprint Decisions & Risks.
## Testing
- Add tests under the corresponding attestor test projects or `src/Attestor/__Tests`.

View File

@@ -155,6 +155,12 @@ public sealed class PredicateSchemaValidator : IJsonSchemaValidator
case "verdict.stella/v1":
errors.AddRange(ValidateVerdictPredicate(root));
break;
case "delta-verdict.stella/v1":
errors.AddRange(ValidateDeltaVerdictPredicate(root));
break;
case "reachability-subgraph.stella/v1":
errors.AddRange(ValidateReachabilitySubgraphPredicate(root));
break;
}
return errors.Count > 0
@@ -192,6 +198,8 @@ public sealed class PredicateSchemaValidator : IJsonSchemaValidator
"proofspine.stella/v1" => true,
"verdict.stella/v1" => true,
"https://stella-ops.org/predicates/sbom-linkage/v1" => true,
"delta-verdict.stella/v1" => true,
"reachability-subgraph.stella/v1" => true,
_ => false
};
}
@@ -248,4 +256,30 @@ public sealed class PredicateSchemaValidator : IJsonSchemaValidator
if (!root.TryGetProperty("verifiedAt", out _))
yield return new() { Path = "/verifiedAt", Message = "Required property missing", Keyword = "required" };
}
private static IEnumerable<SchemaValidationError> ValidateDeltaVerdictPredicate(JsonElement root)
{
// Required: beforeRevisionId, afterRevisionId, hasMaterialChange, priorityScore, changes, comparedAt
if (!root.TryGetProperty("beforeRevisionId", out _))
yield return new() { Path = "/beforeRevisionId", Message = "Required property missing", Keyword = "required" };
if (!root.TryGetProperty("afterRevisionId", out _))
yield return new() { Path = "/afterRevisionId", Message = "Required property missing", Keyword = "required" };
if (!root.TryGetProperty("hasMaterialChange", out _))
yield return new() { Path = "/hasMaterialChange", Message = "Required property missing", Keyword = "required" };
if (!root.TryGetProperty("priorityScore", out _))
yield return new() { Path = "/priorityScore", Message = "Required property missing", Keyword = "required" };
if (!root.TryGetProperty("changes", out _))
yield return new() { Path = "/changes", Message = "Required property missing", Keyword = "required" };
if (!root.TryGetProperty("comparedAt", out _))
yield return new() { Path = "/comparedAt", Message = "Required property missing", Keyword = "required" };
}
private static IEnumerable<SchemaValidationError> ValidateReachabilitySubgraphPredicate(JsonElement root)
{
// Required: graphDigest, analysis
if (!root.TryGetProperty("graphDigest", out _))
yield return new() { Path = "/graphDigest", Message = "Required property missing", Keyword = "required" };
if (!root.TryGetProperty("analysis", out _))
yield return new() { Path = "/analysis", Message = "Required property missing", Keyword = "required" };
}
}

View File

@@ -0,0 +1,55 @@
namespace StellaOps.Attestor.ProofChain.Models;
/// <summary>
/// Aggregated summary of unknowns for inclusion in attestations.
/// Provides verifiable data about unknown risk handled during evaluation.
/// </summary>
public sealed record UnknownsSummary
{
/// <summary>
/// Total count of unknowns encountered.
/// </summary>
public int Total { get; init; }
/// <summary>
/// Count of unknowns by reason code.
/// </summary>
public IReadOnlyDictionary<string, int> ByReasonCode { get; init; }
= new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Count of unknowns that would block if not excepted.
/// </summary>
public int BlockingCount { get; init; }
/// <summary>
/// Count of unknowns that are covered by approved exceptions.
/// </summary>
public int ExceptedCount { get; init; }
/// <summary>
/// Policy thresholds that were evaluated.
/// </summary>
public IReadOnlyList<string> PolicyThresholdsApplied { get; init; } = [];
/// <summary>
/// Exception IDs that were applied to cover unknowns.
/// </summary>
public IReadOnlyList<string> ExceptionsApplied { get; init; } = [];
/// <summary>
/// Hash of the unknowns list for integrity verification.
/// </summary>
public string? UnknownsDigest { get; init; }
/// <summary>
/// Creates an empty summary for cases with no unknowns.
/// </summary>
public static UnknownsSummary Empty { get; } = new()
{
Total = 0,
ByReasonCode = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase),
BlockingCount = 0,
ExceptedCount = 0
};
}

View File

@@ -0,0 +1,184 @@
// -----------------------------------------------------------------------------
// DeltaVerdictPredicate.cs
// Sprint: SPRINT_4400_0001_0001_signed_delta_verdict
// Description: DSSE predicate for Smart-Diff delta verdict attestations.
// -----------------------------------------------------------------------------
using System.Collections.Immutable;
using System.Text.Json.Serialization;
namespace StellaOps.Attestor.ProofChain.Predicates;
/// <summary>
/// DSSE predicate for Smart-Diff delta verdict attestation.
/// predicateType: delta-verdict.stella/v1
/// </summary>
public sealed record DeltaVerdictPredicate
{
/// <summary>
/// The predicate type URI for delta verdict attestations.
/// </summary>
public const string PredicateType = "delta-verdict.stella/v1";
/// <summary>
/// Revision identifier for the baseline scan.
/// </summary>
[JsonPropertyName("beforeRevisionId")]
public required string BeforeRevisionId { get; init; }
/// <summary>
/// Revision identifier for the current scan.
/// </summary>
[JsonPropertyName("afterRevisionId")]
public required string AfterRevisionId { get; init; }
/// <summary>
/// Whether any material change was detected.
/// </summary>
[JsonPropertyName("hasMaterialChange")]
public required bool HasMaterialChange { get; init; }
/// <summary>
/// Aggregate priority score for the delta.
/// </summary>
[JsonPropertyName("priorityScore")]
public required double PriorityScore { get; init; }
/// <summary>
/// Change details captured by Smart-Diff rules.
/// </summary>
[JsonPropertyName("changes")]
public ImmutableArray<DeltaVerdictChange> Changes { get; init; } = [];
/// <summary>
/// Digest of the baseline verdict attestation (if available).
/// </summary>
[JsonPropertyName("beforeVerdictDigest")]
public string? BeforeVerdictDigest { get; init; }
/// <summary>
/// Digest of the current verdict attestation (if available).
/// </summary>
[JsonPropertyName("afterVerdictDigest")]
public string? AfterVerdictDigest { get; init; }
/// <summary>
/// Reference to the baseline proof spine (if available).
/// </summary>
[JsonPropertyName("beforeProofSpine")]
public AttestationReference? BeforeProofSpine { get; init; }
/// <summary>
/// Reference to the current proof spine (if available).
/// </summary>
[JsonPropertyName("afterProofSpine")]
public AttestationReference? AfterProofSpine { get; init; }
/// <summary>
/// Graph revision identifier for the baseline analysis (if available).
/// </summary>
[JsonPropertyName("beforeGraphRevisionId")]
public string? BeforeGraphRevisionId { get; init; }
/// <summary>
/// Graph revision identifier for the current analysis (if available).
/// </summary>
[JsonPropertyName("afterGraphRevisionId")]
public string? AfterGraphRevisionId { get; init; }
/// <summary>
/// When the comparison was performed.
/// </summary>
[JsonPropertyName("comparedAt")]
public required DateTimeOffset ComparedAt { get; init; }
}
/// <summary>
/// Individual change captured in delta verdict.
/// </summary>
public sealed record DeltaVerdictChange
{
/// <summary>
/// Detection rule identifier.
/// </summary>
[JsonPropertyName("rule")]
public required string Rule { get; init; }
/// <summary>
/// Finding key (vulnerability and component).
/// </summary>
[JsonPropertyName("findingKey")]
public required DeltaFindingKey FindingKey { get; init; }
/// <summary>
/// Direction of risk change.
/// </summary>
[JsonPropertyName("direction")]
public required string Direction { get; init; }
/// <summary>
/// Change category (optional).
/// </summary>
[JsonPropertyName("changeType")]
public string? ChangeType { get; init; }
/// <summary>
/// Human-readable reason for the change.
/// </summary>
[JsonPropertyName("reason")]
public required string Reason { get; init; }
/// <summary>
/// Previous value observed (optional).
/// </summary>
[JsonPropertyName("previousValue")]
public string? PreviousValue { get; init; }
/// <summary>
/// Current value observed (optional).
/// </summary>
[JsonPropertyName("currentValue")]
public string? CurrentValue { get; init; }
/// <summary>
/// Weight contribution for this change (optional).
/// </summary>
[JsonPropertyName("weight")]
public double? Weight { get; init; }
}
/// <summary>
/// Finding key for delta verdict changes.
/// </summary>
public sealed record DeltaFindingKey
{
/// <summary>
/// Vulnerability identifier (CVE, GHSA, etc.).
/// </summary>
[JsonPropertyName("vulnId")]
public required string VulnId { get; init; }
/// <summary>
/// Component package URL.
/// </summary>
[JsonPropertyName("purl")]
public required string Purl { get; init; }
}
/// <summary>
/// Reference to an attestation or proof spine.
/// </summary>
public sealed record AttestationReference
{
/// <summary>
/// Digest of the attestation (sha256:... or blake3:...).
/// </summary>
[JsonPropertyName("digest")]
public required string Digest { get; init; }
/// <summary>
/// Optional URI where the attestation can be retrieved.
/// </summary>
[JsonPropertyName("uri")]
public string? Uri { get; init; }
}

View File

@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using StellaOps.Attestor.ProofChain.Models;
namespace StellaOps.Attestor.ProofChain.Predicates;
/// <summary>
/// Predicate type for policy decision attestations.
/// Predicate type: https://stella.ops/predicates/policy-decision@v2
/// </summary>
public sealed record PolicyDecisionPredicate
{
/// <summary>
/// The predicate type URI for policy decisions.
/// </summary>
public const string PredicateType = "https://stella.ops/predicates/policy-decision@v2";
/// <summary>
/// Reference to the policy that was evaluated.
/// </summary>
[JsonPropertyName("policyRef")]
public required string PolicyRef { get; init; }
/// <summary>
/// Final policy decision outcome.
/// </summary>
[JsonPropertyName("decision")]
public required PolicyDecision Decision { get; init; }
/// <summary>
/// Timestamp when the policy was evaluated.
/// </summary>
[JsonPropertyName("evaluatedAt")]
public required DateTimeOffset EvaluatedAt { get; init; }
/// <summary>
/// Summary of findings from the evaluation.
/// </summary>
[JsonPropertyName("findings")]
public IReadOnlyList<FindingSummary> Findings { get; init; } = [];
/// <summary>
/// Summary of unknowns and how they were handled.
/// </summary>
[JsonPropertyName("unknowns")]
public UnknownsSummary? Unknowns { get; init; }
/// <summary>
/// Whether unknowns were a factor in the decision.
/// </summary>
[JsonPropertyName("unknownsAffectedDecision")]
public bool UnknownsAffectedDecision { get; init; }
/// <summary>
/// Reason codes that caused blocking (if any).
/// </summary>
[JsonPropertyName("blockingReasonCodes")]
public IReadOnlyList<string> BlockingReasonCodes { get; init; } = [];
/// <summary>
/// Content-addressed ID of the knowledge snapshot used.
/// </summary>
[JsonPropertyName("knowledgeSnapshotId")]
public string? KnowledgeSnapshotId { get; init; }
}
/// <summary>
/// Policy decision outcome.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum PolicyDecision
{
/// <summary>
/// Policy evaluation passed.
/// </summary>
Pass,
/// <summary>
/// Policy evaluation failed.
/// </summary>
Fail,
/// <summary>
/// Policy passed with approved exceptions.
/// </summary>
PassWithExceptions,
/// <summary>
/// Policy evaluation could not be completed.
/// </summary>
Indeterminate
}
/// <summary>
/// Summary of a finding from policy evaluation.
/// </summary>
public sealed record FindingSummary
{
/// <summary>
/// The finding identifier.
/// </summary>
[JsonPropertyName("id")]
public required string Id { get; init; }
/// <summary>
/// Severity of the finding.
/// </summary>
[JsonPropertyName("severity")]
public required string Severity { get; init; }
/// <summary>
/// Description of the finding.
/// </summary>
[JsonPropertyName("description")]
public string? Description { get; init; }
}

View File

@@ -0,0 +1,94 @@
// -----------------------------------------------------------------------------
// ReachabilitySubgraphPredicate.cs
// Sprint: SPRINT_4400_0001_0002_reachability_subgraph_attestation
// Description: DSSE predicate for reachability subgraph attestations.
// -----------------------------------------------------------------------------
using System.Collections.Immutable;
using System.Text.Json.Serialization;
namespace StellaOps.Attestor.ProofChain.Predicates;
/// <summary>
/// DSSE predicate for reachability subgraph attestation.
/// predicateType: reachability-subgraph.stella/v1
/// </summary>
public sealed record ReachabilitySubgraphPredicate
{
/// <summary>
/// The predicate type URI for reachability subgraph attestations.
/// </summary>
public const string PredicateType = "reachability-subgraph.stella/v1";
/// <summary>
/// Schema version for the predicate payload.
/// </summary>
[JsonPropertyName("schemaVersion")]
public string SchemaVersion { get; init; } = "1.0.0";
/// <summary>
/// Content-addressed digest of the serialized subgraph.
/// </summary>
[JsonPropertyName("graphDigest")]
public required string GraphDigest { get; init; }
/// <summary>
/// Optional CAS URI for the subgraph content.
/// </summary>
[JsonPropertyName("graphCasUri")]
public string? GraphCasUri { get; init; }
/// <summary>
/// Finding keys covered by this subgraph (e.g., "CVE-2024-1234@pkg:...").
/// </summary>
[JsonPropertyName("findingKeys")]
public ImmutableArray<string> FindingKeys { get; init; } = [];
/// <summary>
/// Analysis metadata for the subgraph extraction.
/// </summary>
[JsonPropertyName("analysis")]
public required ReachabilitySubgraphAnalysis Analysis { get; init; }
}
/// <summary>
/// Metadata about subgraph extraction and analysis.
/// </summary>
public sealed record ReachabilitySubgraphAnalysis
{
/// <summary>
/// Analyzer name.
/// </summary>
[JsonPropertyName("analyzer")]
public required string Analyzer { get; init; }
/// <summary>
/// Analyzer version.
/// </summary>
[JsonPropertyName("analyzerVersion")]
public required string AnalyzerVersion { get; init; }
/// <summary>
/// Confidence score (0.0-1.0).
/// </summary>
[JsonPropertyName("confidence")]
public required double Confidence { get; init; }
/// <summary>
/// Completeness indicator (full, partial, unknown).
/// </summary>
[JsonPropertyName("completeness")]
public required string Completeness { get; init; }
/// <summary>
/// When the subgraph was generated.
/// </summary>
[JsonPropertyName("generatedAt")]
public required DateTimeOffset GeneratedAt { get; init; }
/// <summary>
/// Hash algorithm used for graph digest.
/// </summary>
[JsonPropertyName("hashAlgorithm")]
public string HashAlgorithm { get; init; } = "blake3";
}

View File

@@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using StellaOps.Attestor.ProofChain.Models;
namespace StellaOps.Attestor.ProofChain.Services;
/// <summary>
/// Aggregates unknowns data into summary format for attestations.
/// </summary>
public sealed class UnknownsAggregator : IUnknownsAggregator
{
/// <summary>
/// Creates an unknowns summary from evaluation results.
/// </summary>
public UnknownsSummary Aggregate(
IReadOnlyList<UnknownItem> unknowns,
BudgetCheckResult? budgetResult = null,
IReadOnlyList<ExceptionRef>? exceptions = null)
{
if (unknowns.Count == 0)
return UnknownsSummary.Empty;
// Count by reason code
var byReasonCode = unknowns
.GroupBy(u => u.ReasonCode)
.ToDictionary(g => g.Key, g => g.Count(), StringComparer.OrdinalIgnoreCase);
// Calculate blocking count (would block without exceptions)
var blockingCount = budgetResult?.Violations.Values.Sum(v => v.Count) ?? 0;
// Calculate excepted count
var exceptedCount = exceptions?.Count ?? 0;
// Compute digest of unknowns list for integrity
var unknownsDigest = ComputeUnknownsDigest(unknowns);
// Extract policy thresholds that were checked
var thresholds = budgetResult?.Violations.Keys
.Select(k => $"{k}:{budgetResult.Violations[k].Limit}")
.ToList() ?? new List<string>();
// Extract applied exception IDs
var exceptionIds = exceptions?
.Select(e => e.ExceptionId)
.ToList() ?? new List<string>();
return new UnknownsSummary
{
Total = unknowns.Count,
ByReasonCode = byReasonCode,
BlockingCount = blockingCount,
ExceptedCount = exceptedCount,
PolicyThresholdsApplied = thresholds,
ExceptionsApplied = exceptionIds,
UnknownsDigest = unknownsDigest
};
}
/// <summary>
/// Computes a deterministic digest of the unknowns list.
/// </summary>
private static string ComputeUnknownsDigest(IReadOnlyList<UnknownItem> unknowns)
{
// Sort for determinism
var sorted = unknowns
.OrderBy(u => u.PackageUrl)
.ThenBy(u => u.CveId)
.ThenBy(u => u.ReasonCode)
.ToList();
// Serialize to canonical JSON
var json = JsonSerializer.Serialize(sorted, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
});
// Hash the serialized data using SHA256
using var sha256 = SHA256.Create();
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(json));
return Convert.ToHexString(hashBytes).ToLowerInvariant();
}
}
/// <summary>
/// Interface for unknowns aggregation service.
/// </summary>
public interface IUnknownsAggregator
{
/// <summary>
/// Aggregates unknowns into a summary.
/// </summary>
UnknownsSummary Aggregate(
IReadOnlyList<UnknownItem> unknowns,
BudgetCheckResult? budgetResult = null,
IReadOnlyList<ExceptionRef>? exceptions = null);
}
/// <summary>
/// Input item for unknowns aggregation.
/// </summary>
public sealed record UnknownItem(
string PackageUrl,
string? CveId,
string ReasonCode,
string? RemediationHint);
/// <summary>
/// Reference to an applied exception.
/// </summary>
public sealed record ExceptionRef(
string ExceptionId,
string Status,
IReadOnlyList<string> CoveredReasonCodes);
/// <summary>
/// Result of a budget check operation.
/// </summary>
public sealed record BudgetCheckResult
{
/// <summary>
/// Budget violations by reason code.
/// </summary>
public required IReadOnlyDictionary<string, BudgetViolation> Violations { get; init; }
}
/// <summary>
/// Represents a budget violation for a specific reason code.
/// </summary>
public sealed record BudgetViolation(
int Count,
int Limit);

View File

@@ -0,0 +1,21 @@
using System.Text.Json.Serialization;
using StellaOps.Attestor.ProofChain.Predicates;
namespace StellaOps.Attestor.ProofChain.Statements;
/// <summary>
/// In-toto statement for Smart-Diff delta verdicts.
/// Predicate type: delta-verdict.stella/v1
/// </summary>
public sealed record DeltaVerdictStatement : InTotoStatement
{
/// <inheritdoc />
[JsonPropertyName("predicateType")]
public override string PredicateType => DeltaVerdictPredicate.PredicateType;
/// <summary>
/// The delta verdict predicate payload.
/// </summary>
[JsonPropertyName("predicate")]
public required DeltaVerdictPredicate Predicate { get; init; }
}

View File

@@ -0,0 +1,21 @@
using System.Text.Json.Serialization;
using StellaOps.Attestor.ProofChain.Predicates;
namespace StellaOps.Attestor.ProofChain.Statements;
/// <summary>
/// In-toto statement for reachability subgraph attestations.
/// Predicate type: reachability-subgraph.stella/v1
/// </summary>
public sealed record ReachabilitySubgraphStatement : InTotoStatement
{
/// <inheritdoc />
[JsonPropertyName("predicateType")]
public override string PredicateType => ReachabilitySubgraphPredicate.PredicateType;
/// <summary>
/// The reachability subgraph predicate payload.
/// </summary>
[JsonPropertyName("predicate")]
public required ReachabilitySubgraphPredicate Predicate { get; init; }
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Text.Json.Serialization;
using StellaOps.Attestor.ProofChain.Models;
namespace StellaOps.Attestor.ProofChain.Statements;
@@ -66,6 +67,20 @@ public sealed record VerdictReceiptPayload
/// </summary>
[JsonPropertyName("createdAt")]
public required DateTimeOffset CreatedAt { get; init; }
/// <summary>
/// Summary of unknowns encountered during evaluation.
/// Included for transparency about uncertainty in the verdict.
/// </summary>
[JsonPropertyName("unknowns")]
public UnknownsSummary? Unknowns { get; init; }
/// <summary>
/// Reference to the knowledge snapshot used for evaluation.
/// Enables replay and verification of inputs.
/// </summary>
[JsonPropertyName("knowledgeSnapshotId")]
public string? KnowledgeSnapshotId { get; init; }
}
/// <summary>