Add tests and implement StubBearer authentication for Signer endpoints
- Created SignerEndpointsTests to validate the SignDsse and VerifyReferrers endpoints. - Implemented StubBearerAuthenticationDefaults and StubBearerAuthenticationHandler for token-based authentication. - Developed ConcelierExporterClient for managing Trivy DB settings and export operations. - Added TrivyDbSettingsPageComponent for UI interactions with Trivy DB settings, including form handling and export triggering. - Implemented styles and HTML structure for Trivy DB settings page. - Created NotifySmokeCheck tool for validating Redis event streams and Notify deliveries.
This commit is contained in:
		@@ -1,6 +1,8 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Security.Cryptography;
 | 
			
		||||
using Microsoft.Extensions.Caching.Memory;
 | 
			
		||||
using Microsoft.Extensions.Logging.Abstractions;
 | 
			
		||||
using StellaOps.Concelier.Connector.StellaOpsMirror.Security;
 | 
			
		||||
using StellaOps.Cryptography;
 | 
			
		||||
@@ -18,7 +20,7 @@ public sealed class MirrorSignatureVerifierTests
 | 
			
		||||
        provider.UpsertSigningKey(key);
 | 
			
		||||
 | 
			
		||||
        var registry = new CryptoProviderRegistry(new[] { provider });
 | 
			
		||||
        var verifier = new MirrorSignatureVerifier(registry, NullLogger<MirrorSignatureVerifier>.Instance);
 | 
			
		||||
        var verifier = new MirrorSignatureVerifier(registry, NullLogger<MirrorSignatureVerifier>.Instance, new MemoryCache(new MemoryCacheOptions()));
 | 
			
		||||
 | 
			
		||||
        var payloadText = System.Text.Json.JsonSerializer.Serialize(new { advisories = Array.Empty<string>() });
 | 
			
		||||
        var payload = payloadText.ToUtf8Bytes();
 | 
			
		||||
@@ -35,13 +37,13 @@ public sealed class MirrorSignatureVerifierTests
 | 
			
		||||
        provider.UpsertSigningKey(key);
 | 
			
		||||
 | 
			
		||||
        var registry = new CryptoProviderRegistry(new[] { provider });
 | 
			
		||||
        var verifier = new MirrorSignatureVerifier(registry, NullLogger<MirrorSignatureVerifier>.Instance);
 | 
			
		||||
        var verifier = new MirrorSignatureVerifier(registry, NullLogger<MirrorSignatureVerifier>.Instance, new MemoryCache(new MemoryCacheOptions()));
 | 
			
		||||
 | 
			
		||||
        var payloadText = System.Text.Json.JsonSerializer.Serialize(new { advisories = Array.Empty<string>() });
 | 
			
		||||
        var payload = payloadText.ToUtf8Bytes();
 | 
			
		||||
        var (signature, _) = await CreateDetachedJwsAsync(provider, key.Reference.KeyId, payload);
 | 
			
		||||
 | 
			
		||||
        var tampered = signature.Replace('a', 'b', StringComparison.Ordinal);
 | 
			
		||||
        var tampered = signature.Replace('a', 'b');
 | 
			
		||||
 | 
			
		||||
        await Assert.ThrowsAsync<InvalidOperationException>(() => verifier.VerifyAsync(payload, tampered, CancellationToken.None));
 | 
			
		||||
    }
 | 
			
		||||
@@ -54,7 +56,7 @@ public sealed class MirrorSignatureVerifierTests
 | 
			
		||||
        provider.UpsertSigningKey(key);
 | 
			
		||||
 | 
			
		||||
        var registry = new CryptoProviderRegistry(new[] { provider });
 | 
			
		||||
        var verifier = new MirrorSignatureVerifier(registry, NullLogger<MirrorSignatureVerifier>.Instance);
 | 
			
		||||
        var verifier = new MirrorSignatureVerifier(registry, NullLogger<MirrorSignatureVerifier>.Instance, new MemoryCache(new MemoryCacheOptions()));
 | 
			
		||||
 | 
			
		||||
        var payloadText = System.Text.Json.JsonSerializer.Serialize(new { advisories = Array.Empty<string>() });
 | 
			
		||||
        var payload = payloadText.ToUtf8Bytes();
 | 
			
		||||
@@ -65,6 +67,7 @@ public sealed class MirrorSignatureVerifierTests
 | 
			
		||||
            signature,
 | 
			
		||||
            expectedKeyId: "unexpected-key",
 | 
			
		||||
            expectedProvider: null,
 | 
			
		||||
            fallbackPublicKeyPath: null,
 | 
			
		||||
            cancellationToken: CancellationToken.None));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -76,7 +79,7 @@ public sealed class MirrorSignatureVerifierTests
 | 
			
		||||
        provider.UpsertSigningKey(key);
 | 
			
		||||
 | 
			
		||||
        var registry = new CryptoProviderRegistry(new[] { provider });
 | 
			
		||||
        var verifier = new MirrorSignatureVerifier(registry, NullLogger<MirrorSignatureVerifier>.Instance);
 | 
			
		||||
        var verifier = new MirrorSignatureVerifier(registry, NullLogger<MirrorSignatureVerifier>.Instance, new MemoryCache(new MemoryCacheOptions()));
 | 
			
		||||
 | 
			
		||||
        var payloadText = System.Text.Json.JsonSerializer.Serialize(new { advisories = Array.Empty<string>() });
 | 
			
		||||
        var payload = payloadText.ToUtf8Bytes();
 | 
			
		||||
@@ -89,9 +92,42 @@ public sealed class MirrorSignatureVerifierTests
 | 
			
		||||
            signature,
 | 
			
		||||
            expectedKeyId: key.Reference.KeyId,
 | 
			
		||||
            expectedProvider: provider.Name,
 | 
			
		||||
            fallbackPublicKeyPath: null,
 | 
			
		||||
            cancellationToken: CancellationToken.None));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Fact]
 | 
			
		||||
    public async Task VerifyAsync_UsesCachedPublicKeyWhenFileRemoved()
 | 
			
		||||
    {
 | 
			
		||||
        var provider = new DefaultCryptoProvider();
 | 
			
		||||
        var signingKey = CreateSigningKey("mirror-key");
 | 
			
		||||
        provider.UpsertSigningKey(signingKey);
 | 
			
		||||
        var registry = new CryptoProviderRegistry(new[] { provider });
 | 
			
		||||
        var memoryCache = new MemoryCache(new MemoryCacheOptions());
 | 
			
		||||
        var verifier = new MirrorSignatureVerifier(registry, NullLogger<MirrorSignatureVerifier>.Instance, memoryCache);
 | 
			
		||||
 | 
			
		||||
        var payload = "{\"advisories\":[]}";
 | 
			
		||||
        var (signature, _) = await CreateDetachedJwsAsync(provider, signingKey.Reference.KeyId, payload.ToUtf8Bytes());
 | 
			
		||||
        provider.RemoveSigningKey(signingKey.Reference.KeyId);
 | 
			
		||||
        var pemPath = WritePublicKeyPem(signingKey);
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            await verifier.VerifyAsync(payload.ToUtf8Bytes(), signature, expectedKeyId: signingKey.Reference.KeyId, expectedProvider: "default", fallbackPublicKeyPath: pemPath, cancellationToken: CancellationToken.None);
 | 
			
		||||
 | 
			
		||||
            File.Delete(pemPath);
 | 
			
		||||
 | 
			
		||||
            await verifier.VerifyAsync(payload.ToUtf8Bytes(), signature, expectedKeyId: signingKey.Reference.KeyId, expectedProvider: "default", fallbackPublicKeyPath: pemPath, cancellationToken: CancellationToken.None);
 | 
			
		||||
        }
 | 
			
		||||
        finally
 | 
			
		||||
        {
 | 
			
		||||
            if (File.Exists(pemPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(pemPath);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static CryptoSigningKey CreateSigningKey(string keyId)
 | 
			
		||||
    {
 | 
			
		||||
        using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
 | 
			
		||||
@@ -99,6 +135,16 @@ public sealed class MirrorSignatureVerifierTests
 | 
			
		||||
        return new CryptoSigningKey(new CryptoKeyReference(keyId), SignatureAlgorithms.Es256, in parameters, DateTimeOffset.UtcNow);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static string WritePublicKeyPem(CryptoSigningKey signingKey)
 | 
			
		||||
    {
 | 
			
		||||
        using var ecdsa = ECDsa.Create(signingKey.PublicParameters);
 | 
			
		||||
        var info = ecdsa.ExportSubjectPublicKeyInfo();
 | 
			
		||||
        var pem = PemEncoding.Write("PUBLIC KEY", info);
 | 
			
		||||
        var path = Path.Combine(Path.GetTempPath(), $"stellaops-mirror-{Guid.NewGuid():N}.pem");
 | 
			
		||||
        File.WriteAllText(path, pem);
 | 
			
		||||
        return path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static async Task<(string Signature, DateTimeOffset SignedAt)> CreateDetachedJwsAsync(
 | 
			
		||||
        DefaultCryptoProvider provider,
 | 
			
		||||
        string keyId,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user