Add support for ГОСТ Р 34.10 digital signatures
- Implemented the GostKeyValue class for handling public key parameters in ГОСТ Р 34.10 digital signatures. - Created the GostSignedXml class to manage XML signatures using ГОСТ 34.10, including methods for computing and checking signatures. - Developed the GostSignedXmlImpl class to encapsulate the signature computation logic and public key retrieval. - Added specific key value classes for ГОСТ Р 34.10-2001, ГОСТ Р 34.10-2012/256, and ГОСТ Р 34.10-2012/512 to support different signature algorithms. - Ensured compatibility with existing XML signature standards while integrating ГОСТ cryptography.
This commit is contained in:
@@ -522,6 +522,71 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AdvisoryChunksEndpoint_EmitsRequestAndCacheMetrics()
|
||||
{
|
||||
await SeedObservationDocumentsAsync(BuildSampleObservationDocuments());
|
||||
|
||||
using var client = _factory.CreateClient();
|
||||
|
||||
var metrics = await CaptureMetricsAsync(
|
||||
AdvisoryAiMetrics.MeterName,
|
||||
new[] { "advisory_ai_chunk_requests_total", "advisory_ai_chunk_cache_hits_total" },
|
||||
async () =>
|
||||
{
|
||||
const string url = "/advisories/CVE-2025-0001/chunks?tenant=tenant-a";
|
||||
var first = await client.GetAsync(url);
|
||||
first.EnsureSuccessStatusCode();
|
||||
|
||||
var second = await client.GetAsync(url);
|
||||
second.EnsureSuccessStatusCode();
|
||||
});
|
||||
|
||||
Assert.True(metrics.TryGetValue("advisory_ai_chunk_requests_total", out var requests));
|
||||
Assert.NotNull(requests);
|
||||
Assert.Equal(2, requests!.Count);
|
||||
|
||||
Assert.Contains(requests!, measurement =>
|
||||
string.Equals(GetTagValue(measurement, "cache"), "miss", StringComparison.Ordinal));
|
||||
|
||||
Assert.Contains(requests!, measurement =>
|
||||
string.Equals(GetTagValue(measurement, "cache"), "hit", StringComparison.Ordinal));
|
||||
|
||||
Assert.True(metrics.TryGetValue("advisory_ai_chunk_cache_hits_total", out var cacheHitMeasurements));
|
||||
var cacheHit = Assert.Single(cacheHitMeasurements!);
|
||||
Assert.Equal(1, cacheHit.Value);
|
||||
Assert.Equal("hit", GetTagValue(cacheHit, "result"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AdvisoryChunksEndpoint_EmitsGuardrailMetrics()
|
||||
{
|
||||
var raw = BsonDocument.Parse("{\"details\":\"tiny\"}");
|
||||
var document = CreateChunkObservationDocument(
|
||||
"tenant-a:chunk:1",
|
||||
"tenant-a",
|
||||
new DateTime(2025, 2, 1, 0, 0, 0, DateTimeKind.Utc),
|
||||
"CVE-2025-GUARD",
|
||||
raw);
|
||||
|
||||
await SeedObservationDocumentsAsync(new[] { document });
|
||||
|
||||
using var client = _factory.CreateClient();
|
||||
|
||||
var guardrailMetrics = await CaptureMetricsAsync(
|
||||
AdvisoryAiMetrics.MeterName,
|
||||
"advisory_ai_guardrail_blocks_total",
|
||||
async () =>
|
||||
{
|
||||
var response = await client.GetAsync("/advisories/CVE-2025-GUARD/chunks?tenant=tenant-a");
|
||||
response.EnsureSuccessStatusCode();
|
||||
});
|
||||
|
||||
var measurement = Assert.Single(guardrailMetrics);
|
||||
Assert.True(measurement.Value >= 1);
|
||||
Assert.Equal("below_minimum_length", GetTagValue(measurement, "reason"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AdvisoryIngestEndpoint_EmitsMetricsWithExpectedTags()
|
||||
{
|
||||
@@ -2069,13 +2134,28 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
|
||||
private static async Task<IReadOnlyList<MetricMeasurement>> CaptureMetricsAsync(string meterName, string instrumentName, Func<Task> action)
|
||||
{
|
||||
var measurements = new List<MetricMeasurement>();
|
||||
var map = await CaptureMetricsAsync(meterName, new[] { instrumentName }, action).ConfigureAwait(false);
|
||||
return map.TryGetValue(instrumentName, out var measurements)
|
||||
? measurements
|
||||
: Array.Empty<MetricMeasurement>();
|
||||
}
|
||||
|
||||
private static async Task<Dictionary<string, IReadOnlyList<MetricMeasurement>>> CaptureMetricsAsync(
|
||||
string meterName,
|
||||
IReadOnlyCollection<string> instrumentNames,
|
||||
Func<Task> action)
|
||||
{
|
||||
var measurementMap = instrumentNames.ToDictionary(
|
||||
name => name,
|
||||
_ => new List<MetricMeasurement>(),
|
||||
StringComparer.Ordinal);
|
||||
var instrumentSet = new HashSet<string>(instrumentNames, StringComparer.Ordinal);
|
||||
var listener = new MeterListener();
|
||||
|
||||
listener.InstrumentPublished += (instrument, currentListener) =>
|
||||
{
|
||||
if (string.Equals(instrument.Meter.Name, meterName, StringComparison.Ordinal) &&
|
||||
string.Equals(instrument.Name, instrumentName, StringComparison.Ordinal))
|
||||
instrumentSet.Contains(instrument.Name))
|
||||
{
|
||||
currentListener.EnableMeasurementEvents(instrument);
|
||||
}
|
||||
@@ -2083,13 +2163,18 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
|
||||
listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>
|
||||
{
|
||||
if (!measurementMap.TryGetValue(instrument.Name, out var list))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tagDictionary = new Dictionary<string, object?>(StringComparer.Ordinal);
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
tagDictionary[tag.Key] = tag.Value;
|
||||
}
|
||||
|
||||
measurements.Add(new MetricMeasurement(instrument.Name, measurement, tagDictionary));
|
||||
list.Add(new MetricMeasurement(instrument.Name, measurement, tagDictionary));
|
||||
});
|
||||
|
||||
listener.Start();
|
||||
@@ -2102,7 +2187,9 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
listener.Dispose();
|
||||
}
|
||||
|
||||
return measurements;
|
||||
return measurementMap.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => (IReadOnlyList<MetricMeasurement>)kvp.Value);
|
||||
}
|
||||
|
||||
private static string? GetTagValue(MetricMeasurement measurement, string tag)
|
||||
|
||||
Reference in New Issue
Block a user