diff --git a/awx/api/views.py b/awx/api/views.py index 934c822f76..f5fdcf6eb2 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -2941,9 +2941,15 @@ class JobTemplateSurveySpec(GenericAPIView): question_position=str(idx), question_type=survey_item["type"]) ), status=status.HTTP_400_BAD_REQUEST) old_element = old_spec_dict.get(survey_item['variable'], {}) - if (survey_item['variable'] not in old_spec_dict or 'default' not in old_element or - not old_element['default'].startswith('$encrypted$') or - old_element['default'] == '$encrypted$'): + encryptedish_default_exists = False + if 'default' in old_element: + old_default = old_element['default'] + if isinstance(old_default, six.string_types): + if old_default.startswith('$encrypted$'): + encryptedish_default_exists = True + elif old_default == "": # unencrypted blank string is allowed as DB value as special case + encryptedish_default_exists = True + if not encryptedish_default_exists: return Response(dict(error=_( "$encrypted$ is a reserved keyword, may not be used for new default in position {question_position}." ).format(question_position=str(idx))), status=status.HTTP_400_BAD_REQUEST) diff --git a/awx/main/tests/unit/api/test_views.py b/awx/main/tests/unit/api/test_views.py index 10edba02cb..0ad395f296 100644 --- a/awx/main/tests/unit/api/test_views.py +++ b/awx/main/tests/unit/api/test_views.py @@ -302,7 +302,7 @@ class TestSurveySpecValidation: { "question_description": "", "min": 0, - "default": "$encrypted$foooooooo", + "default": "$encrypted$foooooooo", # default remained the same "max": 1024, "required": False, # only thing changed "choices": "", @@ -312,3 +312,49 @@ class TestSurveySpecValidation: } ] } + + def test_use_saved_empty_string_default(self): + ''' + Save is allowed, the $encrypted$ replacement is done with empty string + The empty string value for default is unencrypted, + unlike all other password questions + ''' + view = JobTemplateSurveySpec() + old = { + "name": "old survey", + "description": "foobar", + "spec": [ + { + "question_description": "", + "min": 0, + "default": "", + "max": 1024, + "required": True, + "choices": "", + "variable": "openshift_username", + "question_name": "OpenShift Username", + "type": "password" + } + ] + } + new = deepcopy(old) + new['spec'][0]['default'] = '$encrypted$' + resp = view._validate_spec_data(new, old) + assert resp is None + assert new == { + "name": "old survey", + "description": "foobar", + "spec": [ + { + "question_description": "", + "min": 0, + "default": "", # still has old unencrypted default + "max": 1024, + "required": True, + "choices": "", + "variable": "openshift_username", + "question_name": "OpenShift Username", + "type": "password" + } + ] + }