Example #1
0
    def test_bundle_failure(self):
        b = build_bundle(test_bundle)
        image_obj = Image(id='fakeid1')

        r = b.execute(image_object=image_obj,
                      tag='dockerhub/library/alpine:latest',
                      context=object())
        logger.info((json.dumps((r.json()), indent=2)))
Example #2
0
 def msg_to_db(self, msg):
     db_obj = Image()
     db_obj.id = msg.id
     db_obj.digest = msg.digest
     db_obj.user_id = msg.user_id
     db_obj.created_at = msg.created_at
     db_obj.last_modified = msg.last_modified
     return db_obj
Example #3
0
def test_multi_policy_missing_errors(test_data_env_with_images_loaded):
    """
    Test entries in policy_ids that are not found in bundle

    :return:
    """

    ruby_tag = "dockerhub/library/ruby:latest"

    with pytest.raises(InitializationError) as f:
        built = build_bundle({
            "id":
            "someid",
            "version":
            "1_0",
            "name":
            "testbundle",
            "whitelists": [{
                "id": "whitelist1",
                "version": "1_0",
                "name": "ok whitelist",
                "items": [],
            }],
            "policies": [
                {
                    "id": "okpolicy",
                    "version": "1_0",
                    "name": "ok policy",
                    "rules": [],
                },
                {
                    "id": "okpolicy",
                    "version": "1_0",
                    "name": "ok policy",
                    "rules": [],
                },
            ],
            "mappings": [{
                "id":
                "invalid_mapping",
                "policy_ids": ["okpolicy", "okpolicy2", "notrealpolicy"],
                "whitelist_ids": ["whitelist1"],
                "registry":
                "*",
                "repository":
                "*",
                "image": {
                    "type": "tag",
                    "value": "*"
                },
            }],
        })

        built.execute(image_object=Image(), context=None, tag=ruby_tag)
Example #4
0
    def test_multi_policy_missing_errors(self):
        """
        Test entries in policy_ids that are not found in bundle

        :return:
        """

        ruby_tag = 'dockerhub/library/ruby:latest'

        with self.assertRaises(InitializationError) as f:
            built = build_bundle({
                'id': 'someid',
                'version': '1_0',
                'name': 'testbundle',
                'whitelists': [
                    {'id': 'whitelist1',
                     'version': '1_0',
                     'name': 'ok whitelist',
                     'items': []
                     }
                ],
                'policies': [
                    {
                        'id': 'okpolicy',
                        'version': '1_0',
                        'name': 'ok policy',
                        'rules': []
                    },
                    {
                        'id': 'okpolicy',
                        'version': '1_0',
                        'name': 'ok policy',
                        'rules': []
                    }
                ],
                'mappings': [
                    {
                        'id': 'invalid_mapping',
                        'policy_ids': ['okpolicy', 'okpolicy2', 'notrealpolicy'],
                        'whitelist_ids': ['whitelist1'],
                        'registry': '*',
                        'repository': '*',
                        'image': {
                            'type': 'tag',
                            'value': '*'
                        }

                    }
                ]
            })

            built.execute(image_object=Image(), context=None, tag=ruby_tag)
Example #5
0
    def _match_distro_packages_by_cpe(self, image: Image) -> List[CpeMatch]:
        """
        Returns list of tuples of (imagecpe, vulncpe) that are matches

        :param image:
        :return: list of tuples
        """
        logger.spew(
            "scanning os packages for cpe matches id=%s digest=%s",
            image.id,
            image.digest,
        )

        os_pkg_cpe_mappings = self._get_cpes_for_os_packages(image.packages)

        logger.spew("distro cpes: %s", os_pkg_cpe_mappings)

        os_cpes = [cpe for pkg, cpe in os_pkg_cpe_mappings]
        # Get the matches
        matches = self._query_cpe_matches(os_cpes)

        logger.spew(
            "pre-filter cpe distro findings: %s",
            [(match.image_cpe, match.vuln_cpe.vulnerability_id) for match in matches],
        )

        # Filter the matches if configured to do so
        if matches and self.exclude_distro_records:
            # Remove any matches that are for a CVE ID that is represented in the vendor vuln db, regardless of match status.
            matched_cve_ids = self.get_cve_ids(matches)
            filtered_matched_cve_ids = set(
                filter_secdb_entries(
                    image.distro_namespace_obj(), matched_cve_ids, self.db_manager
                )
            )

            matches = [
                match
                for match in matches
                if match.vuln_cpe.vulnerability_id in filtered_matched_cve_ids
            ]

        logger.debug(
            "post-filter cpe distro findings: %s",
            [
                (match.image_cpe.name, match.vuln_cpe.vulnerability_id)
                for match in matches
            ],
        )

        return matches
Example #6
0
def test_multi_policy_invalid_errors(test_data_env_with_images_loaded):
    """
    Test validation of policies in multi-policy mapping
    :return:
    """

    ruby_tag = 'dockerhub/library/ruby:latest'

    with pytest.raises(InitializationError) as f:
        built = build_bundle({
            'id':
            'someid',
            'version':
            '1_0',
            'name':
            'invalid_version',
            'whitelists': [{
                'id': 'whitelist1',
                'version': '1_0',
                'name': 'ok whitelist',
                'items': []
            }],
            'policies': [{
                'id': 'okpolicy',
                'version': '1_0',
                'name': 'ok policy',
                'rules': []
            }, {
                'id': 'okpolicy',
                'version': '2_0',
                'name': 'ok policy',
                'rules': []
            }],
            'mappings': [{
                'id': 'ok_mapping',
                'policy_ids': ['okpolicy', 'okpolicy2'],
                'whitelist_ids': ['whitelist1'],
                'registry': '*',
                'repository': '*',
                'image': {
                    'type': 'tag',
                    'value': '*'
                }
            }]
        })
        built.execute(image_object=Image(), context=None, tag=ruby_tag)
"""
Gate Unit tests
"""
import pytest
from anchore_engine.db import Image
from anchore_engine.subsys import logger

from anchore_engine.services.policy_engine.engine.policy.gates.image_metadata import (
    ImageMetadataGate,
    ImageMetadataAttributeCheckTrigger,
)
from tests.integration.services.policy_engine.engine.policy.gates import GateUnitTest

logger.enable_test_logging()

test_image = Image()
test_image.distro_name = "debian"
test_image.distro_version = "9"
test_image.like_distro = "debian"
test_image.user_id = "0"
test_image.layers_json = ["sha256:a", "sha256:b", "sha256:c"]
test_image.layer_info_json = ["layer1", "layer2"]
test_image.dockerfile_contents = "FROM SCRATCH\nHEALTHcheck blah\n"
test_image.dockerfile_mode = "Guessed"
test_image.size = 100 * 1024 * 1024
test_image.docker_data_json = {
    "Comment":
    "",
    "Container":
    "4e69ef98747345110dc23069be98ff0ae562cc83a187ff1bdd1d2e0048889679",
    "DockerVersion":
"""
Gate Unit tests
"""

from legacy_test.services.policy_engine.engine.policy.gates import GateUnitTest
from anchore_engine.services.policy_engine.engine.policy.gate import ExecutionContext
from anchore_engine.db import Image

from anchore_engine.services.policy_engine.engine.policy.gates.dockerfile import DockerfileGate, \
    ExposedPortsTrigger, \
    InstructionCheckTrigger, \
    EffectiveUserTrigger, \
    NoDockerfile

test_image = Image()
test_image.distro_name = 'debian'
test_image.distro_version = '9'
test_image.user_id = '0'
test_image.layer_info_json = ['layer1', 'layer2']
test_image.dockerfile_contents = 'FROM SCRATCH\nHEALTHCHECK blah\n'
test_image.dockerfile_mode = 'Guessed'

dockerfile_from = 'FROM library/centos:latest\nRUN apt-get install\nCMD echo helloworld\n'
dockerfile_scratch = 'FROM SCRATCH\nRUN apt-get install\nCMD echo helloworld\n'
dockerfile_healthcheck = 'FROM library/centos:latest\nRUN apt-get install\nCMD echo helloworld\nHEALTHcheck echo hello\n'
dockerfile_no_healthcheck = 'FROM library/centos:latest\nRUN apt-get install\nCMD echo helloworld\n'
dockerfile_no_tag = 'FROM library/centos\nRUN apt-get install\nCMD echo helloworld\n'
dockerfile_no_from = 'ADD ./files/* /\nRUN apt-get install\nCMD echo helloworld\n'
dockerfile_sudo = 'FROM library/centos\nRUN sudo apt-get install\nCMD echo helloworld\n'
dockerfile_volume = 'FROM library/centos\nRUN sudo apt-get install\nVOLUME /var/log\nCMD echo helloworld\n'
dockerfile_expose = 'FROM library/centos\nRUN sudo apt-get install\nEXPOSE 8000\nVOLUME /var/log\nCMD echo helloworld\n'
def test_cve_updates(test_data_env):
    test_env = test_data_env
    test_env.init_feeds()

    test_user_id = 'test1'
    test_img_id = 'img1'
    test_image = Image(user_id=test_user_id, id=test_img_id, distro_name='centos', distro_version='7')
    test_image.familytree_json = [test_img_id]
    test_image.layers_json = [test_img_id]
    test_image.layer_info_json = ['somelayer_here']
    test_image.like_distro = 'centos'
    test_image.state = 'analyzed'
    test_image.digest = 'digest1'
    test_image.anchore_type = 'undefined'
    test_image.dockerfile_mode = 'Guessed'
    test_image.docker_history_json = ['line1', 'line2']
    test_image.docker_data_json = {'Config': {}, 'ContainerConfig': {}}
    test_image.dockerfile_contents = 'FROM BLAH'

    test_package = ImagePackage(image_user_id=test_user_id, image_id=test_img_id, name='testpackage', version='1.0', pkg_type='RPM')
    test_package.src_pkg = 'testpackage'
    test_package.distro_name = 'centos'
    test_package.distro_version = '7'
    test_package.like_distro = 'centos'
    test_package.license = 'apache2'
    test_package.fullversion = '1.0'
    test_package.normalized_src_pkg = '1.0'
    test_package.release = ''
    test_package.size = 1000
    test_package.origin = 'upstream'
    test_package.arch = 'x86_64'
    test_package.image = test_image

    test_cve = Vulnerability(id='CVE123', namespace_name='centos:7')
    test_cve.severity = 'High'
    test_cve.description = 'some test cve'
    test_cve.cvss2_score = '1.0'
    test_cve.metadata_json = {}
    test_cve.cvss2_vectors = ''
    test_cve.link = 'http://mitre.com/cve123'

    test_fixedin = FixedArtifact(vulnerability_id=test_cve.id)
    test_fixedin.name = 'testpackage'
    test_fixedin.version = '1.1'
    test_fixedin.version_format = 'rpm'
    test_fixedin.epochless_version = '1.1'
    test_fixedin.include_later_versions = True
    test_fixedin.parent = test_cve
    test_cve.fixed_in = [test_fixedin]

    test_vulnin = VulnerableArtifact(vulnerability_id=test_cve.id)
    test_vulnin.name = 'testpackage'
    test_vulnin.version = '0.9'
    test_vulnin.epochless_version = '0.9'
    test_vulnin.namespace_name = 'centos:7'
    test_vulnin.version_format = 'rpm'
    test_vulnin.include_previous_versions = False
    test_vulnin.parent = test_cve
    test_cve.vulnerable_in = [test_vulnin]

    db = get_session()
    try:
        db.add(test_image)
        db.add(test_package)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        db.rollback()
    except Exception:
        logger.exception('Unexpected failure')
        raise

    db = get_session()
    try:
        db.add(test_cve)
        feeds.process_updated_vulnerability(db, test_cve)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        logger.exception('Failed!')
        db.rollback()
    finally:
        db = get_session()
        i = db.query(Image).get((test_img_id, test_user_id))
        print(('Vulns: {}'.format(i.vulnerabilities())))
        db.commit()

    test_cve2 = Vulnerability(id='CVE123', namespace_name='centos:7')
    test_cve2.severity = 'Medium'
    test_cve2.description = 'some test cve'
    test_cve2.cvss2_score = '1.0'
    test_cve2.metadata_json = {}
    test_cve2.cvss2_vectors = ''
    test_cve2.link = 'http://mitre.com/cve123'
    fix2 = FixedArtifact(name='pkg2', version='1.2', epochless_version='1.2')
    fix2.namespace_name = 'centos:7'
    fix2.vulnerability_id = test_cve2.id
    test_cve2.fixed_in = [fix2]

    db = get_session()
    try:
        t2 = db.merge(test_cve2)
        db.add(t2)
        feeds.process_updated_vulnerability(db, t2)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        logger.exception('Failed!')
        db.rollback()
    finally:
        db = get_session()
        i = db.query(Image).get((test_img_id, test_user_id))
        print(('Vulns: {}'.format(i.vulnerabilities())))
        db.commit()
Example #10
0
def test_cve_updates(test_data_env):
    test_env = test_data_env
    test_env.init_feeds()

    test_user_id = "test1"
    test_img_id = "img1"
    test_image = Image(user_id=test_user_id,
                       id=test_img_id,
                       distro_name="centos",
                       distro_version="7")
    test_image.familytree_json = [test_img_id]
    test_image.layers_json = [test_img_id]
    test_image.layer_info_json = ["somelayer_here"]
    test_image.like_distro = "centos"
    test_image.state = "analyzed"
    test_image.digest = "digest1"
    test_image.anchore_type = "undefined"
    test_image.dockerfile_mode = "Guessed"
    test_image.docker_history_json = ["line1", "line2"]
    test_image.docker_data_json = {"Config": {}, "ContainerConfig": {}}
    test_image.dockerfile_contents = "FROM BLAH"

    test_package = ImagePackage(
        image_user_id=test_user_id,
        image_id=test_img_id,
        name="testpackage",
        version="1.0",
        pkg_type="RPM",
    )
    test_package.src_pkg = "testpackage"
    test_package.distro_name = "centos"
    test_package.distro_version = "7"
    test_package.like_distro = "centos"
    test_package.license = "apache2"
    test_package.fullversion = "1.0"
    test_package.normalized_src_pkg = "1.0"
    test_package.release = ""
    test_package.size = 1000
    test_package.origin = "upstream"
    test_package.arch = "x86_64"
    test_package.image = test_image

    test_cve = Vulnerability(id="CVE123", namespace_name="centos:7")
    test_cve.severity = "High"
    test_cve.description = "some test cve"
    test_cve.cvss2_score = "1.0"
    test_cve.metadata_json = {}
    test_cve.cvss2_vectors = ""
    test_cve.link = "http://mitre.com/cve123"

    test_fixedin = FixedArtifact(vulnerability_id=test_cve.id)
    test_fixedin.name = "testpackage"
    test_fixedin.version = "1.1"
    test_fixedin.version_format = "rpm"
    test_fixedin.epochless_version = "1.1"
    test_fixedin.include_later_versions = True
    test_fixedin.parent = test_cve
    test_cve.fixed_in = [test_fixedin]

    test_vulnin = VulnerableArtifact(vulnerability_id=test_cve.id)
    test_vulnin.name = "testpackage"
    test_vulnin.version = "0.9"
    test_vulnin.epochless_version = "0.9"
    test_vulnin.namespace_name = "centos:7"
    test_vulnin.version_format = "rpm"
    test_vulnin.include_previous_versions = False
    test_vulnin.parent = test_cve
    test_cve.vulnerable_in = [test_vulnin]

    db = get_session()
    try:
        db.add(test_image)
        db.add(test_package)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        db.rollback()
    except Exception:
        logger.exception("Unexpected failure")
        raise

    db = get_session()
    try:
        db.add(test_cve)
        feeds.process_updated_vulnerability(db, test_cve)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        logger.exception("Failed!")
        db.rollback()
    finally:
        db = get_session()
        i = db.query(Image).get((test_img_id, test_user_id))
        print(("Vulns: {}".format(i.vulnerabilities())))
        db.commit()

    test_cve2 = Vulnerability(id="CVE123", namespace_name="centos:7")
    test_cve2.severity = "Medium"
    test_cve2.description = "some test cve"
    test_cve2.cvss2_score = "1.0"
    test_cve2.metadata_json = {}
    test_cve2.cvss2_vectors = ""
    test_cve2.link = "http://mitre.com/cve123"
    fix2 = FixedArtifact(name="pkg2", version="1.2", epochless_version="1.2")
    fix2.namespace_name = "centos:7"
    fix2.vulnerability_id = test_cve2.id
    test_cve2.fixed_in = [fix2]

    db = get_session()
    try:
        t2 = db.merge(test_cve2)
        db.add(t2)
        feeds.process_updated_vulnerability(db, t2)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        logger.exception("Failed!")
        db.rollback()
    finally:
        db = get_session()
        i = db.query(Image).get((test_img_id, test_user_id))
        print(("Vulns: {}".format(i.vulnerabilities())))
        db.commit()
from anchore_engine.db import get_thread_scoped_session as get_session, end_session, Image, ImagePackageVulnerability, ImagePackage, Vulnerability, VulnerableArtifact, FixedArtifact, FeedMetadata, FeedGroupMetadata
from anchore_engine.services.policy_engine.engine.tasks import FeedsUpdateTask
from legacy_test.services.policy_engine.utils import init_db, LocalTestDataEnvironment

logging.basicConfig(level='INFO')
log = logging.getLogger()

init_db()
test_env = LocalTestDataEnvironment(os.environ['ANCHORE_ENGINE_TEST_HOME'])
test_env.init_feeds()

test_user_id = 'test1'
test_img_id = 'img1'
test_image = Image(user_id=test_user_id,
                   id=test_img_id,
                   distro_name='centos',
                   distro_version='7')
test_image.familytree_json = [test_img_id]
test_image.layers_json = [test_img_id]
test_image.layer_info_json = ['somelayer_here']
test_image.like_distro = 'centos'
test_image.state = 'analyzed'
test_image.digest = 'digest1'
test_image.anchore_type = 'undefined'
test_image.dockerfile_mode = 'Guessed'
test_image.docker_history_json = ['line1', 'line2']
test_image.docker_data_json = {'Config': {}, 'ContainerConfig': {}}
test_image.dockerfile_contents = 'FROM BLAH'

test_package = ImagePackage(image_user_id=test_user_id,
                            image_id=test_img_id,
Example #12
0
def get_image():
    img = Image()
    img.user_id = "unit_test"
    img.id = "da28a15dbf563fbc5a486f622b44970ee1bf10f48013bab640f403b06b278543"
    return img
class TestVulnerabilitiesGate:
    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, feed_group_metadata, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                FeedGroupMetadata(
                    last_sync=datetime.datetime.utcnow() -
                    datetime.timedelta(days=2),
                    name="test-feed-out-of-date",
                ),
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                FeedGroupMetadata(
                    last_sync=datetime.datetime.utcnow(),
                    name="test-feed-not-out-of-date",
                ),
                False,
            ),
        ],
    )
    def test_feed_out_of_date_trigger(
        self,
        image_obj,
        mock_vuln_report,
        feed_group_metadata,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
        setup_mocks_feed_out_of_date_trigger,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        setup_mocks_feed_out_of_date_trigger(feed_group_metadata)
        vulns_gate = VulnerabilitiesGate()
        trigger = FeedOutOfDateTrigger(parent_gate_cls=VulnerabilitiesGate,
                                       max_days_since_sync="1")
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert (
                trigger.fired[0].msg ==
                f"The vulnerability feed for this image distro is older than MAXAGE ({trigger.max_age.value()}) days"
            )

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, feed_metadata, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                FeedMetadata(name="vulnerabilities",
                             groups=[FeedGroupMetadata(name="debian:10")]),
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                FeedMetadata(name="vulnerabilities",
                             groups=[FeedGroupMetadata(name="debian:9")]),
                True,
            ),
        ],
    )
    def test_unsupported_distro_trigger(
        self,
        image_obj,
        mock_vuln_report,
        feed_metadata,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
        setup_mocks_unsupported_distro_trigger,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        setup_mocks_unsupported_distro_trigger(feed_metadata)
        vulns_gate = VulnerabilitiesGate()
        trigger = UnsupportedDistroTrigger(parent_gate_cls=VulnerabilitiesGate)
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert (
                trigger.fired[0].msg ==
                f"Distro-specific feed data not found for distro namespace: {image_obj.distro_namespace}. Cannot perform CVE scan OS/distro packages"
            )

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, vulnerability_ids, vendor_only, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "CVE-2020-13529",  # One matching vuln
                "false",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "CVE-2020-13579",  # One fake vuln
                "false",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "CVE-2020-13529",  # One matching vulns (not a won't fix)
                "true",  # Vendor only
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_wont-fix.json",
                "CVE-2020-15719",  # One matching vulns (was changed to won't fix for the purposes of this test)
                "true",  # Vendor only
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "CVE-2020-13529, CVE-2020-13579",  # One matching vuln and one fake vuln
                "false",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "CVE-2020-13525, CVE-2004-0975",  # Two fake vulns
                "false",
                False,
            ),
        ],
    )
    def test_vulnerabilities_blacklist_trigger(
        self,
        image_obj,
        mock_vuln_report,
        vulnerability_ids,
        vendor_only,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityBlacklistTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            vulnerability_ids=vulnerability_ids,
            vendor_only=vendor_only,
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert re.fullmatch(
                r"Blacklisted vulnerabilities detected: \[((\'CVE-\d{4}-\d{4,}\')(, )?)+\]",
                trigger.fired[0].msg,
            )

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, fix_available, expected_trigger_fired, expected_number_triggers",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_fix-available.json",
                "true",
                True,
                1,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_fix-available.json",
                "false",
                False,
                0,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "true",
                False,
                0,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "false",
                True,
                1,
            ),
        ],
    )
    def test_vulnerability_match_trigger_fix_available(
        self,
        image_obj,
        mock_vuln_report,
        fix_available,
        expected_trigger_fired,
        expected_number_triggers,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            fix_available=fix_available,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        assert len(trigger.fired) == expected_number_triggers

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, vendor_only, expected_trigger_fired, expected_number_triggers",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "true",
                True,
                1,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "false",
                True,
                1,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_wont-fix.json",
                "true",
                False,
                0,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_wont-fix.json",
                "false",
                True,
                1,
            ),
        ],
    )
    def test_vulnerability_match_trigger_vendor_only(
        self,
        image_obj,
        mock_vuln_report,
        vendor_only,
        expected_trigger_fired,
        expected_number_triggers,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            vendor_only=vendor_only,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        assert len(trigger.fired) == expected_number_triggers

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, max_days_since_creation, expected_trigger_fired, expected_number_triggers",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "1000000",
                False,
                0,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "0",
                True,
                1,
            ),
        ],
    )
    def test_vulnerability_match_trigger_max_days_since_creation(
        self,
        image_obj,
        mock_vuln_report,
        max_days_since_creation,
        expected_trigger_fired,
        expected_number_triggers,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            max_days_since_creation=max_days_since_creation,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        assert len(trigger.fired) == expected_number_triggers

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, max_days_since_fix, expected_trigger_fired, expected_number_triggers",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_fix-available.json",
                "1000000",
                False,
                0,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_fix-available.json",
                "0",
                True,
                1,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "1000000",
                False,
                0,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "0",
                False,
                0,
            ),
        ],
    )
    def test_vulnerability_match_trigger_max_days_since_fix(
        self,
        image_obj,
        mock_vuln_report,
        max_days_since_fix,
        expected_trigger_fired,
        expected_number_triggers,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            max_days_since_creation=max_days_since_fix,
            fix_available="true",
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        assert len(trigger.fired) == expected_number_triggers

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, package_path_exclude, expected_trigger_fired, expected_number_triggers",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_non-os_will-fix.json",
                "/usr/.*",
                True,
                1,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_non-os_will-fix.json",
                "/bin/.*",
                False,
                0,
            ),
        ],
    )
    def test_vulnerability_match_trigger_package_path_exclude(
        self,
        image_obj,
        mock_vuln_report,
        package_path_exclude,
        expected_trigger_fired,
        expected_number_triggers,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            package_path_exclude=package_path_exclude,
            package_type="non-os",
            vendor_only=False,
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        assert len(trigger.fired) == expected_number_triggers

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, package_type, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "all",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "os",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_non-os_will-fix.json",
                "os",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "non-os",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_non-os_will-fix.json",
                "non-os",
                True,
            ),
        ],
    )
    def test_vulnerability_match_trigger_package_type(
        self,
        image_obj,
        mock_vuln_report,
        package_type,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate, package_type=package_type)
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, severity_comparison, severity, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "=",
                "unknown",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "=",
                "negligible",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "=",
                "low",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "=",
                "medium",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "=",
                "high",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "=",
                "critical",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "<",
                "medium",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                ">",
                "medium",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "!=",
                "medium",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "<=",
                "medium",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                ">=",
                "medium",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "<",
                "unknown",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                ">",
                "critical",
                False,
            ),
        ],
    )
    def test_vulnerability_match_trigger_severity_comparison(
        self,
        image_obj,
        mock_vuln_report,
        severity_comparison,
        severity,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            severity_comparison=severity_comparison,
            severity=severity,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert len(trigger.fired) == 1
        else:
            assert len(trigger.fired) == 0

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, score_comparison, base_score, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                ">",
                "6.0",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "<",
                "6.0",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "=",
                "6.0",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                ">=",
                "6.0",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "<=",
                "6.0",
                False,
            ),
        ],
    )
    def test_vulnerability_match_trigger_cvssv3_base_score_comparison(
        self,
        image_obj,
        mock_vuln_report,
        score_comparison,
        base_score,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            cvss_v3_base_score_comparison=score_comparison,
            cvss_v3_base_score=base_score,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert len(trigger.fired) == 1
        else:
            assert len(trigger.fired) == 0

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, score_comparison, exploitability_score, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                ">",
                "3.8",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "<",
                "3.8",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "=",
                "3.8",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                ">=",
                "3.8",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "<=",
                "3.8",
                True,
            ),
        ],
    )
    def test_vulnerability_match_trigger_cvssv3_exploitability_score_comparison(
        self,
        image_obj,
        mock_vuln_report,
        score_comparison,
        exploitability_score,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            cvss_v3_exploitability_score_comparison=score_comparison,
            cvss_v3_exploitability_score=exploitability_score,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert len(trigger.fired) == 1
        else:
            assert len(trigger.fired) == 0

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, score_comparison, impact_score, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                ">",
                "3.6",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "<",
                "3.6",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "=",
                "3.6",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                ">=",
                "3.6",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix.json",
                "<=",
                "3.6",
                False,
            ),
        ],
    )
    def test_vulnerability_match_trigger_cvssv3_impact_score_comparison(
        self,
        image_obj,
        mock_vuln_report,
        score_comparison,
        impact_score,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            cvss_v3_impact_score_comparison=score_comparison,
            cvss_v3_impact_score=impact_score,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert len(trigger.fired) == 1
        else:
            assert len(trigger.fired) == 0

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, score_comparison, base_score, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                ">",
                "6.0",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                "<",
                "6.0",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                "=",
                "6.0",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                ">=",
                "6.0",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                "<=",
                "6.0",
                False,
            ),
        ],
    )
    def test_vulnerability_match_trigger_vendor_cvssv3_base_score_comparison(
        self,
        image_obj,
        mock_vuln_report,
        score_comparison,
        base_score,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            vendor_cvss_v3_base_score_comparison=score_comparison,
            vendor_cvss_v3_base_score=base_score,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert len(trigger.fired) == 1
        else:
            assert len(trigger.fired) == 0

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, score_comparison, exploitability_score, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                ">",
                "3.8",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                "<",
                "3.8",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                "=",
                "3.8",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                ">=",
                "3.8",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                "<=",
                "3.8",
                True,
            ),
        ],
    )
    def test_vulnerability_match_trigger_vendor_cvssv3_exploitability_score_comparison(
        self,
        image_obj,
        mock_vuln_report,
        score_comparison,
        exploitability_score,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            vendor_cvss_v3_exploitability_score_comparison=score_comparison,
            vendor_cvss_v3_exploitability_score=exploitability_score,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert len(trigger.fired) == 1
        else:
            assert len(trigger.fired) == 0

    @pytest.mark.parametrize(
        "image_obj, mock_vuln_report, score_comparison, impact_score, expected_trigger_fired",
        [
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                ">",
                "3.6",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                "<",
                "3.6",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                "=",
                "3.6",
                False,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                ">=",
                "3.6",
                True,
            ),
            (
                Image(id="1",
                      user_id="admin",
                      distro_name="debian",
                      distro_version="10"),
                "debian_1_os_will-fix_vendor_cvssv3.json",
                "<=",
                "3.6",
                False,
            ),
        ],
    )
    def test_vulnerability_match_trigger_vendor_cvssv3_impact_score_comparison(
        self,
        image_obj,
        mock_vuln_report,
        score_comparison,
        impact_score,
        expected_trigger_fired,
        setup_mocks_vulnerabilities_gate,
    ):
        setup_mocks_vulnerabilities_gate(mock_vuln_report)
        vulns_gate = VulnerabilitiesGate()
        trigger = VulnerabilityMatchTrigger(
            parent_gate_cls=VulnerabilitiesGate,
            vendor_cvss_v3_impact_score_comparison=score_comparison,
            vendor_cvss_v3_impact_score=impact_score,
            package_type="all",
        )
        exec_context = ExecutionContext(db_session=None, configuration={})
        vulns_gate.prepare_context(image_obj, exec_context)
        trigger.evaluate(image_obj, exec_context)
        assert trigger.did_fire == expected_trigger_fired
        if expected_trigger_fired:
            assert len(trigger.fired) == 1
        else:
            assert len(trigger.fired) == 0
Example #14
0
    GateUnitTest,
    cls_no_feeds_test_env,
)
from anchore_engine.db import Image

from anchore_engine.services.policy_engine.engine.policy.gates.dockerfile import (
    DockerfileGate,
    ExposedPortsTrigger,
    InstructionCheckTrigger,
    EffectiveUserTrigger,
    NoDockerfile,
)

logger.enable_test_logging()

test_image = Image()
test_image.distro_name = "debian"
test_image.distro_version = "9"
test_image.user_id = "0"
test_image.layer_info_json = ["layer1", "layer2"]
test_image.dockerfile_contents = "FROM SCRATCH\nHEALTHCHECK blah\n"
test_image.dockerfile_mode = "Guessed"

dockerfile_from = (
    "FROM library/centos:latest\nRUN apt-get install\nCMD echo helloworld\n")
dockerfile_scratch = "FROM SCRATCH\nRUN apt-get install\nCMD echo helloworld\n"
dockerfile_healthcheck = "FROM library/centos:latest\nRUN apt-get install\nCMD echo helloworld\nHEALTHcheck echo hello\n"
dockerfile_no_healthcheck = (
    "FROM library/centos:latest\nRUN apt-get install\nCMD echo helloworld\n")
dockerfile_no_tag = "FROM library/centos\nRUN apt-get install\nCMD echo helloworld\n"
dockerfile_no_from = "ADD ./files/* /\nRUN apt-get install\nCMD echo helloworld\n"
Example #15
0
        namespace_name="debian:8",
        severity="high",
        fixed_in=[
            FixedArtifact(name="testpkg1",
                          version="1.0.1",
                          version_format="deb")
        ],
    )
]

mock_images = [
    Image(
        user_id="admin",
        id="1",
        digest="sha256:1",
        distro_name="debian",
        distro_version="9",
        like_distro="debian",
        state="analyzed",
    )
]

mock_packages = [
    ImagePackage(
        image_user_id="admin",
        image_id="1",
        name="testpkg1",
        version="1.0.0",
        size=100,
        arch="amd64",
        pkg_type="deb",
Example #16
0
mock_vulnerabilities = [
    Vulnerability(id='cve-1',
                  namespace_name='debian:8',
                  severity='high',
                  fixed_in=[
                      FixedArtifact(name='testpkg1',
                                    version='1.0.1',
                                    version_format='deb')
                  ])
]

mock_images = [
    Image(user_id='admin',
          id='1',
          digest='sha256:1',
          distro_name='debian',
          distro_version='9',
          like_distro='debian',
          state='analyzed')
]

mock_packages = [
    ImagePackage(
        image_user_id='admin',
        image_id='1',
        name='testpkg1',
        version='1.0.0',
        size=100,
        arch='amd64',
        pkg_type='deb',
        distro_name='debian',
def test_github_advisory_fixed_in(test_data_env):
    test_env = test_data_env
    test_env.init_feeds()

    test_user_id = 'test1'
    test_img_id = 'img1'
    test_image = Image(
        user_id=test_user_id, id=test_img_id,
        distro_name='centos', distro_version='7'
    )
    test_image.familytree_json = [test_img_id]
    test_image.layers_json = [test_img_id]
    test_image.layer_info_json = ['somelayer_here']
    test_image.like_distro = 'centos'
    test_image.state = 'analyzed'
    test_image.digest = 'digest1'
    test_image.anchore_type = 'undefined'
    test_image.dockerfile_mode = 'Guessed'
    test_image.docker_history_json = ['line1', 'line2']
    test_image.docker_data_json = {'Config': {}, 'ContainerConfig': {}}
    test_image.dockerfile_contents = 'FROM BLAH'

    test_package = ImagePackage(
        image_user_id=test_user_id, image_id=test_img_id,
        name='testpackage', version='1.0', pkg_type='python'
    )
    test_package.src_pkg = 'testpackage'
    test_package.distro_name = 'centos'
    test_package.distro_version = '7'
    test_package.like_distro = 'centos'
    test_package.license = 'apache2'
    test_package.fullversion = '1.0'
    test_package.normalized_src_pkg = '1.0'
    test_package.release = ''
    test_package.size = 1000
    test_package.origin = 'upstream'
    test_package.arch = 'x86_64'
    test_package.image = test_image

    test_cve = Vulnerability(id='GHSA-rpch-cqj9-h65r', namespace_name='github:python')
    test_cve.severity = 'High'
    test_cve.description = 'some advisory ghsa'
    test_cve.link = 'http://mitre.com/cve123'

    test_fixedin = FixedArtifact(vulnerability_id=test_cve.id)
    test_fixedin.name = 'testpackage'
    test_fixedin.version = 'None'
    test_fixedin.fix_metadata = {'first_patched_version': '1.2'}
    test_fixedin.version_format = 'semver'
    test_fixedin.parent = test_cve
    test_cve.fixed_in = [test_fixedin]

    db = get_session()
    try:
        db.add(test_image)
        db.add(test_package)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        db.rollback()
    except Exception:
        logger.exception('Unexpected failure')
        raise

    db = get_session()
    # XXX This needs to be a fixture
    try:
        db.add(test_cve)
        feeds.process_updated_vulnerability(db, test_cve)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        logger.exception('Failed!')
        db.rollback()

    db = get_session()
    image_vuln = db.query(Image).get((test_img_id, test_user_id))
    # should be one vulnerability
    vulnerabilities = image_vuln.vulnerabilities()
    assert len(vulnerabilities) == 1
    img_pkg_vuln = vulnerabilities[0]
    assert img_pkg_vuln.fixed_in() == '1.2'
Example #18
0
    def load(self):
        """
        Loads the exported image data into this system for usage.

        :param image_export_json:
        :return: an initialized Image() record, not persisted to DB yet
        """

        log.info('Loading image json')

        if type(self.image_export_json) == list and len(
                self.image_export_json) == 1:
            image_id = self.image_export_json[0]['image']['imageId']
            self.image_export_json = self.image_export_json[0]['image'][
                'imagedata']
            log.info(
                'Detected a direct export format for image id: {} rather than a catalog analysis export'
                .format(image_id))

        analysis_report = self.image_export_json['analysis_report']
        image_report = self.image_export_json['image_report']

        image = Image()
        image.id = image_report['meta']['imageId']
        image.size = int(image_report['meta']['sizebytes'])
        repo_digests = image_report['docker_data'].get('RepoDigests', [])
        repo_tags = image_report['docker_data'].get('RepoTags', [])
        if len(repo_digests) > 1:
            log.warn(
                'Found more than one digest for the image {}. Using the first. Digests: {}, Tags: {}'
                .format(image.id, repo_digests, repo_tags))

        image.digest = repo_digests[0].split('@',
                                             1)[1] if repo_digests else None

        # Tags handled in another phase using the docker_data in the image record.

        # get initial metadata
        analyzer_meta = analysis_report['analyzer_meta']['analyzer_meta'][
            'base']
        if 'LIKEDISTRO' in analyzer_meta:
            like_dist = analyzer_meta['LIKEDISTRO']
        else:
            like_dist = analyzer_meta['DISTRO']

        image.distro_name = analyzer_meta['DISTRO']
        image.distro_version = analyzer_meta['DISTROVERS']
        image.like_distro = like_dist

        image.dockerfile_mode = image_report['dockerfile_mode']

        # JSON data
        image.docker_data_json = image_report['docker_data']
        image.docker_history_json = image_report['docker_history']
        image.dockerfile_contents = image_report['dockerfile_contents']
        image.layers_to_dockerfile_json = analysis_report.get('layer_info')
        image.layers_json = image_report['layers']
        image.familytree_json = image_report['familytree']
        image.analyzer_manifest = self.image_export_json['analyzer_manifest']

        # Image content

        # Packages
        log.info('Loading image packages')
        image.packages = self.load_and_normalize_packages(
            analysis_report.get('package_list', {}), image)

        # Package metadata
        log.info('Loading image package db entries')
        self.load_package_verification(analysis_report, image)

        # FileSystem
        log.info('Loading image files')
        image.fs = self.load_fsdump(analysis_report)

        # Npms
        log.info('Loading image npms')
        image.npms = self.load_npms(analysis_report, image)

        # Gems
        log.info('Loading image gems')
        image.gems = self.load_gems(analysis_report, image)

        # CPEs
        log.info('Loading image cpes')
        image.cpes = self.load_cpes(analysis_report, image)

        analysis_artifact_loaders = [
            self.load_retrieved_files, self.load_content_search,
            self.load_secret_search
            #self.load_package_verification
        ]

        # Content searches
        image.analysis_artifacts = []
        for loader in analysis_artifact_loaders:
            for r in loader(analysis_report, image):
                image.analysis_artifacts.append(r)

        image.state = 'analyzed'
        return image
Example #19
0
def test_github_advisory_fixed_in(test_data_env):
    test_env = test_data_env
    test_env.init_feeds()

    test_user_id = "test1"
    test_img_id = "img1"
    test_image = Image(user_id=test_user_id,
                       id=test_img_id,
                       distro_name="centos",
                       distro_version="7")
    test_image.familytree_json = [test_img_id]
    test_image.layers_json = [test_img_id]
    test_image.layer_info_json = ["somelayer_here"]
    test_image.like_distro = "centos"
    test_image.state = "analyzed"
    test_image.digest = "digest1"
    test_image.anchore_type = "undefined"
    test_image.dockerfile_mode = "Guessed"
    test_image.docker_history_json = ["line1", "line2"]
    test_image.docker_data_json = {"Config": {}, "ContainerConfig": {}}
    test_image.dockerfile_contents = "FROM BLAH"

    test_package = ImagePackage(
        image_user_id=test_user_id,
        image_id=test_img_id,
        name="testpackage",
        version="1.0",
        pkg_type="python",
    )
    test_package.src_pkg = "testpackage"
    test_package.distro_name = "centos"
    test_package.distro_version = "7"
    test_package.like_distro = "centos"
    test_package.license = "apache2"
    test_package.fullversion = "1.0"
    test_package.normalized_src_pkg = "1.0"
    test_package.release = ""
    test_package.size = 1000
    test_package.origin = "upstream"
    test_package.arch = "x86_64"
    test_package.image = test_image

    test_cve = Vulnerability(id="GHSA-rpch-cqj9-h65r",
                             namespace_name="github:python")
    test_cve.severity = "High"
    test_cve.description = "some advisory ghsa"
    test_cve.link = "http://mitre.com/cve123"

    test_fixedin = FixedArtifact(vulnerability_id=test_cve.id)
    test_fixedin.name = "testpackage"
    test_fixedin.version = "None"
    test_fixedin.fix_metadata = {"first_patched_version": "1.2"}
    test_fixedin.version_format = "semver"
    test_fixedin.parent = test_cve
    test_cve.fixed_in = [test_fixedin]

    db = get_session()
    try:
        db.add(test_image)
        db.add(test_package)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        db.rollback()
    except Exception:
        logger.exception("Unexpected failure")
        raise

    db = get_session()
    # XXX This needs to be a fixture
    try:
        db.add(test_cve)
        feeds.process_updated_vulnerability(db, test_cve)
        db.commit()
    except sqlalchemy.exc.IntegrityError:
        logger.exception("Failed!")
        db.rollback()

    db = get_session()
    image_vuln = db.query(Image).get((test_img_id, test_user_id))
    # should be one vulnerability
    vulnerabilities = image_vuln.vulnerabilities()
    assert len(vulnerabilities) == 1
    img_pkg_vuln = vulnerabilities[0]
    assert img_pkg_vuln.fixed_in() == "1.2"