@@ -250,42 +250,27 @@ function upstream_projects()
250
250
return UPSTREAM_PROJECTS[] = relevant_info
251
251
end
252
252
253
- # A computed dictionary that maps a (vendor, product) tuple to a known upstream project name
254
- const UPSTREAM_PROJECTS_BY_VENDOR_PRODUCT = Ref {Dict{Tuple{String,String}, String}} ()
255
- function upstream_projects_by_vendor_product ()
256
- isassigned (UPSTREAM_PROJECTS_BY_VENDOR_PRODUCT) && return UPSTREAM_PROJECTS_BY_VENDOR_PRODUCT[]
257
- d = Dict {Tuple{String,String}, String} ()
258
- for (project, deets) in upstream_projects ()
259
- for cpe in get (deets, " cpes" , [])
260
- v, p = split (cpe, " :" , limit= 2 )
261
- d[(lowercase (v),lowercase (p))] = project
253
+ # A computed dictionary that maps a (vendor, product) tuple to known upstream project names
254
+ const UPSTREAM_PROJECTS_BY_VENDOR_PRODUCT = Ref {Dict{Tuple{String,String}, Vector{String}}} ()
255
+ function upstream_projects_by_vendor_product (vendor, product)
256
+ if ! isassigned (UPSTREAM_PROJECTS_BY_VENDOR_PRODUCT)
257
+ d = Dict {Tuple{String,String}, Vector{String}} ()
258
+ for (project, deets) in upstream_projects ()
259
+ for cpe in get (deets, " cpes" , [])
260
+ v, p = split (cpe, " :" , limit= 2 )
261
+ union! (get! (Vector{String}, d, (lowercase (v),lowercase (p))), (project,))
262
+ end
262
263
end
264
+ UPSTREAM_PROJECTS_BY_VENDOR_PRODUCT[] = d
263
265
end
264
- UPSTREAM_PROJECTS_BY_VENDOR_PRODUCT[] = d
266
+ return get ( UPSTREAM_PROJECTS_BY_VENDOR_PRODUCT[], ( lowercase (vendor), lowercase (product)), String[])
265
267
end
268
+ upstream_projects_by_cpe (vendorproduct) = upstream_projects_by_vendor_product (split (vendorproduct, " :" , limit= 2 )... )
266
269
267
270
function packages_with_project (proj)
268
271
return [pkgname for (pkgname,versioninfo) in package_components () if any (v-> haskey (v,proj), values (versioninfo))]
269
272
end
270
273
271
-
272
-
273
- function upstream_versions_used_by_cpe (cpe)
274
- # First find the projects that match the CPE:
275
- matched_projects = [k for (k,v) in upstream_projects () if cpe in get (v, " cpes" , [])]
276
- # Then the _upstream_ versions of that project that are used by JLLs
277
- upstream_components = package_components ()
278
- versions = []
279
- for (_, pkgversions) in upstream_components
280
- for (_, components) in pkgversions
281
- for (k, v) in components
282
- k in matched_projects && push! (versions, v)
283
- end
284
- end
285
- end
286
- return unique (versions)
287
- end
288
-
289
274
function package_project_version_map (pkg, proj)
290
275
return Dict (v => components[proj] for (v, components) in package_components ()[pkg])
291
276
end
@@ -348,31 +333,40 @@ function convert_versions(pkg_project_map, vulnerable_range)
348
333
versions
349
334
end
350
335
336
+ """
337
+ affected_julia_packages(description, vendorproductversions)
338
+
339
+ Given some advisory's description an an array of 3-tuples (vendor, product, versionrange)
340
+ for which the vulnerability applies, return the vector of the corresponding Julia `PackageVulnerability`s.
341
+ """
351
342
function affected_julia_packages (description, vendorproductversions)
352
343
pkgs = DefaultDict {String, Any} (()-> DefaultDict {String, Any} (()-> OrderedDict {String, Any} ()))
353
- # There are three reasons why this might return a ["*"] range
344
+ # There are four reasons why this might return a ["*"] range
354
345
# 1. That's the correct answer
355
346
# 2. It's pessimistically returned because we failed to parse the versions reported in the advisory
356
347
# 3. It's pessimistically returned because we failed to match a mentioned Julia package to a product
348
+ # 4. The upstream component version is unknown — itself a "*" — at the latest Julia package version
357
349
julia_like_pkgs_mentioned = union ((m. captures[1 ] for m in eachmatch (r" \b (\w +)\. jl\b " , description)),
358
350
(m. captures[1 ]* " _jll" for m in eachmatch (r" \b (\w +)_jll\b " , description)))
359
351
jlpkgs_mentioned = filter (registry_has_package, julia_like_pkgs_mentioned)
360
352
found_match = false
361
353
advisory_type = nothing
362
354
for (vendor, product, version) in unique (vendorproductversions)
363
355
# First check for a known **NON-JULIA-PACKAGE** CPE:
364
- if haskey (upstream_projects_by_vendor_product (), (lowercase (vendor), lowercase (product)))
365
- matched_project = upstream_projects_by_vendor_product ()[(lowercase (vendor), lowercase (product))]
366
- found_match = true
356
+ upstream_projects = upstream_projects_by_vendor_product (vendor, product)
357
+ if ! isempty (upstream_projects)
367
358
# We have an upstream component! Compute the remapped version range if we can.
368
- matched_pkgs = packages_with_project (matched_project)
369
- r = tryparse (VersionRange, version)
370
- for pkg in matched_pkgs
371
- pkgs[pkg][" $vendor :$product " ][version] = isnothing (r) ?
372
- [VersionRange {VersionNumber} (" *" )] : convert_versions (package_project_version_map (pkg, matched_project), r)
359
+ found_match = true
360
+ for matched_project in upstream_projects
361
+ matched_pkgs = packages_with_project (matched_project)
362
+ r = tryparse (VersionRange, version)
363
+ for pkg in matched_pkgs
364
+ pkgs[pkg][" $vendor :$product " ][version] = isnothing (r) ?
365
+ [VersionRange {VersionNumber} (" *" )] : convert_versions (package_project_version_map (pkg, matched_project), r)
366
+ end
367
+ isnothing (advisory_type) || @assert (advisory_type == " upstream" , " advisory directly lists $pkg , but it also finds upstream components" )
368
+ advisory_type = " upstream"
373
369
end
374
- isnothing (advisory_type) || @assert (advisory_type == " upstream" , " advisory directly lists $pkg , but it also finds upstream components" )
375
- advisory_type = " upstream"
376
370
else
377
371
if (contains (lowercase (vendor), " julia" ) || endswith (product, " .jl" )) && registry_has_package (chopsuffix (product, " .jl" ))
378
372
# A vendor or package _looks_ really julia-ish and is in the registry
0 commit comments