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

@@ -15,14 +15,15 @@ namespace StellaOps.Scanner.Reachability.Tests.Witnesses;
/// </summary>
public sealed class SuppressionDsseSignerTests
{
private static CancellationToken TestCancellationToken => TestContext.Current.CancellationToken;
/// <summary>
/// Creates a deterministic Ed25519 key pair for testing.
/// </summary>
private static (byte[] privateKey, byte[] publicKey) CreateTestKeyPair()
private static (byte[] privateKey, byte[] publicKey) CreateTestKeyPair(byte startValue = 0x42)
{
// Use a fixed seed for deterministic tests
var generator = new Ed25519KeyPairGenerator();
generator.Init(new Ed25519KeyGenerationParameters(new SecureRandom(new FixedRandomGenerator())));
generator.Init(new Ed25519KeyGenerationParameters(new SecureRandom(new FixedRandomGenerator(startValue))));
var keyPair = generator.GenerateKeyPair();
var privateParams = (Ed25519PrivateKeyParameters)keyPair.Private;
@@ -89,7 +90,7 @@ public sealed class SuppressionDsseSignerTests
var signer = new SuppressionDsseSigner();
// Act
var result = signer.SignWitness(witness, key);
var result = signer.SignWitness(witness, key, TestCancellationToken);
// Assert
Assert.True(result.IsSuccess, result.Error);
@@ -110,14 +111,14 @@ public sealed class SuppressionDsseSignerTests
var signer = new SuppressionDsseSigner();
// Sign the witness
var signResult = signer.SignWitness(witness, signingKey);
var signResult = signer.SignWitness(witness, signingKey, TestCancellationToken);
Assert.True(signResult.IsSuccess, signResult.Error);
// Create public key for verification
var verifyKey = EnvelopeKey.CreateEd25519Verifier(publicKey);
// Act
var verifyResult = signer.VerifyWitness(signResult.Envelope!, verifyKey);
var verifyResult = signer.VerifyWitness(signResult.Envelope!, verifyKey, TestCancellationToken);
// Assert
Assert.True(verifyResult.IsSuccess, verifyResult.Error);
@@ -138,15 +139,15 @@ public sealed class SuppressionDsseSignerTests
var signer = new SuppressionDsseSigner();
// Sign with first key
var signResult = signer.SignWitness(witness, signingKey);
var signResult = signer.SignWitness(witness, signingKey, TestCancellationToken);
Assert.True(signResult.IsSuccess);
// Try to verify with different key
var (_, wrongPublicKey) = CreateTestKeyPair();
var (_, wrongPublicKey) = CreateTestKeyPair(0x99);
var wrongKey = EnvelopeKey.CreateEd25519Verifier(wrongPublicKey);
// Act
var verifyResult = signer.VerifyWitness(signResult.Envelope!, wrongKey);
var verifyResult = signer.VerifyWitness(signResult.Envelope!, wrongKey, TestCancellationToken);
// Assert
Assert.False(verifyResult.IsSuccess);
@@ -163,15 +164,16 @@ public sealed class SuppressionDsseSignerTests
var signer = new SuppressionDsseSigner();
// Create envelope with wrong payload type
var signature = DsseSignature.FromBytes(new byte[] { 0x1 }, "test-key");
var badEnvelope = new DsseEnvelope(
payloadType: "https://wrong.type/v1",
payload: "test"u8.ToArray(),
signatures: []);
signatures: [signature]);
var verifyKey = EnvelopeKey.CreateEd25519Verifier(publicKey);
// Act
var result = signer.VerifyWitness(badEnvelope, verifyKey);
var result = signer.VerifyWitness(badEnvelope, verifyKey, TestCancellationToken);
// Assert
Assert.False(result.IsSuccess);
@@ -192,13 +194,13 @@ public sealed class SuppressionDsseSignerTests
var signer = new SuppressionDsseSigner();
// Sign witness with wrong schema
var signResult = signer.SignWitness(witness, signingKey);
var signResult = signer.SignWitness(witness, signingKey, TestCancellationToken);
Assert.True(signResult.IsSuccess);
var verifyKey = EnvelopeKey.CreateEd25519Verifier(publicKey);
// Act
var verifyResult = signer.VerifyWitness(signResult.Envelope!, verifyKey);
var verifyResult = signer.VerifyWitness(signResult.Envelope!, verifyKey, TestCancellationToken);
// Assert
Assert.False(verifyResult.IsSuccess);
@@ -215,7 +217,7 @@ public sealed class SuppressionDsseSignerTests
var signer = new SuppressionDsseSigner();
// Act & Assert
Assert.Throws<ArgumentNullException>(() => signer.SignWitness(null!, key));
Assert.Throws<ArgumentNullException>(() => signer.SignWitness(null!, key, TestCancellationToken));
}
[Trait("Category", TestCategories.Unit)]
@@ -227,7 +229,7 @@ public sealed class SuppressionDsseSignerTests
var signer = new SuppressionDsseSigner();
// Act & Assert
Assert.Throws<ArgumentNullException>(() => signer.SignWitness(witness, null!));
Assert.Throws<ArgumentNullException>(() => signer.SignWitness(witness, null!, TestCancellationToken));
}
[Trait("Category", TestCategories.Unit)]
@@ -240,7 +242,7 @@ public sealed class SuppressionDsseSignerTests
var signer = new SuppressionDsseSigner();
// Act & Assert
Assert.Throws<ArgumentNullException>(() => signer.VerifyWitness(null!, key));
Assert.Throws<ArgumentNullException>(() => signer.VerifyWitness(null!, key, TestCancellationToken));
}
[Trait("Category", TestCategories.Unit)]
@@ -248,14 +250,15 @@ public sealed class SuppressionDsseSignerTests
public void VerifyWitness_WithNullKey_ThrowsArgumentNullException()
{
// Arrange
var signature = DsseSignature.FromBytes(new byte[] { 0x1 }, "test-key");
var envelope = new DsseEnvelope(
payloadType: SuppressionWitnessSchema.DssePayloadType,
payload: "test"u8.ToArray(),
signatures: []);
signatures: [signature]);
var signer = new SuppressionDsseSigner();
// Act & Assert
Assert.Throws<ArgumentNullException>(() => signer.VerifyWitness(envelope, null!));
Assert.Throws<ArgumentNullException>(() => signer.VerifyWitness(envelope, null!, TestCancellationToken));
}
[Trait("Category", TestCategories.Unit)]
@@ -270,8 +273,8 @@ public sealed class SuppressionDsseSignerTests
var signer = new SuppressionDsseSigner();
// Act
var signResult = signer.SignWitness(witness, signingKey);
var verifyResult = signer.VerifyWitness(signResult.Envelope!, verifyKey);
var signResult = signer.SignWitness(witness, signingKey, TestCancellationToken);
var verifyResult = signer.VerifyWitness(signResult.Envelope!, verifyKey, TestCancellationToken);
// Assert
Assert.True(signResult.IsSuccess);
@@ -285,7 +288,12 @@ public sealed class SuppressionDsseSignerTests
private sealed class FixedRandomGenerator : Org.BouncyCastle.Crypto.Prng.IRandomGenerator
{
private byte _value = 0x42;
private byte _value;
public FixedRandomGenerator(byte startValue)
{
_value = startValue;
}
public void AddSeedMaterial(byte[] seed) { }
public void AddSeedMaterial(ReadOnlySpan<byte> seed) { }

View File

@@ -17,6 +17,7 @@ public sealed class SuppressionWitnessBuilderTests
private readonly Mock<TimeProvider> _mockTimeProvider;
private readonly SuppressionWitnessBuilder _builder;
private static readonly DateTimeOffset FixedTime = new(2025, 1, 7, 12, 0, 0, TimeSpan.Zero);
private static CancellationToken TestCancellationToken => TestContext.Current.CancellationToken;
/// <summary>
/// Test implementation of ICryptoHash.
@@ -94,7 +95,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildUnreachableAsync(request);
var result = await _builder.BuildUnreachableAsync(request, TestCancellationToken);
// Assert
result.Should().NotBeNull();
@@ -131,7 +132,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildPatchedSymbolAsync(request);
var result = await _builder.BuildPatchedSymbolAsync(request, TestCancellationToken);
// Assert
result.Should().NotBeNull();
@@ -161,7 +162,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildFunctionAbsentAsync(request);
var result = await _builder.BuildFunctionAbsentAsync(request, TestCancellationToken);
// Assert
result.Should().NotBeNull();
@@ -197,7 +198,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildGateBlockedAsync(request);
var result = await _builder.BuildGateBlockedAsync(request, TestCancellationToken);
// Assert
result.Should().NotBeNull();
@@ -228,7 +229,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildFeatureFlagDisabledAsync(request);
var result = await _builder.BuildFeatureFlagDisabledAsync(request, TestCancellationToken);
// Assert
result.Should().NotBeNull();
@@ -260,7 +261,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildFromVexStatementAsync(request);
var result = await _builder.BuildFromVexStatementAsync(request, TestCancellationToken);
// Assert
result.Should().NotBeNull();
@@ -290,7 +291,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildVersionNotAffectedAsync(request);
var result = await _builder.BuildVersionNotAffectedAsync(request, TestCancellationToken);
// Assert
result.Should().NotBeNull();
@@ -321,7 +322,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildLinkerGarbageCollectedAsync(request);
var result = await _builder.BuildLinkerGarbageCollectedAsync(request, TestCancellationToken);
// Assert
result.Should().NotBeNull();
@@ -352,7 +353,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildUnreachableAsync(request);
var result = await _builder.BuildUnreachableAsync(request, TestCancellationToken);
// Assert
result.Confidence.Should().Be(1.0); // Clamped to max
@@ -378,8 +379,8 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result1 = await _builder.BuildUnreachableAsync(request);
var result2 = await _builder.BuildUnreachableAsync(request);
var result1 = await _builder.BuildUnreachableAsync(request, TestCancellationToken);
var result2 = await _builder.BuildUnreachableAsync(request, TestCancellationToken);
// Assert
result1.WitnessId.Should().Be(result2.WitnessId);
@@ -406,7 +407,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildUnreachableAsync(request);
var result = await _builder.BuildUnreachableAsync(request, TestCancellationToken);
// Assert
result.ObservedAt.Should().Be(FixedTime);
@@ -434,7 +435,7 @@ public sealed class SuppressionWitnessBuilderTests
};
// Act
var result = await _builder.BuildUnreachableAsync(request);
var result = await _builder.BuildUnreachableAsync(request, TestCancellationToken);
// Assert
result.ExpiresAt.Should().Be(expiresAt);

View File

@@ -28,6 +28,7 @@ namespace StellaOps.Scanner.Reachability.Tests.Witnesses;
public sealed class SuppressionWitnessIdPropertyTests
{
private static readonly DateTimeOffset FixedTime = new(2026, 1, 7, 12, 0, 0, TimeSpan.Zero);
private static CancellationToken TestCancellationToken => TestContext.Current.CancellationToken;
/// <summary>
/// Test implementation of ICryptoHash that uses real SHA256 for determinism verification.
@@ -96,8 +97,8 @@ public sealed class SuppressionWitnessIdPropertyTests
var builder = CreateBuilder();
var request = CreateUnreachabilityRequest(sbomDigest, componentPurl, vulnId);
var result1 = builder.BuildUnreachableAsync(request).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request).GetAwaiter().GetResult();
var result1 = builder.BuildUnreachableAsync(request, TestCancellationToken).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request, TestCancellationToken).GetAwaiter().GetResult();
return result1.WitnessId == result2.WitnessId;
}
@@ -119,8 +120,8 @@ public sealed class SuppressionWitnessIdPropertyTests
var request1 = CreateUnreachabilityRequest(sbomDigest1, componentPurl, vulnId);
var request2 = CreateUnreachabilityRequest(sbomDigest2, componentPurl, vulnId);
var result1 = builder.BuildUnreachableAsync(request1).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2).GetAwaiter().GetResult();
var result1 = builder.BuildUnreachableAsync(request1, TestCancellationToken).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2, TestCancellationToken).GetAwaiter().GetResult();
return result1.WitnessId != result2.WitnessId;
}
@@ -142,8 +143,8 @@ public sealed class SuppressionWitnessIdPropertyTests
var request1 = CreateUnreachabilityRequest(sbomDigest, componentPurl1, vulnId);
var request2 = CreateUnreachabilityRequest(sbomDigest, componentPurl2, vulnId);
var result1 = builder.BuildUnreachableAsync(request1).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2).GetAwaiter().GetResult();
var result1 = builder.BuildUnreachableAsync(request1, TestCancellationToken).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2, TestCancellationToken).GetAwaiter().GetResult();
return result1.WitnessId != result2.WitnessId;
}
@@ -165,8 +166,8 @@ public sealed class SuppressionWitnessIdPropertyTests
var request1 = CreateUnreachabilityRequest(sbomDigest, componentPurl, vulnId1);
var request2 = CreateUnreachabilityRequest(sbomDigest, componentPurl, vulnId2);
var result1 = builder.BuildUnreachableAsync(request1).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2).GetAwaiter().GetResult();
var result1 = builder.BuildUnreachableAsync(request1, TestCancellationToken).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2, TestCancellationToken).GetAwaiter().GetResult();
return result1.WitnessId != result2.WitnessId;
}
@@ -188,7 +189,7 @@ public sealed class SuppressionWitnessIdPropertyTests
var builder = CreateBuilder();
var request = CreateUnreachabilityRequest(sbomDigest, componentPurl, vulnId);
var result = builder.BuildUnreachableAsync(request).GetAwaiter().GetResult();
var result = builder.BuildUnreachableAsync(request, TestCancellationToken).GetAwaiter().GetResult();
return result.WitnessId.StartsWith("sup:sha256:");
}
@@ -206,7 +207,7 @@ public sealed class SuppressionWitnessIdPropertyTests
var builder = CreateBuilder();
var request = CreateUnreachabilityRequest(sbomDigest, componentPurl, vulnId);
var result = builder.BuildUnreachableAsync(request).GetAwaiter().GetResult();
var result = builder.BuildUnreachableAsync(request, TestCancellationToken).GetAwaiter().GetResult();
// Extract hex part after "sup:sha256:"
var hexPart = result.WitnessId["sup:sha256:".Length..];
@@ -248,8 +249,8 @@ public sealed class SuppressionWitnessIdPropertyTests
Confidence = 1.0
};
var unreachableResult = builder.BuildUnreachableAsync(unreachableRequest).GetAwaiter().GetResult();
var versionResult = builder.BuildVersionNotAffectedAsync(versionRequest).GetAwaiter().GetResult();
var unreachableResult = builder.BuildUnreachableAsync(unreachableRequest, TestCancellationToken).GetAwaiter().GetResult();
var versionResult = builder.BuildVersionNotAffectedAsync(versionRequest, TestCancellationToken).GetAwaiter().GetResult();
// Different suppression types should produce different witness IDs
return unreachableResult.WitnessId != versionResult.WitnessId;
@@ -282,8 +283,8 @@ public sealed class SuppressionWitnessIdPropertyTests
var request = CreateUnreachabilityRequest("sbom:sha256:abc", "pkg:npm/test@1.0.0", "CVE-2026-1234");
// Act
var result1 = await builder1.BuildUnreachableAsync(request);
var result2 = await builder2.BuildUnreachableAsync(request);
var result1 = await builder1.BuildUnreachableAsync(request, TestCancellationToken);
var result2 = await builder2.BuildUnreachableAsync(request, TestCancellationToken);
// Assert - different timestamps produce different witness IDs (content-addressed)
result1.WitnessId.Should().NotBe(result2.WitnessId);
@@ -307,8 +308,8 @@ public sealed class SuppressionWitnessIdPropertyTests
var request = CreateUnreachabilityRequest("sbom:sha256:test", "pkg:npm/lib@1.0.0", "CVE-2026-5555");
// Act
var result1 = await builder.BuildUnreachableAsync(request);
var result2 = await builder.BuildUnreachableAsync(request);
var result1 = await builder.BuildUnreachableAsync(request, TestCancellationToken);
var result2 = await builder.BuildUnreachableAsync(request, TestCancellationToken);
// Assert - same inputs with same timestamp = same ID
result1.WitnessId.Should().Be(result2.WitnessId);
@@ -339,8 +340,8 @@ public sealed class SuppressionWitnessIdPropertyTests
"sbom:sha256:abc", "pkg:npm/test@1.0.0", "CVE-2026-1234",
confidence: confidence2);
var result1 = builder.BuildUnreachableAsync(request1).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2).GetAwaiter().GetResult();
var result1 = builder.BuildUnreachableAsync(request1, TestCancellationToken).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2, TestCancellationToken).GetAwaiter().GetResult();
// Different confidence values produce different witness IDs
return result1.WitnessId != result2.WitnessId;
@@ -367,8 +368,8 @@ public sealed class SuppressionWitnessIdPropertyTests
"sbom:sha256:abc", "pkg:npm/test@1.0.0", "CVE-2026-1234",
confidence: confidence);
var result1 = builder.BuildUnreachableAsync(request1).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2).GetAwaiter().GetResult();
var result1 = builder.BuildUnreachableAsync(request1, TestCancellationToken).GetAwaiter().GetResult();
var result2 = builder.BuildUnreachableAsync(request2, TestCancellationToken).GetAwaiter().GetResult();
return result1.WitnessId == result2.WitnessId;
}
@@ -393,7 +394,7 @@ public sealed class SuppressionWitnessIdPropertyTests
$"pkg:npm/test@{i}.0.0",
$"CVE-2026-{i:D4}");
var result = await builder.BuildUnreachableAsync(request);
var result = await builder.BuildUnreachableAsync(request, TestCancellationToken);
witnessIds.Add(result.WitnessId);
}
@@ -418,8 +419,8 @@ public sealed class SuppressionWitnessIdPropertyTests
"CVE-2026-0001");
// Act
var result1 = await builder1.BuildUnreachableAsync(request);
var result2 = await builder2.BuildUnreachableAsync(request);
var result1 = await builder1.BuildUnreachableAsync(request, TestCancellationToken);
var result2 = await builder2.BuildUnreachableAsync(request, TestCancellationToken);
// Assert
result1.WitnessId.Should().Be(result2.WitnessId);
@@ -449,7 +450,7 @@ public sealed class SuppressionWitnessIdPropertyTests
UnreachableSymbol = "func",
AnalysisMethod = "static",
Confidence = 0.95
});
}, TestCancellationToken);
unreachable.WitnessId.Should().StartWith("sup:sha256:");
var patched = await builder.BuildPatchedSymbolAsync(new PatchedSymbolRequest
@@ -465,7 +466,7 @@ public sealed class SuppressionWitnessIdPropertyTests
SymbolDiff = "diff",
PatchRef = "debian/patches/fix.patch",
Confidence = 0.99
});
}, TestCancellationToken);
patched.WitnessId.Should().StartWith("sup:sha256:");
var functionAbsent = await builder.BuildFunctionAbsentAsync(new FunctionAbsentRequest
@@ -480,7 +481,7 @@ public sealed class SuppressionWitnessIdPropertyTests
BinaryDigest = "binary:sha256:123",
VerificationMethod = "symbol-table",
Confidence = 1.0
});
}, TestCancellationToken);
functionAbsent.WitnessId.Should().StartWith("sup:sha256:");
var versionNotAffected = await builder.BuildVersionNotAffectedAsync(new VersionRangeRequest
@@ -495,7 +496,7 @@ public sealed class SuppressionWitnessIdPropertyTests
ComparisonResult = "not_affected",
VersionScheme = "semver",
Confidence = 1.0
});
}, TestCancellationToken);
versionNotAffected.WitnessId.Should().StartWith("sup:sha256:");
// Verify all IDs are unique