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
				
			
		
		
	
	
				
					
				
			
		
			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:
		| @@ -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); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user