示例#1
0
def run_action(version_id):
    log.info('Checking rules and actions for version %s.', version_id)
    version = Version.objects.get(pk=version_id)

    rule = (
        ScannerRule.objects.filter(scannerresult__version=version,
                                   is_active=True).order_by(
                                       # The `-` sign means descending order.
                                       '-action').first())

    if not rule:
        log.info('No action to execute for version %s.', version_id)
        return

    action_id = rule.action
    action_name = ACTIONS.get(action_id, None)

    if not action_name:
        raise Exception("invalid action %s" % action_id)

    ACTION_FUNCTIONS = {
        NO_ACTION: _no_action,
        FLAG_FOR_HUMAN_REVIEW: _flag_for_human_review,
    }

    action_function = ACTION_FUNCTIONS.get(action_id, None)

    if not action_function:
        raise Exception("no implementation for action %s" % action_id)

    # We have a valid action to execute, so let's do it!
    log.info('Starting action "%s" for version %s.', action_name, version_id)
    action_function(version)
    log.info('Ending action "%s" for version %s.', action_name, version_id)
示例#2
0
class AbstractScannerRule(ModelBase):
    name = models.CharField(
        max_length=200,
        help_text=_('This is the exact name of the rule used by a scanner.'),
    )
    scanner = models.PositiveSmallIntegerField(choices=SCANNERS.items())
    action = models.PositiveSmallIntegerField(choices=ACTIONS.items(),
                                              default=NO_ACTION)
    is_active = models.BooleanField(
        default=True,
        help_text=_(
            'When unchecked, the scanner results will not be bound to this '
            'rule and the action will not be executed.'))
    definition = models.TextField(null=True, blank=True)

    class Meta(ModelBase.Meta):
        abstract = True
        unique_together = ('name', 'scanner')

    def __str__(self):
        return self.name

    def clean(self):
        if self.scanner == YARA:
            self.clean_yara()

    def clean_yara(self):
        if not self.definition:
            raise ValidationError(
                {'definition': _('Yara rules should have a definition')})

        if 'rule {}'.format(self.name) not in self.definition:
            raise ValidationError({
                'definition':
                _('The name of the rule in the definition should match '
                  'the name of the scanner rule')
            })

        if len(re.findall(r'rule\s+.+?\s+{', self.definition)) > 1:
            raise ValidationError({
                'definition':
                _('Only one Yara rule is allowed in the definition')
            })

        try:
            yara.compile(source=self.definition)
        except yara.SyntaxError as syntaxError:
            raise ValidationError({
                'definition': _('The definition is not valid: %(error)s') % {
                    'error': syntaxError,
                }
            })
        except Exception:
            raise ValidationError({
                'definition':
                _('An error occurred when compiling the definition')
            })
示例#3
0
    def run_action(cls, version):
        """Try to find and execute an action for a given version, based on the
        scanner results and associated rules.

        If an action is found, it is run synchronously from this method, not in
        a task.
        """
        log.info('Checking rules and actions for version %s.', version.pk)

        rule_model = cls.matched_rules.rel.model
        result_query_name = cls._meta.get_field(
            'matched_rules').related_query_name()

        rule = (
            rule_model.objects.filter(**{
                f'{result_query_name}__version': version, 'is_active': True,
            })
            .order_by(
                # The `-` sign means descending order.
                '-action'
            )
            .first()
        )

        if not rule:
            log.info('No action to execute for version %s.', version.pk)
            return

        action_id = rule.action
        action_name = ACTIONS.get(action_id, None)

        if not action_name:
            raise Exception("invalid action %s" % action_id)

        ACTION_FUNCTIONS = {
            NO_ACTION: _no_action,
            FLAG_FOR_HUMAN_REVIEW: _flag_for_human_review,
            DELAY_AUTO_APPROVAL: _delay_auto_approval,
            DELAY_AUTO_APPROVAL_INDEFINITELY: (
                _delay_auto_approval_indefinitely),
        }

        action_function = ACTION_FUNCTIONS.get(action_id, None)

        if not action_function:
            raise Exception("no implementation for action %s" % action_id)

        # We have a valid action to execute, so let's do it!
        log.info(
            'Starting action "%s" for version %s.', action_name, version.pk)
        action_function(version)
        log.info('Ending action "%s" for version %s.', action_name, version.pk)
示例#4
0
class ScannerRule(ModelBase):
    name = models.CharField(
        max_length=200,
        help_text=_('This is the exact name of the rule used by a scanner.'),
    )
    scanner = models.PositiveSmallIntegerField(choices=SCANNERS.items())
    action = models.PositiveSmallIntegerField(choices=ACTIONS.items(),
                                              default=NO_ACTION)
    is_active = models.BooleanField(default=True)

    class Meta:
        db_table = 'scanners_rules'
        unique_together = ('name', 'scanner')

    def __str__(self):
        return self.name
示例#5
0
def run_action(version_id):
    """This function tries to find an action to execute for a given version,
    based on the scanner results and associated rules.

    It is not run as a Celery task but as a simple function, in the
    auto_approve CRON."""
    log.info('Checking rules and actions for version %s.', version_id)
    version = Version.objects.get(pk=version_id)

    rule = (
        ScannerRule.objects.filter(
            scannerresult__version=version, is_active=True
        )
        .order_by(
            # The `-` sign means descending order.
            '-action'
        )
        .first()
    )

    if not rule:
        log.info('No action to execute for version %s.', version_id)
        return

    action_id = rule.action
    action_name = ACTIONS.get(action_id, None)

    if not action_name:
        raise Exception("invalid action %s" % action_id)

    ACTION_FUNCTIONS = {
        NO_ACTION: _no_action,
        FLAG_FOR_HUMAN_REVIEW: _flag_for_human_review,
        DELAY_AUTO_APPROVAL: _delay_auto_approval,
        DELAY_AUTO_APPROVAL_INDEFINITELY: _delay_auto_approval_indefinitely,
    }

    action_function = ACTION_FUNCTIONS.get(action_id, None)

    if not action_function:
        raise Exception("no implementation for action %s" % action_id)

    # We have a valid action to execute, so let's do it!
    log.info('Starting action "%s" for version %s.', action_name, version_id)
    action_function(version)
    log.info('Ending action "%s" for version %s.', action_name, version_id)
示例#6
0
    def run_action(cls, version):
        """Try to find and execute an action for a given version, based on the
        scanner results and associated rules.

        If an action is found, it is run synchronously from this method, not in
        a task.
        """
        log.info('Checking rules and actions for version %s.', version.pk)

        try:
            mad_result = cls.objects.filter(version=version, scanner=MAD).get()
            customs = mad_result.results.get('scanners', {}).get('customs', {})
            customs_score = customs.get('score', 0.5)
            customs_models_agree = customs.get('result_details', {}).get(
                'models_agree', True
            )

            if (
                customs_score <= 0.01 or
                customs_score >= 0.99 or
                not customs_models_agree
            ):
                log.info('Flagging version %s for human review by MAD.',
                         version.pk)
                _flag_for_human_review_by_scanner(version, MAD)
        except cls.DoesNotExist:
            log.info('No MAD scanner result for version %s.', version.pk)
            pass

        rule_model = cls.matched_rules.rel.model
        result_query_name = cls._meta.get_field(
            'matched_rules'
        ).related_query_name()

        rule = (
            rule_model.objects.filter(
                **{f'{result_query_name}__version': version, 'is_active': True}
            )
            .order_by(
                # The `-` sign means descending order.
                '-action'
            )
            .first()
        )

        if not rule:
            log.info('No action to execute for version %s.', version.pk)
            return

        action_id = rule.action
        action_name = ACTIONS.get(action_id, None)

        if not action_name:
            raise Exception("invalid action %s" % action_id)

        ACTION_FUNCTIONS = {
            NO_ACTION: _no_action,
            FLAG_FOR_HUMAN_REVIEW: _flag_for_human_review,
            DELAY_AUTO_APPROVAL: _delay_auto_approval,
            DELAY_AUTO_APPROVAL_INDEFINITELY: (
                _delay_auto_approval_indefinitely
            ),
        }

        action_function = ACTION_FUNCTIONS.get(action_id, None)

        if not action_function:
            raise Exception("no implementation for action %s" % action_id)

        # We have a valid action to execute, so let's do it!
        log.info(
            'Starting action "%s" for version %s.', action_name, version.pk
        )
        action_function(version)
        log.info('Ending action "%s" for version %s.', action_name, version.pk)
示例#7
0
class AbstractScannerRule(ModelBase):
    name = models.CharField(
        max_length=200,
        help_text=_('This is the exact name of the rule used by a scanner.'),
    )
    scanner = models.PositiveSmallIntegerField(choices=SCANNERS.items())
    action = models.PositiveSmallIntegerField(choices=ACTIONS.items(),
                                              default=NO_ACTION)
    is_active = models.BooleanField(
        default=True,
        help_text=_(
            'When unchecked, the scanner results will not be bound to this '
            'rule and the action will not be executed.'),
    )
    definition = models.TextField(null=True, blank=True)

    class Meta(ModelBase.Meta):
        abstract = True
        unique_together = ('name', 'scanner')

    @classmethod
    def get_yara_externals(cls):
        """
        Return a dict with the various external variables we inject in every
        yara rule automatically and their default values.
        """
        return {
            'is_json_file': False,
            'is_manifest_file': False,
            'is_locale_file': False,
        }

    def __str__(self):
        return self.name

    def clean(self):
        if self.scanner == YARA:
            self.clean_yara()

    def clean_yara(self):
        if not self.definition:
            raise ValidationError(
                {'definition': _('Yara rules should have a definition')})

        if f'rule {self.name}' not in self.definition:
            raise ValidationError({
                'definition':
                _('The name of the rule in the definition should match '
                  'the name of the scanner rule')
            })

        if len(re.findall(r'rule\s+.+?\s+{', self.definition)) > 1:
            raise ValidationError({
                'definition':
                _('Only one Yara rule is allowed in the definition')
            })

        try:
            yara.compile(source=self.definition,
                         externals=self.get_yara_externals())
        except yara.SyntaxError as syntaxError:
            raise ValidationError({
                'definition': _('The definition is not valid: %(error)s') % {
                    'error': syntaxError
                }
            })
        except Exception:
            raise ValidationError({
                'definition':
                _('An error occurred when compiling the definition')
            })