def _get_version_rules(self, vuln_versions): """Version rules for all eco.""" rules = [] regex_op = "[0-9a-zA-Z\\_\\.\\-]+" regex_vr = "[<>=*]+" """For all the vulnerable versions information that we get, we need to create comparable version object so that we can apply these rules on top of all the available versions of a pkg in the market.""" for version in vuln_versions: version = version.replace(" ", "") sub_vers = version.split('||') for sub_ver in sub_vers: tmp = [] vr_relations = re.split(regex_vr, sub_ver) op_relations = re.split(regex_op, sub_ver) # Single affected version. if len(vr_relations) == 1: tmp.append({ 'key': "=", 'val': ComparableVersion(vr_relations[0]) }) # All versions affected. elif len(op_relations) == 1 and op_relations[0] == '*': tmp.append({'key': "*", 'val': ""}) else: for i in range(len(op_relations) - 1): tmp.append({ 'key': op_relations[i], 'val': ComparableVersion(vr_relations[i + 1]) }) rules.append(tmp) return rules
def test_ge_operator(): """Test the >= operator.""" c1 = ComparableVersion('2.0.0') c2 = ComparableVersion('1.0.0') assert c1 >= c2 # ComparableVersion >= None assert c1 >= None assert c2 >= None c3 = ComparableVersion('1.0.0') assert c3 >= c2
def test_le_operator(): """Test the <= operator.""" c1 = ComparableVersion('1.0.0') c2 = ComparableVersion('2.0.0') assert c1 <= c2 # ComparableVersion <= None assert not c1 <= None assert not c2 <= None c3 = ComparableVersion('2.0.0') assert c2 <= c3
def test_init(): """Test ComparableVersion objects `__init__` method.""" # should work version = '1.0.0' v = ComparableVersion(version) # actually should not happen for proper constructor assert v is not None # both should raise with pytest.raises(TypeError): _ = ComparableVersion(None) assert _ is not None _ = ComparableVersion(1.0) assert _ is not None
def test_is_relation_applicable(): """Test is_relation_applicable.""" # Test lt operator res = scs._is_relation_applicable('<', '1.2', ComparableVersion('1.4')) assert res is True res = scs._is_relation_applicable('<', '1.4', ComparableVersion('1.4')) assert res is False # Test gt operator res = scs._is_relation_applicable('>', '1.4', ComparableVersion('1.4')) assert res is False res = scs._is_relation_applicable('>', '1.5', ComparableVersion('1.4')) assert res is True # Test gte operator res = scs._is_relation_applicable('>=', '1.4', ComparableVersion('1.4')) assert res is True # Test lte operator res = scs._is_relation_applicable('<=', '1.4', ComparableVersion('1.4')) assert res is True # Test eq operator res = scs._is_relation_applicable('=', '1.4', ComparableVersion('1.4')) assert res is True # Test universal operator res = scs._is_relation_applicable('*', '1.9', ComparableVersion('')) assert res is True
def _is_relation_applicable(self, key, version, rule): """Check if the version satisfies the relation.""" if key == '<': return ComparableVersion(version) < rule elif key == '>': return ComparableVersion(version) > rule elif key == '=': return ComparableVersion(version) == rule elif key == '<=': return ComparableVersion(version) <= rule elif key == '>=': return ComparableVersion(version) >= rule elif key == '*': return True return False
def select_latest_version(versions=[]): """Select latest version from list.""" version_arr = [] for x in versions: version_arr.append(ComparableVersion(x)) version_arr.sort() return version_arr[-1]
def test_repr(): """Test ComparableVersion objects `__repr__` method.""" version = '1.0.0' expected_repr = "ComparableVersion(version={!r})".format(version) assert repr( ComparableVersion(version)) == expected_repr, "Invalid representation."
def classify_versions(upstream_versions, version_ranges): """Classify versions as affected and unaffected. :param upstream_versions: list[str], list of upstream versions :param version_ranges: list[[VersionRange]], list of CVE version ranges :return: list[ClassifiedVersion] sorted list of classified upstream versions """ sorted_upstream_versions = [ ComparableVersion(x) for x in upstream_versions ] sorted_upstream_versions.sort() # list of sorted upstream versions represented as "classified versions", # all versions are unaffected by default classified_versions = [ ClassifiedVersion(x.version, False) for x in sorted_upstream_versions ] for classified_version in classified_versions: benev_upstream_version = BenevolentVersion(classified_version.version) for version_range in version_ranges: if version_range.contains(benev_upstream_version.exact, cmp_class=BenevolentVersion): # the version is within the range so it is affected, mark it as such classified_version.is_affected = True break return classified_versions
def check_version_different_order(v1, v2): """Check order of versions, the first version must be greater that the second.""" c = ComparableVersion(v1) c1 = ComparableVersion(v2) # check using `compare_to` method res = c.compare_to(c1) assert res is not None assert res == 1, "{} is less than {}".format(v1, v2) # check using `compare_to` method and version string res = c.compare_to(v2) assert res is not None assert res == 1, "{} is less than {}".format(v1, v2) # check using rich comparison assert c > c1, "rich comparison: {} is not greater than {}".format(v1, v2)
def check_version_equal(v1, v2): """Check if versions are equal.""" c = ComparableVersion(v1) c1 = ComparableVersion(v2) # check using `compare_to` method res = c.compare_to(c1) assert res is not None assert res == 0, "{} is not equal to {}".format(v1, v2) # check using `compare_to` method and version string res = c.compare_to(v2) assert res is not None assert res == 0, "{} is not equal to {}".format(v1, v2) # check using rich comparison assert c == c1, "rich comparison: {} is not equal to {}".format(v1, v2)
def check_version_order(v1, v2): """Check order of versions.""" c = ComparableVersion(v1) c1 = ComparableVersion(v2) # check using `compare_to` method res = c.compare_to(c1) assert res is not None assert res == -1, "{} is greater than {}".format(v1, v2) # check using `compare_to` method and version string res = c.compare_to(v2) assert res is not None assert res == -1, "{} is greater than {}".format(v1, v2) # check using rich comparison assert c < c1, "rich comparison: {} is not lower than {}".format(v1, v2)
def test_eq_operator(): """Test the == operator.""" version = '1.0.0' c1 = ComparableVersion(version) c2 = ComparableVersion(version) assert c1 == c2 # ComparableVersion == None assert not c1 == None # noqa - because we really want to use == here version = '2.5.3-alpha' c3 = ComparableVersion(version) c4 = ComparableVersion(version) assert c3 == c4 # ComparableVersion == None assert not c3 == None # noqa - because we really want to use == here
def __select_latest_version(self, versions=[]): """Select latest version from list.""" if len(versions) == 0: return "" version_arr = [] for x in versions: version_arr.append(ComparableVersion(x)) version_arr.sort() return str(version_arr[-1])
def test_ne_operator(): """Test the != operator.""" version1 = '1.0.0' version2 = '2.0.0' c1 = ComparableVersion(version1) c2 = ComparableVersion(version2) assert c1 != c2 # ComparableVersion != None assert c1 != None # noqa - because we really want to use != here version1 = '2.5.3-alpha' version2 = '1.5.3-alpha' c3 = ComparableVersion(version1) c4 = ComparableVersion(version2) assert c3 != c4 # ComparableVersion != None assert c3 != None # noqa - because we really want to use != here
def get_version_without_cves(self, latest_non_cve_versions): """Return higher version which doesn't have any CVEs. None if there is no such version. :return: Highest Version out of all latest_non_cve_versions. """ highest_version = '' try: input_version_comparable = ComparableVersion(self.version) # latest non-cve is list with only one entry. latest_non_cve_version_comparable = ComparableVersion(latest_non_cve_versions[0]) except TypeError: logger.error("Package %s@%s raised a TypeError", self.package, self.version) else: if latest_non_cve_version_comparable > input_version_comparable: highest_version = latest_non_cve_versions[0] logger.info("Highest non-cve version for %s@%s is %s", self.package, self.version, highest_version) return highest_version
def test_lt_operator(): """Test the < operator.""" version = '1.0.0' c1 = ComparableVersion(version) version = '2.0.0' c2 = ComparableVersion(version) assert c1 < c2 # ComparableVersion < None assert not c1 < None assert not c2 < None version = '2.1.1' c3 = ComparableVersion(version) assert c2 < c3 # transitivity check assert c1 < c3 # ComparableVersion < None assert not c3 < None
def __init__(self, version_str): self._version_str = version_str.strip() # https://github.com/victims/victims-cve-db#version-string-common result = re.fullmatch(r'^[><=]{1}=[^, ]+(,[^, ]+)?$', version_str.strip()) if result is None: raise ParseError( 'Invalid version string: {vs}'.format(vs=version_str)) self._operator = self._version_str[:2] if ',' in self._version_str: self._version = ComparableVersion( self._version_str[2:].split(',')[0]) self._explicit_boundary = ComparableVersion( self._version_str.split(',')[1]) else: self._version = ComparableVersion(self._version_str[2:]) self._explicit_boundary = None
def test_gt_operator(): """Test the > operator.""" version = '2.0.0' c1 = ComparableVersion(version) version = '1.0.0' c2 = ComparableVersion(version) assert c1 > c2 # ComparableVersion < None assert c1 > None assert c2 > None version = '2.1.1' c3 = ComparableVersion(version) assert c3 > c2 # transitivity check assert c3 > c1 # ComparableVersion > None assert c3 > None
def test_parse_version(): """Test the method to parse version.""" c = ComparableVersion("1") itemlist = c.items.get_list() assert len(itemlist) == 1 assert str(itemlist[0]) == "1" c = ComparableVersion("1.2") itemlist = c.items.get_list() assert len(itemlist) == 2 assert str(itemlist[0]) == "1" assert str(itemlist[1]) == "2" c = ComparableVersion("1-2") itemlist = c.items.get_list() assert len(itemlist) == 2 c = ComparableVersion(".2") itemlist = c.items.get_list() assert len(itemlist) == 2 c = ComparableVersion("-2") itemlist = c.items.get_list() assert len(itemlist) == 1
def test_comparisons_wrong_type(): """Test function compare_to.""" v1 = "1.0.0" c = ComparableVersion(v1) # check the TypeError with pytest.raises(TypeError): c.compare_to(None) c.compare_to(True) c.compare_to(False) c.compare_to([]) c.compare_to({}) c.compare_to(42) c.compare_to(3.14) c.compare_to(1 + 2j)
def __contains__(self, version): """Return True if `checked_version` is among `affected_versions`.""" checked_version = ComparableVersion(version) # TODO: we are probably missing '>=' here; but do we need it? if self._operator == '==': if checked_version == self._version: return True elif self._operator == '<=': if self._explicit_boundary: if self._explicit_boundary <= checked_version <= self._version: return True else: if checked_version <= self._version: return True return False
def test_parse_item(): """Test the method to parse item.""" c = ComparableVersion("2") p1 = c.parse_item(False, "StringItem") assert p1 is not None assert str(p1) == "StringItem" p2 = c.parse_item(True, "0") assert p2 is not None assert str(p2) == "0" # try to parse empty string (which is definitely not a number) with pytest.raises(ValueError) as e: p3 = c.parse_item(True, "") # try to parse string that does not contain a number with pytest.raises(ValueError) as e: p3 = c.parse_item(True, "foobar")
def test_str(): """Test ComparableVersion objects `__str__` method.""" version = '1.0.0' assert str( ComparableVersion(version)) == version, "Invalid string conversion."
def test_gt_operator(): """Test the > operator.""" version = '2.0.0' c1 = ComparableVersion(version) version = '1.0.0' c2 = ComparableVersion(version) assert c1 > c2 # ComparableVersion < None assert c1 > None assert c2 > None version = '2.1.1' c3 = ComparableVersion(version) assert c3 > c2 # transitivity check assert c3 > c1 # ComparableVersion > None assert c3 > None gt_data = [ { 'v1': '1.1.1', 'v2': '1.1', }, { 'v1': '1.1', 'v2': '1.0.9', }, { 'v1': '1.5.0.2', 'v2': '1.5.0.1', }, { 'v1': '2.0.rc1', 'v2': '2.0.rc0', }, { 'v1': '11.5.4.0', 'v2': '10.4.5', }, { 'v1': '11.5.4.3', 'v2': '11.5.4.2', }, { 'v1': '1.5-2.RELEASE', 'v2': '1.5-1', }, { 'v1': '1.5-2.RELEASE', 'v2': '1.5-1.RELEASE', }, { 'v1': '1.5.2.RELEASE', 'v2': '1.5.1', }, { 'v1': '1.5.2.RELEASE', 'v2': '1.5.1.RELEASE', }, { 'v1': '0.0.0-20201203092726-db298ee30ce6', 'v2': '0.0.0-20201203092725-db298ee30ce6', }, { 'v1': '1.0.0-20201203092720-db298ee30ce6', 'v2': '0.0.0-20201203092725-db298ee30ce6', }, { 'v1': '1.4.1', 'v2': 'upstream/1.0.1', }, { 'v1': '1.40.1', 'v2': 'kubernetes-1.14.0-beta.1', }, ] invalid_c = ComparableVersion('-1') for d in gt_data: c1 = ComparableVersion(d['v1']) c2 = ComparableVersion(d['v2']) assert c1 > c2 # Version must be greated than invalid assert c1 > invalid_c
def test_parse_version(): """Test the method to parse version.""" c = ComparableVersion("1") itemlist = c.items.get_list() assert len(itemlist) == 1 assert str(itemlist[0]) == "1" c = ComparableVersion("1.2") itemlist = c.items.get_list() assert len(itemlist) == 2 assert str(itemlist[0]) == "1" assert str(itemlist[1]) == "2" c = ComparableVersion("1-2") itemlist = c.items.get_list() assert len(itemlist) == 2 c = ComparableVersion(".2") itemlist = c.items.get_list() assert len(itemlist) == 2 c = ComparableVersion("-2") itemlist = c.items.get_list() assert len(itemlist) == 1 c = ComparableVersion("-1") itemlist = c.items.get_list() assert len(itemlist) == 1 assert len(itemlist[0].get_list()) == 1 assert str(itemlist[0].get_list()[0]) == "1" c = ComparableVersion("INVALID_VERSION") itemlist = c.items.get_list() assert len(itemlist) == 1 assert itemlist[0].to_string() == "invalid_version" c = ComparableVersion("upstream/1.0.3") itemlist = c.items.get_list() assert len(itemlist) == 2 assert itemlist[0].to_string() == "upstream/" assert len(itemlist[1].get_list()) == 3 assert itemlist[1].get_list()[0].to_string() == "1" assert itemlist[1].get_list()[1].to_string() == "0" assert itemlist[1].get_list()[2].to_string() == "3" c = ComparableVersion("kubernetes-1.14.0-beta.1") itemlist = c.items.get_list() assert len(itemlist) == 2 assert itemlist[0].to_string() == "kubernetes" assert len(itemlist[1].get_list()) == 3 assert itemlist[1].get_list()[0].to_string() == "1" assert itemlist[1].get_list()[1].to_string() == "14" assert len(itemlist[1].get_list()[2].get_list()) == 2 assert itemlist[1].get_list()[2].get_list()[0].to_string() == "beta" assert itemlist[1].get_list()[2].get_list()[1].to_string() == "1" c = ComparableVersion("1.5.2.RELEASE") itemlist = c.items.get_list() assert len(itemlist) == 4 assert itemlist[0].to_string() == "1" assert itemlist[1].to_string() == "5" assert itemlist[2].to_string() == "2" assert itemlist[3].to_string() == "release" c = ComparableVersion("1.5-2.RELEASE") itemlist = c.items.get_list() assert len(itemlist) == 3 assert itemlist[0].to_string() == "1" assert itemlist[1].to_string() == "5" assert len(itemlist[2].get_list()) == 2 assert itemlist[2].get_list()[0].to_string() == "2" assert itemlist[2].get_list()[1].to_string() == "release" c = ComparableVersion("2.0.rc1") itemlist = c.items.get_list() assert len(itemlist) == 4 assert itemlist[0].to_string() == "2" assert itemlist[1].to_string() == "0" assert itemlist[2].to_string() == "rc" assert len(itemlist[3].get_list()) == 1 assert itemlist[3].get_list()[0].to_string() == "1" c = ComparableVersion("11.5.4.0") itemlist = c.items.get_list() assert len(itemlist) == 3 assert itemlist[0].to_string() == "11" assert itemlist[1].to_string() == "5" assert itemlist[2].to_string() == "4" c = ComparableVersion("1.6.8-20201203092725-db298ee30ce6") itemlist = c.items.get_list() assert len(itemlist) == 4 assert itemlist[0].to_string() == "1" assert itemlist[1].to_string() == "6" assert itemlist[2].to_string() == "8" assert len(itemlist[3].get_list()) == 2 assert itemlist[3].get_list()[0].to_string() == "20201203092725" assert itemlist[3].get_list()[1].get_list()[0].to_string() == "db" assert itemlist[3].get_list()[1].get_list()[1].get_list()[0].to_string( ) == "298" assert itemlist[3].get_list()[1].get_list()[1].get_list()[1].get_list( )[0].to_string() == "ee" sub_list = itemlist[3].get_list()[1].get_list()[1].get_list()[1].get_list( )[1] assert sub_list.get_list()[0].to_string() == "30" assert sub_list.get_list()[1].get_list()[0].to_string() == "ce" assert sub_list.get_list()[1].get_list()[1].get_list()[0].to_string( ) == "6" c = ComparableVersion("1.6.0-20201203092725-db1234567890") itemlist = c.items.get_list() assert len(itemlist) == 3 assert itemlist[0].to_string() == "1" assert itemlist[1].to_string() == "6" assert len(itemlist[2].get_list()) == 2 assert itemlist[2].get_list()[0].to_string() == "20201203092725" assert itemlist[2].get_list()[1].get_list()[0].to_string() == "db" assert itemlist[2].get_list()[1].get_list()[1].get_list()[0].to_string( ) == "1234567890" c = ComparableVersion("0.0.0-20201203092725-db1234567890") itemlist = c.items.get_list() assert len(itemlist) == 1 assert len(itemlist[0].get_list()) == 2 assert itemlist[0].get_list()[0].to_string() == "20201203092725" assert itemlist[0].get_list()[1].get_list()[0].to_string() == "db" assert itemlist[0].get_list()[1].get_list()[1].get_list()[0].to_string( ) == "1234567890"
def check_version_order(v1, v2): """Check order of versions.""" c = ComparableVersion(v1) c1 = ComparableVersion(v2) res = c.compare_to(c1) assert res == -1, "{} is greater than {}".format(v1, v2)
def check_version_different_order(v1, v2): """Check order of versions, the first version must be greater that the second.""" c = ComparableVersion(v1) c1 = ComparableVersion(v2) res = c.compare_to(c1) assert res == 1, "{} is less than {}".format(v1, v2)
def check_version_equal(v1, v2): """Check if versions are equal.""" c = ComparableVersion(v1) c1 = ComparableVersion(v2) res = c.compare_to(c1) assert res == 0, "{} is not equal to {}".format(v1, v2)