diff --git a/vulnerabilities/importers/apache_httpd.py b/vulnerabilities/importers/apache_httpd.py
index 0b6e87bea..09c64f34c 100644
--- a/vulnerabilities/importers/apache_httpd.py
+++ b/vulnerabilities/importers/apache_httpd.py
@@ -106,7 +106,7 @@ def to_advisory(self, data):
fixed_packages.extend(
[
PackageURL(type="apache", name="httpd", version=version)
- for version in self.version_api.get("apache/httpd")
+ for version in self.version_api.get("apache/httpd")["valid"]
if MavenVersion(version) in version_range
]
)
@@ -115,7 +115,7 @@ def to_advisory(self, data):
affected_packages.extend(
[
PackageURL(type="apache", name="httpd", version=version)
- for version in self.version_api.get("apache/httpd")
+ for version in self.version_api.get("apache/httpd")["valid"]
if MavenVersion(version) in version_range
]
)
diff --git a/vulnerabilities/importers/apache_kafka.py b/vulnerabilities/importers/apache_kafka.py
index 105f327f0..d0e8f7d7e 100644
--- a/vulnerabilities/importers/apache_kafka.py
+++ b/vulnerabilities/importers/apache_kafka.py
@@ -72,7 +72,7 @@ def to_advisory(self, advisory_page):
fixed_packages = [
PackageURL(type="apache", name="kafka", version=version)
- for version in self.version_api.get("apache/kafka")
+ for version in self.version_api.get("apache/kafka")["valid"]
if any(
[
MavenVersion(version) in version_range
@@ -83,7 +83,7 @@ def to_advisory(self, advisory_page):
affected_packages = [
PackageURL(type="apache", name="kafka", version=version)
- for version in self.version_api.get("apache/kafka")
+ for version in self.version_api.get("apache/kafka")["valid"]
if any(
[
MavenVersion(version) in version_range
diff --git a/vulnerabilities/importers/apache_tomcat.py b/vulnerabilities/importers/apache_tomcat.py
index 42a728840..3326a3bf9 100644
--- a/vulnerabilities/importers/apache_tomcat.py
+++ b/vulnerabilities/importers/apache_tomcat.py
@@ -62,7 +62,9 @@ def updated_advisories(self):
return self.batch_advisories(advisories)
def fetch_pages(self):
- tomcat_major_versions = {i[0] for i in self.version_api.get("org.apache.tomcat:tomcat")}
+ tomcat_major_versions = {
+ i[0] for i in self.version_api.get("org.apache.tomcat:tomcat")["valid"]
+ }
for version in tomcat_major_versions:
page_url = self.base_url.format(version)
if create_etag(self, page_url, "ETag"):
@@ -102,7 +104,7 @@ def to_advisories(self, apache_tomcat_advisory_html):
PackageURL(
type="maven", namespace="apache", name="tomcat", version=version
)
- for version in self.version_api.get("org.apache.tomcat:tomcat")
+ for version in self.version_api.get("org.apache.tomcat:tomcat")["valid"]
if MavenVersion(version) in version_range
]
)
diff --git a/vulnerabilities/importers/nginx.py b/vulnerabilities/importers/nginx.py
index fb8d82404..13a572f3e 100644
--- a/vulnerabilities/importers/nginx.py
+++ b/vulnerabilities/importers/nginx.py
@@ -171,7 +171,9 @@ def extract_vuln_pkgs(self, vuln_info):
)
)
- valid_versions = find_valid_versions(self.version_api.get("nginx/nginx"), version_ranges)
+ valid_versions = find_valid_versions(
+ self.version_api.get("nginx/nginx")["valid"], version_ranges
+ )
qualifiers = {}
if windows_only:
qualifiers["os"] = "windows"
diff --git a/vulnerabilities/importers/npm.py b/vulnerabilities/importers/npm.py
index eb28869d8..e66f9e5d4 100644
--- a/vulnerabilities/importers/npm.py
+++ b/vulnerabilities/importers/npm.py
@@ -88,7 +88,7 @@ def process_file(self, file) -> List[Advisory]:
publish_date = parse(record["updated_at"])
publish_date.replace(tzinfo=pytz.UTC)
- all_versions = self.versions.get(package_name, until=publish_date)
+ all_versions = self.versions.get(package_name, until=publish_date)["valid"]
aff_range = record.get("vulnerable_versions")
if not aff_range:
aff_range = ""
diff --git a/vulnerabilities/importers/project_kb_msr2019.py b/vulnerabilities/importers/project_kb_msr2019.py
index 8b97eccf1..897a0c4ff 100644
--- a/vulnerabilities/importers/project_kb_msr2019.py
+++ b/vulnerabilities/importers/project_kb_msr2019.py
@@ -22,12 +22,10 @@
import csv
import dataclasses
-import re
import urllib.request
# Reading CSV file from a url using `requests` is bit too complicated.
# Use `urllib.request` for that purpose.
-from packageurl import PackageURL
from vulnerabilities.data_source import Advisory
diff --git a/vulnerabilities/importers/ruby.py b/vulnerabilities/importers/ruby.py
index a801a5f81..0ae3ba7be 100644
--- a/vulnerabilities/importers/ruby.py
+++ b/vulnerabilities/importers/ruby.py
@@ -23,6 +23,8 @@
import asyncio
from typing import Set
from typing import List
+from dateutil.parser import parse
+from pytz import UTC
from packageurl import PackageURL
from univers.version_specifier import VersionSpecifier
@@ -90,6 +92,7 @@ def process_file(self, path) -> List[Advisory]:
else:
return
+ publish_time = parse(record["date"]).replace(tzinfo=UTC)
safe_version_ranges = record.get("patched_versions", [])
# this case happens when the advisory contain only 'patched_versions' field
# and it has value None(i.e it is empty :( ).
@@ -100,7 +103,10 @@ def process_file(self, path) -> List[Advisory]:
if not getattr(self, "pkg_manager_api", None):
self.pkg_manager_api = RubyVersionAPI()
- all_vers = self.pkg_manager_api.get(package_name)
+ all_vers = self.pkg_manager_api.get(package_name, until=publish_time)["valid"]
+ print(
+ f"Ignored {len(self.pkg_manager_api.get(package_name,until=publish_time)['new'])} versions"
+ )
safe_versions, affected_versions = self.categorize_versions(all_vers, safe_version_ranges)
impacted_purls = [
diff --git a/vulnerabilities/importers/safety_db.py b/vulnerabilities/importers/safety_db.py
index 97ea5ae64..38956f708 100755
--- a/vulnerabilities/importers/safety_db.py
+++ b/vulnerabilities/importers/safety_db.py
@@ -111,7 +111,7 @@ def updated_advisories(self) -> Set[Advisory]:
logger.error(e)
continue
- all_package_versions = self.versions.get(package_name)
+ all_package_versions = self.versions.get(package_name)["valid"]
if not len(all_package_versions):
# PyPi does not have data about this package, we skip these
continue
diff --git a/vulnerabilities/importers/suse_backports.py b/vulnerabilities/importers/suse_backports.py
index 6ad43ee08..c80d25969 100644
--- a/vulnerabilities/importers/suse_backports.py
+++ b/vulnerabilities/importers/suse_backports.py
@@ -1,95 +1,95 @@
-# # Copyright (c) 2017 nexB Inc. and others. All rights reserved.
-# # http://nexb.com and https://github.com/nexB/vulnerablecode/
-# # The VulnerableCode software is licensed under the Apache License version 2.0.
-# # Data generated with VulnerableCode require an acknowledgment.
-# #
-# # You may not use this software except in compliance with the License.
-# # You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
-# # Unless required by applicable law or agreed to in writing, software distributed
-# # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-# # CONDITIONS OF ANY KIND, either express or implied. See the License for the
-# # specific language governing permissions and limitations under the License.
-# #
-# # When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
-# # derivative work, you must accompany this data with the following acknowledgment:
-# #
-# # Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
-# # OR CONDITIONS OF ANY KIND, either express or implied. No content created from
-# # VulnerableCode should be considered or used as legal advice. Consult an Attorney
-# # for any legal advice.
-# # VulnerableCode is a free software code scanning tool from nexB Inc. and others.
-# # Visit https://github.com/nexB/vulnerablecode/ for support and download.
-# import dataclasses
+# Copyright (c) 2017 nexB Inc. and others. All rights reserved.
+# http://nexb.com and https://github.com/nexB/vulnerablecode/
+# The VulnerableCode software is licensed under the Apache License version 2.0.
+# Data generated with VulnerableCode require an acknowledgment.
+#
+# You may not use this software except in compliance with the License.
+# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software distributed
+# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+# CONDITIONS OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
+# derivative work, you must accompany this data with the following acknowledgment:
+#
+# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
+# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
+# VulnerableCode should be considered or used as legal advice. Consult an Attorney
+# for any legal advice.
+# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
+# Visit https://github.com/nexB/vulnerablecode/ for support and download.
+import dataclasses
-# import requests
-# import saneyaml
-# from bs4 import BeautifulSoup
-# from packageurl import PackageURL
+import requests
+import saneyaml
+from bs4 import BeautifulSoup
+from packageurl import PackageURL
-# from vulnerabilities.data_source import Advisory
-# from vulnerabilities.data_source import DataSource
-# from vulnerabilities.data_source import DataSourceConfiguration
-# from vulnerabilities.helpers import create_etag
+from vulnerabilities.data_source import Advisory
+from vulnerabilities.data_source import DataSource
+from vulnerabilities.data_source import DataSourceConfiguration
+from vulnerabilities.helpers import create_etag
-# @dataclasses.dataclass
-# class SUSEBackportsConfiguration(DataSourceConfiguration):
-# url: str
-# etags: dict
+@dataclasses.dataclass
+class SUSEBackportsConfiguration(DataSourceConfiguration):
+ url: str
+ etags: dict
-# class SUSEBackportsDataSource(DataSource):
+class SUSEBackportsDataSource(DataSource):
-# CONFIG_CLASS = SUSEBackportsConfiguration
+ CONFIG_CLASS = SUSEBackportsConfiguration
-# @staticmethod
-# def get_all_urls_of_backports(url):
-# r = requests.get(url)
-# soup = BeautifulSoup(r.content, "lxml")
-# for a_tag in soup.find_all("a", href=True):
-# if a_tag["href"].endswith(".yaml") and a_tag["href"].startswith("backports"):
-# yield url + a_tag["href"]
+ @staticmethod
+ def get_all_urls_of_backports(url):
+ r = requests.get(url)
+ soup = BeautifulSoup(r.content, "lxml")
+ for a_tag in soup.find_all("a", href=True):
+ if a_tag["href"].endswith(".yaml") and a_tag["href"].startswith("backports"):
+ yield url + a_tag["href"]
-# def updated_advisories(self):
-# advisories = []
-# all_urls = self.get_all_urls_of_backports(self.config.url)
-# for url in all_urls:
-# if not create_etag(data_src=self, url=url, etag_key="ETag"):
-# continue
-# advisories.extend(self.process_file(self._fetch_yaml(url)))
-# return self.batch_advisories(advisories)
+ def updated_advisories(self):
+ advisories = []
+ all_urls = self.get_all_urls_of_backports(self.config.url)
+ for url in all_urls:
+ if not create_etag(data_src=self, url=url, etag_key="ETag"):
+ continue
+ advisories.extend(self.process_file(self._fetch_yaml(url)))
+ return self.batch_advisories(advisories)
-# def _fetch_yaml(self, url):
+ def _fetch_yaml(self, url):
-# try:
-# resp = requests.get(url)
-# resp.raise_for_status()
-# return saneyaml.load(resp.content)
+ try:
+ resp = requests.get(url)
+ resp.raise_for_status()
+ return saneyaml.load(resp.content)
-# except requests.HTTPError:
-# return {}
+ except requests.HTTPError:
+ return {}
-# @staticmethod
-# def process_file(yaml_file):
-# advisories = []
-# try:
-# for pkg in yaml_file[0]["packages"]:
-# for version in yaml_file[0]["packages"][pkg]["fixed"]:
-# for vuln in yaml_file[0]["packages"][pkg]["fixed"][version]:
-# # yaml_file specific data can be added
-# purl = [
-# PackageURL(name=pkg, type="rpm", version=version, namespace="opensuse")
-# ]
-# advisories.append(
-# Advisory(
-# vulnerability_id=vuln,
-# resolved_package_urls=purl,
-# summary="",
-# impacted_package_urls=[],
-# )
-# )
-# except TypeError:
-# # could've used pass
-# return advisories
+ @staticmethod
+ def process_file(yaml_file):
+ advisories = []
+ try:
+ for pkg in yaml_file[0]["packages"]:
+ for version in yaml_file[0]["packages"][pkg]["fixed"]:
+ for vuln in yaml_file[0]["packages"][pkg]["fixed"][version]:
+ # yaml_file specific data can be added
+ purl = [
+ PackageURL(name=pkg, type="rpm", version=version, namespace="opensuse")
+ ]
+ advisories.append(
+ Advisory(
+ vulnerability_id=vuln,
+ resolved_package_urls=purl,
+ summary="",
+ impacted_package_urls=[],
+ )
+ )
+ except TypeError:
+ # could've used pass
+ return advisories
-# return advisories
+ return advisories
diff --git a/vulnerabilities/importers/ubuntu.py b/vulnerabilities/importers/ubuntu.py
index dadc4e15d..4124317c0 100644
--- a/vulnerabilities/importers/ubuntu.py
+++ b/vulnerabilities/importers/ubuntu.py
@@ -25,19 +25,11 @@
import bz2
import dataclasses
import logging
-from typing import Iterable
-from typing import List
-from typing import Mapping
-from typing import Set
import xml.etree.ElementTree as ET
-
-from aiohttp import ClientSession
-from aiohttp.client_exceptions import ClientResponseError
import requests
from vulnerabilities.data_source import OvalDataSource, DataSourceConfiguration
from vulnerabilities.package_managers import LaunchpadVersionAPI
-from vulnerabilities.helpers import create_etag
logger = logging.getLogger(__name__)
diff --git a/vulnerabilities/package_managers.py b/vulnerabilities/package_managers.py
index 7ce7d7c34..5b9735435 100644
--- a/vulnerabilities/package_managers.py
+++ b/vulnerabilities/package_managers.py
@@ -21,20 +21,24 @@
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
import asyncio
-from collections import namedtuple
+import dataclasses
import pytz
from bs4 import BeautifulSoup
from dateutil import parser
from json import JSONDecodeError
from typing import Mapping
from typing import Set
+from datetime import datetime
from aiohttp import ClientSession
from aiohttp.client_exceptions import ClientResponseError
from aiohttp.client_exceptions import ServerDisconnectedError
-Version = namedtuple("Version", field_names=["value", "release_date"])
+@dataclasses.dataclass(frozen=True)
+class Version:
+ value: str
+ release_date: datetime = None
class VersionAPI:
@@ -303,8 +307,8 @@ def extract_versions(soup: BeautifulSoup) -> Set[Version]:
pre_tag = soup.find("pre")
prev_tag = None
versions = set()
- for atag in pre_tag:
- if atag.name == "a" and atag["href"] != "../":
+ for i, atag in enumerate(pre_tag):
+ if atag.name == "a" and i != 0:
prev_tag = atag
elif prev_tag:
text_groups = atag.split()
diff --git a/vulnerabilities/tests/test_apache_httpd.py b/vulnerabilities/tests/test_apache_httpd.py
index 384696646..47dcbef7e 100644
--- a/vulnerabilities/tests/test_apache_httpd.py
+++ b/vulnerabilities/tests/test_apache_httpd.py
@@ -31,6 +31,7 @@
from vulnerabilities.data_source import Advisory
from vulnerabilities.data_source import VulnerabilitySeverity
from vulnerabilities.package_managers import GitHubTagsAPI
+from vulnerabilities.package_managers import Version
from vulnerabilities.severity_systems import scoring_systems
from vulnerabilities.importers.apache_httpd import ApacheHTTPDDataSource
from vulnerabilities.helpers import AffectedPackage
@@ -44,7 +45,7 @@ class TestApacheHTTPDDataSource(TestCase):
def setUpClass(cls):
data_source_cfg = {"etags": {}}
cls.data_src = ApacheHTTPDDataSource(1, config=data_source_cfg)
- known_versions = ["1.3.2", "1.3.1", "1.3.0"]
+ known_versions = [Version("1.3.2"), Version("1.3.1"), Version("1.3.0")]
cls.data_src.version_api = GitHubTagsAPI(cache={"apache/httpd": known_versions})
with open(TEST_DATA) as f:
cls.data = json.load(f)
diff --git a/vulnerabilities/tests/test_apache_kafka.py b/vulnerabilities/tests/test_apache_kafka.py
index a2435b425..46869ed6c 100644
--- a/vulnerabilities/tests/test_apache_kafka.py
+++ b/vulnerabilities/tests/test_apache_kafka.py
@@ -29,6 +29,7 @@
from vulnerabilities.data_source import Advisory
from vulnerabilities.data_source import Reference
from vulnerabilities.package_managers import GitHubTagsAPI
+from vulnerabilities.package_managers import Version
from vulnerabilities.importers.apache_kafka import ApacheKafkaDataSource
from vulnerabilities.importers.apache_kafka import to_version_ranges
from vulnerabilities.helpers import AffectedPackage
@@ -63,7 +64,9 @@ def test_to_version_ranges(self):
def test_to_advisory(self):
data_source = ApacheKafkaDataSource(batch_size=1)
- data_source.version_api = GitHubTagsAPI(cache={"apache/kafka": ["2.1.2", "0.10.2.2"]})
+ data_source.version_api = GitHubTagsAPI(
+ cache={"apache/kafka": [Version("2.1.2"), Version("0.10.2.2")]}
+ )
expected_advisories = [
Advisory(
summary="In Apache Kafka versions between 0.11.0.0 and 2.1.0, it is possible to manually\n craft a Produce request which bypasses transaction/idempotent ACL validation.\n Only authenticated clients with Write permission on the respective topics are\n able to exploit this vulnerability. Users should upgrade to 2.1.1 or later\n where this vulnerability has been fixed.",
diff --git a/vulnerabilities/tests/test_apache_tomcat.py b/vulnerabilities/tests/test_apache_tomcat.py
index 290ca3652..d7419dedc 100644
--- a/vulnerabilities/tests/test_apache_tomcat.py
+++ b/vulnerabilities/tests/test_apache_tomcat.py
@@ -21,7 +21,6 @@
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
import os
-from unittest.mock import MagicMock
from unittest.mock import patch
from unittest import TestCase
@@ -31,6 +30,8 @@
from vulnerabilities.data_source import Reference
from vulnerabilities.importers.apache_tomcat import ApacheTomcatDataSource
from vulnerabilities.helpers import AffectedPackage
+from vulnerabilities.package_managers import Version
+from vulnerabilities.package_managers import MavenVersionAPI
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
TEST_DATA = os.path.join(BASE_DIR, "test_data", "apache_tomcat", "security-9.html")
@@ -40,11 +41,19 @@ class TestApacheTomcatDataSource(TestCase):
@classmethod
def setUpClass(cls):
data_source_cfg = {"etags": {}}
- mock_api = {"org.apache.tomcat:tomcat": ["9.0.0.M1", "9.0.0.M2", "8.0.0.M1", "6.0.0M2"]}
+ mock_api = MavenVersionAPI(
+ cache={
+ "org.apache.tomcat:tomcat": [
+ Version("9.0.0.M1"),
+ Version("9.0.0.M2"),
+ Version("8.0.0.M1"),
+ Version("6.0.0M2"),
+ ]
+ }
+ )
with patch("vulnerabilities.importers.apache_tomcat.MavenVersionAPI"):
with patch("vulnerabilities.importers.apache_tomcat.asyncio"):
cls.data_src = ApacheTomcatDataSource(1, config=data_source_cfg)
-
cls.data_src.version_api = mock_api
def test_to_advisories(self):
diff --git a/vulnerabilities/tests/test_data/github_api/response.json b/vulnerabilities/tests/test_data/github_api/response.json
index a1fb7e9ea..d890394fe 100644
--- a/vulnerabilities/tests/test_data/github_api/response.json
+++ b/vulnerabilities/tests/test_data/github_api/response.json
@@ -21,7 +21,8 @@
"url":"https://github.com/advisories/GHSA-qcxh-w3j9-58qr"
}
],
- "severity": "MODERATE"
+ "severity": "MODERATE",
+ "publishedAt": "2021-05-24T18:12:20Z"
},
"package": {
"name": "org.apache.tomcat.embed:tomcat-embed-core"
@@ -48,7 +49,8 @@
"url":"https://github.com/advisories/GHSA-qcxh-w3j9-58qr"
}
],
- "severity": "HIGH"
+ "severity": "HIGH",
+ "publishedAt": "2021-05-24T18:12:20Z"
},
"package": {
"name": "org.apache.tomcat.embed:tomcat-embed-core"
@@ -75,7 +77,8 @@
"url":"https://github.com/advisories/GHSA-c9hw-wf7x-jp9j"
}
],
- "severity": "LOW"
+ "severity": "LOW",
+ "publishedAt": "2021-05-24T18:12:20Z"
},
"package": {
"name": "org.apache.tomcat.embed:tomcat-embed-core"
@@ -102,7 +105,8 @@
"url":"https://github.com/advisories/GHSA-c9hw-wf7x-jp9j"
}
],
- "severity": "MODERATE"
+ "severity": "MODERATE",
+ "publishedAt": "2021-05-24T18:12:20Z"
},
"package": {
"name": "org.apache.tomcat.embed:tomcat-embed-core"
@@ -129,7 +133,8 @@
"url":"https://github.com/advisories/GHSA-c9hw-wf7x-jp9j"
}
],
- "severity": "LOW"
+ "severity": "LOW",
+ "publishedAt": "2021-05-24T18:12:20Z"
},
"package": {
"name": "org.apache.tomcat.embed:tomcat-embed-core"
diff --git a/vulnerabilities/tests/test_data/maven_api/easygcm.html b/vulnerabilities/tests/test_data/maven_api/easygcm.html
new file mode 100644
index 000000000..280faf6a2
--- /dev/null
+++ b/vulnerabilities/tests/test_data/maven_api/easygcm.html
@@ -0,0 +1,31 @@
+
+
+
+ Central Repository: eu/inloop/easygcm
+
+
+
+
+
+
+
+
+ ../
+1.2.2/ 2014-12-22 10:29 -
+1.2.3/ 2014-12-22 10:53 -
+1.3.0/ 2015-03-12 15:20 -
+maven-metadata.xml 2015-03-12 15:22 385
+maven-metadata.xml.md5 2015-03-12 15:22 32
+maven-metadata.xml.sha1 2015-03-12 15:22 40
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vulnerabilities/tests/test_data/npm.zip b/vulnerabilities/tests/test_data/npm.zip
index 37d86e7f1..fdb957a32 100644
Binary files a/vulnerabilities/tests/test_data/npm.zip and b/vulnerabilities/tests/test_data/npm.zip differ
diff --git a/vulnerabilities/tests/test_elixir_security.py b/vulnerabilities/tests/test_elixir_security.py
index 774a2209f..68022b17c 100644
--- a/vulnerabilities/tests/test_elixir_security.py
+++ b/vulnerabilities/tests/test_elixir_security.py
@@ -30,6 +30,7 @@
from vulnerabilities.data_source import Reference
from vulnerabilities.importers.elixir_security import ElixirSecurityDataSource
from vulnerabilities.package_managers import HexVersionAPI
+from vulnerabilities.package_managers import Version
from vulnerabilities.helpers import AffectedPackage
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -45,17 +46,17 @@ def setUpClass(cls):
cls.data_src.pkg_manager_api = HexVersionAPI(
{
"coherence": [
- "0.5.2",
- "0.5.1",
- "0.5.0",
- "0.4.0",
- "0.3.1",
- "0.3.0",
- "0.2.0",
- "0.1.3",
- "0.1.2",
- "0.1.1",
- "0.1.0",
+ Version("0.5.2"),
+ Version("0.5.1"),
+ Version("0.5.0"),
+ Version("0.4.0"),
+ Version("0.3.1"),
+ Version("0.3.0"),
+ Version("0.2.0"),
+ Version("0.1.3"),
+ Version("0.1.2"),
+ Version("0.1.1"),
+ Version("0.1.0"),
]
}
)
diff --git a/vulnerabilities/tests/test_github.py b/vulnerabilities/tests/test_github.py
index 3306b75a5..c186711aa 100644
--- a/vulnerabilities/tests/test_github.py
+++ b/vulnerabilities/tests/test_github.py
@@ -26,17 +26,14 @@
from unittest.mock import patch
from unittest.mock import MagicMock
from unittest.mock import call
-import xml.etree.ElementTree as ET
-from collections import OrderedDict
-from requests.models import Response
from packageurl import PackageURL
from vulnerabilities.data_source import Advisory
from vulnerabilities.data_source import Reference
from vulnerabilities.data_source import VulnerabilitySeverity
from vulnerabilities.importers.github import GitHubAPIDataSource
-from vulnerabilities.package_managers import MavenVersionAPI
+from vulnerabilities.package_managers import MavenVersionAPI, Version
from vulnerabilities.package_managers import NugetVersionAPI
from vulnerabilities.package_managers import ComposerVersionAPI
from vulnerabilities.severity_systems import ScoringSystem
@@ -295,12 +292,14 @@ def test_process_response(self):
),
]
- mock_version_api = MagicMock()
- mock_version_api.package_type = "maven"
- mock_version_api.get = lambda x: {"1.2.0", "9.0.2"}
+ mock_version_api = MavenVersionAPI(
+ cache={
+ "org.apache.tomcat.embed:tomcat-embed-core": {Version("1.2.0"), Version("9.0.2")}
+ }
+ )
with patch(
"vulnerabilities.importers.github.MavenVersionAPI", return_value=mock_version_api
- ): # nopep8
+ ):
with patch("vulnerabilities.importers.github.GitHubAPIDataSource.set_api"):
found_advisories = self.data_src.process_response()
diff --git a/vulnerabilities/tests/test_istio.py b/vulnerabilities/tests/test_istio.py
index f17dc64ed..986830edc 100644
--- a/vulnerabilities/tests/test_istio.py
+++ b/vulnerabilities/tests/test_istio.py
@@ -29,6 +29,7 @@
from vulnerabilities.data_source import Advisory, Reference
from vulnerabilities.importers.istio import IstioDataSource
from vulnerabilities.package_managers import GitHubTagsAPI
+from vulnerabilities.package_managers import Version
from vulnerabilities.helpers import AffectedPackage
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -44,16 +45,16 @@ def setUpClass(cls):
cls.data_src.version_api = GitHubTagsAPI(
{
"istio/istio": [
- "1.0.0",
- "1.1.0",
- "1.1.1",
- "1.1.17",
- "1.2.1",
- "1.2.7",
- "1.3.0",
- "1.3.1",
- "1.3.2",
- "1.9.1",
+ Version(value="1.0.0"),
+ Version(value="1.1.0"),
+ Version(value="1.1.1"),
+ Version(value="1.1.17"),
+ Version(value="1.2.1"),
+ Version(value="1.2.7"),
+ Version(value="1.3.0"),
+ Version(value="1.3.1"),
+ Version(value="1.3.2"),
+ Version(value="1.9.1"),
]
}
)
diff --git a/vulnerabilities/tests/test_nginx.py b/vulnerabilities/tests/test_nginx.py
index 38551a46b..a62e009f7 100644
--- a/vulnerabilities/tests/test_nginx.py
+++ b/vulnerabilities/tests/test_nginx.py
@@ -27,9 +27,9 @@
from packageurl import PackageURL
from vulnerabilities.data_source import Advisory
-from vulnerabilities.data_source import Reference
from vulnerabilities.importers.nginx import NginxDataSource
from vulnerabilities.package_managers import GitHubTagsAPI
+from vulnerabilities.package_managers import Version
from vulnerabilities.helpers import AffectedPackage
@@ -45,11 +45,17 @@ def setUpClass(cls):
data_source_cfg = {"etags": {}}
cls.data_src = NginxDataSource(1, config=data_source_cfg)
cls.data_src.version_api = GitHubTagsAPI(
- cache={"nginx/nginx": {"1.2.3", "1.7.0", "1.3.9", "0.7.52"}}
+ cache={
+ "nginx/nginx": {
+ Version("1.2.3"),
+ Version("1.7.0"),
+ Version("1.3.9"),
+ Version("0.7.52"),
+ }
+ }
)
def test_to_advisories(self):
- # expected_advisories = [Advisory(summary='An error log data are not sanitized', vulnerability_id='CVE-2009-4487', affected_packages=[], references=[]), Advisory(summary='Directory traversal vulnerability', vulnerability_id='CVE-2009-3898', affected_packages=[AffectedPackage(vulnerable_package=PackageURL(type='generic', namespace=None, name='nginx', version='0.7.52', qualifiers={}, subpath=None), patched_package=None)], references=[]), Advisory(summary='Stack-based buffer overflow with specially crafted request', vulnerability_id='CVE-2013-2028', affected_packages=[AffectedPackage(vulnerable_package=PackageURL(type='generic', namespace=None, name='nginx', version='1.3.9', qualifiers={}, subpath=None), patched_package=PackageURL(type='generic', namespace=None, name='nginx', version='1.7.0', qualifiers={}, subpath=None))], references=[]), Advisory(summary='The renegotiation vulnerability in SSL protocol', vulnerability_id='CVE-2009-3555', affected_packages=[AffectedPackage(vulnerable_package=PackageURL(type='generic', namespace=None, name='nginx', version='0.7.52', qualifiers={}, subpath=None), patched_package=None)], references=[]), Advisory(summary='Vulnerabilities with Windows directory aliases', vulnerability_id='CVE-2011-4963', affected_packages=[AffectedPackage(vulnerable_package=PackageURL(type='generic', namespace=None, name='nginx', version='0.7.52', qualifiers={'os': 'windows'}, subpath=None), patched_package=PackageURL(type='generic', namespace=None, name='nginx', version='1.2.3', qualifiers={}, subpath=None)), AffectedPackage(vulnerable_package=PackageURL(type='generic', namespace=None, name='nginx', version='1.2.3', qualifiers={'os': 'windows'}, subpath=None), patched_package=PackageURL(type='generic', namespace=None, name='nginx', version='1.3.9', qualifiers={}, subpath=None))], references=[]), Advisory(summary='Vulnerabilities with invalid UTF-8 sequence on Windows', vulnerability_id='CVE-2010-2266', affected_packages=[AffectedPackage(vulnerable_package=PackageURL(type='generic', namespace=None, name='nginx', version='0.7.52', qualifiers={'os': 'windows'}, subpath=None), patched_package=None)], references=[])]
expected_advisories = [
Advisory(
summary="An error log data are not sanitized",
diff --git a/vulnerabilities/tests/test_npm.py b/vulnerabilities/tests/test_npm.py
index 953cb1d96..6deab261d 100644
--- a/vulnerabilities/tests/test_npm.py
+++ b/vulnerabilities/tests/test_npm.py
@@ -20,7 +20,6 @@
# for any legal advice.
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
-import json
import os
import shutil
import tempfile
@@ -32,6 +31,7 @@
from vulnerabilities import models
from vulnerabilities.import_runner import ImportRunner
from vulnerabilities.package_managers import NpmVersionAPI
+from vulnerabilities.package_managers import Version
from vulnerabilities.importers.npm import categorize_versions
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -40,9 +40,15 @@
MOCK_VERSION_API = NpmVersionAPI(
cache={
- "jquery": {"3.4.0", "3.8.0"},
- "kerberos": {"0.5.8", "1.2.0"},
- "@hapi/subtext": {"3.7.0", "4.1.1", "6.1.3", "7.0.0", "7.0.5"},
+ "jquery": {Version("3.4.0"), Version("3.8.0")},
+ "kerberos": {Version("0.5.8"), Version("1.2.0")},
+ "@hapi/subtext": {
+ Version("3.7.0"),
+ Version("4.1.1"),
+ Version("6.1.3"),
+ Version("7.0.0"),
+ Version("7.0.5"),
+ },
}
)
@@ -67,7 +73,7 @@ def setUpClass(cls) -> None:
data_source="NpmDataSource",
data_source_cfg={
"repository_url": "https://example.git",
- "working_directory": os.path.join(cls.tempdir, "npm_test"),
+ "working_directory": os.path.join(cls.tempdir, "npm/npm_test"),
"create_working_directory": False,
"remove_working_directory": False,
},
diff --git a/vulnerabilities/tests/test_package_managers.py b/vulnerabilities/tests/test_package_managers.py
index a74a46907..5a33f3526 100644
--- a/vulnerabilities/tests/test_package_managers.py
+++ b/vulnerabilities/tests/test_package_managers.py
@@ -21,17 +21,20 @@
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
import asyncio
+from datetime import datetime
+from bs4 import BeautifulSoup
+from dateutil.tz import tzlocal
+from pytz import UTC
import os
import json
from unittest import TestCase
-from unittest.mock import patch
-from unittest.mock import MagicMock, AsyncMock
+from unittest.mock import AsyncMock
import xml.etree.ElementTree as ET
-from aiohttp import test_utils
from vulnerabilities.package_managers import ComposerVersionAPI
from vulnerabilities.package_managers import MavenVersionAPI
from vulnerabilities.package_managers import NugetVersionAPI
+from vulnerabilities.package_managers import Version
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
TEST_DATA = os.path.join(BASE_DIR, "test_data")
@@ -62,72 +65,270 @@ def setUpClass(cls):
cls.response = json.load(f)
cls.expected_versions = {
- "9.5.3",
- "8.7.30",
- "9.3.1",
- "9.5.1",
- "9.5.11",
- "9.5.6",
- "8.7.18",
- "8.7.15",
- "9.4.0",
- "9.5.7",
- "8.7.21",
- "9.5.12",
- "9.5.14",
- "8.7.27",
- "8.7.17",
- "8.7.9",
- "10.4.3",
- "10.0.0",
- "10.1.0",
- "9.5.13",
- "9.5.5",
- "8.7.22",
- "8.7.10",
- "8.7.24",
- "8.7.13",
- "8.7.14",
- "8.7.19",
- "9.5.17",
- "9.3.2",
- "9.5.15",
- "8.7.8",
- "9.3.3",
- "8.7.32",
- "10.4.0",
- "10.4.1",
- "9.5.18",
- "9.1.0",
- "9.5.19",
- "9.5.2",
- "8.7.26",
- "8.7.20",
- "10.2.0",
- "8.7.31",
- "8.7.11",
- "9.2.1",
- "8.7.25",
- "9.5.10",
- "10.2.2",
- "10.4.2",
- "9.5.9",
- "9.2.0",
- "9.3.0",
- "9.5.16",
- "10.3.0",
- "8.7.7",
- "10.4.4",
- "8.7.12",
- "8.7.29",
- "10.2.1",
- "9.5.8",
- "9.5.4",
- "9.5.0",
- "8.7.28",
- "8.7.23",
- "9.0.0",
- "8.7.16",
+ Version(
+ value="8.7.10",
+ release_date=datetime(2018, 2, 6, 10, 46, 2, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.11",
+ release_date=datetime(2018, 3, 13, 12, 44, 45, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.12",
+ release_date=datetime(2018, 3, 22, 11, 35, 42, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.13",
+ release_date=datetime(2018, 4, 17, 8, 15, 46, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.14",
+ release_date=datetime(2018, 5, 22, 13, 51, 9, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.15",
+ release_date=datetime(2018, 5, 23, 11, 31, 21, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.16",
+ release_date=datetime(2018, 6, 11, 17, 18, 14, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.17",
+ release_date=datetime(2018, 7, 12, 11, 29, 19, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.18",
+ release_date=datetime(2018, 7, 31, 8, 15, 29, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.19",
+ release_date=datetime(2018, 8, 21, 7, 23, 21, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.21",
+ release_date=datetime(2018, 12, 11, 12, 40, 12, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.20",
+ release_date=datetime(2018, 10, 30, 10, 39, 51, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.22",
+ release_date=datetime(2018, 12, 14, 7, 43, 50, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.23",
+ release_date=datetime(2019, 1, 22, 10, 10, 2, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.24",
+ release_date=datetime(2019, 1, 22, 15, 25, 55, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.25",
+ release_date=datetime(2019, 5, 7, 10, 5, 55, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.26",
+ release_date=datetime(2019, 5, 15, 11, 24, 12, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.27",
+ release_date=datetime(2019, 6, 25, 8, 24, 21, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.28",
+ release_date=datetime(2019, 10, 15, 7, 21, 52, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.29",
+ release_date=datetime(2019, 10, 30, 21, 0, 45, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.30",
+ release_date=datetime(2019, 12, 17, 10, 49, 17, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.31",
+ release_date=datetime(2020, 2, 17, 23, 29, 16, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.7",
+ release_date=datetime(2017, 9, 19, 14, 22, 53, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.32",
+ release_date=datetime(2020, 3, 31, 8, 33, 3, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.8",
+ release_date=datetime(2017, 10, 10, 16, 8, 44, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="8.7.9",
+ release_date=datetime(2017, 12, 12, 16, 9, 50, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.0.0",
+ release_date=datetime(2017, 12, 12, 16, 48, 22, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.1.0",
+ release_date=datetime(2018, 1, 30, 15, 31, 12, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.2.0",
+ release_date=datetime(2018, 4, 9, 20, 51, 35, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.2.1",
+ release_date=datetime(2018, 5, 22, 13, 47, 11, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.3.0",
+ release_date=datetime(2018, 6, 11, 17, 14, 33, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.3.1",
+ release_date=datetime(2018, 7, 12, 11, 33, 12, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.3.2",
+ release_date=datetime(2018, 7, 12, 15, 51, 49, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.3.3",
+ release_date=datetime(2018, 7, 31, 8, 20, 17, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.0",
+ release_date=datetime(2018, 10, 2, 8, 10, 33, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.4.0",
+ release_date=datetime(2018, 9, 4, 12, 8, 20, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.1",
+ release_date=datetime(2018, 10, 30, 10, 45, 30, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.10",
+ release_date=datetime(2019, 10, 15, 7, 29, 55, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.11",
+ release_date=datetime(2019, 10, 30, 20, 46, 49, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.12",
+ release_date=datetime(2019, 12, 17, 10, 53, 45, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.13",
+ release_date=datetime(2019, 12, 17, 14, 17, 37, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.14",
+ release_date=datetime(2020, 2, 17, 23, 37, 2, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.15",
+ release_date=datetime(2020, 3, 31, 8, 40, 25, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.16",
+ release_date=datetime(2020, 4, 28, 9, 22, 14, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.17",
+ release_date=datetime(2020, 5, 12, 10, 36, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.18",
+ release_date=datetime(2020, 5, 19, 13, 10, 50, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.2",
+ release_date=datetime(2018, 12, 11, 12, 42, 55, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.19",
+ release_date=datetime(2020, 6, 9, 8, 44, 34, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.3",
+ release_date=datetime(2018, 12, 14, 7, 28, 48, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.4",
+ release_date=datetime(2019, 1, 22, 10, 12, 4, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.5",
+ release_date=datetime(2019, 3, 4, 20, 25, 8, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.6",
+ release_date=datetime(2019, 5, 7, 10, 16, 30, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.7",
+ release_date=datetime(2019, 5, 15, 11, 41, 51, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.8",
+ release_date=datetime(2019, 6, 25, 8, 28, 51, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="9.5.9",
+ release_date=datetime(2019, 8, 20, 9, 33, 35, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.0.0",
+ release_date=datetime(2019, 7, 23, 7, 6, 3, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.1.0",
+ release_date=datetime(2019, 10, 1, 8, 18, 18, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.2.0",
+ release_date=datetime(2019, 12, 3, 11, 16, 26, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.2.1",
+ release_date=datetime(2019, 12, 17, 11, 0, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.2.2",
+ release_date=datetime(2019, 12, 17, 11, 36, 14, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.3.0",
+ release_date=datetime(2020, 2, 25, 12, 50, 9, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.4.0",
+ release_date=datetime(2020, 4, 21, 8, 0, 15, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.4.1",
+ release_date=datetime(2020, 4, 28, 9, 7, 54, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.4.2",
+ release_date=datetime(2020, 5, 12, 10, 41, 40, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.4.4",
+ release_date=datetime(2020, 6, 9, 8, 56, 30, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="10.4.3",
+ release_date=datetime(2020, 5, 19, 13, 16, 31, tzinfo=tzlocal()),
+ ),
}
def test_composer_url(self):
@@ -142,45 +343,50 @@ def test_extract_versions(self):
def test_fetch(self):
- assert self.version_api.get("typo3/cms-core") == set()
+ assert self.version_api.get("typo3/cms-core") == {"valid": set(), "new": set()}
client_session = MockClientSession(self.response)
asyncio.run(self.version_api.fetch("typo3/cms-core", client_session))
- assert self.version_api.get("typo3/cms-core") == self.expected_versions
+ assert self.version_api.cache["typo3/cms-core"] == self.expected_versions
class TestMavenVersionAPI(TestCase):
@classmethod
def setUpClass(cls):
cls.version_api = MavenVersionAPI()
- with open(os.path.join(TEST_DATA, "maven_api", "maven-metadata.xml")) as f:
- cls.response = ET.parse(f)
-
- with open(os.path.join(TEST_DATA, "maven_api", "maven-metadata.xml"), "rb") as f:
- cls.content = f.read()
+ with open(os.path.join(TEST_DATA, "maven_api", "easygcm.html"), "rb") as f:
+ data = f.read()
+ cls.response = BeautifulSoup(data)
+ cls.content = data
def test_artifact_url(self):
- eg_comps1 = ["org.apache", "kafka"]
- eg_comps2 = ["apple.msft.windows.mac.oss", "exfat-ntfs"]
+ eg_pkg1 = "org.apache:kafka"
+ eg_pkg2 = "apple.msft.windows.mac.oss:exfat-ntfs"
- url1 = self.version_api.artifact_url(eg_comps1)
- url2 = self.version_api.artifact_url(eg_comps2)
+ url1 = self.version_api.artifact_url(eg_pkg1)
+ url2 = self.version_api.artifact_url(eg_pkg2)
- assert "https://repo1.maven.org/maven2/org/apache/kafka/maven-metadata.xml" == url1
- assert (
- "https://repo1.maven.org/maven2"
- "/apple/msft/windows/mac/oss/exfat-ntfs/maven-metadata.xml" == url2
- )
+ assert "https://repo1.maven.org/maven2/org/apache/kafka/" == url1
+ assert "https://repo1.maven.org/maven2/apple/msft/windows/mac/oss/exfat-ntfs/" == url2
def test_extract_versions(self):
- expected_versions = {"1.2.2", "1.2.3", "1.3.0"}
+ expected_versions = {
+ Version(value="1.3.0", release_date=datetime(2015, 3, 12, 15, 20, tzinfo=UTC)),
+ Version(value="1.2.3", release_date=datetime(2014, 12, 22, 10, 53, tzinfo=UTC)),
+ Version(value="1.2.2", release_date=datetime(2014, 12, 22, 10, 29, tzinfo=UTC)),
+ }
assert expected_versions == self.version_api.extract_versions(self.response)
def test_fetch(self):
- assert self.version_api.get("org.apache:kafka") == set()
- expected = {"1.2.3", "1.3.0", "1.2.2"}
+ assert self.version_api.get("org.apache:kafka") == {"new": set(), "valid": set()}
+ expected = {
+ Version(value="1.2.2", release_date=datetime(2014, 12, 22, 10, 29, tzinfo=UTC)),
+ Version(value="1.3.0", release_date=datetime(2015, 3, 12, 15, 20, tzinfo=UTC)),
+ Version(value="1.2.3", release_date=datetime(2014, 12, 22, 10, 53, tzinfo=UTC)),
+ }
+
client_session = MockClientSession(self.content)
asyncio.run(self.version_api.fetch("org.apache:kafka", client_session))
- assert self.version_api.get("org.apache:kafka") == expected
+ assert self.version_api.cache["org.apache:kafka"] == expected
class TestNugetVersionAPI(TestCase):
@@ -191,20 +397,62 @@ def setUpClass(cls):
cls.response = json.load(f)
cls.expected_versions = {
- "0.23.0",
- "0.24.0",
- "1.0.0",
- "1.0.1",
- "1.0.2",
- "2.0.0",
- "2.0.0-preview01",
- "2.6.0",
- "2.1.0",
- "2.2.0",
- "2.3.0",
- "2.4.0",
- "2.5.0",
- "2.7.0",
+ Version(
+ value="1.0.0",
+ release_date=datetime(2018, 9, 13, 8, 16, 0, 420000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="1.0.1",
+ release_date=datetime(2020, 1, 17, 15, 31, 41, 857000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="1.0.2",
+ release_date=datetime(2020, 4, 21, 12, 24, 53, 877000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="2.0.0-preview01",
+ release_date=datetime(2018, 1, 9, 17, 12, 20, 440000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="2.0.0",
+ release_date=datetime(2018, 9, 27, 13, 33, 15, 370000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="2.1.0",
+ release_date=datetime(2018, 10, 16, 6, 59, 44, 680000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="2.2.0",
+ release_date=datetime(2018, 11, 23, 8, 13, 8, 3000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="2.3.0",
+ release_date=datetime(2019, 6, 27, 14, 27, 31, 613000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="2.4.0",
+ release_date=datetime(2020, 1, 17, 15, 11, 5, 810000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="2.5.0",
+ release_date=datetime(2020, 3, 24, 14, 22, 39, 960000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="2.7.0",
+ release_date=datetime(2020, 4, 21, 12, 27, 36, 427000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="2.6.0",
+ release_date=datetime(2020, 3, 27, 11, 6, 27, 500000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="0.24.0",
+ release_date=datetime(2018, 3, 30, 7, 25, 18, 393000, tzinfo=tzlocal()),
+ ),
+ Version(
+ value="0.23.0",
+ release_date=datetime(2018, 1, 17, 9, 32, 59, 283000, tzinfo=tzlocal()),
+ ),
}
def test_nuget_url(self):
@@ -219,13 +467,30 @@ def test_extract_versions(self):
def test_fetch(self):
- assert self.version_api.get("Exfat.Ntfs") == set()
+ assert self.version_api.get("Exfat.Ntfs") == {"new": set(), "valid": set()}
client_session = MockClientSession(self.response)
asyncio.run(self.version_api.fetch("Exfat.Ntfs", client_session))
- assert self.version_api.get("Exfat.Ntfs") == self.expected_versions
+ assert self.version_api.get("Exfat.Ntfs") == {
+ "new": set(),
+ "valid": {
+ "2.0.0",
+ "2.1.0",
+ "2.0.0-preview01",
+ "0.24.0",
+ "0.23.0",
+ "1.0.1",
+ "2.2.0",
+ "2.4.0",
+ "1.0.0",
+ "1.0.2",
+ "2.3.0",
+ "2.7.0",
+ "2.5.0",
+ "2.6.0",
+ },
+ }
# def test_load_to_api(self):
-
# assert self.version_api.get("Exfat.Ntfs") == set()
# mock_response = MagicMock()
diff --git a/vulnerabilities/tests/test_ruby.py b/vulnerabilities/tests/test_ruby.py
index 664f001ed..a666bc5ae 100644
--- a/vulnerabilities/tests/test_ruby.py
+++ b/vulnerabilities/tests/test_ruby.py
@@ -55,7 +55,7 @@ def setUpClass(cls):
@patch(
"vulnerabilities.package_managers.RubyVersionAPI.get",
- return_value={"1.0.0", "1.8.0", "2.0.3"},
+ return_value={"valid": {"1.0.0", "1.8.0", "2.0.3"}, "new": {}},
)
def test_process_file(self, mock_write):
expected_advisories = [
diff --git a/vulnerabilities/tests/test_rust.py b/vulnerabilities/tests/test_rust.py
index f563ccc5e..7a28150b8 100644
--- a/vulnerabilities/tests/test_rust.py
+++ b/vulnerabilities/tests/test_rust.py
@@ -30,23 +30,27 @@
from vulnerabilities.importers.rust import categorize_versions
from vulnerabilities.importers.rust import get_advisory_data
from vulnerabilities.importers.rust import RustDataSource
+from vulnerabilities.package_managers import Version
+from vulnerabilities.package_managers import CratesVersionAPI
from vulnerabilities.helpers import AffectedPackage
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
TEST_DATA = os.path.join(BASE_DIR, "test_data/rust")
-MOCKED_CRATES_API_VERSIONS = {
- "bitvec": {"0.10.0", "0.12.0", "0.18.0"},
- "bumpalo": {"2.8.0", "3.0.1", "3.2.5"},
- "cbox": {"0.10.0", "0.12.0", "0.18.0"},
- "flatbuffers": {"0.3.0", "0.5.0", "0.6.5"},
- "hyper": {"0.10.0", "0.12.0", "0.13.0"},
- "byte_struct": {"0.6.1", "0.6.0", "1.0.0"},
-}
+MOCKED_CRATES_API_VERSIONS = CratesVersionAPI(
+ cache={
+ "bitvec": {Version("0.10.0"), Version("0.12.0"), Version("0.18.0")},
+ "bumpalo": {Version("2.8.0"), Version("3.0.1"), Version("3.2.5")},
+ "cbox": {Version("0.10.0"), Version("0.12.0"), Version("0.18.0")},
+ "flatbuffers": {Version("0.3.0"), Version("0.5.0"), Version("0.6.5")},
+ "hyper": {Version("0.10.0"), Version("0.12.0"), Version("0.13.0")},
+ "byte_struct": {Version("0.6.1"), Version("0.6.0"), Version("1.0.0")},
+ }
+)
def test_categorize_versions():
- flatbuffers_versions = MOCKED_CRATES_API_VERSIONS["flatbuffers"]
+ flatbuffers_versions = MOCKED_CRATES_API_VERSIONS.get("flatbuffers")["valid"]
unaffected_ranges = [VersionSpecifier.from_scheme_version_spec_string("semver", "< 0.4.0")]
affected_ranges = [
diff --git a/vulnerabilities/tests/test_safety_db.py b/vulnerabilities/tests/test_safety_db.py
index 20bbc87b2..ddc78f9a7 100644
--- a/vulnerabilities/tests/test_safety_db.py
+++ b/vulnerabilities/tests/test_safety_db.py
@@ -22,16 +22,16 @@
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
import json
import os
-from unittest.mock import patch
from unittest import TestCase
from packageurl import PackageURL
-from vulnerabilities.importers.safety_db import PypiVersionAPI
from vulnerabilities.importers.safety_db import categorize_versions
from vulnerabilities.importers.safety_db import SafetyDbDataSource
from vulnerabilities.data_source import Advisory
from vulnerabilities.data_source import Reference
+from vulnerabilities.package_managers import PypiVersionAPI
+from vulnerabilities.package_managers import Version
from vulnerabilities.helpers import AffectedPackage
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -39,9 +39,16 @@
MOCK_VERSION_API = PypiVersionAPI(
cache={
- "ampache": {"2.0", "5.2.1"},
- "django": {"1.8", "1.4.19", "1.4.22", "1.5.1", "1.6.9", "1.8.14"},
- "zulip": {"2.0", "2.1.1", "2.1.2", "2.1.3"},
+ "ampache": {Version("2.0"), Version("5.2.1")},
+ "django": {
+ Version("1.8"),
+ Version("1.4.19"),
+ Version("1.4.22"),
+ Version("1.5.1"),
+ Version("1.6.9"),
+ Version("1.8.14"),
+ },
+ "zulip": {Version("2.0"), Version("2.1.1"), Version("2.1.2"), Version("2.1.3")},
}
)