77# See https://aboutcode.org for more information about nexB OSS projects.
88#
99
10- from typing import Iterable
1110from typing import NamedTuple
11+ from urllib .parse import urljoin
1212
1313import requests
1414from bs4 import BeautifulSoup
1515from packageurl import PackageURL
16+ from univers .version_constraint import VersionConstraint
17+ from univers .version_constraint import validate_comparators
1618from univers .version_range import NginxVersionRange
1719from univers .versions import InvalidVersion
1820
1921from vulnerabilities .importer import AdvisoryData
2022from vulnerabilities .importer import AffectedPackageV2
23+ from vulnerabilities .importer import PatchData
2124from vulnerabilities .importer import ReferenceV2
2225from vulnerabilities .importer import VulnerabilitySeverity
2326from vulnerabilities .importer import logger
24- from vulnerabilities .pipelines import VulnerableCodeBaseImporterPipeline
27+ from vulnerabilities .pipelines import VulnerableCodeBaseImporterPipelineV2
2528from vulnerabilities .severity_systems import GENERIC
2629
2730
28- class NginxImporterPipeline (VulnerableCodeBaseImporterPipeline ):
31+ class NginxImporterPipeline (VulnerableCodeBaseImporterPipelineV2 ):
2932 """Collect Nginx security advisories."""
3033
3134 pipeline_id = "nginx_importer_v2"
@@ -49,7 +52,7 @@ def fetch(self):
4952 def advisories_count (self ):
5053 return self .advisory_data .count ("<li><p>" )
5154
52- def collect_advisories (self ) -> Iterable [ AdvisoryData ] :
55+ def collect_advisories (self ):
5356 """
5457 Yield AdvisoryData from nginx security advisories HTML
5558 web page.
@@ -66,6 +69,7 @@ class NginxAdvisory(NamedTuple):
6669 aliases : list
6770 summary : str
6871 severities : list
72+ patches : list
6973 not_vulnerable : str
7074 vulnerable : str
7175 references : list
@@ -78,11 +82,9 @@ def to_advisory_data(nginx_adv: NginxAdvisory) -> AdvisoryData:
7882 """
7983 Return AdvisoryData from an NginxAdvisory tuple.
8084 """
81- package_name = "nginx"
82- package_type = "nginx"
8385 qualifiers = {}
8486
85- purl = PackageURL (type = package_type , name = package_name , qualifiers = qualifiers )
87+ purl = PackageURL (type = "nginx" , name = "nginx" , qualifiers = qualifiers )
8688
8789 _ , _ , affected_versions = nginx_adv .vulnerable .partition (":" )
8890 affected_versions = affected_versions .strip ()
@@ -112,6 +114,28 @@ def to_advisory_data(nginx_adv: NginxAdvisory) -> AdvisoryData:
112114
113115 affected_packages = []
114116 if purl and affected_version_range or fixed_version_range :
117+ try :
118+ if affected_version_range :
119+ validate_comparators (affected_version_range .constraints )
120+ except ValueError as e :
121+ affected_version_range = None
122+ logger .error (
123+ f"Invalid version_range affected_version_range:{ affected_version_range } - error: { e } "
124+ )
125+
126+ try :
127+ if fixed_version_range :
128+ fixed_version_constraints = VersionConstraint .simplify (
129+ fixed_version_range .constraints
130+ )
131+ fixed_version_range = NginxVersionRange (constraints = fixed_version_constraints )
132+ validate_comparators (fixed_version_range .constraints )
133+ except ValueError as e :
134+ fixed_version_range = None
135+ logger .error (
136+ f"Invalid version_range fixed_version_range:{ fixed_version_range } - error: { e } "
137+ )
138+
115139 affected_packages .append (
116140 AffectedPackageV2 (
117141 package = purl ,
@@ -126,6 +150,7 @@ def to_advisory_data(nginx_adv: NginxAdvisory) -> AdvisoryData:
126150 summary = nginx_adv .summary ,
127151 affected_packages = affected_packages ,
128152 references_v2 = nginx_adv .references ,
153+ patches = nginx_adv .patches ,
129154 url = "https://nginx.org/en/security_advisories.html" ,
130155 )
131156
@@ -148,6 +173,7 @@ def parse_advisory_data_from_paragraph(vulnerability_info):
148173 aliases = []
149174 summary = None
150175 severities = []
176+ patches = []
151177 not_vulnerable = None
152178 vulnerable = None
153179 references = []
@@ -196,8 +222,14 @@ def parse_advisory_data_from_paragraph(vulnerability_info):
196222 references .append (ReferenceV2 (reference_id = text , url = link ))
197223 elif "mailman.nginx.org" in link :
198224 references .append (ReferenceV2 (url = link ))
225+ elif "/download/patch" in link :
226+ link = urljoin ("https://nginx.org" , link )
227+ patch = PatchData (
228+ patch_url = link ,
229+ )
230+ patches .append (patch )
199231 else :
200- link = requests . compat . urljoin ("https://nginx.org" , link )
232+ link = urljoin ("https://nginx.org" , link )
201233 references .append (ReferenceV2 (url = link ))
202234
203235 advisory_id = aliases .pop ()
@@ -209,6 +241,7 @@ def parse_advisory_data_from_paragraph(vulnerability_info):
209241 not_vulnerable = not_vulnerable ,
210242 vulnerable = vulnerable ,
211243 references = references ,
244+ patches = patches ,
212245 )
213246
214247
0 commit comments