feat: Add CVSS receipt management endpoints and related functionality
- Introduced new API endpoints for creating, retrieving, amending, and listing CVSS receipts. - Updated IPolicyEngineClient interface to include methods for CVSS receipt operations. - Implemented PolicyEngineClient to handle CVSS receipt requests. - Enhanced Program.cs to map new CVSS receipt routes with appropriate authorization. - Added necessary models and contracts for CVSS receipt requests and responses. - Integrated Postgres document store for managing CVSS receipts and related data. - Updated database schema with new migrations for source documents and payload storage. - Refactored existing components to support new CVSS functionality.
This commit is contained in:
@@ -1,118 +1,118 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Connector.CertCc.Internal;
|
||||
using StellaOps.Concelier.Storage.Mongo.Documents;
|
||||
using StellaOps.Concelier.Storage.Mongo.Dtos;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.CertCc.Tests.Internal;
|
||||
|
||||
public sealed class CertCcMapperTests
|
||||
{
|
||||
private static readonly DateTimeOffset PublishedAt = DateTimeOffset.Parse("2025-10-03T11:35:31Z", CultureInfo.InvariantCulture);
|
||||
|
||||
[Fact]
|
||||
public void Map_ProducesCanonicalAdvisoryWithVendorPrimitives()
|
||||
{
|
||||
const string vendorStatement =
|
||||
"The issue is confirmed, and here is the patch list\n\n" +
|
||||
"V3912/V3910/V2962/V1000B\t4.4.3.6/4.4.5.1\n" +
|
||||
"V2927/V2865/V2866\t4.5.1\n" +
|
||||
"V2765/V2766/V2763/V2135\t4.5.1";
|
||||
|
||||
var vendor = new CertCcVendorDto(
|
||||
"DrayTek Corporation",
|
||||
ContactDate: PublishedAt.AddDays(-10),
|
||||
StatementDate: PublishedAt.AddDays(-5),
|
||||
Updated: PublishedAt,
|
||||
Statement: vendorStatement,
|
||||
Addendum: null,
|
||||
References: new[] { "https://www.draytek.com/support/resources?type=version" });
|
||||
|
||||
var vendorStatus = new CertCcVendorStatusDto(
|
||||
Vendor: "DrayTek Corporation",
|
||||
CveId: "CVE-2025-10547",
|
||||
Status: "Affected",
|
||||
Statement: null,
|
||||
References: Array.Empty<string>(),
|
||||
DateAdded: PublishedAt,
|
||||
DateUpdated: PublishedAt);
|
||||
|
||||
var vulnerability = new CertCcVulnerabilityDto(
|
||||
CveId: "CVE-2025-10547",
|
||||
Description: null,
|
||||
DateAdded: PublishedAt,
|
||||
DateUpdated: PublishedAt);
|
||||
|
||||
var metadata = new CertCcNoteMetadata(
|
||||
VuId: "VU#294418",
|
||||
IdNumber: "294418",
|
||||
Title: "Vigor routers running DrayOS RCE via EasyVPN",
|
||||
Overview: "Overview",
|
||||
Summary: "Summary",
|
||||
Published: PublishedAt,
|
||||
Updated: PublishedAt.AddMinutes(5),
|
||||
Created: PublishedAt,
|
||||
Revision: 2,
|
||||
CveIds: new[] { "CVE-2025-10547" },
|
||||
PublicUrls: new[]
|
||||
{
|
||||
"https://www.draytek.com/about/security-advisory/use-of-uninitialized-variable-vulnerabilities/",
|
||||
"https://www.draytek.com/support/resources?type=version"
|
||||
},
|
||||
PrimaryUrl: "https://www.kb.cert.org/vuls/id/294418/");
|
||||
|
||||
var dto = new CertCcNoteDto(
|
||||
metadata,
|
||||
Vendors: new[] { vendor },
|
||||
VendorStatuses: new[] { vendorStatus },
|
||||
Vulnerabilities: new[] { vulnerability });
|
||||
|
||||
var document = new DocumentRecord(
|
||||
Guid.NewGuid(),
|
||||
"cert-cc",
|
||||
"https://www.kb.cert.org/vuls/id/294418/",
|
||||
PublishedAt,
|
||||
Sha256: new string('0', 64),
|
||||
Status: "pending-map",
|
||||
ContentType: "application/json",
|
||||
Headers: null,
|
||||
Metadata: null,
|
||||
Etag: null,
|
||||
LastModified: PublishedAt,
|
||||
GridFsId: null);
|
||||
|
||||
var dtoRecord = new DtoRecord(
|
||||
Id: Guid.NewGuid(),
|
||||
DocumentId: document.Id,
|
||||
SourceName: "cert-cc",
|
||||
SchemaVersion: "certcc.vince.note.v1",
|
||||
Payload: new BsonDocument(),
|
||||
ValidatedAt: PublishedAt.AddMinutes(1));
|
||||
|
||||
var advisory = CertCcMapper.Map(dto, document, dtoRecord, "cert-cc");
|
||||
|
||||
Assert.Equal("certcc/vu-294418", advisory.AdvisoryKey);
|
||||
Assert.Contains("VU#294418", advisory.Aliases);
|
||||
Assert.Contains("CVE-2025-10547", advisory.Aliases);
|
||||
Assert.Equal("en", advisory.Language);
|
||||
Assert.Equal(PublishedAt, advisory.Published);
|
||||
|
||||
Assert.Contains(advisory.References, reference => reference.Url.Contains("/vuls/id/294418", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var affected = Assert.Single(advisory.AffectedPackages);
|
||||
Assert.Equal("vendor", affected.Type);
|
||||
Assert.Equal("DrayTek Corporation", affected.Identifier);
|
||||
Assert.Contains(affected.Statuses, status => status.Status == AffectedPackageStatusCatalog.Affected);
|
||||
|
||||
var range = Assert.Single(affected.VersionRanges);
|
||||
Assert.NotNull(range.Primitives);
|
||||
Assert.NotNull(range.Primitives!.VendorExtensions);
|
||||
Assert.Contains(range.Primitives.VendorExtensions!, kvp => kvp.Key == "certcc.vendor.patches");
|
||||
|
||||
Assert.NotEmpty(affected.NormalizedVersions);
|
||||
Assert.Contains(affected.NormalizedVersions, rule => rule.Scheme == "certcc.vendor" && rule.Value == "4.5.1");
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Connector.CertCc.Internal;
|
||||
using StellaOps.Concelier.Storage.Mongo.Documents;
|
||||
using StellaOps.Concelier.Storage.Mongo.Dtos;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.CertCc.Tests.Internal;
|
||||
|
||||
public sealed class CertCcMapperTests
|
||||
{
|
||||
private static readonly DateTimeOffset PublishedAt = DateTimeOffset.Parse("2025-10-03T11:35:31Z", CultureInfo.InvariantCulture);
|
||||
|
||||
[Fact]
|
||||
public void Map_ProducesCanonicalAdvisoryWithVendorPrimitives()
|
||||
{
|
||||
const string vendorStatement =
|
||||
"The issue is confirmed, and here is the patch list\n\n" +
|
||||
"V3912/V3910/V2962/V1000B\t4.4.3.6/4.4.5.1\n" +
|
||||
"V2927/V2865/V2866\t4.5.1\n" +
|
||||
"V2765/V2766/V2763/V2135\t4.5.1";
|
||||
|
||||
var vendor = new CertCcVendorDto(
|
||||
"DrayTek Corporation",
|
||||
ContactDate: PublishedAt.AddDays(-10),
|
||||
StatementDate: PublishedAt.AddDays(-5),
|
||||
Updated: PublishedAt,
|
||||
Statement: vendorStatement,
|
||||
Addendum: null,
|
||||
References: new[] { "https://www.draytek.com/support/resources?type=version" });
|
||||
|
||||
var vendorStatus = new CertCcVendorStatusDto(
|
||||
Vendor: "DrayTek Corporation",
|
||||
CveId: "CVE-2025-10547",
|
||||
Status: "Affected",
|
||||
Statement: null,
|
||||
References: Array.Empty<string>(),
|
||||
DateAdded: PublishedAt,
|
||||
DateUpdated: PublishedAt);
|
||||
|
||||
var vulnerability = new CertCcVulnerabilityDto(
|
||||
CveId: "CVE-2025-10547",
|
||||
Description: null,
|
||||
DateAdded: PublishedAt,
|
||||
DateUpdated: PublishedAt);
|
||||
|
||||
var metadata = new CertCcNoteMetadata(
|
||||
VuId: "VU#294418",
|
||||
IdNumber: "294418",
|
||||
Title: "Vigor routers running DrayOS RCE via EasyVPN",
|
||||
Overview: "Overview",
|
||||
Summary: "Summary",
|
||||
Published: PublishedAt,
|
||||
Updated: PublishedAt.AddMinutes(5),
|
||||
Created: PublishedAt,
|
||||
Revision: 2,
|
||||
CveIds: new[] { "CVE-2025-10547" },
|
||||
PublicUrls: new[]
|
||||
{
|
||||
"https://www.draytek.com/about/security-advisory/use-of-uninitialized-variable-vulnerabilities/",
|
||||
"https://www.draytek.com/support/resources?type=version"
|
||||
},
|
||||
PrimaryUrl: "https://www.kb.cert.org/vuls/id/294418/");
|
||||
|
||||
var dto = new CertCcNoteDto(
|
||||
metadata,
|
||||
Vendors: new[] { vendor },
|
||||
VendorStatuses: new[] { vendorStatus },
|
||||
Vulnerabilities: new[] { vulnerability });
|
||||
|
||||
var document = new DocumentRecord(
|
||||
Guid.NewGuid(),
|
||||
"cert-cc",
|
||||
"https://www.kb.cert.org/vuls/id/294418/",
|
||||
PublishedAt,
|
||||
Sha256: new string('0', 64),
|
||||
Status: "pending-map",
|
||||
ContentType: "application/json",
|
||||
Headers: null,
|
||||
Metadata: null,
|
||||
Etag: null,
|
||||
LastModified: PublishedAt,
|
||||
PayloadId: null);
|
||||
|
||||
var dtoRecord = new DtoRecord(
|
||||
Id: Guid.NewGuid(),
|
||||
DocumentId: document.Id,
|
||||
SourceName: "cert-cc",
|
||||
SchemaVersion: "certcc.vince.note.v1",
|
||||
Payload: new BsonDocument(),
|
||||
ValidatedAt: PublishedAt.AddMinutes(1));
|
||||
|
||||
var advisory = CertCcMapper.Map(dto, document, dtoRecord, "cert-cc");
|
||||
|
||||
Assert.Equal("certcc/vu-294418", advisory.AdvisoryKey);
|
||||
Assert.Contains("VU#294418", advisory.Aliases);
|
||||
Assert.Contains("CVE-2025-10547", advisory.Aliases);
|
||||
Assert.Equal("en", advisory.Language);
|
||||
Assert.Equal(PublishedAt, advisory.Published);
|
||||
|
||||
Assert.Contains(advisory.References, reference => reference.Url.Contains("/vuls/id/294418", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var affected = Assert.Single(advisory.AffectedPackages);
|
||||
Assert.Equal("vendor", affected.Type);
|
||||
Assert.Equal("DrayTek Corporation", affected.Identifier);
|
||||
Assert.Contains(affected.Statuses, status => status.Status == AffectedPackageStatusCatalog.Affected);
|
||||
|
||||
var range = Assert.Single(affected.VersionRanges);
|
||||
Assert.NotNull(range.Primitives);
|
||||
Assert.NotNull(range.Primitives!.VendorExtensions);
|
||||
Assert.Contains(range.Primitives.VendorExtensions!, kvp => kvp.Key == "certcc.vendor.patches");
|
||||
|
||||
Assert.NotEmpty(affected.NormalizedVersions);
|
||||
Assert.Contains(affected.NormalizedVersions, rule => rule.Scheme == "certcc.vendor" && rule.Value == "4.5.1");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user