class ActionDB(stormbase.StormFoundationDB, stormbase.TagsMixin, stormbase.ContentPackResourceMixin, stormbase.UIDFieldMixin): """ The system entity that represents a Stack Action/Automation in the system. Attribute: enabled: A flag indicating whether this action is enabled in the system. entry_point: The entry point to the action. runner_type: The actionrunner is used to execute the action. parameters: The specification for parameters for the action. """ RESOURCE_TYPE = ResourceType.ACTION UID_FIELDS = ['pack', 'name'] name = me.StringField(required=True) ref = me.StringField(required=True) description = me.StringField() enabled = me.BooleanField( required=True, default=True, help_text='A flag indicating whether the action is enabled.') entry_point = me.StringField( required=True, help_text='The entry point to the action.') pack = me.StringField( required=False, help_text='Name of the content pack.', unique_with='name') runner_type = me.DictField( required=True, default={}, help_text='The action runner to use for executing the action.') parameters = stormbase.EscapedDynamicField( help_text='The specification for parameters for the action.') output_schema = stormbase.EscapedDynamicField( help_text='The schema for output of the action.') notify = me.EmbeddedDocumentField(NotificationSchema) meta = { 'indexes': [ {'fields': ['name']}, {'fields': ['pack']}, {'fields': ['ref']}, ] + (stormbase.ContentPackResourceMixin.get_indexes() + stormbase.TagsMixin.get_indexes() + stormbase.UIDFieldMixin.get_indexes()) } def __init__(self, *args, **values): super(ActionDB, self).__init__(*args, **values) self.ref = self.get_reference().ref self.uid = self.get_uid() def is_workflow(self): """ Return True if this action is a workflow, False otherwise. :rtype: ``bool`` """ # pylint: disable=unsubscriptable-object return self.runner_type['name'] in WORKFLOW_RUNNER_TYPES
class NotificationSubSchema(me.EmbeddedDocument): """ Schema for notification settings to be specified for action success/failure. """ message = me.StringField() data = stormbase.EscapedDynamicField( default={}, help_text="Payload to be sent as part of notification.") routes = me.ListField(default=["notify.default"], help_text="Routes to post notifications to.") channels = ( me. ListField( # Deprecated. Only here for backward compatibility reasons. default=["notify.default"], help_text="Routes to post notifications to.")) def __str__(self): result = [] result.append("NotificationSubSchema@") result.append(str(id(self))) result.append('(message="%s", ' % str(self.message)) result.append('data="%s", ' % str(self.data)) result.append('routes="%s", ' % str(self.routes)) result.append('[**deprecated**]channels="%s")' % str(self.channels)) return "".join(result)
class ConfigDB(stormbase.StormFoundationDB): """ System entity representing pack config. """ pack = me.StringField( required=True, unique=True, help_text='Name of the content pack this config belongs to.') values = stormbase.EscapedDynamicField( help_text='Config values.', default={}) def mask_secrets(self, value): """ Process the model dictionary and mask secret values. :type value: ``dict`` :param value: Document dictionary. :rtype: ``dict`` """ result = copy.deepcopy(value) config_schema = config_schema_access.get_by_pack(result['pack']) secret_parameters = get_secret_parameters(parameters=config_schema.attributes) result['values'] = mask_secret_parameters(parameters=result['values'], secret_parameters=secret_parameters) return result
class ActionExecutionDB(stormbase.StormFoundationDB): 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 = me.DictField( 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()) meta = { 'indexes': [{ 'fields': ['parent'] }, { 'fields': ['liveaction.id'] }, { 'fields': ['start_timestamp'] }, { 'fields': ['action.ref'] }, { 'fields': ['status'] }] } 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
class ConfigDB(stormbase.StormFoundationDB): """ System entity representing pack config. """ pack = me.StringField( required=True, unique=True, help_text='Name of the content pack this config belongs to.') values = stormbase.EscapedDynamicField(help_text='Config values.')
class ConfigSchemaDB(stormbase.StormFoundationDB): """ System entity representing a config schema for a particular pack. """ pack = me.StringField( required=True, unique=True, help_text='Name of the content pack this schema belongs to.') attributes = stormbase.EscapedDynamicField( help_text='The specification for config schema attributes.')
class WorkflowExecutionDB(stormbase.StormFoundationDB, stormbase.ChangeRevisionFieldMixin): RESOURCE_TYPE = types.ResourceType.EXECUTION action_execution = me.StringField(required=True) spec = stormbase.EscapedDictField() graph = stormbase.EscapedDictField() flow = stormbase.EscapedDictField() input = stormbase.EscapedDictField() output = stormbase.EscapedDictField() status = me.StringField(required=True) errors = stormbase.EscapedDynamicField() start_timestamp = db_field_types.ComplexDateTimeField( default=date_utils.get_datetime_utc_now) end_timestamp = db_field_types.ComplexDateTimeField() meta = {'indexes': [{'fields': ['action_execution']}]}
class NotificationSubSchema(me.EmbeddedDocument): """ Schema for notification settings to be specified for action success/failure. """ message = me.StringField() data = stormbase.EscapedDynamicField( default={}, help_text='Payload to be sent as part of notification.') channels = me.ListField(default=['notify.default'], help_text='Channels to post notifications to.') def __str__(self): result = [] result.append('NotificationSubSchema@') result.append(str(id(self))) result.append('(message="%s", ' % str(self.message)) result.append('data="%s", ' % str(self.data)) result.append('channels="%s")' % str(self.channels)) return ''.join(result)
class WorkflowExecutionDB(stormbase.StormFoundationDB, stormbase.ChangeRevisionFieldMixin): RESOURCE_TYPE = types.ResourceType.EXECUTION action_execution = me.StringField(required=True) spec = stormbase.EscapedDictField() graph = me.DictField() input = JSONDictEscapedFieldCompatibilityField() notify = me.DictField() context = JSONDictEscapedFieldCompatibilityField() state = JSONDictEscapedFieldCompatibilityField() status = me.StringField(required=True) output = JSONDictEscapedFieldCompatibilityField() errors = stormbase.EscapedDynamicField() start_timestamp = db_field_types.ComplexDateTimeField( default=date_utils.get_datetime_utc_now) end_timestamp = db_field_types.ComplexDateTimeField() meta = {"indexes": [{"fields": ["action_execution"]}]}
class ActionExecutionDB(stormbase.StormFoundationDB): 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=datetime.datetime.utcnow, help_text='The timestamp when the liveaction was created.') end_timestamp = ComplexDateTimeField( help_text='The timestamp when the liveaction has finished.') parameters = me.DictField( default={}, help_text= 'The key-value pairs passed as to the action runner & execution.') 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()) meta = { 'indexes': [{ 'fields': ['parent'] }, { 'fields': ['liveaction.id'] }, { 'fields': ['start_timestamp'] }, { 'fields': ['action.ref'] }, { 'fields': ['status'] }] }
class LiveActionDB(stormbase.StormFoundationDB): """ The databse entity that represents a Stack Action/Automation in the system. Attributes: status: the most recently observed status of the execution. One of "starting", "running", "completed", "error". result: an embedded document structure that holds the output and exit status code from the action. """ # TODO: Can status be an enum at the Mongo layer? 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.') action = me.StringField( required=True, help_text='Reference to the action that has to be executed.') parameters = me.DictField( default={}, help_text= 'The key-value pairs passed as to the action runner & execution.') result = stormbase.EscapedDynamicField(default={}, help_text='Action defined result.') context = me.DictField( default={}, help_text='Contextual information on the action execution.') callback = me.DictField( default={}, help_text= 'Callback information for the on completion of action execution.') runner_info = me.DictField( default={}, help_text='Reference to the runner that executed this liveaction.') notify = me.EmbeddedDocumentField(NotificationSchema) meta = {'indexes': ['-start_timestamp', 'action']}
class LiveActionDB_EscapedDynamicField(LiveActionDB): result = stormbase.EscapedDynamicField(default={}) field1 = stormbase.EscapedDynamicField(default={}) field2 = stormbase.EscapedDynamicField(default={}) field3 = stormbase.EscapedDynamicField(default={})
class LiveActionDB_OldFieldType(LiveActionDB): result = stormbase.EscapedDynamicField(default={})
class ActionExecutionDB_OldFieldType(ActionExecutionDB): result = stormbase.EscapedDynamicField(default={})
class LiveActionDB(stormbase.StormFoundationDB): """ The databse entity that represents a Stack Action/Automation in the system. Attributes: status: the most recently observed status of the execution. One of "starting", "running", "completed", "error". result: an embedded document structure that holds the output and exit status code from the action. """ # TODO: Can status be an enum at the Mongo layer? 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.') action = me.StringField( required=True, help_text='Reference to the action that has to be executed.') parameters = stormbase.EscapedDynamicField( default={}, help_text= 'The key-value pairs passed as to the action runner & execution.') result = stormbase.EscapedDynamicField(default={}, help_text='Action defined result.') context = me.DictField( default={}, help_text='Contextual information on the action execution.') callback = me.DictField( default={}, help_text= 'Callback information for the on completion of action execution.') runner_info = me.DictField( default={}, help_text= 'Information about the runner which executed this live action (hostname, pid).' ) notify = me.EmbeddedDocumentField(NotificationSchema) meta = { 'indexes': [ { 'fields': ['-start_timestamp', 'action'] }, { 'fields': ['start_timestamp'] }, { 'fields': ['end_timestamp'] }, { 'fields': ['action'] }, { 'fields': ['status'] }, ] } def mask_secrets(self, value): from st2common.util import action_db result = copy.deepcopy(value) execution_parameters = value['parameters'] # TODO: This results into two DB looks, we should cache action and runner type object # for each liveaction... # # ,-'"-. # . f .--. \ # .\._,\._',' j_ # 7______""-'__`, parameters = action_db.get_action_parameters_specs( action_ref=self.action) 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 LiveActionDB(stormbase.StormFoundationDB): workflow_execution = me.StringField() task_execution = me.StringField() # TODO: Can status be an enum at the Mongo layer? 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.") action = me.StringField( required=True, help_text="Reference to the action that has to be executed.") action_is_workflow = me.BooleanField( default=False, help_text= "A flag indicating whether the referenced action is a workflow.", ) parameters = stormbase.EscapedDynamicField( default={}, help_text= "The key-value pairs passed as to the action runner & execution.", ) result = JSONDictEscapedFieldCompatibilityField( default={}, help_text="Action defined result.") context = me.DictField( default={}, help_text="Contextual information on the action execution.") callback = me.DictField( default={}, help_text= "Callback information for the on completion of action execution.", ) runner_info = me.DictField( default={}, help_text= "Information about the runner which executed this live action (hostname, pid).", ) notify = me.EmbeddedDocumentField(NotificationSchema) delay = me.IntField( min_value=0, help_text= "How long (in milliseconds) to delay the execution before scheduling.", ) meta = { "indexes": [ { "fields": ["-start_timestamp", "action"] }, { "fields": ["start_timestamp"] }, { "fields": ["end_timestamp"] }, { "fields": ["action"] }, { "fields": ["status"] }, { "fields": ["context.trigger_instance.id"] }, { "fields": ["workflow_execution"] }, { "fields": ["task_execution"] }, ], } def mask_secrets(self, value): from st2common.util import action_db result = copy.deepcopy(value) execution_parameters = value["parameters"] # TODO: This results into two DB looks, we should cache action and runner type object # for each liveaction... # # ,-'"-. # . f .--. \ # .\._,\._',' j_ # 7______""-'__`, parameters = action_db.get_action_parameters_specs( action_ref=self.action) 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 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()) meta = { 'indexes': [ {'fields': ['rule.ref']}, {'fields': ['action.ref']}, {'fields': ['liveaction.id']}, {'fields': ['start_timestamp']}, {'fields': ['end_timestamp']}, {'fields': ['status']}, {'fields': ['parent']}, {'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 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): 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"] }, ) # TODO(mierdin): This logic should be moved to the dedicated Inquiry # data model once it exists. result["result"] = ActionExecutionDB.result.parse_field_value( result["result"]) 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 ModelWithEscapedDynamicFieldDB(stormbase.StormFoundationDB): result = stormbase.EscapedDynamicField(default={}, use_header=False) counter = me.IntField(default=0) meta = {"collection": "model_result_test"}
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 = 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 LiveActionDB(stormbase.StormFoundationDB): workflow_execution = me.StringField() task_execution = me.StringField() # TODO: Can status be an enum at the Mongo layer? 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.') action = me.StringField( required=True, help_text='Reference to the action that has to be executed.') action_is_workflow = me.BooleanField( default=False, help_text= 'A flag indicating whether the referenced action is a workflow.') parameters = stormbase.EscapedDynamicField( default={}, help_text= 'The key-value pairs passed as to the action runner & execution.') result = stormbase.EscapedDynamicField(default={}, help_text='Action defined result.') context = me.DictField( default={}, help_text='Contextual information on the action execution.') callback = me.DictField( default={}, help_text= 'Callback information for the on completion of action execution.') runner_info = me.DictField( default={}, help_text= 'Information about the runner which executed this live action (hostname, pid).' ) notify = me.EmbeddedDocumentField(NotificationSchema) meta = { 'indexes': [{ 'fields': ['-start_timestamp', 'action'] }, { 'fields': ['start_timestamp'] }, { 'fields': ['end_timestamp'] }, { 'fields': ['action'] }, { 'fields': ['status'] }, { 'fields': ['context.trigger_instance.id'] }, { 'fields': ['workflow_execution'] }, { 'fields': ['task_execution'] }] } def mask_secrets(self, value): from st2common.util import action_db result = copy.deepcopy(value) execution_parameters = value['parameters'] # TODO: This results into two DB looks, we should cache action and runner type object # for each liveaction... # # ,-'"-. # . f .--. \ # .\._,\._',' j_ # 7______""-'__`, parameters = action_db.get_action_parameters_specs( action_ref=self.action) 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']