feat: Implement CVSS receipt management client and models
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-07 01:14:28 +02:00
parent 53889d85e7
commit 69651212ec
30 changed files with 815 additions and 109 deletions

View File

@@ -0,0 +1,85 @@
using System;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using StellaOps.Cli.Configuration;
using StellaOps.Cli.Services;
using StellaOps.Cli.Services.Models;
using StellaOps.Cli.Tests.Testing;
using StellaOps.Policy.Scoring;
using StellaOps.Policy.Scoring.Engine;
using StellaOps.Policy.Scoring.Policies;
namespace StellaOps.Cli.Tests.Services;
public sealed class CvssClientTests
{
[Fact]
public async Task GetReceiptAsync_ParsesReceipt()
{
var sampleReceipt = CreateSampleReceipt();
var handler = new StubHttpMessageHandler((request, _) =>
{
Assert.Equal("/api/cvss/receipts/r1", request.RequestUri!.AbsolutePath);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(JsonSerializer.Serialize(sampleReceipt, new JsonSerializerOptions(JsonSerializerDefaults.Web))),
RequestMessage = request
};
return response;
});
var httpClient = new HttpClient(handler)
{
BaseAddress = new Uri("https://policy.example")
};
var options = new StellaOpsCliOptions { BackendUrl = "https://policy.example" };
var loggerFactory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.Debug));
var client = new CvssClient(httpClient, options, loggerFactory.CreateLogger<CvssClient>());
var result = await client.GetReceiptAsync("r1", CancellationToken.None);
Assert.NotNull(result);
Assert.Equal("r1", result!.ReceiptId);
Assert.Equal(sampleReceipt.VectorString, result.VectorString);
}
private static CvssScoreReceipt CreateSampleReceipt()
{
var engine = new CvssV4Engine();
var parsed = engine.ParseVector("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H");
var scores = engine.ComputeScores(parsed.BaseMetrics, parsed.ThreatMetrics, parsed.EnvironmentalMetrics);
return new CvssScoreReceipt
{
ReceiptId = "r1",
TenantId = "tenant-1",
VulnerabilityId = "CVE-2025-0001",
CreatedAt = DateTimeOffset.UtcNow,
CreatedBy = "cli",
ModifiedAt = null,
ModifiedBy = null,
BaseMetrics = parsed.BaseMetrics,
ThreatMetrics = parsed.ThreatMetrics,
EnvironmentalMetrics = parsed.EnvironmentalMetrics,
SupplementalMetrics = parsed.SupplementalMetrics,
Scores = scores,
VectorString = engine.BuildVectorString(parsed.BaseMetrics, parsed.ThreatMetrics, parsed.EnvironmentalMetrics, parsed.SupplementalMetrics),
Severity = engine.GetSeverity(scores.EffectiveScore),
PolicyRef = new CvssPolicyReference { PolicyId = "cvss-policy", Version = "1.0.0", Hash = "abc", ActivatedAt = DateTimeOffset.UtcNow },
InputHash = "deadbeef",
History = System.Collections.Immutable.ImmutableList<ReceiptHistoryEntry>.Empty,
Evidence = System.Collections.Immutable.ImmutableList<CvssEvidenceItem>.Empty,
AttestationRefs = System.Collections.Immutable.ImmutableList<string>.Empty,
ExportHash = null,
AmendsReceiptId = null,
SupersedesReceiptId = null,
SupersededReason = null,
IsActive = true
};
}
}