-
-
Notifications
You must be signed in to change notification settings - Fork 782
Fix for #4139 - Secrets not being masked in pack config #4140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ee7947a
7cdcfb6
6a2693e
85dd793
b030f47
1c4cea3
2a2a8c8
78763fe
b104a59
c793abf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,11 @@ | |
| def _randomize_inquiry_id(inquiry): | ||
| newinquiry = copy.deepcopy(inquiry) | ||
| newinquiry['id'] = str(uuid.uuid4()) | ||
| # ID can't have '1440' in it, otherwise our `count()` fails | ||
| # when inspecting the inquiry list output for test: | ||
| # test_list_inquiries_limit() | ||
| while '1440' in newinquiry['id']: | ||
| newinquiry['id'] = str(uuid.uuid4()) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for fixing this intermediate test failure 👍 |
||
| return newinquiry | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,36 +27,146 @@ | |
|
|
||
| def get_secret_parameters(parameters): | ||
| """ | ||
| Filter the provided parameters dict and return a list of parameter names which are marked as | ||
| secret. | ||
| Filter the provided parameters dict and return a dict of parameters which are marked as | ||
| secret. Every key in the dict is the parameter name and values are the parameter type: | ||
|
|
||
| >>> d = get_secret_parameters(params) | ||
| >>> d | ||
| { | ||
| "param_a": "string", | ||
| "param_b": "boolean", | ||
| "param_c": "integer" | ||
| } | ||
|
|
||
| If a paramter is a dictionary or a list, then the value will be a nested dictionary | ||
| containing information about that sub-object: | ||
|
|
||
| >>> d = get_secret_parameters(params) | ||
| >>> d | ||
| { | ||
| "param_dict": { | ||
| "nested_a": "boolean", | ||
| "nested_b": "string", | ||
| }, | ||
| "param_list": { | ||
| "nested_dict: { | ||
| "param_c": "integer" | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Note: in JSON Schema, we're assuming lists contain the same data type for every element | ||
|
|
||
|
|
||
| :param parameters: Dictionary with runner or action parameters schema specification. | ||
| :type parameters: ``dict`` | ||
|
|
||
| :rtype ``list`` | ||
| """ | ||
| secret_parameters = [parameter for parameter, options in | ||
| six.iteritems(parameters) if options.get('secret', False)] | ||
|
|
||
| secret_parameters = {} | ||
| parameters_type = parameters.get('type') | ||
| iterator = None | ||
| if parameters_type == 'object': | ||
| # if this is an object, then iterate over the properties within | ||
| # the object | ||
| # result = dict | ||
| iterator = six.iteritems(parameters.get('properties', {})) | ||
| elif parameters_type == 'array': | ||
| # if this is an array, then iterate over the items definition as a single | ||
| # property | ||
| # result = list | ||
| iterator = enumerate([parameters.get('items', {})]) | ||
| secret_parameters = [] | ||
| elif parameters_type in ['integer', 'number', 'boolean', 'null', 'string']: | ||
| # if this a "plain old datatype", then iterate over the properties set | ||
| # of the data type | ||
| # result = string (property type) | ||
| iterator = enumerate([parameters]) | ||
| else: | ||
| # otherwise, assume we're in an object's properties definition | ||
| # this is the default case for the "root" level for schema specs. | ||
| # result = dict | ||
| iterator = six.iteritems(parameters) | ||
|
|
||
| # iterate over all of the parameters recursively | ||
| for parameter, options in iterator: | ||
| if not isinstance(options, dict): | ||
| continue | ||
|
|
||
| parameter_type = options.get('type') | ||
| if parameter_type in ['object', 'array']: | ||
| sub_params = get_secret_parameters(options) | ||
| if sub_params: | ||
| if isinstance(secret_parameters, list): | ||
| secret_parameters.append(sub_params) | ||
| elif isinstance(secret_parameters, dict): | ||
| secret_parameters[parameter] = sub_params | ||
| else: | ||
| return sub_params | ||
| elif options.get('secret', False): | ||
| # if this parameter is secret, then add it our secret parameters | ||
| if isinstance(secret_parameters, list): | ||
| secret_parameters.append(parameter_type) | ||
| elif isinstance(secret_parameters, dict): | ||
| secret_parameters[parameter] = parameter_type | ||
| else: | ||
| return parameter_type | ||
|
|
||
| return secret_parameters | ||
|
|
||
|
|
||
| def mask_secret_parameters(parameters, secret_parameters): | ||
| def mask_secret_parameters(parameters, secret_parameters, result=None): | ||
| """ | ||
| Introspect the parameters dict and return a new dict with masked secret | ||
| parameters. | ||
|
|
||
| :param parameters: Parameters to process. | ||
| :type parameters: ``dict`` | ||
|
|
||
| :param secret_parameters: List of parameter names which are secret. | ||
| :type secret_parameters: ``list`` | ||
| :type parameters: ``dict`` or ``list`` or ``string`` | ||
|
|
||
| :param secret_parameters: Dict of parameter names which are secret. | ||
| The type must be the same type as ``parameters`` | ||
| (or at least behave in the same way), | ||
| so that they can be traversed in the same way as | ||
| recurse down into the structure. | ||
| :type secret_parameters: ``dict`` | ||
|
|
||
| :param result: Deep copy of parameters so that parameters is not modified | ||
| in place. Default = None, meaning this function will make a | ||
| deep copy before starting. | ||
| :type result: ``dict`` or ``list`` or ``string`` | ||
| """ | ||
| result = copy.deepcopy(parameters) | ||
|
|
||
| for parameter in secret_parameters: | ||
| if parameter in result: | ||
| result[parameter] = MASKED_ATTRIBUTE_VALUE | ||
| # how we iterate depends on what data type was passed in | ||
| iterator = None | ||
| is_dict = isinstance(secret_parameters, dict) | ||
| is_list = isinstance(secret_parameters, list) | ||
| if is_dict: | ||
| iterator = six.iteritems(secret_parameters) | ||
| elif is_list: | ||
| iterator = enumerate(secret_parameters) | ||
| else: | ||
| return MASKED_ATTRIBUTE_VALUE | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's fine or we could also throw because an unsupported type was passed it :)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried that and we run into a couple weird scenarios where we might pass in an OrderedDict or a MongoEngineDict. As long as the the behavior of the type is compatible, then we should be OK. Not entirely sure how we can verify that. If you have any ideas i will happily implement them! |
||
|
|
||
| # only create a deep copy of parameters on the first call | ||
| # all other recursive calls pass back referneces to this result object | ||
| # so we can reuse it, saving memory and CPU cycles | ||
| if result is None: | ||
| result = copy.deepcopy(parameters) | ||
|
|
||
| # iterate over the secret parameters | ||
| for secret_param, secret_sub_params in iterator: | ||
| if is_dict: | ||
| if secret_param in result: | ||
| result[secret_param] = mask_secret_parameters(parameters[secret_param], | ||
| secret_sub_params, | ||
| result=result[secret_param]) | ||
| elif is_list: | ||
| # we're assuming lists contain the same data type for every element | ||
| for idx, value in enumerate(result): | ||
| result[idx] = mask_secret_parameters(parameters[idx], | ||
| secret_sub_params, | ||
| result=result[idx]) | ||
| else: | ||
| result[secret_param] = MASKED_ATTRIBUTE_VALUE | ||
|
|
||
| return result | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor thing - we use 100 characters wide lines. Not a big deal and this can be changed in a subsequent PR.