save progress
This commit is contained in:
@@ -11,16 +11,16 @@ namespace StellaOps.Policy.Engine.Storage.InMemory;
|
||||
/// In-memory implementation of IExceptionRepository for offline/test runs.
|
||||
/// Provides minimal semantics needed for lifecycle processing.
|
||||
/// </summary>
|
||||
public sealed class InMemoryExceptionRepository(TimeProvider timeProvider, IGuidProvider guidProvider) : IExceptionRepository
|
||||
public sealed class InMemoryExceptionRepository : IExceptionRepository
|
||||
{
|
||||
private readonly TimeProvider _timeProvider = timeProvider;
|
||||
private readonly IGuidProvider _guidProvider = guidProvider;
|
||||
private readonly ConcurrentDictionary<(string Tenant, Guid Id), ExceptionEntity> _exceptions = new();
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
private readonly ConcurrentDictionary<(string Tenant, Guid Id), ExceptionEntity> _exceptions = new();
|
||||
|
||||
public InMemoryExceptionRepository(TimeProvider? timeProvider = null)
|
||||
public InMemoryExceptionRepository(TimeProvider? timeProvider = null, IGuidProvider? guidProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? new SystemGuidProvider();
|
||||
}
|
||||
|
||||
public Task<ExceptionEntity> CreateAsync(ExceptionEntity exception, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -29,7 +29,7 @@ public sealed class BatchSimulationOrchestrator : IBatchSimulationOrchestrator,
|
||||
{
|
||||
_simulationService = simulationService ?? throw new ArgumentNullException(nameof(simulationService));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? GuidProvider.Default;
|
||||
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
|
||||
// Start background processing
|
||||
_processingTask = Task.Run(ProcessJobsAsync);
|
||||
|
||||
@@ -25,7 +25,7 @@ public sealed class ReviewWorkflowService : IReviewWorkflowService
|
||||
{
|
||||
_packStore = packStore ?? throw new ArgumentNullException(nameof(packStore));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? GuidProvider.Default;
|
||||
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
}
|
||||
|
||||
public async Task<ReviewRequest> SubmitForReviewAsync(
|
||||
|
||||
@@ -16,4 +16,8 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Options" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Determinism.Abstractions\StellaOps.Determinism.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -6,11 +6,10 @@ namespace StellaOps.Policy.Registry.Storage;
|
||||
/// <summary>
|
||||
/// In-memory implementation of IVerificationPolicyStore for testing and development.
|
||||
/// </summary>
|
||||
public sealed class InMemoryVerificationPolicyStore(TimeProvider timeProvider) : IVerificationPolicyStore
|
||||
public sealed class InMemoryVerificationPolicyStore : IVerificationPolicyStore
|
||||
{
|
||||
private readonly TimeProvider _timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
private readonly ConcurrentDictionary<(Guid TenantId, string PolicyId), VerificationPolicyEntity> _policies = new();
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly ConcurrentDictionary<(Guid TenantId, string PolicyId), VerificationPolicyEntity> _policies = new();
|
||||
|
||||
public InMemoryVerificationPolicyStore(TimeProvider? timeProvider = null)
|
||||
{
|
||||
|
||||
@@ -71,7 +71,7 @@ public class DeterminismPropertyTests
|
||||
/// Property: Parallel execution produces consistent results.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Entropy_ParallelExecution_ProducesConsistentResults()
|
||||
public async Task Entropy_ParallelExecution_ProducesConsistentResults()
|
||||
{
|
||||
// Arrange
|
||||
var calculator = new UncertaintyScoreCalculator(NullLogger<UncertaintyScoreCalculator>.Instance);
|
||||
@@ -82,7 +82,7 @@ public class DeterminismPropertyTests
|
||||
.Select(_ => Task.Run(() => calculator.CalculateEntropy(snapshot)))
|
||||
.ToArray();
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
await Task.WhenAll(tasks);
|
||||
var results = tasks.Select(t => t.Result).ToList();
|
||||
|
||||
// Assert - all results should be identical
|
||||
|
||||
@@ -12,7 +12,7 @@ public sealed class RvaBuilderTests
|
||||
[Fact]
|
||||
public void Build_ValidInputs_CreatesRva()
|
||||
{
|
||||
var rva = new RvaBuilder(_hasher)
|
||||
var rva = new RvaBuilder(_hasher, TimeProvider.System)
|
||||
.WithVerdict(RiskVerdictStatus.Pass)
|
||||
.WithSubject("sha256:abc123", "container-image", "myapp:v1.0")
|
||||
.WithPolicy("policy-1", "1.0", "sha256:xyz")
|
||||
@@ -31,7 +31,7 @@ public sealed class RvaBuilderTests
|
||||
[Fact]
|
||||
public void Build_MissingSubject_Throws()
|
||||
{
|
||||
var builder = new RvaBuilder(_hasher)
|
||||
var builder = new RvaBuilder(_hasher, TimeProvider.System)
|
||||
.WithVerdict(RiskVerdictStatus.Pass)
|
||||
.WithPolicy("p", "1.0", "sha256:x")
|
||||
.WithKnowledgeSnapshot("ksm:sha256:y");
|
||||
@@ -45,7 +45,7 @@ public sealed class RvaBuilderTests
|
||||
[Fact]
|
||||
public void Build_MissingPolicy_Throws()
|
||||
{
|
||||
var builder = new RvaBuilder(_hasher)
|
||||
var builder = new RvaBuilder(_hasher, TimeProvider.System)
|
||||
.WithVerdict(RiskVerdictStatus.Pass)
|
||||
.WithSubject("sha256:abc", "container-image")
|
||||
.WithKnowledgeSnapshot("ksm:sha256:y");
|
||||
@@ -59,7 +59,7 @@ public sealed class RvaBuilderTests
|
||||
[Fact]
|
||||
public void Build_MissingSnapshot_Throws()
|
||||
{
|
||||
var builder = new RvaBuilder(_hasher)
|
||||
var builder = new RvaBuilder(_hasher, TimeProvider.System)
|
||||
.WithVerdict(RiskVerdictStatus.Pass)
|
||||
.WithSubject("sha256:abc", "container-image")
|
||||
.WithPolicy("p", "1.0", "sha256:x");
|
||||
@@ -158,7 +158,7 @@ public sealed class RvaBuilderTests
|
||||
|
||||
private RvaBuilder CreateBuilder()
|
||||
{
|
||||
return new RvaBuilder(_hasher)
|
||||
return new RvaBuilder(_hasher, TimeProvider.System)
|
||||
.WithVerdict(RiskVerdictStatus.Pass)
|
||||
.WithSubject("sha256:test123", "container-image", "test:v1")
|
||||
.WithPolicy("policy-1", "1.0", "sha256:policy")
|
||||
|
||||
@@ -23,7 +23,8 @@ public sealed class RvaVerifierTests
|
||||
NullLogger<SnapshotService>.Instance);
|
||||
_verifier = new RvaVerifier(
|
||||
_snapshotService,
|
||||
NullLogger<RvaVerifier>.Instance);
|
||||
NullLogger<RvaVerifier>.Instance,
|
||||
TimeProvider.System);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -124,7 +125,7 @@ public sealed class RvaVerifierTests
|
||||
|
||||
private RiskVerdictAttestation CreateValidRva(DateTimeOffset? expiresAt = null)
|
||||
{
|
||||
return new RvaBuilder(_hasher)
|
||||
return new RvaBuilder(_hasher, TimeProvider.System)
|
||||
.WithVerdict(RiskVerdictStatus.Pass)
|
||||
.WithSubject("sha256:test123", "container-image", "test:v1")
|
||||
.WithPolicy("policy-1", "1.0", "sha256:policy")
|
||||
|
||||
@@ -15,6 +15,7 @@ using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using StellaOps.Auth.Client;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Policy.Gateway.Clients;
|
||||
using StellaOps.Policy.Gateway.Contracts;
|
||||
using StellaOps.Policy.Gateway.Options;
|
||||
@@ -41,7 +42,7 @@ public class PolicyEngineClientTests
|
||||
|
||||
var optionsMonitor = new TestOptionsMonitor(options);
|
||||
var tokenClient = new StubTokenClient();
|
||||
var dpopGenerator = new PolicyGatewayDpopProofGenerator(new StubHostEnvironment(), optionsMonitor, TimeProvider.System, NullLogger<PolicyGatewayDpopProofGenerator>.Instance);
|
||||
var dpopGenerator = new PolicyGatewayDpopProofGenerator(new StubHostEnvironment(), optionsMonitor, TimeProvider.System, SystemGuidProvider.Instance, NullLogger<PolicyGatewayDpopProofGenerator>.Instance);
|
||||
var tokenProvider = new PolicyEngineTokenProvider(tokenClient, optionsMonitor, dpopGenerator, TimeProvider.System, NullLogger<PolicyEngineTokenProvider>.Instance);
|
||||
|
||||
using var recordingHandler = new RecordingHandler();
|
||||
|
||||
@@ -8,12 +8,11 @@ using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Policy.Gateway.Options;
|
||||
using StellaOps.Policy.Gateway.Services;
|
||||
using Xunit;
|
||||
|
||||
|
||||
using StellaOps.TestKit;
|
||||
using Xunit;
|
||||
namespace StellaOps.Policy.Gateway.Tests;
|
||||
|
||||
public sealed class PolicyGatewayDpopProofGeneratorTests
|
||||
@@ -29,6 +28,7 @@ public sealed class PolicyGatewayDpopProofGeneratorTests
|
||||
new StubHostEnvironment(AppContext.BaseDirectory),
|
||||
new TestOptionsMonitor(options),
|
||||
TimeProvider.System,
|
||||
SystemGuidProvider.Instance,
|
||||
NullLogger<PolicyGatewayDpopProofGenerator>.Instance);
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() =>
|
||||
@@ -52,6 +52,7 @@ public sealed class PolicyGatewayDpopProofGeneratorTests
|
||||
new StubHostEnvironment(tempRoot.FullName),
|
||||
new TestOptionsMonitor(options),
|
||||
TimeProvider.System,
|
||||
SystemGuidProvider.Instance,
|
||||
NullLogger<PolicyGatewayDpopProofGenerator>.Instance);
|
||||
|
||||
var exception = Assert.Throws<FileNotFoundException>(() =>
|
||||
@@ -82,6 +83,7 @@ public sealed class PolicyGatewayDpopProofGeneratorTests
|
||||
new StubHostEnvironment(tempRoot.FullName),
|
||||
new TestOptionsMonitor(options),
|
||||
TimeProvider.System,
|
||||
SystemGuidProvider.Instance,
|
||||
NullLogger<PolicyGatewayDpopProofGenerator>.Instance);
|
||||
|
||||
const string accessToken = "sample-access-token";
|
||||
|
||||
@@ -8,6 +8,7 @@ using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using Moq;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Policy.Exceptions.Models;
|
||||
using StellaOps.Policy.Exceptions.Repositories;
|
||||
using StellaOps.Policy.Gateway.Services;
|
||||
@@ -32,6 +33,7 @@ public class ExceptionServiceTests
|
||||
_repositoryMock.Object,
|
||||
_notificationMock.Object,
|
||||
_timeProvider,
|
||||
new SequentialGuidProvider(),
|
||||
NullLogger<ExceptionService>.Instance);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Immutable;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Policy.Exceptions.Models;
|
||||
using StellaOps.Policy.Exceptions.Repositories;
|
||||
using StellaOps.Policy.Persistence.Postgres;
|
||||
@@ -28,7 +29,7 @@ public sealed class ExceptionObjectRepositoryTests : IAsyncLifetime
|
||||
var options = fixture.Fixture.CreateOptions();
|
||||
options.SchemaName = fixture.SchemaName;
|
||||
var dataSource = new PolicyDataSource(Options.Create(options), NullLogger<PolicyDataSource>.Instance);
|
||||
_repository = new PostgresExceptionObjectRepository(dataSource, NullLogger<PostgresExceptionObjectRepository>.Instance);
|
||||
_repository = new PostgresExceptionObjectRepository(dataSource, NullLogger<PostgresExceptionObjectRepository>.Instance, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
}
|
||||
|
||||
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
|
||||
|
||||
@@ -173,7 +173,7 @@ public sealed class PostgresExceptionApplicationRepositoryTests : IAsyncLifetime
|
||||
string findId,
|
||||
string? vulnId = null,
|
||||
string eff = "suppress") =>
|
||||
ExceptionApplication.Create(_tenantId, excId, findId, "affected", "not_affected", "test", eff, vulnId);
|
||||
ExceptionApplication.Create(_tenantId, excId, findId, "affected", "not_affected", "test", eff, Guid.NewGuid(), DateTimeOffset.UtcNow, vulnId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Immutable;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Policy.Exceptions.Models;
|
||||
using StellaOps.Policy.Exceptions.Repositories;
|
||||
using StellaOps.Policy.Persistence.Postgres;
|
||||
@@ -29,7 +30,7 @@ public sealed class PostgresExceptionObjectRepositoryTests : IAsyncLifetime
|
||||
var options = fixture.Fixture.CreateOptions();
|
||||
options.SchemaName = fixture.SchemaName;
|
||||
var dataSource = new PolicyDataSource(Options.Create(options), NullLogger<PolicyDataSource>.Instance);
|
||||
_repository = new PostgresExceptionObjectRepository(dataSource, NullLogger<PostgresExceptionObjectRepository>.Instance);
|
||||
_repository = new PostgresExceptionObjectRepository(dataSource, NullLogger<PostgresExceptionObjectRepository>.Instance, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
}
|
||||
|
||||
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Immutable;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Policy.Scoring.Engine;
|
||||
using StellaOps.Policy.Scoring.Receipts;
|
||||
using StellaOps.Policy.Scoring.Tests.Fakes;
|
||||
@@ -25,7 +26,7 @@ public sealed class CvssPipelineIntegrationTests
|
||||
{
|
||||
// Arrange
|
||||
var repository = new InMemoryReceiptRepository();
|
||||
var builder = new ReceiptBuilder(_v4Engine, repository);
|
||||
var builder = new ReceiptBuilder(_v4Engine, repository, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
|
||||
var policy = CreateTestPolicy();
|
||||
var baseMetrics = CreateMaxSeverityBaseMetrics();
|
||||
@@ -61,7 +62,7 @@ public sealed class CvssPipelineIntegrationTests
|
||||
{
|
||||
// Arrange
|
||||
var repository = new InMemoryReceiptRepository();
|
||||
var builder = new ReceiptBuilder(_v4Engine, repository);
|
||||
var builder = new ReceiptBuilder(_v4Engine, repository, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
|
||||
var policy = CreateTestPolicy();
|
||||
var baseMetrics = CreateMaxSeverityBaseMetrics();
|
||||
@@ -149,8 +150,8 @@ public sealed class CvssPipelineIntegrationTests
|
||||
// Arrange
|
||||
var repository1 = new InMemoryReceiptRepository();
|
||||
var repository2 = new InMemoryReceiptRepository();
|
||||
var builder1 = new ReceiptBuilder(_v4Engine, repository1);
|
||||
var builder2 = new ReceiptBuilder(_v4Engine, repository2);
|
||||
var builder1 = new ReceiptBuilder(_v4Engine, repository1, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
var builder2 = new ReceiptBuilder(_v4Engine, repository2, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
|
||||
var policy = CreateTestPolicy();
|
||||
var baseMetrics = CreateMaxSeverityBaseMetrics();
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Immutable;
|
||||
using FluentAssertions;
|
||||
using System.Linq;
|
||||
using StellaOps.Attestor.Envelope;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Policy.Scoring.Engine;
|
||||
using StellaOps.Policy.Scoring.Receipts;
|
||||
using StellaOps.Policy.Scoring.Tests.Fakes;
|
||||
@@ -60,7 +61,7 @@ public sealed class ReceiptBuilderTests
|
||||
})
|
||||
};
|
||||
|
||||
var builder = new ReceiptBuilder(_engine, _repository);
|
||||
var builder = new ReceiptBuilder(_engine, _repository, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
|
||||
// Act
|
||||
var receipt1 = await builder.CreateAsync(request);
|
||||
@@ -118,7 +119,7 @@ public sealed class ReceiptBuilderTests
|
||||
|
||||
var evidence2 = evidence1.Reverse().ToImmutableList();
|
||||
|
||||
var builder = new ReceiptBuilder(_engine, _repository);
|
||||
var builder = new ReceiptBuilder(_engine, _repository, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
|
||||
var r1 = await builder.CreateAsync(new CreateReceiptRequest
|
||||
{
|
||||
@@ -182,7 +183,7 @@ public sealed class ReceiptBuilderTests
|
||||
SigningKey = signingKey
|
||||
};
|
||||
|
||||
var builder = new ReceiptBuilder(_engine, _repository);
|
||||
var builder = new ReceiptBuilder(_engine, _repository, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
|
||||
// Act
|
||||
var receipt = await builder.CreateAsync(request);
|
||||
@@ -240,7 +241,7 @@ public sealed class ReceiptBuilderTests
|
||||
})
|
||||
};
|
||||
|
||||
var builder = new ReceiptBuilder(_engine, _repository);
|
||||
var builder = new ReceiptBuilder(_engine, _repository, TimeProvider.System, SystemGuidProvider.Instance);
|
||||
|
||||
// Act
|
||||
var act = async () => await builder.CreateAsync(request);
|
||||
|
||||
@@ -222,7 +222,7 @@ public class ProofLedgerTests
|
||||
var originalRootHash = ledger.RootHash();
|
||||
|
||||
// Act
|
||||
var json = ledger.ToJson();
|
||||
var json = ledger.ToJson(DateTimeOffset.UtcNow);
|
||||
var restored = ProofLedger.FromJson(json);
|
||||
|
||||
// Assert
|
||||
@@ -236,7 +236,7 @@ public class ProofLedgerTests
|
||||
// Arrange
|
||||
var nodes = CreateTestNodes();
|
||||
var ledger = ProofLedger.FromNodes(nodes);
|
||||
var json = ledger.ToJson();
|
||||
var json = ledger.ToJson(DateTimeOffset.UtcNow);
|
||||
|
||||
// Tamper with the JSON (9.0 serializes as 9 without decimal point)
|
||||
var tampered = json.Replace("\"total\":9,", "\"total\":8,");
|
||||
|
||||
@@ -274,7 +274,7 @@ public class VexNormalizerTests
|
||||
var normalizer = new CsafVexNormalizer();
|
||||
var subject = CreateTestSubject();
|
||||
|
||||
var claim = normalizer.NormalizeStatement(subject, CsafProductStatus.KnownAffected);
|
||||
var claim = normalizer.NormalizeStatement(subject, CsafProductStatus.KnownAffected, DateTimeOffset.UtcNow);
|
||||
|
||||
Assert.Contains(claim.Assertions, a =>
|
||||
a.Atom == SecurityAtom.Present && a.Value == true);
|
||||
@@ -288,7 +288,7 @@ public class VexNormalizerTests
|
||||
var normalizer = new CsafVexNormalizer();
|
||||
var subject = CreateTestSubject();
|
||||
|
||||
var claim = normalizer.NormalizeStatement(subject, CsafProductStatus.KnownNotAffected);
|
||||
var claim = normalizer.NormalizeStatement(subject, CsafProductStatus.KnownNotAffected, DateTimeOffset.UtcNow);
|
||||
|
||||
Assert.Contains(claim.Assertions, a =>
|
||||
a.Atom == SecurityAtom.Applies && a.Value == false);
|
||||
@@ -300,7 +300,7 @@ public class VexNormalizerTests
|
||||
var normalizer = new CsafVexNormalizer();
|
||||
var subject = CreateTestSubject();
|
||||
|
||||
var claim = normalizer.NormalizeStatement(subject, CsafProductStatus.Fixed);
|
||||
var claim = normalizer.NormalizeStatement(subject, CsafProductStatus.Fixed, DateTimeOffset.UtcNow);
|
||||
|
||||
Assert.Contains(claim.Assertions, a =>
|
||||
a.Atom == SecurityAtom.Fixed && a.Value == true);
|
||||
@@ -312,7 +312,7 @@ public class VexNormalizerTests
|
||||
var normalizer = new CsafVexNormalizer();
|
||||
var subject = CreateTestSubject();
|
||||
|
||||
var claim = normalizer.NormalizeStatement(subject, CsafProductStatus.UnderInvestigation);
|
||||
var claim = normalizer.NormalizeStatement(subject, CsafProductStatus.UnderInvestigation, DateTimeOffset.UtcNow);
|
||||
|
||||
Assert.Empty(claim.Assertions);
|
||||
}
|
||||
@@ -326,6 +326,7 @@ public class VexNormalizerTests
|
||||
var claim = normalizer.NormalizeStatement(
|
||||
subject,
|
||||
CsafProductStatus.KnownNotAffected,
|
||||
DateTimeOffset.UtcNow,
|
||||
CsafFlagLabel.VulnerableCodeNotInExecutePath);
|
||||
|
||||
Assert.Contains(claim.Assertions, a =>
|
||||
@@ -341,6 +342,7 @@ public class VexNormalizerTests
|
||||
var claim = normalizer.NormalizeStatement(
|
||||
subject,
|
||||
CsafProductStatus.KnownNotAffected,
|
||||
DateTimeOffset.UtcNow,
|
||||
CsafFlagLabel.ComponentNotPresent);
|
||||
|
||||
Assert.Contains(claim.Assertions, a =>
|
||||
|
||||
Reference in New Issue
Block a user