up
Some checks failed
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
Build Test Deploy / authority-container (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled

This commit is contained in:
2025-10-12 20:37:18 +03:00
parent b97fc7685a
commit 607e72e2a1
306 changed files with 21409 additions and 4449 deletions

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using StellaOps.Feedser.Models;
using StellaOps.Feedser.Normalization.SemVer;
using StellaOps.Feedser.Storage.Mongo.Documents;
namespace StellaOps.Feedser.Source.Ghsa.Internal;
@@ -120,29 +121,9 @@ internal static class GhsaMapper
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 (ranges, normalizedVersions) = SemVerEcosystems.Contains(ecosystem)
? CreateSemVerVersionArtifacts(affected, identifier, ecosystem, packageName, recordedAt)
: CreateVendorVersionArtifacts(affected, rangeKind, identifier, ecosystem, packageName, recordedAt);
var statuses = new[]
{
@@ -160,9 +141,10 @@ internal static class GhsaMapper
packageType,
identifier,
platform: null,
versionRanges: versionRanges,
versionRanges: ranges,
statuses: statuses,
provenance: provenance));
provenance: provenance,
normalizedVersions: normalizedVersions));
}
return packages;
@@ -206,4 +188,142 @@ internal static class GhsaMapper
return results.Count == 0 ? Array.Empty<AdvisoryCredit>() : results;
}
private static (IReadOnlyList<AffectedVersionRange> Ranges, IReadOnlyList<NormalizedVersionRule> Normalized) CreateSemVerVersionArtifacts(
GhsaAffectedDto affected,
string identifier,
string ecosystem,
string packageName,
DateTimeOffset recordedAt)
{
var note = BuildNormalizedNote(identifier);
var results = SemVerRangeRuleBuilder.Build(affected.VulnerableRange, affected.PatchedVersion, note);
if (results.Count > 0)
{
var ranges = new List<AffectedVersionRange>(results.Count);
var normalized = new List<NormalizedVersionRule>(results.Count);
foreach (var result in results)
{
var primitive = result.Primitive;
var rangeExpression = ResolveRangeExpression(result.Expression, primitive.ConstraintExpression, affected.VulnerableRange);
ranges.Add(new AffectedVersionRange(
rangeKind: "semver",
introducedVersion: Validation.TrimToNull(primitive.Introduced),
fixedVersion: Validation.TrimToNull(primitive.Fixed),
lastAffectedVersion: Validation.TrimToNull(primitive.LastAffected),
rangeExpression: rangeExpression,
provenance: CreateRangeProvenance(identifier, recordedAt),
primitives: new RangePrimitives(
SemVer: primitive,
Nevra: null,
Evr: null,
VendorExtensions: CreateVendorExtensions(ecosystem, packageName))));
normalized.Add(result.NormalizedRule);
}
return (ranges.ToArray(), normalized.ToArray());
}
var fallbackRange = CreateFallbackRange("semver", affected, identifier, ecosystem, packageName, recordedAt);
if (fallbackRange is null)
{
return (Array.Empty<AffectedVersionRange>(), Array.Empty<NormalizedVersionRule>());
}
var fallbackRule = fallbackRange.ToNormalizedVersionRule(note);
var normalizedFallback = fallbackRule is null
? Array.Empty<NormalizedVersionRule>()
: new[] { fallbackRule };
return (new[] { fallbackRange }, normalizedFallback);
}
private static (IReadOnlyList<AffectedVersionRange> Ranges, IReadOnlyList<NormalizedVersionRule> Normalized) CreateVendorVersionArtifacts(
GhsaAffectedDto affected,
string rangeKind,
string identifier,
string ecosystem,
string packageName,
DateTimeOffset recordedAt)
{
var range = CreateFallbackRange(rangeKind, affected, identifier, ecosystem, packageName, recordedAt);
if (range is null)
{
return (Array.Empty<AffectedVersionRange>(), Array.Empty<NormalizedVersionRule>());
}
return (new[] { range }, Array.Empty<NormalizedVersionRule>());
}
private static AffectedVersionRange? CreateFallbackRange(
string rangeKind,
GhsaAffectedDto affected,
string identifier,
string ecosystem,
string packageName,
DateTimeOffset recordedAt)
{
var fixedVersion = Validation.TrimToNull(affected.PatchedVersion);
var rangeExpression = Validation.TrimToNull(affected.VulnerableRange);
if (fixedVersion is null && rangeExpression is null)
{
return null;
}
return new AffectedVersionRange(
rangeKind,
introducedVersion: null,
fixedVersion: fixedVersion,
lastAffectedVersion: null,
rangeExpression: rangeExpression,
provenance: CreateRangeProvenance(identifier, recordedAt),
primitives: new RangePrimitives(
SemVer: null,
Nevra: null,
Evr: null,
VendorExtensions: CreateVendorExtensions(ecosystem, packageName)));
}
private static AdvisoryProvenance CreateRangeProvenance(string identifier, DateTimeOffset recordedAt)
=> new(
GhsaConnectorPlugin.SourceName,
"affected-range",
identifier,
recordedAt,
new[] { ProvenanceFieldMasks.VersionRanges });
private static IReadOnlyDictionary<string, string> CreateVendorExtensions(string ecosystem, string packageName)
=> new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["ecosystem"] = ecosystem,
["package"] = packageName,
};
private static string? BuildNormalizedNote(string identifier)
{
var trimmed = Validation.TrimToNull(identifier);
return trimmed is null ? null : $"ghsa:{trimmed}";
}
private static string? ResolveRangeExpression(string? parsedExpression, string? constraintExpression, string? fallbackExpression)
{
var parsed = Validation.TrimToNull(parsedExpression);
if (parsed is not null)
{
return parsed;
}
var constraint = Validation.TrimToNull(constraintExpression);
if (constraint is not null)
{
return constraint;
}
return Validation.TrimToNull(fallbackExpression);
}
}