예제 #1
0
class PkgMatchTrigger(BaseTrigger):
    __trigger_name__ = 'blacklisted_name_version'
    __description__ = 'Triggers if the evaluated image has an NPM package installed that matches the name and optionally a version specified in the parameters.'

    name = TriggerParameter(validator=TypeValidator('string'), name='name', is_required=True, description='Npm package name to blacklist.', example_str='time_diff', sort_order=1)
    version = TriggerParameter(validator=TypeValidator('string'), name='version', is_required=False, description='Npm package version to blacklist specifically.', example_str='0.2.9', sort_order=2)

    def evaluate(self, image_obj, context):
        """
        Fire for any npm that is on the blacklist with a full name + version match
        :param image_obj:
        :param context:
        :return:
        """
        npms = image_obj.npms
        if not npms:
            return

        pkgs = context.data.get(NPM_LISTING_KEY)
        if not pkgs:
            return

        name = self.name.value()
        version = self.version.value(default_if_none=None)

        if name in pkgs:
            pkg_versions = pkgs.get(name)
            if not pkg_versions:
                pkg_versions = []
            if version and version in pkg_versions:
                self._fire(msg='NPM Package is blacklisted: ' + name + "-" + version)
            elif version is None:
                self._fire(msg='NPM Package is blacklisted: ' + name)
예제 #2
0
class BlacklistedGemTrigger(BaseTrigger):
    __trigger_name__ = 'blacklist'
    __description__ = 'Triggers if the evaluated image has a GEM package installed that matches the specified name and version.'

    name = TriggerParameter(validator=TypeValidator('string'), name='name', is_required=True, description='Gem name to blacklist.', example_str='time_diff', sort_order=1)
    version = TriggerParameter(validator=TypeValidator('string'), name='version', is_required=False, description='Optional version to blacklist specifically.', example_str='0.2.9', sort_order=2)

    def evaluate(self, image_obj, context):
        """
        Fire for any gem that is on the blacklist with a full name + version match
        :param image_obj:
        :param context:
        :return:
        """
        gems = image_obj.get_packages_by_type('gem')
        if not gems:
            return

        pkgs = context.data.get(GEM_LIST_KEY)
        if not pkgs:
            return

        name = self.name.value()
        version = self.version.value(default_if_none=None)

        if name in pkgs:
            if version and version in pkgs.get(name, []):
                self._fire(msg='Gem Package is blacklisted: ' + name + "-" + version)
            elif version is None:
                self._fire(msg='Gem Package is blacklisted: ' + name)
예제 #3
0
class SecretContentChecksTrigger(BaseTrigger):
    __trigger_name__ = 'content_regex_checks'
    __description__ = 'Triggers if the content search analyzer has found any matches with the configured and named regexes. Matches are filtered by the content_regex_name and filename_regex if they are set. The content_regex_name shoud be a value from the "secret_search" section of the analyzer_config.yaml.'

    secret_contentregexp = TriggerParameter(
        name='content_regex_name',
        validator=TypeValidator('string'),
        example_str=default_included_regex_names[0],
        description=
        'Name of content regexps configured in the analyzer that should trigger if found in the image, instead of triggering for any match. Names available by default are: {}.'
        .format(default_included_regex_names))
    name_regexps = TriggerParameter(
        name='filename_regex',
        validator=TypeValidator('string'),
        example_str='/etc/.*',
        description='Regexp to filter the content matched files by.')

    def evaluate(self, image_obj, context):
        match_filter = self.secret_contentregexp.value(default_if_none=[])
        name_re = re.compile(
            self.name_regexps.value()) if self.name_regexps.value() else None

        if match_filter:
            matches = [x.encode('base64') for x in match_filter]
            matches_decoded = match_filter
        else:
            matches = []
            matches_decoded = []

        for thefile, regexps in context.data.get('secret_content_regexp',
                                                 {}).items():
            thefile = thefile.encode('ascii', errors='replace')
            if not regexps:
                continue

            if regexps and (not name_re or name_re.match(thefile)):
                for regexp in regexps.keys():
                    try:
                        regexp_name, theregexp = regexp.decode('base64').split(
                            "=", 1)
                    except:
                        regexp_name = None
                        theregexp = regexp.decode('base64')

                    if not matches:
                        self._fire(
                            msg=
                            'Secret search analyzer found regexp match in container: file={} regexp={}'
                            .format(thefile, regexp.decode('base64')))
                    elif regexp in matches or theregexp in matches_decoded:
                        self._fire(
                            msg=
                            'Secret search analyzer found regexp match in container: file={} regexp={}'
                            .format(thefile, regexp.decode('base64')))
                    elif regexp_name and regexp_name in matches_decoded:
                        self._fire(
                            msg=
                            'Secret search analyzer found regexp match in container: file={} regexp={}'
                            .format(thefile, regexp.decode('base64')))
예제 #4
0
class SecretContentChecksTrigger(BaseTrigger):
    __trigger_name__ = 'content_regex_checks'
    __description__ = 'Triggers if the secret content search analyzer has found any matches with the configured and named regexes. Checks can be configured to trigger if a match is found or is not found (selected using match_type parameter).  Matches are filtered by the content_regex_name and filename_regex if they are set. The content_regex_name shoud be a value from the "secret_search" section of the analyzer_config.yaml.'

    secret_contentregexp = TriggerParameter(name='content_regex_name', validator=TypeValidator('string'), example_str=default_included_regex_names[0], description='Name of content regexps configured in the analyzer that match if found in the image, instead of matching all. Names available by default are: {}.'.format(default_included_regex_names), sort_order=1)
    name_regexps = TriggerParameter(name='filename_regex', validator=TypeValidator('string'), example_str='/etc/.*', description='Regexp to filter the content matched files by.', sort_order=2)
    match_type = EnumStringParameter(name='match_type', enum_values=['notfound', 'found'], example_str='found', description='Set to define the type of match - trigger if match is found (default) or not found.', is_required=False, sort_order=3)
    
    def evaluate(self, image_obj, context):
        match_filter = self.secret_contentregexp.value(default_if_none=[])
        name_filter = self.name_regexps.value()
        name_re = re.compile(name_filter) if self.name_regexps.value() else None
        match_type = self.match_type.value(default_if_none="found")

        if match_filter:
            matches = [base64.b64encode(ensure_bytes(x)) for x in match_filter]
            matches_decoded = match_filter
        else:
            matches = []
            matches_decoded = []

        onefound=False        
        for thefile, regexps in list(context.data.get('secret_content_regexp', {}).items()):
            thefile = ensure_str(thefile)

            if not regexps:
                continue

            if regexps and (not name_re or name_re.match(thefile)):
                for regexp in list(regexps.keys()):
                    found=False
                    decoded_regexp = ensure_str(base64.b64decode(ensure_bytes(regexp)))

                    try:
                        regexp_name, theregexp = decoded_regexp.split("=", 1)
                    except:
                        regexp_name = None
                        theregexp = decoded_regexp

                    if not matches:
                        found=onefound=True
                    elif regexp in matches or theregexp in matches_decoded:
                        found=onefound=True
                    elif regexp_name and regexp_name in matches_decoded:
                        found=onefound=True
                        
                    if found and match_type=='found':
                        self._fire(msg='Secret content search analyzer found regexp match in container: file={} regexp={}'.format(thefile, decoded_regexp))

        if not onefound and match_type=='notfound':
            f_filter = name_filter
            if not f_filter:
                f_filter = '*'

            m_filter = match_filter
            if not m_filter:
                m_filter = 'all'
            self._fire(msg='Secret content search analyzer did not find regexp match in container: filename_regex={} content_regex_name={}'.format(f_filter, m_filter))
예제 #5
0
class PkgMatchTrigger(BaseTrigger):
    __trigger_name__ = "blacklisted_name_version"
    __description__ = "Triggers if the evaluated image has an NPM package installed that matches the name and optionally a version specified in the parameters."

    name = TriggerParameter(
        validator=TypeValidator("string"),
        name="name",
        is_required=True,
        description="Npm package name to blacklist.",
        example_str="time_diff",
        sort_order=1,
    )
    version = TriggerParameter(
        validator=TypeValidator("string"),
        name="version",
        is_required=False,
        description="Npm package version to blacklist specifically.",
        example_str="0.2.9",
        sort_order=2,
    )

    def evaluate(self, image_obj, context):
        """
        Fire for any npm that is on the blacklist with a full name + version match
        :param image_obj:
        :param context:
        :return:
        """
        npms = image_obj.get_packages_by_type("npm")
        if not npms:
            return

        pkgs = context.data.get(NPM_LISTING_KEY)
        if not pkgs:
            return

        name = self.name.value()
        version = self.version.value(default_if_none=None)

        if name in pkgs:
            pkg_versions = pkgs.get(name)
            if not pkg_versions:
                pkg_versions = []
            if version and version in pkg_versions:
                self._fire(msg="NPM Package is blacklisted: " + name + "-" +
                           version)
            elif version is None:
                self._fire(msg="NPM Package is blacklisted: " + name)
예제 #6
0
class ContentMatchTrigger(BaseTrigger):
    __trigger_name__ = 'content_regex_match'
    __description__ = 'Triggers for each file where the content search analyzer has found a match using configured regexes in the analyzer_config.yaml "content_search" section. If the parameter is set, the trigger will only fire for files that matched the named regex. Refer to your analyzer_config.yaml for the regex values.'

    regex_name = TriggerParameter(validator=TypeValidator('string'), name='regex_name', example_str='.*password.*', description='Regex string that also appears in the FILECHECK_CONTENTMATCH analyzer parameter in analyzer configuration, to limit the check to. If set, will only fire trigger when the specific named regex was found in a file.',
                                  is_required=False)

    def evaluate(self, image_obj, context):
        match_filter = self.regex_name.value()

        if match_filter:
            match_decoded = ensure_str(base64.b64encode(ensure_bytes(match_filter)))
        else:
            return

        for thefile, regexps in list(context.data.get('content_regexp', {}).items()):
            thefile = ensure_str(thefile)
            if not regexps:
                continue
            for regexp in regexps.keys():
                decoded_regexp = ensure_str(base64.b64decode(ensure_bytes(regexp)))
                try:
                    regexp_name, theregexp = decoded_regexp.split("=", 1)
                except:
                    regexp_name = None
                    theregexp = decoded_regexp

                if not match_filter:
                    self._fire(msg='File content analyzer found regexp match in container: file={} regexp={}'.format(thefile, decoded_regexp))
                elif regexp == match_filter or theregexp == match_decoded:
                    self._fire(msg='File content analyzer found regexp match in container: file={} regexp={}'.format(thefile, decoded_regexp))
                elif regexp_name and regexp_name == match_decoded:
                    self._fire(msg='File content analyzer found regexp match in container: file={} regexp={}'.format(thefile, decoded_regexp))
예제 #7
0
class FilenameMatchTrigger(BaseTrigger):
    __trigger_name__ = "name_match"
    __description__ = "Triggers if a file exists in the container that has a filename that matches the provided regex. This does have a performance impact on policy evaluation."

    regex = TriggerParameter(
        validator=TypeValidator("string"),
        name="regex",
        example_str=".*\.pem",
        description="Regex to apply to file names for match.",
        is_required=True,
    )

    def evaluate(self, image_obj, context):
        # decode the param regexes from b64
        regex_param = self.regex.value()

        files = []
        if hasattr(context, "data"):
            files = context.data.get("filenames")

        for thefile in files:
            thefile = ensure_str(thefile)
            if re.match(regex_param, thefile):
                self._fire(
                    msg="Application of regex matched file found in container: file={} regexp={}".format(
                        thefile, regex_param
                    )
                )
예제 #8
0
class PEntryMatchTrigger(BaseTrigger, PentryBlacklistMixin):
    __trigger_name__ = 'blacklist_full_entry'
    __description__ = 'Triggers if entire specified passwd entry is found in the /etc/passwd file.'

    pentry_blacklist = TriggerParameter(
        name='entry',
        example_str='ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin',
        description='Full entry to match in /etc/passwd.',
        validator=TypeValidator('string'),
        is_required=True)

    def evaluate(self, image_obj, context):
        if not context.data.get('passwd_entries'):
            return

        user_entries = context.data.get('passwd_entries')
        blacklisted = [self.pentry_blacklist.value().strip()]

        for pentry, pentry in self.exec_blacklist(blacklisted, None,
                                                  user_entries):
            self._fire(
                msg=
                "Blacklisted pentry '{}' found in image's /etc/passwd: pentry={}"
                .format(pentry, str(pentry)))

        return
예제 #9
0
class FilenameMatchTrigger(BaseTrigger):
    __trigger_name__ = 'name_match'
    __description__ = 'Triggers if a file exists in the container that has a filename that matches the provided regex. This does have a performance impact on policy evaluation.'

    regex = TriggerParameter(
        validator=TypeValidator('string'),
        name='regex',
        example_str='.*\.pem',
        description='Regex to apply to file names for match.',
        is_required=True)

    def evaluate(self, image_obj, context):
        # decode the param regexes from b64
        regex_param = self.regex.value()

        files = []
        if hasattr(context, 'data'):
            files = context.data.get('filenames')

        for thefile in files:
            thefile = ensure_str(thefile)
            if re.match(regex_param, thefile):
                self._fire(
                    msg=
                    'Application of regex matched file found in container: file={} regexp={}'
                    .format(thefile, regex_param))
예제 #10
0
    def test_object(self):
        matrix = [('blah', False), (1, False), (['a'], False), ({}, True),
                  ({
                      'a': 'b'
                  }, True)]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator('object'))
예제 #11
0
    def test_string(self):
        matrix = [('blah', True), ('', True), (1, False), (['a'], False),
                  ({}, False), ({
                      'a': 'b'
                  }, False)]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator('string'))
예제 #12
0
    def test_array(self):
        matrix = [('blah', False), (1, False), (['a'], True), ([], True),
                  ({
                      'a': 'b'
                  }, False), ('null', False)]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator('array'))
예제 #13
0
    def test_number(self):
        matrix = [('blah', False), (1, True), (1.0, True), (['a'], False),
                  ({}, False), ({
                      'a': 'b'
                  }, False)]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator('number'))
예제 #14
0
    def test_boolean(self):
        matrix = [(True, True), (False, True), ('true', False),
                  ('True', False), ('false', False), ('False', False),
                  ('abc', False), (1, False), (['a'], False),
                  ({
                      'a': 'b'
                  }, False)]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator("boolean"))
예제 #15
0
class EffectiveUserTrigger(DockerfileModeCheckedBaseTrigger):
    __trigger_name__ = "effective_user"
    __description__ = "Checks if the effective user matches the provided user names, either as a whitelist or blacklist depending on the type parameter setting."

    user = CommaDelimitedStringListParameter(
        name="users",
        example_str="root,docker",
        description=
        "User names to check against as the effective user (last user entry) in the images history.",
        is_required=True,
        validator=TypeValidator("string"),
        sort_order=1,
    )
    allowed_type = EnumStringParameter(
        name="type",
        enum_values=["whitelist", "blacklist"],
        example_str="blacklist",
        description="How to treat the provided user names.",
        is_required=True,
        sort_order=2,
    )

    _sanitize_regex = "\s*USER\s+\[?([^\]]+)\]?\s*"

    def _evaluate(self, image_obj, context):
        rule_users = self.user.value()
        is_allowed = self.allowed_type.value().lower() == "whitelist"

        user_lines = context.data.get("prepared_dockerfile").get("USER", [])

        # If not overt, make it so
        if not user_lines:
            user_lines = ["USER root"]

        user = user_lines[-1].strip(
        )  # The last USER line is the determining entry
        match = re.search(self._sanitize_regex, user)
        if match and match.groups():
            user = match.groups()[0]
        else:
            logger.warn(
                "Found USER line in dockerfile that does not match expected regex: {}, Line: {}"
                .format(self._sanitize_regex, user))
            return

        if is_allowed and user not in rule_users:
            self._fire(
                msg=
                "User {} found as effective user, which is not on the allowed list"
                .format(user))
        elif not is_allowed and user in rule_users:
            self._fire(
                msg=
                "User {} found as effective user, which is explicity not allowed"
                .format(user))
예제 #16
0
class EffectiveUserTrigger(DockerfileModeCheckedBaseTrigger):
    __trigger_name__ = 'effective_user'
    __description__ = 'Checks if the effective user matches the provided user names and fires based on the allowed parameter. If allowed=true, the rule behaves as a whitelist, otherwise acts as a blacklist.'

    user = CommaDelimitedStringListParameter(
        name='users',
        example_str='root,docker',
        description=
        'User names to check against as the effective user (last user entry) in the images history.',
        is_required=True,
        validator=TypeValidator('string'),
        sort_order=1)
    allowed_type = EnumStringParameter(
        name='type',
        enum_values=['whitelist', 'blacklist'],
        description='How to treat the provided user names.',
        is_required=True,
        sort_order=2)

    _sanitize_regex = '\s*USER\s+\[?([^\]]+)\]?\s*'

    def _evaluate(self, image_obj, context):
        rule_users = self.user.value()
        is_allowed = self.allowed_type.value().lower() == 'whitelist'

        user_lines = context.data.get('prepared_dockerfile').get('USER', [])

        # If not overt, make it so
        if not user_lines:
            user_lines = ['USER root']

        user = user_lines[-1].strip(
        )  # The last USER line is the determining entry
        match = re.search(self._sanitize_regex, user)
        if match and match.groups():
            user = match.groups()[0]
        else:
            log.warn(
                'Found USER line in dockerfile that does not match expected regex: {}, Line: {}'
                .format(self._sanitize_regex, user))
            return

        if is_allowed and user not in rule_users:
            self._fire(
                msg=
                'User {} found as effective user, which is not on the allowed list'
                .format(user))
        elif not is_allowed and user in rule_users:
            self._fire(
                msg=
                'User {} found as effective user, which is explicity not allowed list'
                .format(user))
예제 #17
0
    def test_object(self):
        matrix = [
            ("blah", False),
            (1, False),
            (["a"], False),
            ({}, True),
            ({
                "a": "b"
            }, True),
        ]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator("object"))
예제 #18
0
class BlackListTrigger(BaseTrigger):
    __trigger_name__ = "blacklist"
    __description__ = "Triggers if the evaluated image has a package installed that matches the named package optionally with a specific version as well."

    pkg_name = TriggerParameter(
        name="name",
        example_str="openssh-server",
        description="Package name to blacklist.",
        sort_order=1,
        validator=TypeValidator("string"),
        is_required=True,
    )
    pkg_version = TriggerParameter(
        name="version",
        example_str="1.0.1",
        description="Specific version of package to blacklist.",
        validator=TypeValidator("string"),
        sort_order=2,
        is_required=False,
    )

    def evaluate(self, image_obj, context):
        pkg = self.pkg_name.value()
        vers = self.pkg_version.value()

        try:
            if vers:
                matches = image_obj.packages.filter(
                    ImagePackage.name == pkg, ImagePackage.version == vers)
                for m in matches:
                    self._fire(msg="Package is blacklisted: " + m.name + "-" +
                               m.version)
            else:
                matches = image_obj.packages.filter(ImagePackage.name == pkg)
                for m in matches:
                    self._fire(msg="Package is blacklisted: " + m.name)
        except Exception as e:
            logger.exception("Error filtering packages for full match")
            pass
예제 #19
0
class FakeTrigger(gate.BaseTrigger):
    __trigger_name__ = 'TestingTrigger'
    __description__ = 'Not real'
    __trigger_id__ = 'Blah123'

    param1 = params.TriggerParameter(name='param_test',
                                     example_str='somevalue',
                                     description='Test parameter',
                                     validator=TypeValidator("string"),
                                     is_required=False)

    def test1(self):
        print((type(self.param1)))
예제 #20
0
    def test_array(self):
        matrix = [
            ("blah", False),
            (1, False),
            (["a"], True),
            ([], True),
            ({
                "a": "b"
            }, False),
            ("null", False),
        ]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator("array"))
예제 #21
0
    def test_number(self):
        matrix = [
            ("blah", False),
            (1, True),
            (1.0, True),
            (["a"], False),
            ({}, False),
            ({
                "a": "b"
            }, False),
        ]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator("number"))
예제 #22
0
    def test_string(self):
        matrix = [
            ("blah", True),
            ("", True),
            (1, False),
            (["a"], False),
            ({}, False),
            ({
                "a": "b"
            }, False),
        ]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator("string"))
예제 #23
0
class BlackListTrigger(BaseTrigger):
    __trigger_name__ = 'blacklist'
    __description__ = 'Triggers if the evaluated image has a package installed that matches the named package optionally with a specific version as well.'

    pkg_name = TriggerParameter(name='name',
                                example_str='openssh-server',
                                description="Package name to blacklist.",
                                sort_order=1,
                                validator=TypeValidator('string'),
                                is_required=True)
    pkg_version = TriggerParameter(
        name='version',
        example_str='1.0.1',
        description='Specific version of package to blacklist.',
        validator=TypeValidator('string'),
        sort_order=2,
        is_required=False)

    def evaluate(self, image_obj, context):
        pkg = self.pkg_name.value()
        vers = self.pkg_version.value()

        try:
            if vers:
                matches = image_obj.packages.filter(
                    ImagePackage.name == pkg, ImagePackage.version == vers)
                for m in matches:
                    self._fire(msg='Package is blacklisted: ' + m.name + "-" +
                               m.version)
            else:
                matches = image_obj.packages.filter(ImagePackage.name == pkg)
                for m in matches:
                    self._fire(msg='Package is blacklisted: ' + m.name)
        except Exception as e:
            logger.exception('Error filtering packages for full match')
            pass
예제 #24
0
class FakeTrigger(gate.BaseTrigger):
    __trigger_name__ = "TestingTrigger"
    __description__ = "Not real"
    __trigger_id__ = "Blah123"

    param1 = params.TriggerParameter(
        name="param_test",
        example_str="somevalue",
        description="Test parameter",
        validator=TypeValidator("string"),
        is_required=False,
    )

    def test1(self):
        print((type(self.param1)))
예제 #25
0
    def test_linked(self):
        p1 = params.EnumStringParameter(
            name="attribute",
            description="Testing123",
            enum_values=["a", "b"],
            is_required=True,
        )
        p2 = params.SimpleStringParameter(
            name="downstream",
            validator=LinkedValidator(
                discriminator_parameter="attribute",
                default_validator=TypeValidator("string"),
                value_map={
                    "a": BooleanStringValidator(),
                    "b": IntegerValidator()
                },
            ),
            description="test123",
        )

        print(p2.validator.validation_criteria())

        # p1.set_value('a')
        p2.validator.inject_discriminator(None)
        test_matrix = [
            ("true", "true"),
            ("blah", "blah"),  # p1 not set, so uses default
        ]
        self.run_matrix_test(test_matrix, p2)

        p1._param_value = None
        p2._param_value = None
        p2.validator.inject_discriminator("a")
        p1.set_value("a")
        test_matrix = [
            ("true", "true"),
            ("blah", False),  # should fail now that p1 has a value
        ]

        self.run_matrix_test(test_matrix, p2)

        p1._param_value = None
        p2._param_value = None
        p1.set_value("b")
        p2.validator.inject_discriminator("b")
        test_matrix = [("true", False), ("blah", False), ("123", "123")]

        self.run_matrix_test(test_matrix, p2)
예제 #26
0
    def test_boolean(self):
        matrix = [
            (True, True),
            (False, True),
            ("true", False),
            ("True", False),
            ("false", False),
            ("False", False),
            ("abc", False),
            (1, False),
            (["a"], False),
            ({
                "a": "b"
            }, False),
        ]

        self.run_matrix_test(value_matrix=matrix,
                             validator=TypeValidator("boolean"))
예제 #27
0
    def test_param_basics(self):
        p = params.TriggerParameter(
            'TestParam1',
            description='Param for testing basic strings',
            validator=TypeValidator("string"),
            related_to='ThisOtherParam')

        print('Trying string that should pass validation')

        # Should pass validation
        print((p.set_value('somestring')))
        print(('Got value: {}'.format(p.value())))

        print('Trying an int that should fail validation')

        # Should fail validation
        with self.assertRaises(ValidationError) as ex:
            print((p.set_value(10)))

        print(('Correctly got exception {}'.format(ex.exception)))
예제 #28
0
    def test_param_basics(self):
        p = params.TriggerParameter(
            "TestParam1",
            description="Param for testing basic strings",
            validator=TypeValidator("string"),
            related_to="ThisOtherParam",
        )

        print("Trying string that should pass validation")

        # Should pass validation
        print((p.set_value("somestring")))
        print(("Got value: {}".format(p.value())))

        print("Trying an int that should fail validation")

        # Should fail validation
        with self.assertRaises(ValidationError) as ex:
            print((p.set_value(10)))

        print(("Correctly got exception {}".format(ex.exception)))
예제 #29
0
class FileAttributeMatchTrigger(BaseTrigger):
    __trigger_name__ = 'attribute_match'
    __description__ = 'Triggers if a filename exists in the container that has attributes that match those which are provided . This check has a performance impact on policy evaluation.'

    filename = TriggerParameter(
        validator=TypeValidator('string'),
        name='filename',
        example_str='/etc/passwd',
        description='Filename to check against provided checksum.',
        is_required=True,
        sort_order=1)

    checksum_algo = EnumStringParameter(name='checksum_algorithm',
                                        enum_values=['sha256'],
                                        example_str='sha256',
                                        description='Checksum algorithm',
                                        is_required=False,
                                        sort_order=2)
    checksum = TriggerParameter(
        validator=TypeValidator('string'),
        name='checksum',
        example_str=
        '832cd0f75b227d13aac82b1f70b7f90191a4186c151f9db50851d209c45ede11',
        description='Checksum of file.',
        is_required=False,
        sort_order=3)

    checksum_op = EnumStringParameter(
        name='checksum_match',
        enum_values=['equals', 'not_equals'],
        example_str='equals',
        description='Checksum operation to perform.',
        is_required=False,
        sort_order=4)

    mode = TriggerParameter(validator=TypeValidator('string'),
                            name='mode',
                            example_str='00644',
                            description='File mode of file.',
                            is_required=False,
                            sort_order=5)
    mode_op = EnumStringParameter(
        name='mode_op',
        enum_values=['equals', 'not_equals'],
        example_str='equals',
        description='File mode operation to perform.',
        is_required=False,
        sort_order=6)

    skip_if_file_missing = BooleanStringParameter(
        name='skip_missing',
        example_str='true',
        description=
        'If set to true, do not fire this trigger if the file is not present.  If set to false, fire this trigger ignoring the other parameter settings.',
        is_required=False,
        sort_order=7)

    def evaluate(self, image_obj, context):
        filename = self.filename.value()

        checksum_algo = self.checksum_algo.value(default_if_none='sha256')
        checksum = self.checksum.value()
        checksum_op = self.checksum_op.value(default_if_none='equals')

        mode = self.mode.value()
        mode_op = self.mode_op.value(default_if_none='equals')

        skip_if_file_missing = self.skip_if_file_missing.value(
            default_if_none=True)

        filedetails = {}
        if hasattr(context, 'data'):
            filedetails = context.data.get('filedetail')

        fire_params = {}
        filedetail = filedetails.get(filename, None)

        if filedetail:

            # checksum checks

            if checksum and checksum_op and checksum_algo:
                file_checksum = None
                if checksum_algo == 'sha256':
                    file_checksum = filedetail.get('sha256_checksum', "")

                if checksum_op == 'equals' and file_checksum == checksum:
                    fire_params[
                        'checksum'] = "checksum={} op={} specified_checksum={}".format(
                            file_checksum, checksum_op, checksum)
                elif checksum_op == 'not_equals' and file_checksum != checksum:
                    fire_params[
                        'checksum'] = "checksum={} op={} specified_checksum={}".format(
                            file_checksum, checksum_op, checksum)
                else:
                    return

            # mode checks

            if mode and mode_op:
                file_mode = filedetail.get('mode', 0)

                file_mode_cmp = oct(stat.S_IMODE(file_mode))
                input_mode_cmp = oct(int(mode, 8))

                if mode_op == 'equals' and file_mode_cmp == input_mode_cmp:
                    fire_params[
                        'mode'] = "mode={} op={} specified_mode={}".format(
                            file_mode_cmp, mode_op, input_mode_cmp)
                elif mode_op == 'not_equals' and file_mode_cmp != input_mode_cmp:
                    fire_params[
                        'mode'] = "mode={} op={} specified_mode={}".format(
                            file_mode_cmp, mode_op, input_mode_cmp)
                else:
                    return
        else:
            # case where file doesn't exist
            if skip_if_file_missing:
                return
            fire_params['skip'] = "skip_missing=False"

        if fire_params:
            msg = "filename={}".format(filename)
            for k in fire_params.keys():
                msg += " and {}".format(fire_params[k])

            self._fire(msg=msg)
예제 #30
0
class DirectiveCheckTrigger(BaseTrigger):
    __trigger_name__ = 'directivecheck'
    __description__ = 'Triggers if any directives in the list are found to match the described condition in the dockerfile'

    directives = EnumCommaDelimStringListParameter(name='directives', description='The Dockerfile instruction to check', enum_values=DIRECTIVES, is_required=True, related_to='check')
    check = EnumStringParameter(name='check', description='The type of check to perform', enum_values=CONDITIONS, is_required=True, related_to='directive, check_value')
    check_value = TriggerParameter(name='check_value', description='The value to check the dockerfile instruction against', is_required=False, related_to='directive, check', validator=TypeValidator("string"))

    _conditions_requiring_check_val = [
        '=', '!=', 'like', 'not_like'
    ]

    ops = {
        '=': lambda x, y: x == y,
        '!=': lambda x, y: x != y,
        'exists': lambda x, y: True,
        'not_exists': lambda x, y: False,
        'like': lambda x, y: bool(re.match(y, x)),
        'not_like': lambda x, y: not bool(re.match(y, x))
    }

    def evaluate(self, image_obj, context):
        if not context.data.get('prepared_dockerfile'):
            return # Prep step blocked this eval due to condition on the dockerfile, so skip

        directives = set(self.directives.value(default_if_none=[])) # Note: change from multiple values to a single value
        condition = self.check.value(default_if_none='')
        check_value = self.check_value.value(default_if_none=[])
        operation = self.ops.get(condition)

        if not condition or not directives:
            return

        df = context.data.get('prepared_dockerfile')

        for directive, lines in filter(lambda x: x[0] in directives, df.items()):
            for l in lines:
                l = l[len(directive):].strip()
                if operation(l, check_value):
                    self._fire(msg="Dockerfile directive '{}' check '{}' matched against '{}' for line '{}'".format(directive, condition, check_value if check_value else '', l))

        if condition == 'not_exists':
            for match in directives.difference(directives.intersection(set(map(lambda x: x.upper(), df.keys())))):
                self._fire(msg="Dockerfile directive '{}' not found, matching condition '{}' check".format(match, condition))