def test_from_with_nvd(self, test_input): match = VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), ) match.nvd = test_input identity_objects = VulnerabilityIdentity.from_match(match) assert identity_objects assert isinstance(identity_objects, list) and len(identity_objects) == len( test_input ) for identity_object, input_nvd in zip(identity_objects, test_input): assert identity_object.vuln_id == input_nvd.vulnerability_id assert identity_object.pkg_name == match.artifact.name assert identity_object.pkg_type == match.artifact.pkg_type assert identity_object.pkg_version == match.artifact.version assert identity_object.pkg_path == match.artifact.location
def test_transfer_vulnerability_timestamps_fix_observed_at( self, test_source, test_destination, expected ): random = VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), match=Match(detected_at=datetime.datetime.utcnow()), ) source = copy.deepcopy(random) source.fix = test_source destination = copy.deepcopy(random) destination.fix = test_destination results = transfer_vulnerability_timestamps( source=[source], destination=[destination] ) assert results and len(results) == 1 assert results[0].fix.observed_at == expected
def test_transfer_vulnerability_timestamps_single( self, test_source, test_destination ): random = VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), fix=FixedArtifact(), ) source = copy.deepcopy(random) source.match = Match(detected_at=test_source) destination = copy.deepcopy(random) destination.match = Match(detected_at=test_destination) results = transfer_vulnerability_timestamps( source=[source], destination=[destination] ) assert results and len(results) == 1 assert results[0].match.detected_at == test_source
def test_from(self): match = VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ) rank_strategy = FeedGroupRank() ranked_match = RankedVulnerabilityMatch.from_match(match, FeedGroupRank()) assert ranked_match assert ranked_match.vuln_id == match.vulnerability.vulnerability_id assert ranked_match.vuln_namespace == match.vulnerability.feed_group assert ranked_match.pkg_name == match.artifact.name assert ranked_match.pkg_type == match.artifact.pkg_type assert ranked_match.pkg_version == match.artifact.version assert ranked_match.pkg_path == match.artifact.location assert ranked_match.rank == rank_strategy.__default__
def to_engine( self, result: Dict, package_mapper: PackageMapper, now: datetime.datetime, ): artifact_dict = result.get("artifact") vuln_dict = result.get("vulnerability") # parse cvss fields cvss_objs = VulnerabilityMapper._try_parse_cvss( vuln_dict.get("cvss", [])) # parse fix details fix_dict = vuln_dict.get("fix") fix_obj = FixedArtifact(versions=[], wont_fix=False, observed_at=None, advisories=[]) if fix_dict: fix_obj.versions = fix_dict.get("versions", []) fix_obj.wont_fix = (fix_dict.get("state").lower() == "wont-fix" ) # TODO format check with toolbox fix_obj.observed_at = now if fix_obj.versions else None fix_obj.advisories = VulnerabilityMapper._try_parse_advisories( fix_dict.get("advisories", [])) # parse nvd references nvd_objs = VulnerabilityMapper._try_parse_related_vulnerabilities( result.get("relatedVulnerabilities", [])) # parse package path pkg_path = (artifact_dict.get("locations")[0].get("path") if artifact_dict.get("locations") else "NA") vuln_match = VulnerabilityMatch( vulnerability=Vulnerability( vulnerability_id=vuln_dict.get("id"), description=vuln_dict.get("description"), severity=vuln_dict.get("severity"), link=vuln_dict.get("dataSource"), feed="grypedb", feed_group=vuln_dict.get("namespace"), cvss=cvss_objs, ), artifact=Artifact( name=artifact_dict.get("name"), version=artifact_dict.get("version"), pkg_type=package_mapper.engine_type, location=pkg_path, cpe=None, # vestige of the old system cpes=self._try_parse_matched_cpes(result), ), fix=fix_obj, match=Match(detected_at=now), nvd=nvd_objs, ) return vuln_match
def test_hash_empty_match(self, count): record = RankedVulnerabilityMatch( vuln_id="meh", vuln_namespace="trusty:chameleon", pkg_name="blah", pkg_version="1.2.3maven", pkg_type="java", pkg_path="blah", rank=100, match_obj=VulnerabilityMatch(), ) test_input = [record for x in range(count)] result = set(test_input) assert result and len(result) == 1
def test_filter_vulnerability_matches_namespace(self, test_input, test_filter, expected_output): vuln_match = VulnerabilityMatch( vulnerability=Vulnerability(vulnerability_id="CVE-xyz", feed_group=test_input), artifact=Artifact(name="foo"), ) results = GrypeProvider._filter_vulnerability_matches( matches=[vuln_match], vulnerability_id="CVE-xyz", severity_filter=None, namespace_filter=test_filter, affected_package_filter=None, vendor_only=None, ) assert results == expected_output
def test_filter_vulnerability_matches_no_optional_filters( self, test_input, expected_output): vuln_match = VulnerabilityMatch( vulnerability=test_input, artifact=Artifact( name="foo", version="0.0", pkg_type="bar", location="/usr/local/lib", ), ) results = GrypeProvider._filter_vulnerability_matches( matches=[vuln_match], vulnerability_id="CVE-xyz", severity_filter=None, namespace_filter=None, affected_package_filter=None, vendor_only=None, ) assert results == expected_output
def test_execute_absolute_duplicates(self, count): a = VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ) input_matches = [a for x in range(count)] results = ImageVulnerabilitiesDeduplicator(FeedGroupRank()).execute( input_matches ) assert len(results) == 1
[ VulnerabilityMatch.from_json({ "artifact": { "cpe": None, "cpes": [], "location": "/usr/lib/python3.8/site-packages/aiohttp", "name": "aiohttp", "pkg_type": "python", "version": "3.7.3", }, "fix": { "advisories": [], "observed_at": "2021-03-31T17:30:49Z", "versions": ["3.7.4"], "wont_fix": False, }, "match": { "detected_at": "2021-06-07T20:20:47Z" }, "nvd": [], "vulnerability": { "cvss": [], "description": None, "feed": "vulnerabilities", "feed_group": "github:python", "link": "https://github.com/advisories/GHSA-v6wp-4m6f-gcjg", "severity": "Low", "vulnerability_id": "GHSA-v6wp-4m6f-gcjg", }, }) ],
class TestGrypeProvider: @pytest.mark.parametrize( "test_input", [ pytest.param( [VulnerabilityMatch(fix=FixedArtifact(wont_fix="true"))], id="str", ), pytest.param( [VulnerabilityMatch(fix=FixedArtifact(wont_fix=" "))], id="whitespace", ), pytest.param( [VulnerabilityMatch(fix=FixedArtifact(wont_fix=""))], id="blank", ), pytest.param( [VulnerabilityMatch(fix=FixedArtifact(wont_fix=False))], id="boolean_false", ), pytest.param( [VulnerabilityMatch(fix=None)], id="fix_none", ), ], ) def test_exclude_wont_fix_false(self, test_input): assert len(GrypeProvider._exclude_wont_fix(test_input)) == 1 @pytest.mark.parametrize( "test_input", [ pytest.param( [VulnerabilityMatch(fix=FixedArtifact(wont_fix=True))], id="boolean_true", ), ], ) def test_exclude_wont_fix_true(self, test_input): assert len(GrypeProvider._exclude_wont_fix(test_input)) == 0 @pytest.mark.parametrize( "test_input, expected_output", [ pytest.param( Vulnerability(vulnerability_id="CVE-xyz"), [{ "name": "foo", "version": "0.0", "type": "bar", "namespace": None, "severity": None, }], id="match-1", ), pytest.param( Vulnerability(vulnerability_id="CVE-xyz", severity="Critical", feed_group="meh"), [{ "name": "foo", "version": "0.0", "type": "bar", "namespace": "meh", "severity": "Critical", }], id="match-2", ), pytest.param( Vulnerability(vulnerability_id="CVE-pqr", severity="Critical", feed_group="meh"), [], id="no-match", ), ], ) def test_filter_vulnerability_matches_no_optional_filters( self, test_input, expected_output): vuln_match = VulnerabilityMatch( vulnerability=test_input, artifact=Artifact( name="foo", version="0.0", pkg_type="bar", location="/usr/local/lib", ), ) results = GrypeProvider._filter_vulnerability_matches( matches=[vuln_match], vulnerability_id="CVE-xyz", severity_filter=None, namespace_filter=None, affected_package_filter=None, vendor_only=None, ) assert results == expected_output @pytest.mark.parametrize( "test_input, test_filter, expected_output", [ pytest.param( True, False, [{ "name": "foo", "version": None, "type": None, "namespace": None, "severity": None, }], id="wontfix-true_vendoronly_false", ), pytest.param( False, False, [{ "name": "foo", "version": None, "type": None, "namespace": None, "severity": None, }], id="wontfix-false_vendoronly_false", ), pytest.param( False, True, [{ "name": "foo", "version": None, "type": None, "namespace": None, "severity": None, }], id="wontfix-false_vendoronly_true", ), pytest.param( True, True, [], id="wontfix-true_vendoronly_true", ), ], ) def test_filter_vulnerability_matches_vendor_only(self, test_input, test_filter, expected_output): vuln_match = VulnerabilityMatch( vulnerability=Vulnerability(vulnerability_id="CVE-xyz"), artifact=Artifact(name="foo"), fix=FixedArtifact(wont_fix=test_input), ) results = GrypeProvider._filter_vulnerability_matches( matches=[vuln_match], vulnerability_id="CVE-xyz", severity_filter=None, namespace_filter=None, affected_package_filter=None, vendor_only=test_filter, ) assert results == expected_output @pytest.mark.parametrize( "test_input, test_filter, expected_output", [ pytest.param( "High", "Critical", [], id="no-match", ), pytest.param( "High", "High", [{ "name": "foo", "version": None, "type": None, "namespace": None, "severity": "High", }], id="match", ), ], ) def test_filter_vulnerability_matches_severity(self, test_input, test_filter, expected_output): vuln_match = VulnerabilityMatch( vulnerability=Vulnerability(vulnerability_id="CVE-xyz", severity=test_input), artifact=Artifact(name="foo"), ) results = GrypeProvider._filter_vulnerability_matches( matches=[vuln_match], vulnerability_id="CVE-xyz", severity_filter=test_filter, namespace_filter=None, affected_package_filter=None, vendor_only=None, ) assert results == expected_output @pytest.mark.parametrize( "test_input, test_filter, expected_output", [ pytest.param( "foo", "bar", [], id="no-match", ), pytest.param( "meh", "meh", [{ "name": "foo", "version": None, "type": None, "namespace": "meh", "severity": None, }], id="match", ), ], ) def test_filter_vulnerability_matches_namespace(self, test_input, test_filter, expected_output): vuln_match = VulnerabilityMatch( vulnerability=Vulnerability(vulnerability_id="CVE-xyz", feed_group=test_input), artifact=Artifact(name="foo"), ) results = GrypeProvider._filter_vulnerability_matches( matches=[vuln_match], vulnerability_id="CVE-xyz", severity_filter=None, namespace_filter=test_filter, affected_package_filter=None, vendor_only=None, ) assert results == expected_output
def test_transfer_vulnerability_timestamps_multiple(self): dest_ts = datetime.datetime.utcnow() src_ts = datetime.datetime.utcnow() - datetime.timedelta(days=1) destination = [ VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), match=Match(detected_at=dest_ts), fix=FixedArtifact(), ), VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="foo", ), match=Match(detected_at=dest_ts), fix=FixedArtifact(), ), ] source = [ VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), match=Match(detected_at=src_ts), fix=FixedArtifact(), ) ] results = transfer_vulnerability_timestamps( source=source, destination=destination ) assert results and len(results) == 2 for result in results: if ( result.vulnerability.vulnerability_id == source[0].vulnerability.vulnerability_id ): assert result.match.detected_at == src_ts else: assert result.match.detected_at == dest_ts
class TestImageVulnerabilitiesDeduplicator: @pytest.mark.parametrize( "test_input, expected_index", [ pytest.param( [ VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="nvdv2:cves", vulnerability_id="CVE-2019-12904", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="ubuntu:20.04", vulnerability_id="CVE-2019-12904", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ), ], 1, id="different-namespaces", ), pytest.param( [ VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="nvdv2:cves", vulnerability_id="CVE-2019-12904", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="github:java", vulnerability_id="GHSA-foobar", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ), ], 1, id="different-identifiers", ), pytest.param( [ VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="github:java", vulnerability_id="GHSA-foobar", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="ubuntu:20.04", vulnerability_id="CVE-2019-12904", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ), ], 1, id="non-nvd-namespaces", ), pytest.param( [ VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="nvdv2:cves", vulnerability_id="CVE-2019-12904", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="ubuntu:20.04", vulnerability_id="CVE-2019-12904", ), nvd=[], ), ], 1, id="no-nvd-refs", ), pytest.param( [ VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="nvdv2:cves", vulnerability_id="CVE-2019-12904", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12345")], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="nvdv2:cves", vulnerability_id="CVE-2019-12904", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="vulnerabilities", feed_group="github:java", vulnerability_id="GHSA-foobar", ), nvd=[ NVDReference(vulnerability_id="CVE-2019-12904"), NVDReference(vulnerability_id="CVE-2019-12345"), ], ), ], 2, id="multiple-nvd-refs", ), ], ) def test_execute(self, test_input, expected_index): artifact = Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ) for item in test_input: item.artifact = artifact results = ImageVulnerabilitiesDeduplicator(FeedGroupRank()).execute(test_input) assert len(results) == 1 actual = results[0].vulnerability expected = test_input[expected_index] assert actual.vulnerability_id == expected.vulnerability.vulnerability_id assert actual.feed_group == expected.vulnerability.feed_group @pytest.mark.parametrize("count", [1, 2, 3, 4, 5]) def test_execute_absolute_duplicates(self, count): a = VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-2019-12904")], ) input_matches = [a for x in range(count)] results = ImageVulnerabilitiesDeduplicator(FeedGroupRank()).execute( input_matches ) assert len(results) == 1 @pytest.mark.parametrize( "test_input", [pytest.param([], id="empty-list"), pytest.param(None, id="none")], ) def test_execute_invalid_input(self, test_input): assert ( ImageVulnerabilitiesDeduplicator(FeedGroupRank()).execute(test_input) == list() )
class TestVulnerabilityIdentity: @pytest.mark.parametrize( "test_input", [ pytest.param( [NVDReference(vulnerability_id="CVE-abc")], id="single-nvd", ), pytest.param( [ NVDReference(vulnerability_id="CVE-abc"), NVDReference(vulnerability_id="CVE-def"), NVDReference(vulnerability_id="CVE-ghi"), ], id="multiple-nvd", ), ], ) def test_from_with_nvd(self, test_input): match = VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), ) match.nvd = test_input identity_objects = VulnerabilityIdentity.from_match(match) assert identity_objects assert isinstance(identity_objects, list) and len(identity_objects) == len( test_input ) for identity_object, input_nvd in zip(identity_objects, test_input): assert identity_object.vuln_id == input_nvd.vulnerability_id assert identity_object.pkg_name == match.artifact.name assert identity_object.pkg_type == match.artifact.pkg_type assert identity_object.pkg_version == match.artifact.version assert identity_object.pkg_path == match.artifact.location def test_from_without_nvd(self): match = VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), nvd=[], ) identity_objects = VulnerabilityIdentity.from_match(match) assert identity_objects assert isinstance(identity_objects, list) and len(identity_objects) == 1 identity_object = identity_objects[0] assert identity_object.vuln_id == match.vulnerability.vulnerability_id assert identity_object.pkg_name == match.artifact.name assert identity_object.pkg_type == match.artifact.pkg_type assert identity_object.pkg_version == match.artifact.version assert identity_object.pkg_path == match.artifact.location @pytest.mark.parametrize( "lhs, rhs, expected", [ pytest.param( VulnerabilityMatch( vulnerability=Vulnerability( feed="trusty", feed_group="trusty:chameleon", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), VulnerabilityMatch( Vulnerability( feed="hedgehog", feed_group="hedgy:thorny", vulnerability_id="foo", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), True, id="equal-different-namespaces", ), pytest.param( VulnerabilityMatch( vulnerability=Vulnerability( feed="trusty", feed_group="trusty:chameleon", vulnerability_id="meh", ), nvd=[ NVDReference(vulnerability_id="CVE-abc"), NVDReference(vulnerability_id="CVE-def"), NVDReference(vulnerability_id="CVE-ghi"), ], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="hedgehog", feed_group="hedgy:thorny", vulnerability_id="foo", ), nvd=[ NVDReference(vulnerability_id="CVE-abc"), NVDReference(vulnerability_id="CVE-def"), NVDReference(vulnerability_id="CVE-ghi"), ], ), True, id="equal-multiple-cvss", ), pytest.param( VulnerabilityMatch( vulnerability=Vulnerability( feed="trusty", feed_group="trusty:chameleon", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="hedgehog", feed_group="hedgy:thorny", vulnerability_id="foo", ), nvd=[NVDReference(vulnerability_id="CVE-def")], ), False, id="not-equal", ), ], ) def test_equality_constant_artifact(self, lhs, rhs, expected): artifact = Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ) lhs.artifact = artifact rhs.artifact = artifact assert ( VulnerabilityIdentity.from_match(lhs) == VulnerabilityIdentity.from_match(rhs) ) == expected @pytest.mark.parametrize("count", [1, 2, 3, 4, 5]) def test_hash(self, count): record = VulnerabilityIdentity( vuln_id="meh", pkg_name="blah", pkg_version="1.2.3maven", pkg_type="java", pkg_path="blah", ) test_input = [record for x in range(count)] result = set(test_input) assert result and len(result) == 1
class TestRankedVulnerabilityMatch: def test_from(self): match = VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="vulnerabilities", feed_group="whatever:hello", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ) rank_strategy = FeedGroupRank() ranked_match = RankedVulnerabilityMatch.from_match(match, FeedGroupRank()) assert ranked_match assert ranked_match.vuln_id == match.vulnerability.vulnerability_id assert ranked_match.vuln_namespace == match.vulnerability.feed_group assert ranked_match.pkg_name == match.artifact.name assert ranked_match.pkg_type == match.artifact.pkg_type assert ranked_match.pkg_version == match.artifact.version assert ranked_match.pkg_path == match.artifact.location assert ranked_match.rank == rank_strategy.__default__ @pytest.mark.parametrize( "lhs, rhs, expected", [ pytest.param( VulnerabilityMatch( vulnerability=Vulnerability( feed="trusty", feed_group="trusty:chameleon", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="hedgehog", feed_group="hedgy:thorny", vulnerability_id="foo", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), False, id="not-equal-different-ids", ), pytest.param( VulnerabilityMatch( vulnerability=Vulnerability( feed="trusty", feed_group="trusty:chameleon", vulnerability_id="meh", ), nvd=[ NVDReference(vulnerability_id="CVE-abc"), NVDReference(vulnerability_id="CVE-def"), NVDReference(vulnerability_id="CVE-ghi"), ], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="trusty", feed_group="trusty:chameleon", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), True, id="equal-different-cvss", ), pytest.param( VulnerabilityMatch( vulnerability=Vulnerability( feed="trusty", feed_group="trusty:chameleon", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), VulnerabilityMatch( vulnerability=Vulnerability( feed="trusty", feed_group="trusty:python", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), False, id="not-equal-different-namespaces", ), ], ) def test_equality_constant_artifact(self, lhs, rhs, expected): artifact = Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ) lhs.artifact = artifact rhs.artifact = artifact assert ( RankedVulnerabilityMatch.from_match(lhs, FeedGroupRank()) == RankedVulnerabilityMatch.from_match(rhs, FeedGroupRank()) ) == expected @pytest.mark.parametrize("count", [1, 2, 3, 4, 5]) def test_hash_empty_match(self, count): record = RankedVulnerabilityMatch( vuln_id="meh", vuln_namespace="trusty:chameleon", pkg_name="blah", pkg_version="1.2.3maven", pkg_type="java", pkg_path="blah", rank=100, match_obj=VulnerabilityMatch(), ) test_input = [record for x in range(count)] result = set(test_input) assert result and len(result) == 1 @pytest.mark.parametrize( "test_input", [ pytest.param( [ VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="twisty", feed_group="twisty:python", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), VulnerabilityMatch( artifact=Artifact( name="foo", location="/usr/local/java/foo", pkg_type="unknown", version="1.2.3", ), vulnerability=Vulnerability( feed="tricky", feed_group="tricky:chameleon", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-def")], ), ], id="different-matches", ), pytest.param( [ VulnerabilityMatch( artifact=Artifact( name="blah", location="/usr/local/java/blah", pkg_type="java", version="1.2.3maven", ), vulnerability=Vulnerability( feed="twisty", feed_group="twisty:python", vulnerability_id="meh", ), nvd=[NVDReference(vulnerability_id="CVE-abc")], ), ] * 3, id="same-matches", ), ], ) def test_hash(self, test_input): vuln_rank_objects = [ RankedVulnerabilityMatch( vuln_id="meh", vuln_namespace="trusty:chameleon", pkg_name="blah", pkg_version="1.2.3maven", pkg_type="java", pkg_path="/usr/local/blah", rank=100, match_obj=item, ) for item in test_input ] result = set(vuln_rank_objects) assert result and len(result) == 1 result = list(result)[0] assert result.vuln_id == "meh" assert result.vuln_namespace == "trusty:chameleon" assert result.pkg_name == "blah" assert result.pkg_type == "java" assert result.pkg_path == "/usr/local/blah" assert result.rank == 100