class ChangeRevFakeModelDB(stormbase.StormBaseDB, stormbase.ChangeRevisionFieldMixin): context = stormbase.EscapedDictField()
class ActionExecutionDB(stormbase.StormFoundationDB): RESOURCE_TYPE = ResourceType.EXECUTION UID_FIELDS = ['id'] trigger = stormbase.EscapedDictField() trigger_type = stormbase.EscapedDictField() trigger_instance = stormbase.EscapedDictField() rule = stormbase.EscapedDictField() action = stormbase.EscapedDictField(required=True) runner = stormbase.EscapedDictField(required=True) # Only the diff between the liveaction type and what is replicated # in the ActionExecutionDB object. liveaction = stormbase.EscapedDictField(required=True) workflow_execution = me.StringField() task_execution = me.StringField() status = me.StringField(required=True, help_text='The current status of the liveaction.') start_timestamp = ComplexDateTimeField( default=date_utils.get_datetime_utc_now, help_text='The timestamp when the liveaction was created.') end_timestamp = ComplexDateTimeField( help_text='The timestamp when the liveaction has finished.') parameters = stormbase.EscapedDynamicField( default={}, help_text='The key-value pairs passed as to the action runner & action.' ) result = stormbase.EscapedDynamicField(default={}, help_text='Action defined result.') context = me.DictField( default={}, help_text='Contextual information on the action execution.') parent = me.StringField() children = me.ListField(field=me.StringField()) log = me.ListField(field=me.DictField()) # Do not use URLField for web_url. If host doesn't have FQDN set, URLField validation blows. web_url = me.StringField(required=False) meta = { 'indexes': [{ 'fields': ['rule.ref'] }, { 'fields': ['action.ref'] }, { 'fields': ['liveaction.id'] }, { 'fields': ['start_timestamp'] }, { 'fields': ['end_timestamp'] }, { 'fields': ['status'] }, { 'fields': ['parent'] }, { 'fields': ['rule.name'] }, { 'fields': ['runner.name'] }, { 'fields': ['trigger.name'] }, { 'fields': ['trigger_type.name'] }, { 'fields': ['trigger_instance.id'] }, { 'fields': ['context.user'] }, { 'fields': ['-start_timestamp', 'action.ref', 'status'] }, { 'fields': ['workflow_execution'] }, { 'fields': ['task_execution'] }] } def get_uid(self): # TODO Construct od from non id field: uid = [self.RESOURCE_TYPE, str(self.id)] return ':'.join(uid) def mask_secrets(self, value): result = copy.deepcopy(value) liveaction = result['liveaction'] parameters = {} # pylint: disable=no-member parameters.update(value.get('action', {}).get('parameters', {})) parameters.update(value.get('runner', {}).get('runner_parameters', {})) secret_parameters = get_secret_parameters(parameters=parameters) result['parameters'] = mask_secret_parameters( parameters=result['parameters'], secret_parameters=secret_parameters) if 'parameters' in liveaction: liveaction['parameters'] = mask_secret_parameters( parameters=liveaction['parameters'], secret_parameters=secret_parameters) if liveaction.get('action', '') == 'st2.inquiry.respond': # Special case to mask parameters for `st2.inquiry.respond` action # In this case, this execution is just a plain python action, not # an inquiry, so we don't natively have a handle on the response # schema. # # To prevent leakage, we can just mask all response fields. # # Note: The 'string' type in secret_parameters doesn't matter, # it's just a placeholder to tell mask_secret_parameters() # that this parameter is indeed a secret parameter and to # mask it. result['parameters']['response'] = mask_secret_parameters( parameters=liveaction['parameters']['response'], secret_parameters={ p: 'string' for p in liveaction['parameters']['response'] }) # TODO(mierdin): This logic should be moved to the dedicated Inquiry # data model once it exists. if self.runner.get('name') == "inquirer": schema = result['result'].get('schema', {}) response = result['result'].get('response', {}) # We can only mask response secrets if response and schema exist and are # not empty if response and schema: result['result']['response'] = mask_inquiry_response( response, schema) return result def get_masked_parameters(self): """ Retrieve parameters with the secrets masked. :rtype: ``dict`` """ serializable_dict = self.to_serializable_dict(mask_secrets=True) return serializable_dict['parameters']
class ActionExecutionDB(stormbase.StormFoundationDB): RESOURCE_TYPE = ResourceType.EXECUTION UID_FIELDS = ['id'] trigger = stormbase.EscapedDictField() trigger_type = stormbase.EscapedDictField() trigger_instance = stormbase.EscapedDictField() rule = stormbase.EscapedDictField() action = stormbase.EscapedDictField(required=True) runner = stormbase.EscapedDictField(required=True) # Only the diff between the liveaction type and what is replicated # in the ActionExecutionDB object. liveaction = stormbase.EscapedDictField(required=True) status = me.StringField(required=True, help_text='The current status of the liveaction.') start_timestamp = ComplexDateTimeField( default=date_utils.get_datetime_utc_now, help_text='The timestamp when the liveaction was created.') end_timestamp = ComplexDateTimeField( help_text='The timestamp when the liveaction has finished.') parameters = stormbase.EscapedDynamicField( default={}, help_text='The key-value pairs passed as to the action runner & action.' ) result = stormbase.EscapedDynamicField(default={}, help_text='Action defined result.') context = me.DictField( default={}, help_text='Contextual information on the action execution.') parent = me.StringField() children = me.ListField(field=me.StringField()) log = me.ListField(field=me.DictField()) # Do not use URLField for web_url. If host doesn't have FQDN set, URLField validation blows. web_url = me.StringField(required=False) meta = { 'indexes': [{ 'fields': ['rule.ref'] }, { 'fields': ['action.ref'] }, { 'fields': ['liveaction.id'] }, { 'fields': ['start_timestamp'] }, { 'fields': ['end_timestamp'] }, { 'fields': ['status'] }, { 'fields': ['parent'] }, { 'fields': ['rule.name'] }, { 'fields': ['runner.name'] }, { 'fields': ['trigger.name'] }, { 'fields': ['trigger_type.name'] }, { 'fields': ['context.user'] }, { 'fields': ['-start_timestamp', 'action.ref', 'status'] }] } def get_uid(self): # TODO Construct od from non id field: uid = [self.RESOURCE_TYPE, str(self.id)] return ':'.join(uid) def mask_secrets(self, value): result = copy.deepcopy(value) execution_parameters = value['parameters'] parameters = {} # pylint: disable=no-member parameters.update(value.get('action', {}).get('parameters', {})) parameters.update(value.get('runner', {}).get('runner_parameters', {})) secret_parameters = get_secret_parameters(parameters=parameters) result['parameters'] = mask_secret_parameters( parameters=execution_parameters, secret_parameters=secret_parameters) return result def get_masked_parameters(self): """ Retrieve parameters with the secrets masked. :rtype: ``dict`` """ serializable_dict = self.to_serializable_dict(mask_secrets=True) return serializable_dict['parameters']
class RuleDB(stormbase.StormFoundationDB, stormbase.TagsMixin, stormbase.ContentPackResourceMixin, stormbase.UIDFieldMixin): """Specifies the action to invoke on the occurrence of a Trigger. It also includes the transformation to perform to match the impedance between the payload of a TriggerInstance and input of a action. Attribute: trigger: Trigger that trips this rule. criteria: action: Action to execute when the rule is tripped. status: enabled or disabled. If disabled occurrence of the trigger does not lead to execution of a action and vice-versa. """ RESOURCE_TYPE = ResourceType.RULE UID_FIELDS = ['pack', 'name'] name = me.StringField(required=True) ref = me.StringField(required=True) description = me.StringField() pack = me.StringField(required=False, help_text='Name of the content pack.', unique_with='name') type = me.EmbeddedDocumentField(RuleTypeSpecDB, default=RuleTypeSpecDB()) trigger = me.StringField() criteria = stormbase.EscapedDictField() action = me.EmbeddedDocumentField(ActionExecutionSpecDB) context = me.DictField(default={}, help_text='Contextual info on the rule') enabled = me.BooleanField( required=True, default=True, help_text=u'Flag indicating whether the rule is enabled.') meta = { 'indexes': [ { 'fields': ['enabled'] }, { 'fields': ['action.ref'] }, { 'fields': ['trigger'] }, { 'fields': ['context.user'] }, ] + (stormbase.ContentPackResourceMixin.get_indexes() + stormbase.TagsMixin.get_indexes() + stormbase.UIDFieldMixin.get_indexes()) } def mask_secrets(self, value): """ Process the model dictionary and mask secret values. NOTE: This method results in one addition "get one" query where we retrieve corresponding action model so we can correctly mask secret parameters. :type value: ``dict`` :param value: Document dictionary. :rtype: ``dict`` """ result = copy.deepcopy(value) action_ref = result.get('action', {}).get('ref', None) if not action_ref: return result action_db = self._get_referenced_action_model(action_ref=action_ref) if not action_db: return result secret_parameters = get_secret_parameters( parameters=action_db.parameters) result['action']['parameters'] = mask_secret_parameters( parameters=result['action']['parameters'], secret_parameters=secret_parameters) return result def _get_referenced_action_model(self, action_ref): """ Return Action object for the action referenced in a rule. :param action_ref: Action reference. :type action_ref: ``str`` :rtype: ``ActionDB`` """ # NOTE: We need to retrieve pack and name since that's needed for the PK action_dbs = Action.query( only_fields=['pack', 'ref', 'name', 'parameters'], ref=action_ref, limit=1) if action_dbs: return action_dbs[0] return None def __init__(self, *args, **values): super(RuleDB, self).__init__(*args, **values) self.ref = self.get_reference().ref self.uid = self.get_uid()
class FakeModelDB(stormbase.StormBaseDB): context = stormbase.EscapedDictField() index = mongoengine.IntField(min_value=0) category = mongoengine.StringField() timestamp = mongoengine.DateTimeField()
class LiveActionDB_EscapedDictField(LiveActionDB): result = stormbase.EscapedDictField(default={}) field1 = stormbase.EscapedDynamicField(default={}, use_header=False) field2 = stormbase.EscapedDynamicField(default={}, use_header=False) field3 = stormbase.EscapedDynamicField(default={}, use_header=False)
class ActionExecutionDB(stormbase.StormFoundationDB): RESOURCE_TYPE = ResourceType.EXECUTION UID_FIELDS = ["id"] trigger = stormbase.EscapedDictField() trigger_type = stormbase.EscapedDictField() trigger_instance = stormbase.EscapedDictField() rule = stormbase.EscapedDictField() action = stormbase.EscapedDictField(required=True) runner = stormbase.EscapedDictField(required=True) # Only the diff between the liveaction type and what is replicated # in the ActionExecutionDB object. liveaction = stormbase.EscapedDictField(required=True) workflow_execution = me.StringField() task_execution = me.StringField() status = me.StringField( required=True, help_text="The current status of the liveaction." ) start_timestamp = ComplexDateTimeField( default=date_utils.get_datetime_utc_now, help_text="The timestamp when the liveaction was created.", ) end_timestamp = ComplexDateTimeField( help_text="The timestamp when the liveaction has finished." ) parameters = stormbase.EscapedDynamicField( default={}, help_text="The key-value pairs passed as to the action runner & action.", ) result = JSONDictEscapedFieldCompatibilityField( default={}, help_text="Action defined result." ) result_size = me.IntField(default=0, help_text="Serialized result size in bytes") context = me.DictField( default={}, help_text="Contextual information on the action execution." ) parent = me.StringField() children = me.ListField(field=me.StringField()) log = me.ListField(field=me.DictField()) delay = me.IntField(min_value=0) # Do not use URLField for web_url. If host doesn't have FQDN set, URLField validation blows. web_url = me.StringField(required=False) meta = { "indexes": [ {"fields": ["rule.ref"]}, {"fields": ["action.ref"]}, {"fields": ["liveaction.id"]}, {"fields": ["start_timestamp"]}, {"fields": ["end_timestamp"]}, {"fields": ["status"]}, {"fields": ["parent"]}, {"fields": ["rule.name"]}, {"fields": ["runner.name"]}, {"fields": ["trigger.name"]}, {"fields": ["trigger_type.name"]}, {"fields": ["trigger_instance.id"]}, {"fields": ["context.user"]}, {"fields": ["-start_timestamp", "action.ref", "status"]}, {"fields": ["workflow_execution"]}, {"fields": ["task_execution"]}, ] } def get_uid(self): # TODO Construct id from non id field: uid = [self.RESOURCE_TYPE, str(self.id)] # pylint: disable=no-member return ":".join(uid) def mask_secrets(self, value): """ Masks the secret parameters in input and output schema for action execution output. :param value: action execution object. :type value: ``dict`` :return: result: action execution object with masked secret paramters in input and output schema. :rtype: result: ``dict`` """ result = copy.deepcopy(value) liveaction = result["liveaction"] parameters = {} # pylint: disable=no-member parameters.update(value.get("action", {}).get("parameters", {})) parameters.update(value.get("runner", {}).get("runner_parameters", {})) secret_parameters = get_secret_parameters(parameters=parameters) result["parameters"] = mask_secret_parameters( parameters=result.get("parameters", {}), secret_parameters=secret_parameters ) if "parameters" in liveaction: liveaction["parameters"] = mask_secret_parameters( parameters=liveaction["parameters"], secret_parameters=secret_parameters ) if liveaction.get("action", "") == "st2.inquiry.respond": # Special case to mask parameters for `st2.inquiry.respond` action # In this case, this execution is just a plain python action, not # an inquiry, so we don't natively have a handle on the response # schema. # # To prevent leakage, we can just mask all response fields. # # Note: The 'string' type in secret_parameters doesn't matter, # it's just a placeholder to tell mask_secret_parameters() # that this parameter is indeed a secret parameter and to # mask it. result["parameters"]["response"] = mask_secret_parameters( parameters=liveaction["parameters"]["response"], secret_parameters={ p: "string" for p in liveaction["parameters"]["response"] }, ) output_value = ActionExecutionDB.result.parse_field_value(result["result"]) masked_output_value = output_schema.mask_secret_output(result, output_value) result["result"] = masked_output_value # TODO(mierdin): This logic should be moved to the dedicated Inquiry # data model once it exists. if self.runner.get("name") == "inquirer": schema = result["result"].get("schema", {}) response = result["result"].get("response", {}) # We can only mask response secrets if response and schema exist and are # not empty if response and schema: result["result"]["response"] = mask_inquiry_response(response, schema) return result def get_masked_parameters(self): """ Retrieve parameters with the secrets masked. :rtype: ``dict`` """ serializable_dict = self.to_serializable_dict(mask_secrets=True) return serializable_dict["parameters"]