more audit work

This commit is contained in:
master
2026-01-08 10:21:51 +02:00
parent 43c02081ef
commit 51cf4bc16c
546 changed files with 36721 additions and 4003 deletions

View File

@@ -23,6 +23,7 @@ public class FileSystemRootStoreTests : IDisposable
{
private readonly Mock<ILogger<FileSystemRootStore>> _loggerMock;
private readonly string _testRootPath;
private static CancellationToken TestCancellationToken => TestContext.Current.CancellationToken;
public FileSystemRootStoreTests()
{
@@ -48,7 +49,7 @@ public class FileSystemRootStoreTests : IDisposable
var store = CreateStore(options);
// Act
var roots = await store.GetFulcioRootsAsync();
var roots = await store.GetFulcioRootsAsync(TestCancellationToken);
// Assert
roots.Should().BeEmpty();
@@ -61,13 +62,13 @@ public class FileSystemRootStoreTests : IDisposable
// Arrange
var cert = CreateTestCertificate("CN=Test Fulcio Root");
var pemPath = Path.Combine(_testRootPath, "fulcio.pem");
await WritePemFileAsync(pemPath, cert);
await WritePemFileAsync(pemPath, cert, TestCancellationToken);
var options = CreateOptions(fulcioPath: pemPath);
var store = CreateStore(options);
// Act
var roots = await store.GetFulcioRootsAsync();
var roots = await store.GetFulcioRootsAsync(TestCancellationToken);
// Assert
roots.Should().HaveCount(1);
@@ -85,14 +86,14 @@ public class FileSystemRootStoreTests : IDisposable
var cert1 = CreateTestCertificate("CN=Root 1");
var cert2 = CreateTestCertificate("CN=Root 2");
await WritePemFileAsync(Path.Combine(fulcioDir, "root1.pem"), cert1);
await WritePemFileAsync(Path.Combine(fulcioDir, "root2.pem"), cert2);
await WritePemFileAsync(Path.Combine(fulcioDir, "root1.pem"), cert1, TestCancellationToken);
await WritePemFileAsync(Path.Combine(fulcioDir, "root2.pem"), cert2, TestCancellationToken);
var options = CreateOptions(fulcioPath: fulcioDir);
var store = CreateStore(options);
// Act
var roots = await store.GetFulcioRootsAsync();
var roots = await store.GetFulcioRootsAsync(TestCancellationToken);
// Assert
roots.Should().HaveCount(2);
@@ -109,14 +110,14 @@ public class FileSystemRootStoreTests : IDisposable
var certA = CreateTestCertificate("CN=Root A");
var certB = CreateTestCertificate("CN=Root B");
await WritePemFileAsync(Path.Combine(fulcioDir, "b.pem"), certB);
await WritePemFileAsync(Path.Combine(fulcioDir, "a.pem"), certA);
await WritePemFileAsync(Path.Combine(fulcioDir, "b.pem"), certB, TestCancellationToken);
await WritePemFileAsync(Path.Combine(fulcioDir, "a.pem"), certA, TestCancellationToken);
var options = CreateOptions(fulcioPath: fulcioDir);
var store = CreateStore(options);
// Act
var roots = await store.GetFulcioRootsAsync();
var roots = await store.GetFulcioRootsAsync(TestCancellationToken);
// Assert
roots.Should().HaveCount(2);
@@ -131,14 +132,14 @@ public class FileSystemRootStoreTests : IDisposable
// Arrange
var cert = CreateTestCertificate("CN=Cached Root");
var pemPath = Path.Combine(_testRootPath, "cached.pem");
await WritePemFileAsync(pemPath, cert);
await WritePemFileAsync(pemPath, cert, TestCancellationToken);
var options = CreateOptions(fulcioPath: pemPath);
var store = CreateStore(options);
// Act
var roots1 = await store.GetFulcioRootsAsync();
var roots2 = await store.GetFulcioRootsAsync();
var roots1 = await store.GetFulcioRootsAsync(TestCancellationToken);
var roots2 = await store.GetFulcioRootsAsync(TestCancellationToken);
// Assert - same collection instance (cached)
roots1.Should().HaveCount(1);
@@ -154,14 +155,14 @@ public class FileSystemRootStoreTests : IDisposable
// Arrange
var cert = CreateTestCertificate("CN=Imported Root");
var sourcePath = Path.Combine(_testRootPath, "import-source.pem");
await WritePemFileAsync(sourcePath, cert);
await WritePemFileAsync(sourcePath, cert, TestCancellationToken);
var options = CreateOptions();
options.Value.BaseRootPath = _testRootPath;
var store = CreateStore(options);
// Act
await store.ImportRootsAsync(sourcePath, RootType.Fulcio);
await store.ImportRootsAsync(sourcePath, RootType.Fulcio, TestCancellationToken);
// Assert
var targetDir = Path.Combine(_testRootPath, "fulcio");
@@ -179,7 +180,7 @@ public class FileSystemRootStoreTests : IDisposable
// Act & Assert
await Assert.ThrowsAsync<FileNotFoundException>(
() => store.ImportRootsAsync("/nonexistent/path.pem", RootType.Fulcio));
() => store.ImportRootsAsync("/nonexistent/path.pem", RootType.Fulcio, TestCancellationToken));
}
[Trait("Category", TestCategories.Unit)]
@@ -190,24 +191,24 @@ public class FileSystemRootStoreTests : IDisposable
var cert1 = CreateTestCertificate("CN=Initial Root");
var fulcioDir = Path.Combine(_testRootPath, "fulcio");
Directory.CreateDirectory(fulcioDir);
await WritePemFileAsync(Path.Combine(fulcioDir, "initial.pem"), cert1);
await WritePemFileAsync(Path.Combine(fulcioDir, "initial.pem"), cert1, TestCancellationToken);
var options = CreateOptions(fulcioPath: fulcioDir);
options.Value.BaseRootPath = _testRootPath;
var store = CreateStore(options);
// Load initial cache
var initialRoots = await store.GetFulcioRootsAsync();
var initialRoots = await store.GetFulcioRootsAsync(TestCancellationToken);
initialRoots.Should().HaveCount(1);
// Import a new certificate
var cert2 = CreateTestCertificate("CN=Imported Root");
var importPath = Path.Combine(_testRootPath, "import.pem");
await WritePemFileAsync(importPath, cert2);
await WritePemFileAsync(importPath, cert2, TestCancellationToken);
// Act
await store.ImportRootsAsync(importPath, RootType.Fulcio);
var updatedRoots = await store.GetFulcioRootsAsync();
await store.ImportRootsAsync(importPath, RootType.Fulcio, TestCancellationToken);
var updatedRoots = await store.GetFulcioRootsAsync(TestCancellationToken);
// Assert - cache invalidated and new cert loaded
updatedRoots.Should().HaveCount(2);
@@ -221,13 +222,13 @@ public class FileSystemRootStoreTests : IDisposable
var cert = CreateTestCertificate("CN=Listed Root");
var fulcioDir = Path.Combine(_testRootPath, "fulcio");
Directory.CreateDirectory(fulcioDir);
await WritePemFileAsync(Path.Combine(fulcioDir, "root.pem"), cert);
await WritePemFileAsync(Path.Combine(fulcioDir, "root.pem"), cert, TestCancellationToken);
var options = CreateOptions(fulcioPath: fulcioDir);
var store = CreateStore(options);
// Act
var roots = await store.ListRootsAsync(RootType.Fulcio);
var roots = await store.ListRootsAsync(RootType.Fulcio, TestCancellationToken);
// Assert
roots.Should().HaveCount(1);
@@ -244,20 +245,20 @@ public class FileSystemRootStoreTests : IDisposable
var cert = CreateTestCertificate("CN=Org Signing Key");
var orgDir = Path.Combine(_testRootPath, "org-signing");
Directory.CreateDirectory(orgDir);
await WritePemFileAsync(Path.Combine(orgDir, "org.pem"), cert);
await WritePemFileAsync(Path.Combine(orgDir, "org.pem"), cert, TestCancellationToken);
var options = CreateOptions(orgSigningPath: orgDir);
var store = CreateStore(options);
// First, verify the cert was loaded and get its thumbprint from listing
var orgKeys = await store.GetOrgSigningKeysAsync();
var orgKeys = await store.GetOrgSigningKeysAsync(TestCancellationToken);
orgKeys.Should().HaveCount(1);
// Get the thumbprint from the loaded certificate
var thumbprint = ComputeThumbprint(orgKeys[0]);
// Act
var found = await store.GetOrgKeyByIdAsync(thumbprint);
var found = await store.GetOrgKeyByIdAsync(thumbprint, TestCancellationToken);
// Assert
found.Should().NotBeNull();
@@ -272,13 +273,13 @@ public class FileSystemRootStoreTests : IDisposable
var cert = CreateTestCertificate("CN=Org Key");
var orgDir = Path.Combine(_testRootPath, "org-signing");
Directory.CreateDirectory(orgDir);
await WritePemFileAsync(Path.Combine(orgDir, "org.pem"), cert);
await WritePemFileAsync(Path.Combine(orgDir, "org.pem"), cert, TestCancellationToken);
var options = CreateOptions(orgSigningPath: orgDir);
var store = CreateStore(options);
// Act
var found = await store.GetOrgKeyByIdAsync("nonexistent-key-id");
var found = await store.GetOrgKeyByIdAsync("nonexistent-key-id", TestCancellationToken);
// Assert
found.Should().BeNull();
@@ -291,13 +292,13 @@ public class FileSystemRootStoreTests : IDisposable
// Arrange
var cert = CreateTestCertificate("CN=Rekor Key");
var rekorPath = Path.Combine(_testRootPath, "rekor.pem");
await WritePemFileAsync(rekorPath, cert);
await WritePemFileAsync(rekorPath, cert, TestCancellationToken);
var options = CreateOptions(rekorPath: rekorPath);
var store = CreateStore(options);
// Act
var keys = await store.GetRekorKeysAsync();
var keys = await store.GetRekorKeysAsync(TestCancellationToken);
// Assert
keys.Should().HaveCount(1);
@@ -314,13 +315,13 @@ public class FileSystemRootStoreTests : IDisposable
var cert3 = CreateTestCertificate("CN=Cert 3");
var pemPath = Path.Combine(_testRootPath, "multi.pem");
await WriteMultiplePemFileAsync(pemPath, [cert1, cert2, cert3]);
await WriteMultiplePemFileAsync(pemPath, [cert1, cert2, cert3], TestCancellationToken);
var options = CreateOptions(fulcioPath: pemPath);
var store = CreateStore(options);
// Act
var roots = await store.GetFulcioRootsAsync();
var roots = await store.GetFulcioRootsAsync(TestCancellationToken);
// Assert
roots.Should().HaveCount(3);
@@ -336,7 +337,7 @@ public class FileSystemRootStoreTests : IDisposable
Directory.CreateDirectory(fulcioKitDir);
var cert = CreateTestCertificate("CN=Offline Kit Root");
await WritePemFileAsync(Path.Combine(fulcioKitDir, "root.pem"), cert);
await WritePemFileAsync(Path.Combine(fulcioKitDir, "root.pem"), cert, TestCancellationToken);
var options = Options.Create(new OfflineRootStoreOptions
{
@@ -347,7 +348,7 @@ public class FileSystemRootStoreTests : IDisposable
var store = CreateStore(options);
// Act
var roots = await store.GetFulcioRootsAsync();
var roots = await store.GetFulcioRootsAsync(TestCancellationToken);
// Assert
roots.Should().HaveCount(1);
@@ -364,7 +365,7 @@ public class FileSystemRootStoreTests : IDisposable
Directory.CreateDirectory(fulcioKitDir);
var cert = CreateTestCertificate("CN=Offline Kit Root");
await WritePemFileAsync(Path.Combine(fulcioKitDir, "root.pem"), cert);
await WritePemFileAsync(Path.Combine(fulcioKitDir, "root.pem"), cert, TestCancellationToken);
var options = Options.Create(new OfflineRootStoreOptions
{
@@ -375,7 +376,7 @@ public class FileSystemRootStoreTests : IDisposable
var store = CreateStore(options);
// Act
var roots = await store.GetFulcioRootsAsync();
var roots = await store.GetFulcioRootsAsync(TestCancellationToken);
// Assert
roots.Should().BeEmpty();
@@ -423,17 +424,17 @@ public class FileSystemRootStoreTests : IDisposable
return request.CreateSelfSigned(notBefore, notAfter);
}
private static async Task WritePemFileAsync(string path, X509Certificate2 cert)
private static async Task WritePemFileAsync(string path, X509Certificate2 cert, CancellationToken cancellationToken)
{
var pem = new StringBuilder();
pem.AppendLine("-----BEGIN CERTIFICATE-----");
pem.AppendLine(Convert.ToBase64String(cert.RawData, Base64FormattingOptions.InsertLineBreaks));
pem.AppendLine("-----END CERTIFICATE-----");
await File.WriteAllTextAsync(path, pem.ToString());
await File.WriteAllTextAsync(path, pem.ToString(), cancellationToken);
}
private static async Task WriteMultiplePemFileAsync(string path, X509Certificate2[] certs)
private static async Task WriteMultiplePemFileAsync(string path, X509Certificate2[] certs, CancellationToken cancellationToken)
{
var pem = new StringBuilder();
foreach (var cert in certs)
@@ -444,7 +445,7 @@ public class FileSystemRootStoreTests : IDisposable
pem.AppendLine();
}
await File.WriteAllTextAsync(path, pem.ToString());
await File.WriteAllTextAsync(path, pem.ToString(), cancellationToken);
}
private static string ComputeThumbprint(X509Certificate2 cert)

View File

@@ -26,6 +26,7 @@ public class OfflineCertChainValidatorTests
private readonly Mock<ILogger<OfflineVerifier>> _loggerMock;
private readonly IMerkleTreeBuilder _merkleBuilder;
private readonly IOptions<OfflineVerificationConfig> _config;
private static CancellationToken TestCancellationToken => TestContext.Current.CancellationToken;
public OfflineCertChainValidatorTests()
{
@@ -51,7 +52,7 @@ public class OfflineCertChainValidatorTests
VerifyCertificateChain: true);
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options);
var result = await verifier.VerifyAttestationAsync(attestation, options, TestCancellationToken);
// Assert
result.CertificateChainValid.Should().BeTrue();
@@ -77,7 +78,7 @@ public class OfflineCertChainValidatorTests
VerifyCertificateChain: true);
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options);
var result = await verifier.VerifyAttestationAsync(attestation, options, TestCancellationToken);
// Assert
result.CertificateChainValid.Should().BeFalse();
@@ -100,7 +101,7 @@ public class OfflineCertChainValidatorTests
VerifyCertificateChain: true);
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options);
var result = await verifier.VerifyAttestationAsync(attestation, options, TestCancellationToken);
// Assert
result.CertificateChainValid.Should().BeFalse();
@@ -125,7 +126,7 @@ public class OfflineCertChainValidatorTests
VerifyCertificateChain: true);
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options);
var result = await verifier.VerifyAttestationAsync(attestation, options, TestCancellationToken);
// Assert
result.CertificateChainValid.Should().BeFalse();
@@ -150,7 +151,7 @@ public class OfflineCertChainValidatorTests
VerifyCertificateChain: true);
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options);
var result = await verifier.VerifyAttestationAsync(attestation, options, TestCancellationToken);
// Assert
result.CertificateChainValid.Should().BeFalse();
@@ -178,7 +179,7 @@ public class OfflineCertChainValidatorTests
VerifyCertificateChain: true);
// Act
var result = await verifier.VerifyBundleAsync(bundle, options);
var result = await verifier.VerifyBundleAsync(bundle, options, TestCancellationToken);
// Assert
result.CertificateChainValid.Should().BeTrue();
@@ -200,7 +201,7 @@ public class OfflineCertChainValidatorTests
VerifyCertificateChain: false); // Disabled
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options);
var result = await verifier.VerifyAttestationAsync(attestation, options, TestCancellationToken);
// Assert - When cert chain validation is disabled, it should not report cert-related issues
result.Issues.Should().NotContain(i => i.Code.Contains("CERT_CHAIN"));
@@ -224,7 +225,7 @@ public class OfflineCertChainValidatorTests
VerifyCertificateChain: true);
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options);
var result = await verifier.VerifyAttestationAsync(attestation, options, TestCancellationToken);
// Assert
result.CertificateChainValid.Should().BeFalse();
@@ -247,7 +248,7 @@ public class OfflineCertChainValidatorTests
VerifyCertificateChain: true);
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options);
var result = await verifier.VerifyAttestationAsync(attestation, options, TestCancellationToken);
// Assert
result.CertificateChainValid.Should().BeFalse();

View File

@@ -30,6 +30,7 @@ namespace StellaOps.Attestor.Offline.Tests;
public class OfflineVerifierTests
{
private static readonly DateTimeOffset FixedNow = new(2025, 1, 1, 0, 0, 0, TimeSpan.Zero);
private static CancellationToken TestCancellationToken => TestContext.Current.CancellationToken;
private readonly Mock<IOfflineRootStore> _rootStoreMock;
private readonly IMerkleTreeBuilder _merkleBuilder;
private readonly Mock<IOrgKeySigner> _orgSignerMock;
@@ -65,7 +66,7 @@ public class OfflineVerifierTests
VerifyOrgSignature: false);
// Act
var result = await verifier.VerifyBundleAsync(bundle, options);
var result = await verifier.VerifyBundleAsync(bundle, options, TestCancellationToken);
// Assert
result.Valid.Should().BeTrue();
@@ -99,7 +100,7 @@ public class OfflineVerifierTests
VerifyCertificateChain: false);
// Act
var result = await verifier.VerifyBundleAsync(tamperedBundle, options);
var result = await verifier.VerifyBundleAsync(tamperedBundle, options, TestCancellationToken);
// Assert
result.Valid.Should().BeFalse();
@@ -123,7 +124,7 @@ public class OfflineVerifierTests
RequireOrgSignature: true);
// Act
var result = await verifier.VerifyBundleAsync(bundle, options);
var result = await verifier.VerifyBundleAsync(bundle, options, TestCancellationToken);
// Assert
result.Valid.Should().BeFalse();
@@ -161,7 +162,7 @@ public class OfflineVerifierTests
VerifyOrgSignature: true);
// Act
var result = await verifier.VerifyBundleAsync(signedBundle, options);
var result = await verifier.VerifyBundleAsync(signedBundle, options, TestCancellationToken);
// Assert
result.Valid.Should().BeTrue();
@@ -183,7 +184,7 @@ public class OfflineVerifierTests
VerifyCertificateChain: false);
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options);
var result = await verifier.VerifyAttestationAsync(attestation, options, TestCancellationToken);
// Assert
result.Valid.Should().BeTrue();
@@ -214,7 +215,7 @@ public class OfflineVerifierTests
VerifyCertificateChain: false);
// Act
var result = await verifier.VerifyAttestationAsync(tamperedAttestation, options);
var result = await verifier.VerifyAttestationAsync(tamperedAttestation, options, TestCancellationToken);
// Assert
result.Valid.Should().BeFalse();
@@ -236,7 +237,7 @@ public class OfflineVerifierTests
VerifyCertificateChain: false);
// Act
var summaries = await verifier.GetVerificationSummariesAsync(bundle, options);
var summaries = await verifier.GetVerificationSummariesAsync(bundle, options, TestCancellationToken);
// Assert
summaries.Should().HaveCount(10);
@@ -276,7 +277,7 @@ public class OfflineVerifierTests
StrictMode: true);
// Act
var result = await verifier.VerifyBundleAsync(bundle, options);
var result = await verifier.VerifyBundleAsync(bundle, options, TestCancellationToken);
// Assert
result.Valid.Should().BeFalse();
@@ -296,7 +297,7 @@ public class OfflineVerifierTests
var verifier = CreateVerifier(config);
// Act
var result = await verifier.VerifyBundleAsync(bundle, options: null);
var result = await verifier.VerifyBundleAsync(bundle, options: null, cancellationToken: TestCancellationToken);
// Assert
result.Valid.Should().BeFalse();
@@ -316,7 +317,7 @@ public class OfflineVerifierTests
var verifier = CreateVerifier(config);
// Act
var result = await verifier.VerifyAttestationAsync(attestation, options: null);
var result = await verifier.VerifyAttestationAsync(attestation, options: null, cancellationToken: TestCancellationToken);
// Assert
result.Valid.Should().BeFalse();
@@ -331,7 +332,7 @@ public class OfflineVerifierTests
var tempPath = Path.Combine(Path.GetTempPath(), $"bundle-{Guid.NewGuid():N}.json");
try
{
await File.WriteAllBytesAsync(tempPath, new byte[2 * 1024 * 1024]);
await File.WriteAllBytesAsync(tempPath, new byte[2 * 1024 * 1024], TestCancellationToken);
var config = Options.Create(new OfflineVerificationConfig
{
@@ -347,7 +348,8 @@ public class OfflineVerifierTests
VerifyMerkleProof: false,
VerifySignatures: false,
VerifyCertificateChain: false,
VerifyOrgSignature: false));
VerifyOrgSignature: false),
TestCancellationToken);
// Assert
result.Valid.Should().BeFalse();
@@ -383,8 +385,8 @@ public class OfflineVerifierTests
VerifyCertificateChain: false);
// Act
var result1 = await verifier.VerifyBundleAsync(bundle1, options);
var result2 = await verifier.VerifyBundleAsync(bundle2, options);
var result1 = await verifier.VerifyBundleAsync(bundle1, options, TestCancellationToken);
var result2 = await verifier.VerifyBundleAsync(bundle2, options, TestCancellationToken);
// Assert - both should have the same merkle validation result
result1.MerkleProofValid.Should().Be(result2.MerkleProofValid);

View File

@@ -8,3 +8,5 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
| AUDIT-0059-M | DONE | Revalidated 2026-01-06. |
| AUDIT-0059-T | DONE | Revalidated 2026-01-06. |
| AUDIT-0059-A | DONE | Waived after revalidation 2026-01-06. |
| AUDIT-0210-T | DONE | Revalidated 2026-01-08 (xUnit1051 fixes). |
| AUDIT-0210-A | DONE | Applied fixes 2026-01-08 (xUnit1051 fixes). |