Add property-based tests for SBOM/VEX document ordering and Unicode normalization determinism
- Implement `SbomVexOrderingDeterminismProperties` for testing component list and vulnerability metadata hash consistency. - Create `UnicodeNormalizationDeterminismProperties` to validate NFC normalization and Unicode string handling. - Add project file for `StellaOps.Testing.Determinism.Properties` with necessary dependencies. - Introduce CI/CD template validation tests including YAML syntax checks and documentation content verification. - Create validation script for CI/CD templates ensuring all required files and structures are present.
This commit is contained in:
@@ -80,7 +80,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var beforeKeyAdded = _key2024AddedAt.AddDays(-30); // Dec 2023
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", beforeKeyAdded);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", beforeKeyAdded);
|
||||
|
||||
// Assert
|
||||
result.IsValid.Should().BeFalse();
|
||||
@@ -96,7 +96,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var duringActiveWindow = _key2024AddedAt.AddMonths(3); // April 2024
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", duringActiveWindow);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", duringActiveWindow);
|
||||
|
||||
// Assert
|
||||
result.IsValid.Should().BeTrue();
|
||||
@@ -112,7 +112,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var signedDuringOverlap = _key2024RevokedAt.AddDays(-30); // Dec 2024
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", signedDuringOverlap);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", signedDuringOverlap);
|
||||
|
||||
// Assert - key-2024 should be valid because signature was made before revocation
|
||||
result.IsValid.Should().BeTrue();
|
||||
@@ -127,7 +127,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var signedAfterRevocation = _key2024RevokedAt.AddDays(30); // Feb 2025
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", signedAfterRevocation);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", signedAfterRevocation);
|
||||
|
||||
// Assert - key-2024 should be invalid because signature was made after revocation
|
||||
result.IsValid.Should().BeFalse();
|
||||
@@ -143,7 +143,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var signedWithNewKey = _key2024RevokedAt.AddDays(30); // Feb 2025
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "key-2025", signedWithNewKey);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2025", signedWithNewKey);
|
||||
|
||||
// Assert - key-2025 should be valid
|
||||
result.IsValid.Should().BeTrue();
|
||||
@@ -163,8 +163,8 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var duringOverlap = new DateTimeOffset(2024, 9, 15, 0, 0, 0, TimeSpan.Zero); // Sep 2024
|
||||
|
||||
// Act
|
||||
var result2024 = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", duringOverlap);
|
||||
var result2025 = await _service.CheckKeyValidityAsync(anchor.Id, "key-2025", duringOverlap);
|
||||
var result2024 = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", duringOverlap);
|
||||
var result2025 = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2025", duringOverlap);
|
||||
|
||||
// Assert - both keys should be valid during overlap
|
||||
result2024.IsValid.Should().BeTrue();
|
||||
@@ -181,7 +181,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var anchor = await CreateTestAnchorWithTimelineAsync();
|
||||
|
||||
// Act - at exact revocation time, key is already revoked
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", _key2024RevokedAt);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", _key2024RevokedAt);
|
||||
|
||||
// Assert - at revocation time, key should be considered revoked
|
||||
result.IsValid.Should().BeFalse();
|
||||
@@ -196,7 +196,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var justBeforeRevocation = _key2024RevokedAt.AddMilliseconds(-1);
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", justBeforeRevocation);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", justBeforeRevocation);
|
||||
|
||||
// Assert - key should still be valid
|
||||
result.IsValid.Should().BeTrue();
|
||||
@@ -216,7 +216,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var signedBeforeExpiry = expiryDate.AddDays(-30); // Feb 2025
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "expiring-key", signedBeforeExpiry);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "expiring-key", signedBeforeExpiry);
|
||||
|
||||
// Assert - should be valid because signed before expiry
|
||||
result.IsValid.Should().BeTrue();
|
||||
@@ -232,7 +232,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var signedAfterExpiry = expiryDate.AddDays(30); // April 2025
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "expiring-key", signedAfterExpiry);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "expiring-key", signedAfterExpiry);
|
||||
|
||||
// Assert - should be invalid because signed after expiry
|
||||
result.IsValid.Should().BeFalse();
|
||||
@@ -250,7 +250,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var anchor = await CreateTestAnchorWithTimelineAsync();
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.Id, "nonexistent-key", _currentTime);
|
||||
var result = await _service.CheckKeyValidityAsync(anchor.AnchorId, "nonexistent-key", _currentTime);
|
||||
|
||||
// Assert
|
||||
result.IsValid.Should().BeFalse();
|
||||
@@ -281,9 +281,9 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var checkTime = new DateTimeOffset(2024, 9, 15, 10, 30, 45, TimeSpan.Zero);
|
||||
|
||||
// Act - call multiple times
|
||||
var result1 = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", checkTime);
|
||||
var result2 = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", checkTime);
|
||||
var result3 = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", checkTime);
|
||||
var result1 = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", checkTime);
|
||||
var result2 = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", checkTime);
|
||||
var result3 = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", checkTime);
|
||||
|
||||
// Assert - all results should be identical
|
||||
result1.Should().BeEquivalentTo(result2);
|
||||
@@ -301,9 +301,9 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
var jstTime = new DateTimeOffset(2024, 9, 15, 21, 0, 0, TimeSpan.FromHours(9));
|
||||
|
||||
// Act
|
||||
var resultUtc = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", utcTime);
|
||||
var resultPst = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", pstTime);
|
||||
var resultJst = await _service.CheckKeyValidityAsync(anchor.Id, "key-2024", jstTime);
|
||||
var resultUtc = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", utcTime);
|
||||
var resultPst = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", pstTime);
|
||||
var resultJst = await _service.CheckKeyValidityAsync(anchor.AnchorId, "key-2024", jstTime);
|
||||
|
||||
// Assert - all should return same result (same UTC instant)
|
||||
resultUtc.IsValid.Should().Be(resultPst.IsValid);
|
||||
@@ -320,7 +320,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
{
|
||||
var anchor = new TrustAnchorEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AnchorId = Guid.NewGuid(),
|
||||
PurlPattern = "pkg:npm/*",
|
||||
AllowedKeyIds = ["key-2024", "key-2025"],
|
||||
RevokedKeyIds = ["key-2024"],
|
||||
@@ -333,30 +333,32 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
{
|
||||
new KeyHistoryEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TrustAnchorId = anchor.Id,
|
||||
HistoryId = Guid.NewGuid(),
|
||||
AnchorId = anchor.AnchorId,
|
||||
KeyId = "key-2024",
|
||||
PublicKey = "-----BEGIN PUBLIC KEY-----\ntest-key-2024\n-----END PUBLIC KEY-----",
|
||||
Algorithm = "Ed25519",
|
||||
AddedAt = _key2024AddedAt,
|
||||
RevokedAt = _key2024RevokedAt,
|
||||
RevokeReason = "annual-rotation",
|
||||
CreatedBy = "test-user"
|
||||
CreatedAt = _key2024AddedAt
|
||||
},
|
||||
new KeyHistoryEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TrustAnchorId = anchor.Id,
|
||||
HistoryId = Guid.NewGuid(),
|
||||
AnchorId = anchor.AnchorId,
|
||||
KeyId = "key-2025",
|
||||
PublicKey = "-----BEGIN PUBLIC KEY-----\ntest-key-2025\n-----END PUBLIC KEY-----",
|
||||
Algorithm = "Ed25519",
|
||||
AddedAt = _key2025AddedAt,
|
||||
RevokedAt = null,
|
||||
RevokeReason = null,
|
||||
CreatedBy = "test-user"
|
||||
CreatedAt = _key2025AddedAt
|
||||
}
|
||||
};
|
||||
|
||||
_dbContext.TrustAnchors.Add(anchor);
|
||||
_dbContext.KeyHistories.AddRange(keyHistory);
|
||||
_dbContext.KeyHistory.AddRange(keyHistory);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
return anchor;
|
||||
@@ -366,7 +368,7 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
{
|
||||
var anchor = new TrustAnchorEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
AnchorId = Guid.NewGuid(),
|
||||
PurlPattern = "pkg:pypi/*",
|
||||
AllowedKeyIds = ["expiring-key"],
|
||||
RevokedKeyIds = [],
|
||||
@@ -377,19 +379,20 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
|
||||
var keyHistory = new KeyHistoryEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TrustAnchorId = anchor.Id,
|
||||
HistoryId = Guid.NewGuid(),
|
||||
AnchorId = anchor.AnchorId,
|
||||
KeyId = "expiring-key",
|
||||
PublicKey = "-----BEGIN PUBLIC KEY-----\ntest-expiring-key\n-----END PUBLIC KEY-----",
|
||||
Algorithm = "Ed25519",
|
||||
AddedAt = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
|
||||
ExpiresAt = new DateTimeOffset(2025, 3, 1, 0, 0, 0, TimeSpan.Zero),
|
||||
RevokedAt = null,
|
||||
RevokeReason = null,
|
||||
CreatedBy = "test-user"
|
||||
CreatedAt = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero)
|
||||
};
|
||||
|
||||
_dbContext.TrustAnchors.Add(anchor);
|
||||
_dbContext.KeyHistories.Add(keyHistory);
|
||||
_dbContext.KeyHistory.Add(keyHistory);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
|
||||
return anchor;
|
||||
@@ -398,21 +401,4 @@ public class TemporalKeyVerificationTests : IDisposable
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fake time provider for testing temporal logic.
|
||||
/// </summary>
|
||||
public class FakeTimeProvider : TimeProvider
|
||||
{
|
||||
private DateTimeOffset _currentTime;
|
||||
|
||||
public FakeTimeProvider(DateTimeOffset startTime)
|
||||
{
|
||||
_currentTime = startTime;
|
||||
}
|
||||
|
||||
public override DateTimeOffset GetUtcNow() => _currentTime;
|
||||
|
||||
public void SetTime(DateTimeOffset newTime) => _currentTime = newTime;
|
||||
|
||||
public void AdvanceBy(TimeSpan duration) => _currentTime += duration;
|
||||
}
|
||||
// Note: FakeTimeProvider is defined in KeyRotationServiceTests.cs
|
||||
|
||||
Reference in New Issue
Block a user