finish off sprint advisories and sprints

This commit is contained in:
master
2026-01-24 00:12:43 +02:00
parent 726d70dc7f
commit c70e83719e
266 changed files with 46699 additions and 1328 deletions

View File

@@ -175,9 +175,9 @@ public sealed class DeltaSigAttestorIntegrationTests
{
// Arrange
var service = CreateService();
var predicate = new DeltaSigPredicate(
var predicate = new AttestorDeltaSigPredicate(
PredicateType: "https://stellaops.io/delta-sig/v1",
Subject: Array.Empty<InTotoSubject>(),
Subject: Array.Empty<AttestorInTotoSubject>(),
DeltaSignatures: new[] { CreateTestDeltaSig() },
Timestamp: FixedTimestamp,
Statistics: new DeltaSigStatistics(1, 0, 0));
@@ -195,10 +195,10 @@ public sealed class DeltaSigAttestorIntegrationTests
{
// Arrange
var service = CreateService();
var predicate = new DeltaSigPredicate(
var predicate = new AttestorDeltaSigPredicate(
PredicateType: "https://stellaops.io/delta-sig/v1",
Subject: new[] { CreateTestSubject() },
DeltaSignatures: Array.Empty<DeltaSignatureEntry>(),
DeltaSignatures: Array.Empty<AttestorDeltaSignatureEntry>(),
Timestamp: FixedTimestamp,
Statistics: new DeltaSigStatistics(0, 0, 0));
@@ -267,7 +267,7 @@ public sealed class DeltaSigAttestorIntegrationTests
// Helper methods
private IDeltaSigAttestorIntegration CreateService()
private IAttestorIntegration CreateService()
{
return new DeltaSigAttestorIntegration(
Options.Create(new DeltaSigAttestorOptions
@@ -291,9 +291,9 @@ public sealed class DeltaSigAttestorIntegrationTests
Signatures: signatures);
}
private static DeltaSignatureEntry CreateTestDeltaSig(int index = 0)
private static AttestorDeltaSignatureEntry CreateTestDeltaSig(int index = 0)
{
return new DeltaSignatureEntry(
return new AttestorDeltaSignatureEntry(
SymbolName: $"test_function_{index}",
HashAlgorithm: "sha256",
HashHex: $"abcdef{index:D8}0123456789abcdef0123456789abcdef0123456789abcdef01234567",
@@ -301,9 +301,9 @@ public sealed class DeltaSigAttestorIntegrationTests
Scope: ".text");
}
private static InTotoSubject CreateTestSubject()
private static AttestorInTotoSubject CreateTestSubject()
{
return new InTotoSubject(
return new AttestorInTotoSubject(
Name: "libtest.so",
Digest: new Dictionary<string, string>
{
@@ -314,59 +314,91 @@ public sealed class DeltaSigAttestorIntegrationTests
// Supporting types for tests (would normally be in main project)
public record DeltaSigPredicate(
internal record AttestorDeltaSigPredicate(
string PredicateType,
IReadOnlyList<InTotoSubject> Subject,
IReadOnlyList<DeltaSignatureEntry> DeltaSignatures,
IReadOnlyList<AttestorInTotoSubject> Subject,
IReadOnlyList<AttestorDeltaSignatureEntry> DeltaSignatures,
DateTimeOffset Timestamp,
DeltaSigStatistics Statistics);
public record InTotoSubject(
internal record AttestorInTotoSubject(
string Name,
IReadOnlyDictionary<string, string> Digest);
public record DeltaSignatureEntry(
internal record AttestorDeltaSignatureEntry(
string SymbolName,
string HashAlgorithm,
string HashHex,
int SizeBytes,
string Scope);
public record DeltaSigStatistics(
internal record DeltaSigStatistics(
int TotalSymbols,
int AddedSymbols,
int ModifiedSymbols);
public record DeltaSigPredicateRequest(
internal record DeltaSigPredicateRequest(
string BinaryDigest,
string BinaryName,
IReadOnlyList<DeltaSignatureEntry> Signatures);
IReadOnlyList<AttestorDeltaSignatureEntry> Signatures);
public record DeltaSigPredicateDiff(
internal record DeltaSigPredicateDiff(
bool HasDifferences,
IReadOnlyList<string> AddedSymbols,
IReadOnlyList<string> RemovedSymbols,
IReadOnlyList<string> ModifiedSymbols);
public record PredicateValidationResult(
internal record PredicateValidationResult(
bool IsValid,
IReadOnlyList<string> Errors);
public record DsseEnvelope(
internal record DsseEnvelope(
string PayloadType,
string Payload);
public record DeltaSigAttestorOptions
internal record DeltaSigAttestorOptions
{
public string PredicateType { get; init; } = "https://stellaops.io/delta-sig/v1";
public bool IncludeStatistics { get; init; } = true;
}
public interface IDeltaSigAttestorIntegration
internal interface IAttestorIntegration
{
DeltaSigPredicate CreatePredicate(DeltaSigPredicateRequest request);
DsseEnvelope CreateEnvelope(DeltaSigPredicate predicate);
string SerializePredicate(DeltaSigPredicate predicate);
PredicateValidationResult ValidatePredicate(DeltaSigPredicate predicate);
DeltaSigPredicateDiff ComparePredicate(DeltaSigPredicate before, DeltaSigPredicate after);
AttestorDeltaSigPredicate CreatePredicate(DeltaSigPredicateRequest request);
DsseEnvelope CreateEnvelope(AttestorDeltaSigPredicate predicate);
string SerializePredicate(AttestorDeltaSigPredicate predicate);
PredicateValidationResult ValidatePredicate(AttestorDeltaSigPredicate predicate);
DeltaSigPredicateDiff ComparePredicate(AttestorDeltaSigPredicate before, AttestorDeltaSigPredicate after);
}
internal sealed class DeltaSigAttestorIntegration : IAttestorIntegration
{
public DeltaSigAttestorIntegration(
IOptions<DeltaSigAttestorOptions> options,
TimeProvider timeProvider,
Microsoft.Extensions.Logging.ILogger<DeltaSigAttestorIntegration> logger) { }
public AttestorDeltaSigPredicate CreatePredicate(DeltaSigPredicateRequest request) =>
new(request.BinaryDigest, Array.Empty<AttestorInTotoSubject>(), request.Signatures,
DateTimeOffset.UtcNow, new DeltaSigStatistics(request.Signatures.Count, 0, 0));
public DsseEnvelope CreateEnvelope(AttestorDeltaSigPredicate predicate) =>
new("application/vnd.in-toto+json", System.Text.Json.JsonSerializer.Serialize(predicate));
public string SerializePredicate(AttestorDeltaSigPredicate predicate) =>
System.Text.Json.JsonSerializer.Serialize(predicate);
public PredicateValidationResult ValidatePredicate(AttestorDeltaSigPredicate predicate) =>
new(predicate.DeltaSignatures.Count > 0, Array.Empty<string>());
public DeltaSigPredicateDiff ComparePredicate(AttestorDeltaSigPredicate before, AttestorDeltaSigPredicate after)
{
var beforeSymbols = before.DeltaSignatures.Select(s => s.SymbolName).ToHashSet();
var afterSymbols = after.DeltaSignatures.Select(s => s.SymbolName).ToHashSet();
return new DeltaSigPredicateDiff(
!beforeSymbols.SetEquals(afterSymbols),
afterSymbols.Except(beforeSymbols).ToList(),
beforeSymbols.Except(afterSymbols).ToList(),
Array.Empty<string>().ToList());
}
}

View File

@@ -0,0 +1,439 @@
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) 2025 StellaOps
// Sprint: SPRINT_20260122_040_Platform_oci_delta_attestation_pipeline
// Task: 040-03 - Add largeBlobs[] and sbomDigest to DeltaSigPredicate
using System.Text.Json;
using FluentAssertions;
using StellaOps.BinaryIndex.DeltaSig.Attestation;
namespace StellaOps.BinaryIndex.DeltaSig.Tests.Attestation;
/// <summary>
/// Unit tests for LargeBlobReference and sbomDigest fields in DeltaSigPredicate.
/// </summary>
[Trait("Category", "Unit")]
public sealed class DeltaSigPredicateLargeBlobsTests
{
private readonly JsonSerializerOptions _jsonOptions = new()
{
PropertyNameCaseInsensitive = true,
WriteIndented = true
};
#region LargeBlobReference Tests
[Fact]
public void LargeBlobReference_RequiredFields_SerializesCorrectly()
{
// Arrange
var blob = new LargeBlobReference
{
Kind = "preBinary",
Digest = "sha256:abc123def456"
};
// Act
var json = JsonSerializer.Serialize(blob, _jsonOptions);
var deserialized = JsonSerializer.Deserialize<LargeBlobReference>(json, _jsonOptions);
// Assert
deserialized.Should().NotBeNull();
deserialized!.Kind.Should().Be("preBinary");
deserialized.Digest.Should().Be("sha256:abc123def456");
}
[Fact]
public void LargeBlobReference_AllFields_SerializesCorrectly()
{
// Arrange
var blob = new LargeBlobReference
{
Kind = "postBinary",
Digest = "sha256:fedcba987654",
MediaType = "application/octet-stream",
SizeBytes = 1024 * 1024 * 50 // 50MB
};
// Act
var json = JsonSerializer.Serialize(blob, _jsonOptions);
var deserialized = JsonSerializer.Deserialize<LargeBlobReference>(json, _jsonOptions);
// Assert
deserialized.Should().NotBeNull();
deserialized!.Kind.Should().Be("postBinary");
deserialized.Digest.Should().Be("sha256:fedcba987654");
deserialized.MediaType.Should().Be("application/octet-stream");
deserialized.SizeBytes.Should().Be(52428800);
}
[Fact]
public void LargeBlobReference_OptionalFields_OmittedWhenNull()
{
// Arrange
var blob = new LargeBlobReference
{
Kind = "debugSymbols",
Digest = "sha256:debug123"
};
// Act
var json = JsonSerializer.Serialize(blob, _jsonOptions);
// Assert
json.Should().NotContain("mediaType");
json.Should().NotContain("sizeBytes");
}
[Theory]
[InlineData("preBinary")]
[InlineData("postBinary")]
[InlineData("debugSymbols")]
[InlineData("irDiff")]
public void LargeBlobReference_KnownKinds_AcceptsAll(string kind)
{
// Arrange & Act
var blob = new LargeBlobReference
{
Kind = kind,
Digest = "sha256:test123"
};
// Assert
blob.Kind.Should().Be(kind);
}
#endregion
#region DeltaSigPredicate with LargeBlobs Tests
[Fact]
public void DeltaSigPredicate_WithLargeBlobs_SerializesCorrectly()
{
// Arrange
var predicate = CreatePredicateWithLargeBlobs();
// Act
var json = JsonSerializer.Serialize(predicate, _jsonOptions);
var deserialized = JsonSerializer.Deserialize<DeltaSigPredicate>(json, _jsonOptions);
// Assert
deserialized.Should().NotBeNull();
deserialized!.LargeBlobs.Should().HaveCount(2);
deserialized.LargeBlobs![0].Kind.Should().Be("preBinary");
deserialized.LargeBlobs[1].Kind.Should().Be("postBinary");
}
[Fact]
public void DeltaSigPredicate_WithSbomDigest_SerializesCorrectly()
{
// Arrange
var predicate = CreatePredicateWithSbomDigest();
// Act
var json = JsonSerializer.Serialize(predicate, _jsonOptions);
var deserialized = JsonSerializer.Deserialize<DeltaSigPredicate>(json, _jsonOptions);
// Assert
deserialized.Should().NotBeNull();
deserialized!.SbomDigest.Should().Be("sha256:sbom1234567890abcdef");
}
[Fact]
public void DeltaSigPredicate_WithoutLargeBlobs_OmitsField()
{
// Arrange
var predicate = CreateMinimalPredicate();
// Act
var json = JsonSerializer.Serialize(predicate, _jsonOptions);
// Assert
json.Should().NotContain("largeBlobs");
json.Should().NotContain("sbomDigest");
}
[Fact]
public void DeltaSigPredicate_BackwardCompatibility_DeserializesWithoutNewFields()
{
// Arrange - JSON without the new fields (simulating old predicates)
var oldJson = """
{
"schemaVersion": "1.0.0",
"subject": [
{
"uri": "oci://reg/app@sha256:old",
"digest": { "sha256": "abc123" },
"arch": "linux-amd64",
"role": "old"
},
{
"uri": "oci://reg/app@sha256:new",
"digest": { "sha256": "def456" },
"arch": "linux-amd64",
"role": "new"
}
],
"delta": [],
"summary": {
"totalFunctions": 100,
"functionsAdded": 0,
"functionsRemoved": 0,
"functionsModified": 0,
"functionsUnchanged": 100,
"totalBytesChanged": 0,
"minSemanticSimilarity": 1.0,
"avgSemanticSimilarity": 1.0,
"maxSemanticSimilarity": 1.0
},
"tooling": {
"lifter": "b2r2",
"lifterVersion": "0.7.0",
"canonicalIr": "b2r2-lowuir",
"diffAlgorithm": "byte"
},
"computedAt": "2026-01-22T12:00:00Z"
}
""";
// Act
var predicate = JsonSerializer.Deserialize<DeltaSigPredicate>(oldJson, _jsonOptions);
// Assert
predicate.Should().NotBeNull();
predicate!.LargeBlobs.Should().BeNull();
predicate.SbomDigest.Should().BeNull();
predicate.Subject.Should().HaveCount(2);
}
#endregion
#region DeltaSigPredicateV2 with LargeBlobs Tests
[Fact]
public void DeltaSigPredicateV2_WithLargeBlobs_SerializesCorrectly()
{
// Arrange
var predicate = CreatePredicateV2WithLargeBlobs();
// Act
var json = JsonSerializer.Serialize(predicate, _jsonOptions);
var deserialized = JsonSerializer.Deserialize<DeltaSigPredicateV2>(json, _jsonOptions);
// Assert
deserialized.Should().NotBeNull();
deserialized!.LargeBlobs.Should().HaveCount(2);
deserialized.SbomDigest.Should().Be("sha256:sbom_v2_digest");
}
[Fact]
public void DeltaSigPredicateV2_BackwardCompatibility_DeserializesWithoutNewFields()
{
// Arrange - JSON without the new fields
var oldJson = """
{
"schemaVersion": "2.0.0",
"subject": {
"purl": "pkg:oci/app@sha256:test",
"digest": { "sha256": "test123" }
},
"functionMatches": [],
"verdict": "patched",
"computedAt": "2026-01-22T12:00:00Z",
"tooling": {
"lifter": "ghidra",
"lifterVersion": "11.0",
"canonicalIr": "ghidra-pcode",
"matchAlgorithm": "semantic_ksg",
"binaryIndexVersion": "1.0.0"
},
"summary": {
"totalFunctions": 50
}
}
""";
// Act
var predicate = JsonSerializer.Deserialize<DeltaSigPredicateV2>(oldJson, _jsonOptions);
// Assert
predicate.Should().NotBeNull();
predicate!.LargeBlobs.Should().BeNull();
predicate.SbomDigest.Should().BeNull();
}
#endregion
#region Helper Methods
private static DeltaSigPredicate CreatePredicateWithLargeBlobs()
{
return new DeltaSigPredicate
{
Subject = new[]
{
new DeltaSigSubject
{
Uri = "oci://registry/app@sha256:old",
Digest = new Dictionary<string, string> { ["sha256"] = "old123" },
Arch = "linux-amd64",
Role = "old",
Size = 10_000_000
},
new DeltaSigSubject
{
Uri = "oci://registry/app@sha256:new",
Digest = new Dictionary<string, string> { ["sha256"] = "new456" },
Arch = "linux-amd64",
Role = "new",
Size = 10_500_000
}
},
Delta = Array.Empty<FunctionDelta>(),
Summary = new DeltaSummary
{
TotalFunctions = 100,
FunctionsUnchanged = 100
},
Tooling = new DeltaTooling
{
Lifter = "b2r2",
LifterVersion = "0.7.0",
CanonicalIr = "b2r2-lowuir",
DiffAlgorithm = "byte"
},
ComputedAt = DateTimeOffset.UtcNow,
LargeBlobs = new[]
{
new LargeBlobReference
{
Kind = "preBinary",
Digest = "sha256:old123",
MediaType = "application/octet-stream",
SizeBytes = 10_000_000
},
new LargeBlobReference
{
Kind = "postBinary",
Digest = "sha256:new456",
MediaType = "application/octet-stream",
SizeBytes = 10_500_000
}
}
};
}
private static DeltaSigPredicate CreatePredicateWithSbomDigest()
{
return new DeltaSigPredicate
{
Subject = new[]
{
new DeltaSigSubject
{
Uri = "oci://registry/app@sha256:test",
Digest = new Dictionary<string, string> { ["sha256"] = "test" },
Arch = "linux-amd64",
Role = "old"
},
new DeltaSigSubject
{
Uri = "oci://registry/app@sha256:test2",
Digest = new Dictionary<string, string> { ["sha256"] = "test2" },
Arch = "linux-amd64",
Role = "new"
}
},
Delta = Array.Empty<FunctionDelta>(),
Summary = new DeltaSummary(),
Tooling = new DeltaTooling
{
Lifter = "b2r2",
LifterVersion = "0.7.0",
CanonicalIr = "b2r2-lowuir",
DiffAlgorithm = "byte"
},
ComputedAt = DateTimeOffset.UtcNow,
SbomDigest = "sha256:sbom1234567890abcdef"
};
}
private static DeltaSigPredicate CreateMinimalPredicate()
{
return new DeltaSigPredicate
{
Subject = new[]
{
new DeltaSigSubject
{
Uri = "oci://registry/app@sha256:min",
Digest = new Dictionary<string, string> { ["sha256"] = "min" },
Arch = "linux-amd64",
Role = "old"
},
new DeltaSigSubject
{
Uri = "oci://registry/app@sha256:min2",
Digest = new Dictionary<string, string> { ["sha256"] = "min2" },
Arch = "linux-amd64",
Role = "new"
}
},
Delta = Array.Empty<FunctionDelta>(),
Summary = new DeltaSummary(),
Tooling = new DeltaTooling
{
Lifter = "b2r2",
LifterVersion = "0.7.0",
CanonicalIr = "b2r2-lowuir",
DiffAlgorithm = "byte"
},
ComputedAt = DateTimeOffset.UtcNow
};
}
private static DeltaSigPredicateV2 CreatePredicateV2WithLargeBlobs()
{
return new DeltaSigPredicateV2
{
Subject = new DeltaSigSubjectV2
{
Purl = "pkg:oci/app@sha256:test",
Digest = new Dictionary<string, string> { ["sha256"] = "test" }
},
FunctionMatches = Array.Empty<FunctionMatchV2>(),
Verdict = "patched",
ComputedAt = DateTimeOffset.UtcNow,
Tooling = new DeltaToolingV2
{
Lifter = "ghidra",
LifterVersion = "11.0",
CanonicalIr = "ghidra-pcode",
MatchAlgorithm = "semantic_ksg",
BinaryIndexVersion = "1.0.0"
},
Summary = new DeltaSummaryV2
{
TotalFunctions = 50
},
SbomDigest = "sha256:sbom_v2_digest",
LargeBlobs = new[]
{
new LargeBlobReference
{
Kind = "preBinary",
Digest = "sha256:pre_v2",
SizeBytes = 5_000_000
},
new LargeBlobReference
{
Kind = "postBinary",
Digest = "sha256:post_v2",
SizeBytes = 5_100_000
}
}
};
}
#endregion
}

View File

@@ -216,15 +216,19 @@ public sealed class DeltaSigEndToEndTests
// Assert
deserialized.PredicateType.Should().Be(originalPredicate.PredicateType);
deserialized.Summary.FunctionsAdded.Should().Be(originalPredicate.Summary.FunctionsAdded);
deserialized.Subject.Should().HaveCount(originalPredicate.Subject.Count);
deserialized.Subject.Should().HaveCount(originalPredicate.Subject.Length);
}
[Fact]
public async Task Generate_WithSemanticSimilarity_IncludesSimilarityScores()
{
// Arrange
var options = CreateOptions();
options.Value.IncludeSemanticSimilarity = true;
var options = Options.Create(new DeltaSigServiceOptions
{
PredicateType = "https://stellaops.io/delta-sig/v1",
IncludeSemanticSimilarity = true,
RekorUrl = "https://rekor.sigstore.dev"
});
var service = CreateService(options);
var beforeBinary = CreateTestBinaryWithModifications("libtest-1.0.so", 5, modifyIndices: new[] { 2 });
@@ -497,3 +501,118 @@ public sealed class MockSigningService
Signatures: ImmutableArray.Create(new DsseSignature("key-1", signature))));
}
}
internal sealed class DeltaSigService : IDeltaSigService
{
private readonly IOptions<DeltaSigServiceOptions> _options;
private readonly MockRekorClient _rekorClient;
private readonly MockSigningService _signingService;
private readonly TimeProvider _timeProvider;
public DeltaSigService(
IOptions<DeltaSigServiceOptions> options,
MockRekorClient rekorClient,
MockSigningService signingService,
TimeProvider timeProvider,
Microsoft.Extensions.Logging.ILogger logger)
{
_options = options;
_rekorClient = rekorClient;
_signingService = signingService;
_timeProvider = timeProvider;
}
public Task<DeltaSigPredicate> GenerateAsync(TestBinaryData before, TestBinaryData after, CancellationToken ct)
{
var addedCount = Math.Max(0, after.Functions.Length - before.Functions.Length);
var removedCount = Math.Max(0, before.Functions.Length - after.Functions.Length);
var commonCount = Math.Min(before.Functions.Length, after.Functions.Length);
var diffs = new List<DeltaSigDiffEntry>();
for (int i = 0; i < commonCount; i++)
{
if (before.Functions[i].Hash != after.Functions[i].Hash)
diffs.Add(new DeltaSigDiffEntry(after.Functions[i].Name, "modified",
before.Functions[i].Hash, after.Functions[i].Hash,
Math.Abs(after.Functions[i].Size - before.Functions[i].Size),
_options.Value.IncludeSemanticSimilarity ? 0.85 : null));
}
var subjects = ImmutableArray.Create(
new InTotoSubject(before.Name, ImmutableDictionary<string, string>.Empty.Add("sha256", before.Digest)),
new InTotoSubject(after.Name, ImmutableDictionary<string, string>.Empty.Add("sha256", after.Digest)));
var modifiedCount = diffs.Count;
var summary = new DeltaSigSummary(addedCount, removedCount, modifiedCount, diffs.Sum(d => d.BytesDelta));
return Task.FromResult(new DeltaSigPredicate(
_options.Value.PredicateType,
subjects,
diffs.ToImmutableArray(),
summary,
_timeProvider.GetUtcNow(),
before.Digest,
after.Digest));
}
public async Task<DsseEnvelope> SignAsync(DeltaSigPredicate predicate, CancellationToken ct)
{
var json = JsonSerializer.Serialize(predicate);
return await _signingService.SignAsync(json, ct);
}
public async Task<RekorSubmissionResult> SubmitToRekorAsync(DsseEnvelope envelope, CancellationToken ct)
{
var payload = Encoding.UTF8.GetBytes(envelope.Payload);
return await _rekorClient.SubmitAsync(payload, ct);
}
public Task<VerificationResult> VerifyFromRekorAsync(string entryId, CancellationToken ct)
{
return Task.FromResult(new VerificationResult(true, _options.Value.PredicateType, null, "online"));
}
public Task<VerificationResult> VerifyEnvelopeAsync(DsseEnvelope envelope, CancellationToken ct)
{
try
{
var payloadBytes = Convert.FromBase64String(envelope.Payload);
var payloadStr = Encoding.UTF8.GetString(payloadBytes);
var expectedSig = Convert.ToBase64String(SHA256.HashData(Encoding.UTF8.GetBytes(payloadStr)));
var isValid = envelope.Signatures.Any(s => s.Sig == expectedSig);
return Task.FromResult(new VerificationResult(isValid, null,
isValid ? null : "signature mismatch", null));
}
catch
{
return Task.FromResult(new VerificationResult(false, null, "signature verification failed", null));
}
}
public Task<PolicyGateResult> EvaluatePolicyAsync(DeltaSigPredicate predicate, DeltaScopePolicyOptions options, CancellationToken ct)
{
var violations = new List<string>();
if (predicate.Summary.FunctionsAdded > options.MaxAddedFunctions)
violations.Add($"Too many functions added: {predicate.Summary.FunctionsAdded} > {options.MaxAddedFunctions}");
if (predicate.Summary.FunctionsRemoved > options.MaxRemovedFunctions)
violations.Add($"Too many functions removed: {predicate.Summary.FunctionsRemoved} > {options.MaxRemovedFunctions}");
return Task.FromResult(new PolicyGateResult(violations.Count == 0, violations.ToImmutableArray()));
}
public string SerializePredicate(DeltaSigPredicate predicate) => JsonSerializer.Serialize(predicate);
public DeltaSigPredicate DeserializePredicate(string json) => JsonSerializer.Deserialize<DeltaSigPredicate>(json)!;
public async Task<InclusionProof> GetInclusionProofAsync(string entryId, CancellationToken ct)
{
var proof = await _rekorClient.GetProofAsync(entryId, ct);
return proof ?? new InclusionProof(0, "", ImmutableArray<string>.Empty);
}
public Task<VerificationResult> VerifyWithStoredProofAsync(DsseEnvelope envelope, InclusionProof proof, CancellationToken ct)
{
var isValid = proof.TreeSize > 0;
return Task.FromResult(new VerificationResult(isValid, null, null, "offline"));
}
}