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) # 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 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 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 test_mask_secret_parameters_root_array(self): parameters = [ { "secret_field_in_object": "Secret $tr!ng" }, { "secret_field_in_object": "Secret $tr!ng 2" }, { "secret_field_in_object": "Secret $tr!ng 3" }, { "secret_field_in_object": "Secret $tr!ng 4" }, ] result = secrets.mask_secret_parameters(parameters, TEST_ROOT_ARRAY_SECRET_PARAMS) expected = [ { "secret_field_in_object": MASKED_ATTRIBUTE_VALUE }, { "secret_field_in_object": MASKED_ATTRIBUTE_VALUE }, { "secret_field_in_object": MASKED_ATTRIBUTE_VALUE }, { "secret_field_in_object": MASKED_ATTRIBUTE_VALUE }, ] self.assertEqual(expected, result)
def test_mask_secret_parameters_secret_nested_objects(self): parameters = { "arg_object": { "arg_nested_secret": "nested Secret", "arg_nested_object": { "arg_double_nested_secret": "double nested $ecret", }, }, "arg_secret_object": { "arg_nested_secret": "secret data", "arg_nested_object": { "arg_double_nested_secret": "double nested $ecret", }, }, } result = secrets.mask_secret_parameters( parameters, TEST_SECRET_NESTED_OBJECTS_SECRET_PARAMS) expected = { "arg_object": { "arg_nested_secret": MASKED_ATTRIBUTE_VALUE, "arg_nested_object": MASKED_ATTRIBUTE_VALUE, }, "arg_secret_object": MASKED_ATTRIBUTE_VALUE, } self.assertEqual(expected, result)
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 test_mask_secret_parameters_root_array(self): parameters = [ { 'secret_field_in_object': 'Secret $tr!ng' }, { 'secret_field_in_object': 'Secret $tr!ng 2' }, { 'secret_field_in_object': 'Secret $tr!ng 3' }, { 'secret_field_in_object': 'Secret $tr!ng 4' } ] result = secrets.mask_secret_parameters(parameters, TEST_ROOT_ARRAY_SECRET_PARAMS) expected = [ { 'secret_field_in_object': MASKED_ATTRIBUTE_VALUE }, { 'secret_field_in_object': MASKED_ATTRIBUTE_VALUE }, { 'secret_field_in_object': MASKED_ATTRIBUTE_VALUE }, { 'secret_field_in_object': MASKED_ATTRIBUTE_VALUE } ] self.assertEqual(expected, result)
def test_mask_secret_parameters_secret_nested_objects(self): parameters = { 'arg_object': { 'arg_nested_secret': 'nested Secret', 'arg_nested_object': { 'arg_double_nested_secret': 'double nested $ecret', } }, 'arg_secret_object': { 'arg_nested_secret': 'secret data', 'arg_nested_object': { 'arg_double_nested_secret': 'double nested $ecret', } } } result = secrets.mask_secret_parameters(parameters, TEST_SECRET_NESTED_OBJECTS_SECRET_PARAMS) expected = { 'arg_object': { 'arg_nested_secret': MASKED_ATTRIBUTE_VALUE, 'arg_nested_object': MASKED_ATTRIBUTE_VALUE, }, 'arg_secret_object': MASKED_ATTRIBUTE_VALUE, } self.assertEqual(expected, result)
def test_mask_secret_parameters_nested_array_with_object(self): parameters = { 'arg_optional_array_with_object': [ { 'arg_nested_secret': 'secret 1' }, { 'arg_nested_secret': 'secret 2' }, { 'arg_nested_secret': 'secret 3' } ] } result = secrets.mask_secret_parameters(parameters, TEST_NESTED_ARRAY_WITH_OBJECT_SECRET_PARAMS) expected = { 'arg_optional_array_with_object': [ { 'arg_nested_secret': MASKED_ATTRIBUTE_VALUE }, { 'arg_nested_secret': MASKED_ATTRIBUTE_VALUE }, { 'arg_nested_secret': MASKED_ATTRIBUTE_VALUE } ] } self.assertEqual(expected, result)
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) return result
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. 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 test_mask_secret_parameters_no_secrets(self): parameters = {'arg_required_no_default': 'junk'} result = secrets.mask_secret_parameters(parameters, TEST_NO_SECRETS_SECRET_PARAMS) expected = { 'arg_required_no_default': 'junk' } self.assertEqual(expected, result)
def test_mask_secret_parameters_secret_root_array(self): parameters = [ "abc", 123, True ] result = secrets.mask_secret_parameters(parameters, TEST_SECRET_ROOT_ARRAY_SECRET_PARAMS) expected = MASKED_ATTRIBUTE_VALUE self.assertEqual(expected, result)
def test_mask_secret_parameters_secret_root_object(self): parameters = { "arg_level_one": { "secret_field_in_object": "Secret $tr!ng" } } result = secrets.mask_secret_parameters( parameters, TEST_SECRET_ROOT_OBJECT_SECRET_PARAMS) expected = MASKED_ATTRIBUTE_VALUE self.assertEqual(expected, result)
def mask_secrets(self, value): result = copy.deepcopy(value) runner_parameters = result['runner_parameters'] action_parameters = result['action_parameters'] runner_parameters_specs = self._runner_type_db.runner_parameters action_parameters_sepcs = self._action_db.parameters secret_runner_parameters = get_secret_parameters(parameters=runner_parameters_specs) secret_action_parameters = get_secret_parameters(parameters=action_parameters_sepcs) runner_parameters = mask_secret_parameters(parameters=runner_parameters, secret_parameters=secret_runner_parameters) action_parameters = mask_secret_parameters(parameters=action_parameters, secret_parameters=secret_action_parameters) result['runner_parameters'] = runner_parameters result['action_parameters'] = action_parameters return result
def test_mask_secret_parameters_secret_root_object(self): parameters = { 'arg_level_one': { 'secret_field_in_object': 'Secret $tr!ng' } } result = secrets.mask_secret_parameters(parameters, TEST_SECRET_ROOT_OBJECT_SECRET_PARAMS) expected = MASKED_ATTRIBUTE_VALUE self.assertEqual(expected, result)
def test_mask_secret_parameters_flat(self): parameters = { 'arg_required_no_default': 'test', 'arg_optional_no_type_secret': None } result = secrets.mask_secret_parameters(parameters, TEST_FLAT_SECRET_PARAMS) expected = { 'arg_required_no_default': 'test', 'arg_optional_no_type_secret': MASKED_ATTRIBUTE_VALUE } self.assertEqual(expected, result)
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 test_mask_secret_parameters_secret_array(self): parameters = { 'arg_secret_array': [ "abc", 123, True ] } result = secrets.mask_secret_parameters(parameters, TEST_SECRET_ARRAY_SECRET_PARAMS) expected = { 'arg_secret_array': MASKED_ATTRIBUTE_VALUE } self.assertEqual(expected, result)
def test_mask_secret_parameters_nested_object_with_double_array(self): parameters = { 'arg_optional_object_with_double_array': { 'arg_double_nested_array': [ [ 'secret 1', 'secret 2', 'secret 3' ], [ 'secret 4', 'secret 5', 'secret 6', ], [ 'secret 7', 'secret 8', 'secret 9', 'secret 10', ] ] } } result = secrets.mask_secret_parameters(parameters, TEST_NESTED_OBJECT_WITH_DOUBLE_ARRAY_SECRET_PARAMS) expected = { 'arg_optional_object_with_double_array': { 'arg_double_nested_array': [ [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE ], [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ], [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ] ] } } self.assertEqual(expected, result)
def test_mask_secret_parameters_secret_object(self): parameters = { "arg_secret_object": { "abc": 123, "key": "value", "bool": True, "array": ["x", "y", "z"], "obj": { "x": "deep" }, } } result = secrets.mask_secret_parameters( parameters, TEST_SECRET_OBJECT_SECRET_PARAMS) expected = {"arg_secret_object": MASKED_ATTRIBUTE_VALUE} self.assertEqual(expected, result)
def test_mask_secret_parameters_root_object(self): parameters = { 'arg_level_one': { 'secret_field_in_object': 'Secret $tr!ng' } } result = secrets.mask_secret_parameters(parameters, TEST_ROOT_OBJECT_SECRET_PARAMS) expected = { 'arg_level_one': { 'secret_field_in_object': MASKED_ATTRIBUTE_VALUE } } self.assertEqual(expected, result)
def test_mask_secret_parameters_secret_nested_arrays(self): parameters = { "arg_optional_array": [ "secret 1", "secret 2", "secret 3", ], "arg_optional_double_array": [ [ "secret 4", "secret 5", "secret 6", ], [ "secret 7", "secret 8", "secret 9", ], ], "arg_optional_tripple_array": [ [["secret 10", "secret 11"], ["secret 12", "secret 13", "secret 14"]], [["secret 15", "secret 16"]], ], "arg_optional_quad_array": [[[["secret 17", "secret 18"], ["secret 19"]]]], } result = secrets.mask_secret_parameters( parameters, TEST_SECRET_NESTED_ARRAYS_SECRET_PARAMS) expected = { "arg_optional_array": MASKED_ATTRIBUTE_VALUE, "arg_optional_double_array": MASKED_ATTRIBUTE_VALUE, "arg_optional_tripple_array": [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ], "arg_optional_quad_array": [[ MASKED_ATTRIBUTE_VALUE, ]], } self.assertEqual(expected, result)
def test_mask_secret_parameters_array(self): parameters = { 'arg_optional_array': [ '$ecret $tring 1', '$ecret $tring 2', '$ecret $tring 3' ] } result = secrets.mask_secret_parameters(parameters, TEST_ARRAY_SECRET_PARAMS) expected = { 'arg_optional_array': [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE ] } self.assertEqual(expected, result)
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
def test_mask_secret_parameters_nested_object_with_double_array(self): parameters = { "arg_optional_object_with_double_array": { "arg_double_nested_array": [ ["secret 1", "secret 2", "secret 3"], [ "secret 4", "secret 5", "secret 6", ], [ "secret 7", "secret 8", "secret 9", "secret 10", ], ] } } result = secrets.mask_secret_parameters( parameters, TEST_NESTED_OBJECT_WITH_DOUBLE_ARRAY_SECRET_PARAMS) expected = { "arg_optional_object_with_double_array": { "arg_double_nested_array": [ [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ], [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ], [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ], ] } } self.assertEqual(expected, result)
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 test_mask_secret_parameters_secret_object(self): parameters = { 'arg_secret_object': { "abc": 123, "key": "value", "bool": True, "array": ["x", "y", "z"], "obj": { "x": "deep" } } } result = secrets.mask_secret_parameters(parameters, TEST_SECRET_OBJECT_SECRET_PARAMS) expected = { 'arg_secret_object': MASKED_ATTRIBUTE_VALUE } self.assertEqual(expected, result)
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 test_mask_secret_parameters_nested_object_with_array(self): parameters = { 'arg_optional_object_with_array': { 'arg_nested_array': [ 'secret array value 1', 'secret array value 2', 'secret array value 3', ] } } result = secrets.mask_secret_parameters(parameters, TEST_NESTED_OBJECT_WITH_ARRAY_SECRET_PARAMS) expected = { 'arg_optional_object_with_array': { 'arg_nested_array': [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ] } } self.assertEqual(expected, result)
def test_mask_secret_parameters_nested_arrays(self): parameters = { 'arg_optional_array': [ 'secret 1', 'secret 2', 'secret 3', ], 'arg_optional_double_array': [ [ 'secret 4', 'secret 5', 'secret 6', ], [ 'secret 7', 'secret 8', 'secret 9', ] ], 'arg_optional_tripple_array': [ [ [ 'secret 10', 'secret 11' ], [ 'secret 12', 'secret 13', 'secret 14' ] ], [ [ 'secret 15', 'secret 16' ] ] ], 'arg_optional_quad_array': [ [ [ [ 'secret 17', 'secret 18' ], [ 'secret 19' ] ] ] ] } result = secrets.mask_secret_parameters(parameters, TEST_NESTED_ARRAYS_SECRET_PARAMS) expected = { 'arg_optional_array': [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ], 'arg_optional_double_array': [ [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ], [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, ] ], 'arg_optional_tripple_array': [ [ [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE ], [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE ] ], [ [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE ] ] ], 'arg_optional_quad_array': [ [ [ [ MASKED_ATTRIBUTE_VALUE, MASKED_ATTRIBUTE_VALUE ], [ MASKED_ATTRIBUTE_VALUE ] ] ] ] } self.assertEqual(expected, result)