diff --git a/vulnerabilities/helpers.py b/vulnerabilities/helpers.py index 95dc2d801..5239d3df3 100644 --- a/vulnerabilities/helpers.py +++ b/vulnerabilities/helpers.py @@ -124,7 +124,7 @@ def requests_with_5xx_retry(max_retries=5, backoff_factor=0.5): def nearest_patched_package( vulnerable_packages: List[PackageURL], resolved_packages: List[PackageURL] -) -> List[AffectedPackage]: +) -> List[Tuple]: class PackageURLWithVersionComparator: """ This class is used to get around bisect module's lack of supplying custom @@ -158,11 +158,12 @@ def __lt__(self, other): if patched_package_index < resolved_package_count: patched_package = resolved_packages[patched_package_index].package - affected_package_with_patched_package_objects.append( - AffectedPackage( - vulnerable_package=vulnerable_package.package, patched_package=patched_package - ) - ) +# affected_package_with_patched_package_objects.append( +# AffectedPackage( +# vulnerable_package=vulnerable_package.package, patched_package=patched_package +# ) +# ) + affected_package_with_patched_package_objects.append((vulnerable_package.package, patched_package)) return affected_package_with_patched_package_objects diff --git a/vulnerabilities/importers/nginx.py b/vulnerabilities/importers/nginx.py index e603c9ecc..bdd276b62 100644 --- a/vulnerabilities/importers/nginx.py +++ b/vulnerabilities/importers/nginx.py @@ -36,10 +36,12 @@ from vulnerabilities.data_source import DataSource from vulnerabilities.data_source import DataSourceConfiguration from vulnerabilities.data_source import Reference +from vulnerabilities.data_inference import Inference +from vulnerabilities.data_inference import Improver from vulnerabilities.package_managers import GitHubTagsAPI from vulnerabilities.package_managers import Version from vulnerabilities.helpers import nearest_patched_package - +from vulnerabilities.models import Advisory @dataclasses.dataclass class NginxDataSourceConfiguration(DataSourceConfiguration): @@ -51,21 +53,6 @@ class NginxDataSource(DataSource): url = "http://nginx.org/en/security_advisories.html" - def set_api(self): - self.version_api = GitHubTagsAPI() - asyncio.run(self.version_api.load_api(["nginx/nginx"])) - - # For some reason nginx tags it's releases are in the form of `release-1.2.3` - # Chop off the `release-` part here. - normalized_versions = set() - while self.version_api.cache["nginx/nginx"]: - version = self.version_api.cache["nginx/nginx"].pop() - normalized_version = Version( - version.value.replace("release-", ""), version.release_date - ) - normalized_versions.add(normalized_version) - self.version_api.cache["nginx/nginx"] = normalized_versions - def advisory_data(self) -> List[AdvisoryData]: adv_data = [] # self.set_api() @@ -170,7 +157,9 @@ def extract_vuln_pkgs(self, vuln_info): if "-" not in version_info: # These are discrete versions version_ranges.append( - VersionSpecifier.from_scheme_version_spec_string("semver", version_info[0]) + VersionSpecifier.from_scheme_version_spec_string( + "semver", version_info[0] + ) ) continue @@ -195,6 +184,67 @@ def extract_vuln_pkgs(self, vuln_info): ] +class NginxTimeTravel(Improver): + def infer(self): + self.set_api() + advisories = Advisory.objects.filter( + source="vulnerabilities.importers.nginx.NginxDataSource" + ) + inferences = [] + for advisory in advisories: + advisory_data = AdvisoryData.from_json(advisory.data) + + affected_package_ranges = [ + pkg.version_specifier for pkg in advisory_data.affected_packages + ] + affected_package_versions = find_valid_versions( + self.version_api.get("nginx/nginx").valid_versions, + affected_package_ranges, + ) + affected_packages = [] + for pkg in advisory_data.affected_packages: + for + affected_packages.extend([]) + affected_packages = [advisory_data.affected_packages] + + fixed_package_ranges = [ + pkg.version_specifier for pkg in advisory_data.affected_packages + ] + fixed_packages = find_valid_versions( + self.version_api.get("nginx/nginx").valid_versions, fixed_package_ranges + ) + + pkgs = nearest_patched_package(affected_package_versions, fixed_package_ranges) + for pkg in pkgs: + print(pkg) + print(type(pkg)) + inferences.append( + Inference( + confidence=90, # TODO: Decide properly + vulnerability_id=advisory_data.vulnerability_id, + affected_packages=pkg[0], + fixed_packages=pkg[1], + ) + ) + + return inferences + + def set_api(self): + self.version_api = GitHubTagsAPI() + asyncio.run(self.version_api.load_api(["nginx/nginx"])) + + # For some reason nginx tags it's releases are in the form of `release-1.2.3` + # Chop off the `release-` part here. + normalized_versions = set() + while self.version_api.cache["nginx/nginx"]: + version = self.version_api.cache["nginx/nginx"].pop() + normalized_version = Version( + version.value.replace("release-", ""), version.release_date + ) + normalized_versions.add(normalized_version) + self.version_api.cache["nginx/nginx"] = normalized_versions + + def find_valid_versions(versions, version_ranges): valid_versions = set() for version in versions: diff --git a/vulnerabilities/improvers/__init__.py b/vulnerabilities/improvers/__init__.py index 4350f8612..96be7565c 100644 --- a/vulnerabilities/improvers/__init__.py +++ b/vulnerabilities/improvers/__init__.py @@ -1,6 +1,10 @@ +from vulnerabilities import importers from . import nginx from . import default -IMPROVER_REGISTRY = [default.DefaultImprover] +IMPROVER_REGISTRY = [ + default.DefaultImprover, + importers.nginx.NginxTimeTravel, +] improver_mapping = {f"{x.__module__}.{x.__name__}": x for x in IMPROVER_REGISTRY}