Skip to content

Commit 3ac3c98

Browse files
Merge branch 'main' into improve-ssvc-yaml-display
2 parents 4a8b41e + 2ff2906 commit 3ac3c98

78 files changed

Lines changed: 2628 additions & 427 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

aboutcode/federated/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ def large_size_configs(cls):
10281028
"mlflow": 16,
10291029
"pub": 16,
10301030
"rpm": 16,
1031-
# Small Ecosystem all use the defaul
1031+
# Small Ecosystem all use the default
10321032
"default": 1,
10331033
}
10341034
return [
@@ -1069,7 +1069,7 @@ def medium_size_configs(cls):
10691069
"mlflow": 8,
10701070
"pub": 8,
10711071
"rpm": 8,
1072-
# Small Ecosystem all use the defaul
1072+
# Small Ecosystem all use the default
10731073
"default": 1,
10741074
}
10751075
return [
@@ -1110,7 +1110,7 @@ def small_size_configs(cls):
11101110
"mlflow": 4,
11111111
"pub": 4,
11121112
"rpm": 4,
1113-
# Small Ecosystem all use the defaul
1113+
# Small Ecosystem all use the default
11141114
"default": 1,
11151115
}
11161116
return [
@@ -1181,7 +1181,7 @@ def cluster_preset():
11811181
DataCluster(
11821182
data_kind="security_advisories",
11831183
description="VulnerableCode security advisories for each package version.",
1184-
datafile_path_template="{/namespace}/{name}/{version}/advisories.json",
1184+
datafile_path_template="{/namespace}/{name}/{version}/advisories.yml",
11851185
purl_type_configs=[PurlTypeConfig.default_config()],
11861186
data_schema_url="",
11871187
documentation_url="",

aboutcode/federated/tests/test_data/all-presets/foo/aboutcode-federated-config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ data_clusters:
933933
data_license: CC-BY-4.0
934934
data_maintainers: []
935935
- data_kind: security_advisories
936-
datafile_path_template: '{/namespace}/{name}/{version}/advisories.json'
936+
datafile_path_template: '{/namespace}/{name}/{version}/advisories.yml'
937937
purl_type_configs:
938938
- purl_type: default
939939
number_of_repos: 1

docs/source/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"https://nvd.nist.gov/products/cpe",
4141
"https://ftp.suse.com/pub/projects/security/yaml/suse-cvss-scores.yaml",
4242
"http://ftp.suse.com/pub/projects/security/yaml/",
43+
r"https://nixos\.wiki/", # NixOS wiki blocks CI bots with 403
4344
]
4445

4546
# Add any Sphinx extension module names here, as strings. They can be

vulnerabilities/api_v2.py

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
from vulnerabilities.models import VulnerabilitySeverity
4242
from vulnerabilities.models import Weakness
4343
from vulnerabilities.throttling import PermissionBasedUserRateThrottle
44+
from vulnerabilities.utils import group_advisories_by_content
4445

4546

4647
class CharInFilter(filters.BaseInFilter, filters.CharFilter):
@@ -361,19 +362,39 @@ def get_affected_by_vulnerabilities(self, package):
361362

362363
latest_advisories = AdvisoryV2.objects.latest_for_avids(avids)
363364
advisory_by_avid = {adv.avid: adv for adv in latest_advisories}
365+
impact_by_avid = {}
364366

365-
result = {}
366-
367+
advisories = []
367368
for impact in impacts:
368369
avid = impact.advisory.avid
369370
advisory = advisory_by_avid.get(avid)
370371
if not advisory:
371372
continue
372-
fixed_by_packages = [pkg.purl for pkg in impact.fixed_by_packages.all()]
373-
result[advisory.avid] = {
374-
"advisory_id": advisory.avid,
375-
"fixed_by_packages": fixed_by_packages,
376-
}
373+
advisories.append(advisory)
374+
impact_by_avid[avid] = impact
375+
376+
grouped_advisories = group_advisories_by_content(advisories=advisories)
377+
378+
advs = []
379+
380+
for hash in grouped_advisories:
381+
advs.append(grouped_advisories[hash])
382+
383+
result = []
384+
385+
for advisory in advs:
386+
primary_advisory = advisory["primary"]
387+
avid = primary_advisory.avid
388+
impact = impact_by_avid.get(avid)
389+
if not impact:
390+
continue
391+
result.append(
392+
{
393+
"advisory_id": primary_advisory.avid,
394+
"fixed_by_packages": [pkg.purl for pkg in impact.fixed_by_packages.all()],
395+
"duplicate_advisory_ids": [adv.avid for adv in advisory["secondary"]],
396+
}
397+
)
377398

378399
return result
379400

@@ -384,7 +405,25 @@ def get_fixing_vulnerabilities(self, package):
384405

385406
latest_advisories = AdvisoryV2.objects.latest_for_avids(avids)
386407

387-
return [adv.avid for adv in latest_advisories]
408+
grouped_advisories = group_advisories_by_content(advisories=latest_advisories)
409+
410+
advs = []
411+
412+
for hash in grouped_advisories:
413+
advs.append(grouped_advisories[hash])
414+
415+
result = []
416+
417+
for advisory in advs:
418+
primary_advisory = advisory["primary"]
419+
result.append(
420+
{
421+
"advisory_id": primary_advisory.avid,
422+
"duplicate_advisory_ids": [adv.avid for adv in advisory["secondary"]],
423+
}
424+
)
425+
426+
return result
388427

389428
def get_next_non_vulnerable_version(self, package):
390429
if next_non_vulnerable := package.get_non_vulnerable_versions()[0]:
@@ -1078,14 +1117,14 @@ def list(self, request, *args, **kwargs):
10781117
return self.get_paginated_response(
10791118
{
10801119
"packages": serializer.data,
1081-
"advisories": advisory_data,
1120+
"advisories_by_id": advisory_data,
10821121
}
10831122
)
10841123

10851124
return Response(
10861125
{
10871126
"packages": serializer.data,
1088-
"advisories": advisory_data,
1127+
"advisories_by_id": advisory_data,
10891128
}
10901129
)
10911130

@@ -1160,7 +1199,7 @@ def bulk_lookup(self, request):
11601199
return Response(
11611200
{
11621201
"packages": package_data,
1163-
"advisories": advisory_data,
1202+
"advisories_by_id": advisory_data,
11641203
}
11651204
)
11661205

@@ -1254,7 +1293,7 @@ def bulk_search(self, request):
12541293
return Response(
12551294
{
12561295
"packages": package_data,
1257-
"advisories": advisory_data,
1296+
"advisories_by_id": advisory_data,
12581297
}
12591298
)
12601299

@@ -1308,7 +1347,7 @@ def bulk_search(self, request):
13081347
return Response(
13091348
{
13101349
"packages": package_data,
1311-
"advisories": advisory_data,
1350+
"advisories_by_id": advisory_data,
13121351
}
13131352
)
13141353

vulnerabilities/importers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
)
5656
from vulnerabilities.pipelines.v2_importers import epss_importer_v2
5757
from vulnerabilities.pipelines.v2_importers import fireeye_importer_v2
58+
from vulnerabilities.pipelines.v2_importers import gentoo_importer as gentoo_importer_v2
5859
from vulnerabilities.pipelines.v2_importers import github_osv_importer as github_osv_importer_v2
5960
from vulnerabilities.pipelines.v2_importers import gitlab_importer as gitlab_importer_v2
6061
from vulnerabilities.pipelines.v2_importers import istio_importer as istio_importer_v2
@@ -108,6 +109,7 @@
108109
project_kb_msr2019_importer_v2.ProjectKBMSR2019Pipeline,
109110
ruby_importer_v2.RubyImporterPipeline,
110111
epss_importer_v2.EPSSImporterPipeline,
112+
gentoo_importer_v2.GentooImporterPipeline,
111113
nginx_importer_v2.NginxImporterPipeline,
112114
debian_importer_v2.DebianImporterPipeline,
113115
mattermost_importer_v2.MattermostImporterPipeline,

vulnerabilities/importers/fireeye.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def matcher_url(ref) -> str:
112112
"""
113113
Returns URL of the reference markup from reference url in Markdown format
114114
"""
115-
markup_regex = "\[([^\[]+)]\(\s*(http[s]?://.+)\s*\)"
115+
markup_regex = r"\[([^\[]+)]\(\s*(http[s]?://.+)\s*\)"
116116
matched_markup = re.findall(markup_regex, ref)
117117
if matched_markup:
118118
return matched_markup[0][1]

vulnerabilities/importers/gentoo.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
9-
10-
9+
import logging
1110
import re
1211
import xml.etree.ElementTree as ET
1312
from pathlib import Path
@@ -17,12 +16,15 @@
1716
from univers.version_constraint import VersionConstraint
1817
from univers.version_range import EbuildVersionRange
1918
from univers.versions import GentooVersion
19+
from univers.versions import InvalidVersion
2020

2121
from vulnerabilities.importer import AdvisoryData
2222
from vulnerabilities.importer import AffectedPackage
2323
from vulnerabilities.importer import Importer
2424
from vulnerabilities.importer import Reference
2525

26+
logger = logging.getLogger(__name__)
27+
2628

2729
class GentooImporter(Importer):
2830
repo_url = "git+https://anongit.gentoo.org/git/data/glsa.git"
@@ -104,14 +106,20 @@ def affected_and_safe_purls(affected_elem):
104106
safe_versions, affected_versions = GentooImporter.get_safe_and_affected_versions(pkg)
105107

106108
for version in safe_versions:
107-
constraints.append(
108-
VersionConstraint(version=GentooVersion(version), comparator="=").invert()
109-
)
109+
try:
110+
constraints.append(
111+
VersionConstraint(version=GentooVersion(version), comparator="=").invert()
112+
)
113+
except InvalidVersion as e:
114+
logger.error(f"Invalid safe_version {version} - error: {e}")
110115

111116
for version in affected_versions:
112-
constraints.append(
113-
VersionConstraint(version=GentooVersion(version), comparator="=")
114-
)
117+
try:
118+
constraints.append(
119+
VersionConstraint(version=GentooVersion(version), comparator="=")
120+
)
121+
except InvalidVersion as e:
122+
logger.error(f"Invalid affected_version {version} - error: {e}")
115123

116124
if not constraints:
117125
continue

vulnerabilities/improvers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
enhance_with_metasploit as enhance_with_metasploit_v2,
3232
)
3333
from vulnerabilities.pipelines.v2_improvers import flag_ghost_packages as flag_ghost_packages_v2
34+
from vulnerabilities.pipelines.v2_improvers import relate_severities
3435
from vulnerabilities.pipelines.v2_improvers import unfurl_version_range as unfurl_version_range_v2
3536
from vulnerabilities.utils import create_registry
3637

@@ -72,5 +73,6 @@
7273
unfurl_version_range_v2.UnfurlVersionRangePipeline,
7374
compute_advisory_todo.ComputeToDo,
7475
collect_ssvc_trees.CollectSSVCPipeline,
76+
relate_severities.RelateSeveritiesPipeline,
7577
]
7678
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 4.2.25 on 2026-02-10 12:46
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("vulnerabilities", "0112_alter_advisoryseverity_scoring_system_and_more"),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name="advisoryv2",
15+
name="precedence",
16+
field=models.IntegerField(
17+
blank=True,
18+
help_text="Precedence indicates the priority of advisory from different datasources. It is determined based on the reliability of the datasource and how close it is to the source.",
19+
null=True,
20+
),
21+
),
22+
]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 5.2.11 on 2026-02-17 13:27
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("vulnerabilities", "0113_advisoryv2_precedence"),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name="advisoryv2",
15+
name="related_advisory_severities",
16+
field=models.ManyToManyField(
17+
help_text="Related advisories that are used to calculate the severity of this advisory.",
18+
related_name="related_to_advisory_severities",
19+
to="vulnerabilities.advisoryv2",
20+
),
21+
),
22+
]

0 commit comments

Comments
 (0)