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:
master
2025-10-21 09:37:07 +03:00
parent d6cb41dd51
commit 48f3071e2a
298 changed files with 20490 additions and 5751 deletions

View File

@@ -1,7 +1,6 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Channels;
using StellaOps.Scanner.WebService.Domain;
@@ -58,7 +57,8 @@ public sealed class ScanProgressStream : IScanProgressPublisher, IScanProgressRe
public int NextSequence() => ++Sequence;
}
private static readonly IReadOnlyDictionary<string, object?> EmptyData = new ReadOnlyDictionary<string, object?>(new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase));
private static readonly IReadOnlyDictionary<string, object?> EmptyData =
new ReadOnlyDictionary<string, object?>(new SortedDictionary<string, object?>(StringComparer.OrdinalIgnoreCase));
private readonly ConcurrentDictionary<string, ProgressChannel> channels = new(StringComparer.OrdinalIgnoreCase);
private readonly TimeProvider timeProvider;
@@ -85,18 +85,14 @@ public sealed class ScanProgressStream : IScanProgressPublisher, IScanProgressRe
{
var sequence = channel.NextSequence();
var correlation = correlationId ?? $"{scanId.Value}:{sequence:D4}";
var payload = data is null || data.Count == 0
? EmptyData
: new ReadOnlyDictionary<string, object?>(new Dictionary<string, object?>(data, StringComparer.OrdinalIgnoreCase));
progressEvent = new ScanProgressEvent(
scanId,
sequence,
timeProvider.GetUtcNow(),
state,
message,
correlation,
payload);
progressEvent = new ScanProgressEvent(
scanId,
sequence,
timeProvider.GetUtcNow(),
state,
message,
correlation,
NormalizePayload(data));
channel.Append(progressEvent);
}
@@ -131,6 +127,24 @@ public sealed class ScanProgressStream : IScanProgressPublisher, IScanProgressRe
{
yield return progressEvent;
}
}
}
}
}
}
private static IReadOnlyDictionary<string, object?> NormalizePayload(IReadOnlyDictionary<string, object?>? data)
{
if (data is null || data.Count == 0)
{
return EmptyData;
}
var sorted = new SortedDictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
foreach (var pair in data)
{
sorted[pair.Key] = pair.Value;
}
return sorted.Count == 0
? EmptyData
: new ReadOnlyDictionary<string, object?>(sorted);
}
}