Initial commit (history squashed)
Some checks failed
Build Test Deploy / authority-container (push) Has been cancelled
Build Test Deploy / docs (push) Has been cancelled
Build Test Deploy / deploy (push) Has been cancelled
Build Test Deploy / build-test (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled

This commit is contained in:
2025-10-07 10:14:21 +03:00
commit b97fc7685a
1132 changed files with 117842 additions and 0 deletions

View File

@@ -0,0 +1,209 @@
using System.Collections.Generic;
using System.Linq;
using StellaOps.Feedser.Models;
using StellaOps.Feedser.Storage.Mongo.Documents;
namespace StellaOps.Feedser.Source.Ghsa.Internal;
internal static class GhsaMapper
{
private static readonly HashSet<string> SemVerEcosystems = new(StringComparer.OrdinalIgnoreCase)
{
"npm",
"maven",
"pip",
"rubygems",
"composer",
"nuget",
"go",
"cargo",
};
public static Advisory Map(GhsaRecordDto dto, DocumentRecord document, DateTimeOffset recordedAt)
{
ArgumentNullException.ThrowIfNull(dto);
ArgumentNullException.ThrowIfNull(document);
var fetchProvenance = new AdvisoryProvenance(
GhsaConnectorPlugin.SourceName,
"document",
document.Uri,
document.FetchedAt,
new[] { ProvenanceFieldMasks.Advisory });
var mapProvenance = new AdvisoryProvenance(
GhsaConnectorPlugin.SourceName,
"mapping",
dto.GhsaId,
recordedAt,
new[] { ProvenanceFieldMasks.Advisory });
var aliases = dto.Aliases
.Where(static alias => !string.IsNullOrWhiteSpace(alias))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
var references = dto.References
.Select(reference => CreateReference(reference, recordedAt))
.Where(static reference => reference is not null)
.Cast<AdvisoryReference>()
.ToList();
var affected = CreateAffectedPackages(dto, recordedAt);
var credits = CreateCredits(dto.Credits, recordedAt);
var severity = dto.Severity?.ToLowerInvariant();
var summary = dto.Summary ?? dto.Description;
return new Advisory(
advisoryKey: dto.GhsaId,
title: dto.Summary ?? dto.GhsaId,
summary: summary,
language: "en",
published: dto.PublishedAt,
modified: dto.UpdatedAt ?? dto.PublishedAt,
severity: severity,
exploitKnown: false,
aliases: aliases,
credits: credits,
references: references,
affectedPackages: affected,
cvssMetrics: Array.Empty<CvssMetric>(),
provenance: new[] { fetchProvenance, mapProvenance });
}
private static AdvisoryReference? CreateReference(GhsaReferenceDto reference, DateTimeOffset recordedAt)
{
if (string.IsNullOrWhiteSpace(reference.Url) || !Validation.LooksLikeHttpUrl(reference.Url))
{
return null;
}
var kind = reference.Type?.ToLowerInvariant();
return new AdvisoryReference(
reference.Url,
kind,
reference.Name,
summary: null,
provenance: new AdvisoryProvenance(
GhsaConnectorPlugin.SourceName,
"reference",
reference.Url,
recordedAt,
new[] { ProvenanceFieldMasks.References }));
}
private static IReadOnlyList<AffectedPackage> CreateAffectedPackages(GhsaRecordDto dto, DateTimeOffset recordedAt)
{
if (dto.Affected.Count == 0)
{
return Array.Empty<AffectedPackage>();
}
var packages = new List<AffectedPackage>(dto.Affected.Count);
foreach (var affected in dto.Affected)
{
var ecosystem = string.IsNullOrWhiteSpace(affected.Ecosystem) ? "unknown" : affected.Ecosystem.Trim();
var packageName = string.IsNullOrWhiteSpace(affected.PackageName) ? "unknown-package" : affected.PackageName.Trim();
var identifier = $"{ecosystem.ToLowerInvariant()}:{packageName}";
var provenance = new[]
{
new AdvisoryProvenance(
GhsaConnectorPlugin.SourceName,
"affected",
identifier,
recordedAt,
new[] { ProvenanceFieldMasks.AffectedPackages }),
};
var rangeKind = SemVerEcosystems.Contains(ecosystem) ? "semver" : "vendor";
var packageType = SemVerEcosystems.Contains(ecosystem) ? AffectedPackageTypes.SemVer : AffectedPackageTypes.Vendor;
var versionRanges = new List<AffectedVersionRange>();
if (!string.IsNullOrWhiteSpace(affected.VulnerableRange) || !string.IsNullOrWhiteSpace(affected.PatchedVersion))
{
var primitives = new RangePrimitives(null, null, null, new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["ecosystem"] = ecosystem,
["package"] = packageName,
});
versionRanges.Add(new AffectedVersionRange(
rangeKind,
introducedVersion: null,
fixedVersion: Validation.TrimToNull(affected.PatchedVersion),
lastAffectedVersion: null,
rangeExpression: Validation.TrimToNull(affected.VulnerableRange),
provenance: new AdvisoryProvenance(
GhsaConnectorPlugin.SourceName,
"affected-range",
identifier,
recordedAt,
new[] { ProvenanceFieldMasks.VersionRanges }),
primitives: primitives));
}
var statuses = new[]
{
new AffectedPackageStatus(
"affected",
new AdvisoryProvenance(
GhsaConnectorPlugin.SourceName,
"affected-status",
identifier,
recordedAt,
new[] { ProvenanceFieldMasks.PackageStatuses })),
};
packages.Add(new AffectedPackage(
packageType,
identifier,
platform: null,
versionRanges: versionRanges,
statuses: statuses,
provenance: provenance));
}
return packages;
}
private static IReadOnlyList<AdvisoryCredit> CreateCredits(IReadOnlyList<GhsaCreditDto> credits, DateTimeOffset recordedAt)
{
if (credits.Count == 0)
{
return Array.Empty<AdvisoryCredit>();
}
var results = new List<AdvisoryCredit>(credits.Count);
foreach (var credit in credits)
{
var displayName = Validation.TrimToNull(credit.Name) ?? Validation.TrimToNull(credit.Login);
if (displayName is null)
{
continue;
}
var contacts = new List<string>();
if (!string.IsNullOrWhiteSpace(credit.ProfileUrl) && Validation.LooksLikeHttpUrl(credit.ProfileUrl))
{
contacts.Add(credit.ProfileUrl.Trim());
}
else if (!string.IsNullOrWhiteSpace(credit.Login))
{
contacts.Add($"https://github.com/{credit.Login.Trim()}");
}
var provenance = new AdvisoryProvenance(
GhsaConnectorPlugin.SourceName,
"credit",
displayName,
recordedAt,
new[] { ProvenanceFieldMasks.Credits });
results.Add(new AdvisoryCredit(displayName, credit.Type, contacts, provenance));
}
return results.Count == 0 ? Array.Empty<AdvisoryCredit>() : results;
}
}