Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.

This commit is contained in:
StellaOps Bot
2025-12-26 21:54:17 +02:00
parent 335ff7da16
commit c2b9cd8d1f
3717 changed files with 264714 additions and 48202 deletions

View File

@@ -8,25 +8,23 @@
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<UseConcelierTestInfra>false</UseConcelierTestInfra>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.1" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
<PackageReference Include="BouncyCastle.Cryptography" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="xunit.runner.visualstudio" >
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" >
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Attestor.Core\StellaOps.Attestor.Core.csproj" />
<ProjectReference Include="../../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -0,0 +1,325 @@
// -----------------------------------------------------------------------------
// DeltaAttestationService.cs
// Sprint: SPRINT_20251228_007_BE_sbom_lineage_graph_ii (LIN-BE-025)
// Task: Implement IDeltaVerdictAttestationService
// Description: Creates DSSE-signed in-toto statements for lineage delta changes.
// -----------------------------------------------------------------------------
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Attestor.Core.Signing;
using StellaOps.Attestor.Core.Submission;
using StellaOps.Signer.Core;
using StellaOps.Signer.Core.Predicates;
namespace StellaOps.Attestor.Core.Delta;
/// <summary>
/// Implementation of <see cref="IDeltaAttestationService"/> that creates DSSE-signed
/// in-toto statements for lineage delta changes.
/// </summary>
public sealed class DeltaAttestationService : IDeltaAttestationService
{
private static readonly ActivitySource ActivitySource = new("StellaOps.Attestor.Delta");
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
private readonly IAttestationSigningService _signingService;
private readonly ILogger<DeltaAttestationService> _logger;
private readonly DeltaAttestationOptions _options;
public DeltaAttestationService(
IAttestationSigningService signingService,
IOptions<DeltaAttestationOptions> options,
ILogger<DeltaAttestationService> logger)
{
_signingService = signingService ?? throw new ArgumentNullException(nameof(signingService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_options = options?.Value ?? new DeltaAttestationOptions();
}
/// <inheritdoc />
public async Task<DeltaAttestationResult> CreateVexDeltaAttestationAsync(
VexDeltaAttestationRequest request,
CancellationToken cancellationToken = default)
{
using var activity = ActivitySource.StartActivity("CreateVexDeltaAttestation");
activity?.SetTag("from_digest", request.FromDigest);
activity?.SetTag("to_digest", request.ToDigest);
activity?.SetTag("tenant_id", request.TenantId);
_logger.LogInformation(
"Creating VEX delta attestation from {FromDigest} to {ToDigest}",
request.FromDigest, request.ToDigest);
return await CreateDeltaAttestationAsync(
request,
request.Delta,
PredicateTypes.StellaOpsVexDelta,
cancellationToken);
}
/// <inheritdoc />
public async Task<DeltaAttestationResult> CreateSbomDeltaAttestationAsync(
SbomDeltaAttestationRequest request,
CancellationToken cancellationToken = default)
{
using var activity = ActivitySource.StartActivity("CreateSbomDeltaAttestation");
activity?.SetTag("from_digest", request.FromDigest);
activity?.SetTag("to_digest", request.ToDigest);
activity?.SetTag("tenant_id", request.TenantId);
_logger.LogInformation(
"Creating SBOM delta attestation from {FromDigest} to {ToDigest}",
request.FromDigest, request.ToDigest);
return await CreateDeltaAttestationAsync(
request,
request.Delta,
PredicateTypes.StellaOpsSbomDelta,
cancellationToken);
}
/// <inheritdoc />
public async Task<DeltaAttestationResult> CreateVerdictDeltaAttestationAsync(
VerdictDeltaAttestationRequest request,
CancellationToken cancellationToken = default)
{
using var activity = ActivitySource.StartActivity("CreateVerdictDeltaAttestation");
activity?.SetTag("from_digest", request.FromDigest);
activity?.SetTag("to_digest", request.ToDigest);
activity?.SetTag("tenant_id", request.TenantId);
_logger.LogInformation(
"Creating verdict delta attestation from {FromDigest} to {ToDigest}",
request.FromDigest, request.ToDigest);
return await CreateDeltaAttestationAsync(
request,
request.Delta,
PredicateTypes.StellaOpsVerdictDelta,
cancellationToken);
}
/// <inheritdoc />
public async Task<DeltaAttestationResult> CreateReachabilityDeltaAttestationAsync(
ReachabilityDeltaAttestationRequest request,
CancellationToken cancellationToken = default)
{
using var activity = ActivitySource.StartActivity("CreateReachabilityDeltaAttestation");
activity?.SetTag("from_digest", request.FromDigest);
activity?.SetTag("to_digest", request.ToDigest);
activity?.SetTag("tenant_id", request.TenantId);
_logger.LogInformation(
"Creating reachability delta attestation from {FromDigest} to {ToDigest}",
request.FromDigest, request.ToDigest);
return await CreateDeltaAttestationAsync(
request,
request.Delta,
PredicateTypes.StellaOpsReachabilityDelta,
cancellationToken);
}
private async Task<DeltaAttestationResult> CreateDeltaAttestationAsync<TPredicate>(
DeltaAttestationRequestBase request,
TPredicate predicate,
string predicateType,
CancellationToken cancellationToken)
where TPredicate : class
{
try
{
// Build in-toto statement
var statement = BuildInTotoStatement(request, predicate, predicateType);
var statementJson = JsonSerializer.Serialize(statement, JsonOptions);
var payloadBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(statementJson));
// Compute envelope digest
var envelopeDigest = ComputeSha256(statementJson);
// Build signing request
var signRequest = new AttestationSignRequest
{
KeyId = request.KeyId ?? _options.DefaultKeyId ?? string.Empty,
PayloadType = "application/vnd.in-toto+json",
PayloadBase64 = payloadBase64,
Mode = request.UseKeyless ? "keyless" : "local",
LogPreference = request.UseTransparencyLog ? "primary" : "none",
Archive = true,
Artifact = new AttestorSubmissionRequest.ArtifactInfo
{
Sha256 = envelopeDigest,
Kind = "delta-attestation",
SubjectUri = $"urn:stellaops:lineage:{request.FromDigest}..{request.ToDigest}"
}
};
// Create submission context
var context = new SubmissionContext
{
CallerSubject = $"tenant:{request.TenantId}",
CallerAudience = "stellaops-attestor",
CallerClientId = "delta-attestation-service",
CallerTenant = request.TenantId
};
// Sign the attestation
var signResult = await _signingService.SignAsync(signRequest, context, cancellationToken);
// Extract transparency log index if present
long? logIndex = null;
if (signResult.Bundle?.Dsse?.Signatures?.Count > 0)
{
// Log index would typically be returned in a separate field after Rekor submission
_logger.LogDebug("Attestation signed with mode {Mode}", signResult.Mode);
}
// Build envelope base64 from signed result
var envelopeBase64 = signResult.Bundle?.Dsse != null
? Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(signResult.Bundle.Dsse, JsonOptions)))
: null;
_logger.LogInformation(
"Created delta attestation with digest {Digest} for predicate type {PredicateType}",
envelopeDigest, predicateType);
return new DeltaAttestationResult
{
Success = true,
AttestationDigest = envelopeDigest,
EnvelopeBase64 = envelopeBase64,
TransparencyLogIndex = logIndex,
PredicateType = predicateType,
CreatedAt = DateTimeOffset.UtcNow
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create delta attestation from {FromDigest} to {ToDigest}",
request.FromDigest, request.ToDigest);
return new DeltaAttestationResult
{
Success = false,
Error = ex.Message,
PredicateType = predicateType,
CreatedAt = DateTimeOffset.UtcNow
};
}
}
private InTotoStatement<TPredicate> BuildInTotoStatement<TPredicate>(
DeltaAttestationRequestBase request,
TPredicate predicate,
string predicateType)
where TPredicate : class
{
var subjects = new List<InTotoSubject>
{
new()
{
Name = $"lineage:{request.FromDigest}..{request.ToDigest}",
Digest = new Dictionary<string, string>
{
["sha256_from"] = ExtractHash(request.FromDigest),
["sha256_to"] = ExtractHash(request.ToDigest)
}
}
};
// Add annotations if provided
if (request.Annotations?.Count > 0)
{
foreach (var (key, value) in request.Annotations)
{
subjects[0].Digest[$"annotation:{key}"] = value;
}
}
return new InTotoStatement<TPredicate>
{
Type = "https://in-toto.io/Statement/v1",
Subject = subjects,
PredicateType = predicateType,
Predicate = predicate
};
}
private static string ExtractHash(string digest)
{
// Remove algorithm prefix if present (e.g., "sha256:abc123" -> "abc123")
var colonIndex = digest.IndexOf(':');
return colonIndex >= 0 ? digest[(colonIndex + 1)..] : digest;
}
private static string ComputeSha256(string content)
{
var bytes = Encoding.UTF8.GetBytes(content);
var hash = SHA256.HashData(bytes);
return Convert.ToHexStringLower(hash);
}
}
/// <summary>
/// In-toto statement structure.
/// </summary>
public sealed class InTotoStatement<TPredicate>
where TPredicate : class
{
[JsonPropertyName("_type")]
public string Type { get; set; } = "https://in-toto.io/Statement/v1";
[JsonPropertyName("subject")]
public IList<InTotoSubject> Subject { get; set; } = new List<InTotoSubject>();
[JsonPropertyName("predicateType")]
public string PredicateType { get; set; } = string.Empty;
[JsonPropertyName("predicate")]
public TPredicate? Predicate { get; set; }
}
/// <summary>
/// Subject entry for in-toto statements.
/// </summary>
public sealed class InTotoSubject
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("digest")]
public IDictionary<string, string> Digest { get; set; } = new Dictionary<string, string>();
}
/// <summary>
/// Configuration options for delta attestation service.
/// </summary>
public sealed class DeltaAttestationOptions
{
/// <summary>
/// Default key ID to use for signing when not specified in request.
/// </summary>
public string? DefaultKeyId { get; set; }
/// <summary>
/// Whether to use keyless signing by default.
/// </summary>
public bool DefaultUseKeyless { get; set; }
/// <summary>
/// Whether to publish to transparency log by default.
/// </summary>
public bool DefaultUseTransparencyLog { get; set; } = true;
}

View File

@@ -0,0 +1,184 @@
// -----------------------------------------------------------------------------
// IDeltaAttestationService.cs
// Sprint: SPRINT_20251228_007_BE_sbom_lineage_graph_ii (LIN-BE-025)
// Task: Implement IDeltaVerdictAttestationService
// Description: Service interface for creating delta attestations for lineage changes.
// -----------------------------------------------------------------------------
using StellaOps.Attestor.Core.Signing;
using StellaOps.Signer.Core.Predicates;
namespace StellaOps.Attestor.Core.Delta;
/// <summary>
/// Service for creating DSSE-signed attestations for delta changes between lineage versions.
/// Generates in-toto statements with delta predicates and signs them using the configured signer.
/// </summary>
public interface IDeltaAttestationService
{
/// <summary>
/// Creates a VEX delta attestation.
/// </summary>
/// <param name="request">The delta attestation request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The signed attestation result.</returns>
Task<DeltaAttestationResult> CreateVexDeltaAttestationAsync(
VexDeltaAttestationRequest request,
CancellationToken cancellationToken = default);
/// <summary>
/// Creates an SBOM delta attestation.
/// </summary>
/// <param name="request">The delta attestation request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The signed attestation result.</returns>
Task<DeltaAttestationResult> CreateSbomDeltaAttestationAsync(
SbomDeltaAttestationRequest request,
CancellationToken cancellationToken = default);
/// <summary>
/// Creates a verdict delta attestation.
/// </summary>
/// <param name="request">The delta attestation request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The signed attestation result.</returns>
Task<DeltaAttestationResult> CreateVerdictDeltaAttestationAsync(
VerdictDeltaAttestationRequest request,
CancellationToken cancellationToken = default);
/// <summary>
/// Creates a reachability delta attestation.
/// </summary>
/// <param name="request">The delta attestation request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The signed attestation result.</returns>
Task<DeltaAttestationResult> CreateReachabilityDeltaAttestationAsync(
ReachabilityDeltaAttestationRequest request,
CancellationToken cancellationToken = default);
}
/// <summary>
/// Base request for delta attestations.
/// </summary>
public abstract record DeltaAttestationRequestBase
{
/// <summary>
/// Digest of the source artifact.
/// </summary>
public required string FromDigest { get; init; }
/// <summary>
/// Digest of the target artifact.
/// </summary>
public required string ToDigest { get; init; }
/// <summary>
/// Tenant identifier.
/// </summary>
public required string TenantId { get; init; }
/// <summary>
/// Key ID for signing. If null, uses default.
/// </summary>
public string? KeyId { get; init; }
/// <summary>
/// Whether to use keyless signing (Sigstore Fulcio).
/// </summary>
public bool UseKeyless { get; init; }
/// <summary>
/// Whether to record in transparency log (Rekor).
/// </summary>
public bool UseTransparencyLog { get; init; } = true;
/// <summary>
/// Additional annotations to include.
/// </summary>
public IDictionary<string, string>? Annotations { get; init; }
}
/// <summary>
/// Request to create a VEX delta attestation.
/// </summary>
public sealed record VexDeltaAttestationRequest : DeltaAttestationRequestBase
{
/// <summary>
/// The VEX delta predicate to attest.
/// </summary>
public required VexDeltaPredicate Delta { get; init; }
}
/// <summary>
/// Request to create an SBOM delta attestation.
/// </summary>
public sealed record SbomDeltaAttestationRequest : DeltaAttestationRequestBase
{
/// <summary>
/// The SBOM delta predicate to attest.
/// </summary>
public required SbomDeltaPredicate Delta { get; init; }
}
/// <summary>
/// Request to create a verdict delta attestation.
/// </summary>
public sealed record VerdictDeltaAttestationRequest : DeltaAttestationRequestBase
{
/// <summary>
/// The verdict delta predicate to attest.
/// </summary>
public required VerdictDeltaPredicate Delta { get; init; }
}
/// <summary>
/// Request to create a reachability delta attestation.
/// </summary>
public sealed record ReachabilityDeltaAttestationRequest : DeltaAttestationRequestBase
{
/// <summary>
/// The reachability delta predicate to attest.
/// </summary>
public required ReachabilityDeltaPredicate Delta { get; init; }
}
/// <summary>
/// Result of creating a delta attestation.
/// </summary>
public sealed record DeltaAttestationResult
{
/// <summary>
/// Whether the attestation was successfully created and signed.
/// </summary>
public required bool Success { get; init; }
/// <summary>
/// Digest of the signed attestation envelope.
/// </summary>
public string? AttestationDigest { get; init; }
/// <summary>
/// Base64-encoded DSSE envelope.
/// </summary>
public string? EnvelopeBase64 { get; init; }
/// <summary>
/// Transparency log entry index (if published to Rekor).
/// </summary>
public long? TransparencyLogIndex { get; init; }
/// <summary>
/// Predicate type used.
/// </summary>
public string? PredicateType { get; init; }
/// <summary>
/// Timestamp of attestation creation.
/// </summary>
public DateTimeOffset CreatedAt { get; init; }
/// <summary>
/// Error message if failed.
/// </summary>
public string? Error { get; init; }
}

View File

@@ -0,0 +1,116 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "stella.ops/sbom-delta@v1",
"title": "SBOM Delta Predicate",
"description": "Schema for SBOM delta attestations between artifact versions",
"type": "object",
"required": ["fromDigest", "toDigest", "fromSbomDigest", "toSbomDigest", "tenantId", "summary", "comparedAt"],
"properties": {
"fromDigest": {
"type": "string",
"description": "Digest of the source (baseline) artifact",
"pattern": "^(sha256|sha384|sha512|blake3):[a-fA-F0-9]+$"
},
"toDigest": {
"type": "string",
"description": "Digest of the target (current) artifact",
"pattern": "^(sha256|sha384|sha512|blake3):[a-fA-F0-9]+$"
},
"fromSbomDigest": {
"type": "string",
"description": "Digest of the source SBOM"
},
"toSbomDigest": {
"type": "string",
"description": "Digest of the target SBOM"
},
"tenantId": {
"type": "string",
"description": "Tenant identifier"
},
"added": {
"type": "array",
"description": "Components added in the target SBOM",
"items": { "$ref": "#/$defs/component" }
},
"removed": {
"type": "array",
"description": "Components removed from the baseline SBOM",
"items": { "$ref": "#/$defs/component" }
},
"versionChanged": {
"type": "array",
"description": "Components that changed version between SBOMs",
"items": { "$ref": "#/$defs/versionChange" }
},
"summary": {
"$ref": "#/$defs/summary"
},
"comparedAt": {
"type": "string",
"format": "date-time",
"description": "When the comparison was performed"
},
"algorithmVersion": {
"type": "string",
"description": "Version of the delta computation algorithm"
}
},
"$defs": {
"component": {
"type": "object",
"required": ["purl", "name", "version"],
"properties": {
"purl": { "type": "string" },
"name": { "type": "string" },
"version": { "type": "string" },
"type": { "type": "string" },
"ecosystem": { "type": "string" },
"knownVulnerabilities": {
"type": "array",
"items": { "type": "string" }
},
"licenses": {
"type": "array",
"items": { "type": "string" }
}
}
},
"versionChange": {
"type": "object",
"required": ["purl", "name", "previousVersion", "currentVersion", "changeType"],
"properties": {
"purl": { "type": "string" },
"name": { "type": "string" },
"previousVersion": { "type": "string" },
"currentVersion": { "type": "string" },
"changeType": {
"type": "string",
"enum": ["major", "minor", "patch", "unknown"]
},
"vulnerabilitiesFixed": {
"type": "array",
"items": { "type": "string" }
},
"vulnerabilitiesIntroduced": {
"type": "array",
"items": { "type": "string" }
}
}
},
"summary": {
"type": "object",
"required": ["addedCount", "removedCount", "versionChangedCount", "unchangedCount", "fromTotalCount", "toTotalCount", "vulnerabilitiesFixedCount", "vulnerabilitiesIntroducedCount"],
"properties": {
"addedCount": { "type": "integer", "minimum": 0 },
"removedCount": { "type": "integer", "minimum": 0 },
"versionChangedCount": { "type": "integer", "minimum": 0 },
"unchangedCount": { "type": "integer", "minimum": 0 },
"fromTotalCount": { "type": "integer", "minimum": 0 },
"toTotalCount": { "type": "integer", "minimum": 0 },
"vulnerabilitiesFixedCount": { "type": "integer", "minimum": 0 },
"vulnerabilitiesIntroducedCount": { "type": "integer", "minimum": 0 }
}
}
}
}

View File

@@ -0,0 +1,129 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "stella.ops/verdict-delta@v1",
"title": "Verdict Delta Predicate",
"description": "Schema for policy verdict delta attestations between artifact versions",
"type": "object",
"required": ["fromDigest", "toDigest", "tenantId", "fromPolicyVersion", "toPolicyVersion", "fromVerdict", "toVerdict", "summary", "comparedAt"],
"properties": {
"fromDigest": {
"type": "string",
"description": "Digest of the source (baseline) artifact",
"pattern": "^(sha256|sha384|sha512|blake3):[a-fA-F0-9]+$"
},
"toDigest": {
"type": "string",
"description": "Digest of the target (current) artifact",
"pattern": "^(sha256|sha384|sha512|blake3):[a-fA-F0-9]+$"
},
"tenantId": {
"type": "string",
"description": "Tenant identifier"
},
"fromPolicyVersion": {
"type": "string",
"description": "Policy pack version used for baseline evaluation"
},
"toPolicyVersion": {
"type": "string",
"description": "Policy pack version used for target evaluation"
},
"fromVerdict": {
"$ref": "#/$defs/verdictSummary"
},
"toVerdict": {
"$ref": "#/$defs/verdictSummary"
},
"findingChanges": {
"type": "array",
"description": "Individual finding verdicts that changed",
"items": { "$ref": "#/$defs/findingChange" }
},
"ruleChanges": {
"type": "array",
"description": "Rule evaluations that changed",
"items": { "$ref": "#/$defs/ruleChange" }
},
"summary": {
"$ref": "#/$defs/deltaSummary"
},
"comparedAt": {
"type": "string",
"format": "date-time",
"description": "When the comparison was performed"
},
"algorithmVersion": {
"type": "string",
"description": "Version of the delta computation algorithm"
}
},
"$defs": {
"verdictSummary": {
"type": "object",
"required": ["outcome", "confidence", "riskScore", "passingRules", "failingRules", "warningRules"],
"properties": {
"outcome": {
"type": "string",
"enum": ["pass", "fail", "warn"]
},
"confidence": { "type": "number", "minimum": 0, "maximum": 1 },
"riskScore": { "type": "number" },
"verdictDigest": { "type": "string" },
"passingRules": { "type": "integer", "minimum": 0 },
"failingRules": { "type": "integer", "minimum": 0 },
"warningRules": { "type": "integer", "minimum": 0 }
}
},
"findingChange": {
"type": "object",
"required": ["vulnerabilityId", "purl", "previousVerdict", "currentVerdict", "changeReason", "riskDirection"],
"properties": {
"vulnerabilityId": { "type": "string" },
"purl": { "type": "string" },
"previousVerdict": { "type": "string" },
"currentVerdict": { "type": "string" },
"changeReason": { "type": "string" },
"riskDirection": {
"type": "string",
"enum": ["increased", "decreased", "neutral"]
}
}
},
"ruleChange": {
"type": "object",
"required": ["ruleId", "ruleName", "previousResult", "currentResult"],
"properties": {
"ruleId": { "type": "string" },
"ruleName": { "type": "string" },
"previousResult": {
"type": "string",
"enum": ["pass", "fail", "warn", "skip"]
},
"currentResult": {
"type": "string",
"enum": ["pass", "fail", "warn", "skip"]
},
"previousMessage": { "type": "string" },
"currentMessage": { "type": "string" }
}
},
"deltaSummary": {
"type": "object",
"required": ["verdictChanged", "riskDirection", "riskScoreDelta", "confidenceDelta", "findingsImproved", "findingsWorsened", "findingsNew", "findingsResolved", "rulesChanged"],
"properties": {
"verdictChanged": { "type": "boolean" },
"riskDirection": {
"type": "string",
"enum": ["increased", "decreased", "neutral"]
},
"riskScoreDelta": { "type": "number" },
"confidenceDelta": { "type": "number" },
"findingsImproved": { "type": "integer", "minimum": 0 },
"findingsWorsened": { "type": "integer", "minimum": 0 },
"findingsNew": { "type": "integer", "minimum": 0 },
"findingsResolved": { "type": "integer", "minimum": 0 },
"rulesChanged": { "type": "integer", "minimum": 0 }
}
}
}
}

View File

@@ -0,0 +1,98 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "stella.ops/vex-delta@v1",
"title": "VEX Delta Predicate",
"description": "Schema for VEX delta attestations between artifact versions",
"type": "object",
"required": ["fromDigest", "toDigest", "tenantId", "summary", "comparedAt"],
"properties": {
"fromDigest": {
"type": "string",
"description": "Digest of the source (baseline) artifact",
"pattern": "^(sha256|sha384|sha512|blake3):[a-fA-F0-9]+$"
},
"toDigest": {
"type": "string",
"description": "Digest of the target (current) artifact",
"pattern": "^(sha256|sha384|sha512|blake3):[a-fA-F0-9]+$"
},
"tenantId": {
"type": "string",
"description": "Tenant identifier"
},
"added": {
"type": "array",
"description": "VEX statements added in the target artifact",
"items": { "$ref": "#/$defs/vexStatement" }
},
"removed": {
"type": "array",
"description": "VEX statements removed from the baseline artifact",
"items": { "$ref": "#/$defs/vexStatement" }
},
"changed": {
"type": "array",
"description": "VEX statements that changed status between versions",
"items": { "$ref": "#/$defs/vexChange" }
},
"summary": {
"$ref": "#/$defs/summary"
},
"comparedAt": {
"type": "string",
"format": "date-time",
"description": "When the comparison was performed"
},
"algorithmVersion": {
"type": "string",
"description": "Version of the delta computation algorithm"
}
},
"$defs": {
"vexStatement": {
"type": "object",
"required": ["vulnerabilityId", "productId", "status"],
"properties": {
"vulnerabilityId": { "type": "string" },
"productId": { "type": "string" },
"status": {
"type": "string",
"enum": ["not_affected", "affected", "fixed", "under_investigation"]
},
"justification": { "type": "string" },
"issuer": { "type": "string" },
"timestamp": { "type": "string", "format": "date-time" }
}
},
"vexChange": {
"type": "object",
"required": ["vulnerabilityId", "productId", "previousStatus", "currentStatus", "riskDirection"],
"properties": {
"vulnerabilityId": { "type": "string" },
"productId": { "type": "string" },
"previousStatus": { "type": "string" },
"currentStatus": { "type": "string" },
"previousJustification": { "type": "string" },
"currentJustification": { "type": "string" },
"riskDirection": {
"type": "string",
"enum": ["increased", "decreased", "neutral"]
}
}
},
"summary": {
"type": "object",
"required": ["addedCount", "removedCount", "changedCount", "unchangedCount", "netRiskDirection"],
"properties": {
"addedCount": { "type": "integer", "minimum": 0 },
"removedCount": { "type": "integer", "minimum": 0 },
"changedCount": { "type": "integer", "minimum": 0 },
"unchangedCount": { "type": "integer", "minimum": 0 },
"netRiskDirection": {
"type": "string",
"enum": ["increased", "decreased", "neutral"]
}
}
}
}
}

View File

@@ -7,11 +7,16 @@
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JsonSchema.Net" Version="7.3.4" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="JsonSchema.Net" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Options" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Schemas\*.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography\StellaOps.Cryptography.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Kms\StellaOps.Cryptography.Kms.csproj" />
<ProjectReference Include="..\..\..\Signer\StellaOps.Signer\StellaOps.Signer.Core\StellaOps.Signer.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -114,13 +114,13 @@ public sealed class PredicateSchemaValidator : IPredicateSchemaValidator
{
var errors = new List<string>();
if (results.HasErrors)
if (!results.IsValid && results.Details is not null)
{
foreach (var detail in results.Details)
foreach (var detail in results.Details!)
{
if (detail.HasErrors && detail.Errors is not null)
if (!detail.IsValid && detail.Errors is not null)
{
foreach (var error in detail.Errors)
foreach (var error in detail.Errors!)
{
var errorMsg = error.Value ?? "Unknown error";
var location = detail.InstanceLocation.ToString();
@@ -148,7 +148,11 @@ public sealed class PredicateSchemaValidator : IPredicateSchemaValidator
("reachability@v1", "reachability.v1.schema.json"),
("boundary@v1", "boundary.v1.schema.json"),
("policy-decision@v1", "policy-decision.v1.schema.json"),
("human-approval@v1", "human-approval.v1.schema.json")
("human-approval@v1", "human-approval.v1.schema.json"),
// Delta predicate schemas (Sprint 20251228_007 LIN-BE-024)
("vex-delta@v1", "vex-delta.v1.schema.json"),
("sbom-delta@v1", "sbom-delta.v1.schema.json"),
("verdict-delta@v1", "verdict-delta.v1.schema.json")
};
foreach (var (key, fileName) in schemaFiles)

View File

@@ -0,0 +1,21 @@
# Archived Pre-1.0 Migrations
This directory contains the original migrations that were compacted into `001_initial_schema.sql`
in the `StellaOps.Attestor.Persistence` project for the 1.0.0 release.
## Original Files
- `20251216_001_create_rekor_submission_queue.sql` - Rekor submission queue for durable retry
## Why Archived
Pre-1.0, the schema evolved incrementally. For 1.0.0, migrations were compacted into a single
initial schema (in `StellaOps.Attestor.Persistence`) to:
- Simplify new deployments
- Reduce startup time
- Provide cleaner upgrade path
## For Existing Deployments
If upgrading from pre-1.0, run the reset script directly with psql:
```bash
psql -h <host> -U <user> -d <db> -f devops/scripts/migrations-reset-pre-1.0.sql
```
This updates `schema_migrations` to recognize the compacted schema.

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS0618 // FallbackCredentialsFactory is obsolete - transitioning to DefaultAWSCredentialsIdentityResolver
using System;
using Amazon.Runtime;
using Amazon.S3;

View File

@@ -13,17 +13,17 @@
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Plugin.BouncyCastle\StellaOps.Cryptography.Plugin.BouncyCastle.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Kms\StellaOps.Cryptography.Kms.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Plugin.SmSoft\StellaOps.Cryptography.Plugin.SmSoft.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Messaging\StellaOps.Messaging.csproj" />
<ProjectReference Include="..\..\..\Router/__Libraries/StellaOps.Messaging\StellaOps.Messaging.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.37" />
<PackageReference Include="AWSSDK.S3" Version="4.0.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.Extensions.Options" />
<PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="StackExchange.Redis" />
<PackageReference Include="AWSSDK.S3" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Attestor.Core\StellaOps.Attestor.Core.csproj" />
<ProjectReference Include="..\..\StellaOps.Attestor.Verify\StellaOps.Attestor.Verify.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography\StellaOps.Cryptography.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Plugin.BouncyCastle\StellaOps.Cryptography.Plugin.BouncyCastle.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Kms\StellaOps.Cryptography.Kms.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Plugin.SmSoft\StellaOps.Cryptography.Plugin.SmSoft.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Messaging\StellaOps.Messaging.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.37" />
<PackageReference Include="AWSSDK.S3" Version="4.0.2" />
</ItemGroup>
</Project>

View File

@@ -33,6 +33,7 @@ using StellaOps.Attestor.Core.Transparency;
using StellaOps.Attestor.Core.Bulk;
using StellaOps.Attestor.WebService;
using StellaOps.Attestor.Tests.Support;
using StellaOps.TestKit;
using Xunit;
namespace StellaOps.Attestor.Tests;
@@ -66,7 +67,6 @@ public sealed class AttestationBundleEndpointsTests
using (var scope = factory.Services.CreateScope())
{
var repository = scope.ServiceProvider.GetRequiredService<IAttestorEntryRepository>();
using StellaOps.TestKit;
var archiveStore = scope.ServiceProvider.GetRequiredService<IAttestorArchiveStore>();
var entry = new AttestorEntry

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
@@ -256,7 +256,6 @@ public sealed class AttestorSigningServiceTests : IDisposable
using var metrics = new AttestorMetrics();
using var registry = new AttestorSigningKeyRegistry(options, TimeProvider.System, NullLogger<AttestorSigningKeyRegistry>.Instance);
using StellaOps.TestKit;
var auditSink = new InMemoryAttestorAuditSink();
var service = new AttestorSigningService(
registry,

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
@@ -277,7 +277,6 @@ public sealed class AttestorSubmissionServiceTests
var logger = new NullLogger<AttestorSubmissionService>();
using var metrics = new AttestorMetrics();
using StellaOps.TestKit;
var service = new AttestorSubmissionService(
validator,
repository,

View File

@@ -1,4 +1,4 @@
using System.Buffers.Binary;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
@@ -700,7 +700,6 @@ public sealed class AttestorVerificationServiceTests
private static byte[] ComputeMerkleNode(byte[] left, byte[] right)
{
using var sha = SHA256.Create();
using StellaOps.TestKit;
var buffer = new byte[1 + left.Length + right.Length];
buffer[0] = 0x01;
Buffer.BlockCopy(left, 0, buffer, 1, left.Length);

View File

@@ -12,7 +12,6 @@ using System.Text;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using Xunit.Abstractions;
namespace StellaOps.Attestor.WebService.Tests.Auth;

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
@@ -24,7 +24,6 @@ public sealed class BulkVerificationWorkerTests
var jobStore = new InMemoryBulkVerificationJobStore();
var verificationService = new StubVerificationService();
using var metrics = new AttestorMetrics();
using StellaOps.TestKit;
var options = Options.Create(new AttestorOptions
{
BulkVerification = new AttestorOptions.BulkVerificationOptions

View File

@@ -1,4 +1,4 @@
using System.Threading;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging.Abstractions;
@@ -86,7 +86,6 @@ public sealed class CachedAttestorVerificationServiceTests
var options = Options.Create(new AttestorOptions());
using var memoryCache = new MemoryCache(new MemoryCacheOptions());
using var metrics = new AttestorMetrics();
using StellaOps.TestKit;
var cache = new InMemoryAttestorVerificationCache(memoryCache, options, new NullLogger<InMemoryAttestorVerificationCache>());
var inner = new StubVerificationService();
var service = new CachedAttestorVerificationService(

View File

@@ -13,7 +13,6 @@ using System.Text.Json;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using Xunit.Abstractions;
namespace StellaOps.Attestor.WebService.Tests.Contract;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Net;
using System.Net.Http;
using System.Text.Json;
@@ -136,7 +136,6 @@ public sealed class HttpTransparencyWitnessClientTests
using var metrics = new AttestorMetrics();
using var activitySource = new AttestorActivitySource();
using StellaOps.TestKit;
var options = Options.Create(new AttestorOptions
{
TransparencyWitness = new AttestorOptions.TransparencyWitnessOptions

View File

@@ -150,7 +150,7 @@ public class PostgresRekorSubmissionQueueIntegrationTests : IAsyncLifetime
// Assert
var count = await GetQueueCountAsync();
count.Should().BeGreaterOrEqualTo(5);
count.Should().BeGreaterThanOrEqualTo(5);
}
#endregion
@@ -168,7 +168,7 @@ public class PostgresRekorSubmissionQueueIntegrationTests : IAsyncLifetime
var items = await _queue.DequeueAsync(10);
// Assert
items.Should().HaveCountGreaterOrEqualTo(2);
items.Should().HaveCountGreaterThanOrEqualTo(2);
items.Should().OnlyContain(i => i.Status == RekorSubmissionStatus.Submitting);
}
@@ -195,7 +195,7 @@ public class PostgresRekorSubmissionQueueIntegrationTests : IAsyncLifetime
var items = await _queue.DequeueAsync(3);
// Assert
items.Should().HaveCountLessOrEqualTo(3);
items.Should().HaveCountLessThanOrEqualTo(3);
}
[Fact]
@@ -213,7 +213,7 @@ public class PostgresRekorSubmissionQueueIntegrationTests : IAsyncLifetime
// Assert - Item should only appear in one result
var allItems = results.SelectMany(r => r).Where(i => i.BundleSha256 == uniqueBundle).ToList();
allItems.Should().HaveCountLessOrEqualTo(1);
allItems.Should().HaveCountLessThanOrEqualTo(1);
}
#endregion
@@ -295,7 +295,7 @@ public class PostgresRekorSubmissionQueueIntegrationTests : IAsyncLifetime
var newDepth = await _queue.GetQueueDepthAsync();
// Assert
newDepth.Should().BeGreaterOrEqualTo(baseDepth + 2);
newDepth.Should().BeGreaterThanOrEqualTo(baseDepth + 2);
}
[Fact]
@@ -317,7 +317,7 @@ public class PostgresRekorSubmissionQueueIntegrationTests : IAsyncLifetime
var dlqCount = await queue.GetDeadLetterCountAsync();
// Assert
dlqCount.Should().BeGreaterOrEqualTo(1);
dlqCount.Should().BeGreaterThanOrEqualTo(1);
}
#endregion

View File

@@ -13,7 +13,6 @@ using System.Text.Json;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using Xunit.Abstractions;
namespace StellaOps.Attestor.WebService.Tests.Negative;

View File

@@ -10,7 +10,6 @@ using System.Net.Http.Json;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
using Xunit.Abstractions;
namespace StellaOps.Attestor.WebService.Tests.Observability;

View File

@@ -1,4 +1,4 @@
using System.Text;
using System.Text;
using System.Text.Json;
using StellaOps.Attestor.Core.Verification;
using Xunit;
@@ -309,7 +309,6 @@ public sealed class RekorInclusionVerificationIntegrationTests
private static byte[] ComputeInteriorHash(byte[] left, byte[] right)
{
using var sha256 = System.Security.Cryptography.SHA256.Create();
using StellaOps.TestKit;
var combined = new byte[1 + left.Length + right.Length];
combined[0] = 0x01; // Interior node prefix
left.CopyTo(combined, 1);

View File

@@ -5,20 +5,26 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<UseConcelierTestInfra>false</UseConcelierTestInfra>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="Testcontainers" Version="4.3.0" />
<PackageReference Include="Testcontainers.PostgreSql" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<Using Include="Xunit.Abstractions" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="NSubstitute" />
<PackageReference Include="Testcontainers" />
<PackageReference Include="Testcontainers.PostgreSql" />
<PackageReference Include="xunit.runner.visualstudio" >
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" >
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Attestor.WebService\StellaOps.Attestor.WebService.csproj" />
<ProjectReference Include="..\StellaOps.Attestor.Infrastructure\StellaOps.Attestor.Infrastructure.csproj" />
@@ -29,4 +35,4 @@
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Plugin.SmSoft\StellaOps.Cryptography.Plugin.SmSoft.csproj" />
<ProjectReference Include="../../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@@ -97,7 +97,7 @@ public sealed class ProofChainController : ControllerBase
var chain = await _queryService.GetProofChainAsync(subjectDigest, depth, cancellationToken);
if (chain is null || chain.Nodes.Count == 0)
if (chain is null || chain.Nodes.Length == 0)
{
return NotFound(new { error = $"No proof chain found for subject {subjectDigest}" });
}

View File

@@ -0,0 +1,12 @@
{
"profiles": {
"StellaOps.Attestor.WebService": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:62507;http://localhost:62508"
}
}
}

View File

@@ -25,7 +25,11 @@ public sealed class PredicateTypeRouter : IPredicateTypeRouter
"https://stella-ops.org/predicates/reachability-subgraph/v1",
"https://stella-ops.org/predicates/delta-verdict/v1",
"https://stella-ops.org/predicates/policy-decision/v1",
"https://stella-ops.org/predicates/unknowns-budget/v1"
"https://stella-ops.org/predicates/unknowns-budget/v1",
// Delta predicate types for lineage comparison (Sprint 20251228_007)
"stella.ops/vex-delta@v1",
"stella.ops/sbom-delta@v1",
"stella.ops/verdict-delta@v1"
};
public PredicateTypeRouter(
@@ -169,7 +173,7 @@ public sealed class PredicateTypeRouter : IPredicateTypeRouter
Metadata = new PredicateMetadata
{
Format = parseResult.Metadata.Format,
Version = parseResult.Metadata.Version,
Version = parseResult.Metadata.Version ?? "unknown",
Properties = parseResult.Metadata.Properties.ToImmutableDictionary()
},
Sbom = sbom,

View File

@@ -37,18 +37,17 @@ public sealed class ProofChainQueryService : IProofChainQueryService
// Query attestor entries by artifact sha256
var query = new AttestorEntryQuery
{
ArtifactSha256 = NormalizeDigest(subjectDigest),
PageSize = 100,
SortBy = "CreatedAt",
SortDirection = "Descending"
Subject = NormalizeDigest(subjectDigest),
PageSize = 100
};
var entries = await _entryRepository.QueryAsync(query, cancellationToken);
var proofs = entries.Items
.OrderByDescending(e => e.CreatedAt)
.Select(entry => new ProofSummary
{
ProofId = entry.RekorUuid ?? entry.Id.ToString(),
ProofId = entry.RekorUuid,
Type = DetermineProofType(entry.Artifact.Kind),
Digest = entry.BundleSha256,
CreatedAt = entry.CreatedAt,
@@ -154,7 +153,7 @@ public sealed class ProofChainQueryService : IProofChainQueryService
var detail = new ProofDetail
{
ProofId = entry.RekorUuid ?? entry.Id.ToString(),
ProofId = entry.RekorUuid,
Type = DetermineProofType(entry.Artifact.Kind),
Digest = entry.BundleSha256,
CreatedAt = entry.CreatedAt,

View File

@@ -8,14 +8,14 @@
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="StackExchange.Redis" Version="2.8.37" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Sinks.Console" />
<PackageReference Include="StackExchange.Redis" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Attestor.Core\StellaOps.Attestor.Core.csproj" />
@@ -27,7 +27,7 @@
<ProjectReference Include="../../../Authority/StellaOps.Authority/StellaOps.Auth.Client/StellaOps.Auth.Client.csproj" />
<ProjectReference Include="../../../Authority/StellaOps.Authority/StellaOps.Auth.ServerIntegration/StellaOps.Auth.ServerIntegration.csproj" />
<ProjectReference Include="../../__Libraries/StellaOps.Attestor.StandardPredicates/StellaOps.Attestor.StandardPredicates.csproj" />
<ProjectReference Include="../../../__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj" />
<ProjectReference Include="../../../Router/__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj" />
<ProjectReference Include="..\..\__Libraries\StellaOps.Attestor.Bundling\StellaOps.Attestor.Bundling.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,132 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Attestor.Core", "StellaOps.Attestor.Core\StellaOps.Attestor.Core.csproj", "{C0FE77EB-933C-4E47-8195-758AB049157A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Attestor.Infrastructure", "StellaOps.Attestor.Infrastructure\StellaOps.Attestor.Infrastructure.csproj", "{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Attestor.WebService", "StellaOps.Attestor.WebService\StellaOps.Attestor.WebService.csproj", "{B238B098-32B1-4875-99A7-393A63AC3CCF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Configuration", "..\..\__Libraries\StellaOps.Configuration\StellaOps.Configuration.csproj", "{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Cryptography", "..\..\__Libraries\StellaOps.Cryptography\StellaOps.Cryptography.csproj", "{82EFA477-307D-4B47-A4CF-1627F076D60A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.DependencyInjection", "..\..\__Libraries\StellaOps.DependencyInjection\StellaOps.DependencyInjection.csproj", "{21327A4F-2586-49F8-9D4A-3840DE64C48E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Attestor.Tests", "StellaOps.Attestor.Tests\StellaOps.Attestor.Tests.csproj", "{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Attestor.Verify", "..\StellaOps.Attestor.Verify\StellaOps.Attestor.Verify.csproj", "{99EC90D8-0D5E-41E4-A895-585A7680916C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C0FE77EB-933C-4E47-8195-758AB049157A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Debug|x64.ActiveCfg = Debug|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Debug|x64.Build.0 = Debug|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Debug|x86.ActiveCfg = Debug|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Debug|x86.Build.0 = Debug|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Release|Any CPU.Build.0 = Release|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Release|x64.ActiveCfg = Release|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Release|x64.Build.0 = Release|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Release|x86.ActiveCfg = Release|Any CPU
{C0FE77EB-933C-4E47-8195-758AB049157A}.Release|x86.Build.0 = Release|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Debug|x64.ActiveCfg = Debug|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Debug|x64.Build.0 = Debug|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Debug|x86.ActiveCfg = Debug|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Debug|x86.Build.0 = Debug|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Release|Any CPU.Build.0 = Release|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Release|x64.ActiveCfg = Release|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Release|x64.Build.0 = Release|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Release|x86.ActiveCfg = Release|Any CPU
{996D74F8-8683-45FA-90AB-DA7ACE78D4B3}.Release|x86.Build.0 = Release|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Debug|x64.ActiveCfg = Debug|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Debug|x64.Build.0 = Debug|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Debug|x86.ActiveCfg = Debug|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Debug|x86.Build.0 = Debug|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Release|Any CPU.Build.0 = Release|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Release|x64.ActiveCfg = Release|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Release|x64.Build.0 = Release|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Release|x86.ActiveCfg = Release|Any CPU
{B238B098-32B1-4875-99A7-393A63AC3CCF}.Release|x86.Build.0 = Release|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Debug|x64.ActiveCfg = Debug|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Debug|x64.Build.0 = Debug|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Debug|x86.ActiveCfg = Debug|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Debug|x86.Build.0 = Debug|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Release|Any CPU.Build.0 = Release|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Release|x64.ActiveCfg = Release|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Release|x64.Build.0 = Release|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Release|x86.ActiveCfg = Release|Any CPU
{988E2AC7-50E0-4845-B1C2-BA4931F2FFD7}.Release|x86.Build.0 = Release|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Debug|x64.ActiveCfg = Debug|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Debug|x64.Build.0 = Debug|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Debug|x86.ActiveCfg = Debug|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Debug|x86.Build.0 = Debug|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Release|Any CPU.Build.0 = Release|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Release|x64.ActiveCfg = Release|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Release|x64.Build.0 = Release|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Release|x86.ActiveCfg = Release|Any CPU
{82EFA477-307D-4B47-A4CF-1627F076D60A}.Release|x86.Build.0 = Release|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Debug|x64.ActiveCfg = Debug|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Debug|x64.Build.0 = Debug|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Debug|x86.ActiveCfg = Debug|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Debug|x86.Build.0 = Debug|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Release|Any CPU.Build.0 = Release|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Release|x64.ActiveCfg = Release|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Release|x64.Build.0 = Release|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Release|x86.ActiveCfg = Release|Any CPU
{21327A4F-2586-49F8-9D4A-3840DE64C48E}.Release|x86.Build.0 = Release|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Debug|x64.ActiveCfg = Debug|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Debug|x64.Build.0 = Debug|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Debug|x86.ActiveCfg = Debug|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Debug|x86.Build.0 = Debug|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Release|Any CPU.Build.0 = Release|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Release|x64.ActiveCfg = Release|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Release|x64.Build.0 = Release|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Release|x86.ActiveCfg = Release|Any CPU
{4B7592CD-D67C-4F4D-82FE-DF99BAAC4275}.Release|x86.Build.0 = Release|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Debug|x64.ActiveCfg = Debug|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Debug|x64.Build.0 = Debug|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Debug|x86.ActiveCfg = Debug|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Debug|x86.Build.0 = Debug|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Release|Any CPU.Build.0 = Release|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Release|x64.ActiveCfg = Release|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Release|x64.Build.0 = Release|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Release|x86.ActiveCfg = Release|Any CPU
{99EC90D8-0D5E-41E4-A895-585A7680916C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal