diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 3def9ae19b..fb8cd89db1 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1980,7 +1980,7 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer): return ret if 'job_template' in ret and not obj.job_template: ret['job_template'] = None - if obj.job_template and obj.job_template.survey_enabled and 'extra_vars' in ret: + if 'extra_vars' in ret: ret['extra_vars'] = obj.display_extra_vars() return ret diff --git a/awx/main/migrations/0030_v302_job_survey_passwords.py b/awx/main/migrations/0030_v302_job_survey_passwords.py new file mode 100644 index 0000000000..fa6c2cd3fe --- /dev/null +++ b/awx/main/migrations/0030_v302_job_survey_passwords.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import jsonfield.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0029_v302_add_ask_skip_tags'), + ] + + operations = [ + migrations.AddField( + model_name='job', + name='survey_passwords', + field=jsonfield.fields.JSONField(default={}, editable=False, blank=True), + ), + ] diff --git a/awx/main/migrations/0031_v302_migrate_survey_passwords.py b/awx/main/migrations/0031_v302_migrate_survey_passwords.py new file mode 100644 index 0000000000..5eac01b853 --- /dev/null +++ b/awx/main/migrations/0031_v302_migrate_survey_passwords.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from awx.main.migrations import _save_password_keys +from awx.main.migrations import _migration_utils as migration_utils +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0030_v302_job_survey_passwords'), + ] + + operations = [ + migrations.RunPython(migration_utils.set_current_apps_for_migrations), + migrations.RunPython(_save_password_keys.migrate_survey_passwords), + ] diff --git a/awx/main/migrations/_save_password_keys.py b/awx/main/migrations/_save_password_keys.py new file mode 100644 index 0000000000..3ff7b17562 --- /dev/null +++ b/awx/main/migrations/_save_password_keys.py @@ -0,0 +1,25 @@ +def survey_password_variables(survey_spec): + vars = [] + # Get variables that are type password + for survey_element in survey_spec['spec']: + if survey_element['type'] == 'password': + vars.append(survey_element['variable']) + return vars + + +def migrate_survey_passwords(apps, schema_editor): + '''Take the output of the Job Template password list for all that + have a survey enabled, and then save it into the job model. + ''' + Job = apps.get_model('main', 'Job') + for job in Job.objects.iterator(): + if not job.job_template: + continue + jt = job.job_template + if jt.survey_spec is not None and jt.survey_enabled: + password_list = survey_password_variables(jt.survey_spec) + hide_password_dict = {} + for password in password_list: + hide_password_dict[password] = "$encrypted$" + job.survey_passwords = hide_password_dict + job.save() diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index a7c1c6041d..8a4ba4e1d3 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -513,6 +513,11 @@ class Job(UnifiedJob, JobOptions): editable=False, through='JobHostSummary', ) + survey_passwords = JSONField( + blank=True, + default={}, + editable=False, + ) @classmethod def _get_parent_field_name(cls): @@ -721,16 +726,12 @@ class Job(UnifiedJob, JobOptions): ''' Hides fields marked as passwords in survey. ''' - if self.extra_vars and self.job_template and self.job_template.survey_enabled: - try: - extra_vars = json.loads(self.extra_vars) - for key in self.job_template.survey_password_variables(): - if key in extra_vars: - extra_vars[key] = REPLACE_STR - return json.dumps(extra_vars) - except ValueError: - pass - return self.extra_vars + if self.survey_passwords: + extra_vars = json.loads(self.extra_vars) + extra_vars.update(self.survey_passwords) + return json.dumps(extra_vars) + else: + return self.extra_vars def _survey_search_and_replace(self, content): # Use job template survey spec to identify password fields. diff --git a/awx/main/models/unified_jobs.py b/awx/main/models/unified_jobs.py index f7106eb7ab..77cafef746 100644 --- a/awx/main/models/unified_jobs.py +++ b/awx/main/models/unified_jobs.py @@ -343,6 +343,13 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio create_kwargs[field_name] = getattr(self, field_name) new_kwargs = self._update_unified_job_kwargs(**create_kwargs) unified_job = unified_job_class(**new_kwargs) + # For JobTemplate-based jobs with surveys, save list for perma-redaction + if hasattr(self, 'survey_spec') and getattr(self, 'survey_enabled', False): + password_list = self.survey_password_variables() + hide_password_dict = {} + for password in password_list: + hide_password_dict[password] = REPLACE_STR + unified_job.survey_passwords = hide_password_dict unified_job.save() for field_name, src_field_value in m2m_fields.iteritems(): dest_field = getattr(unified_job, field_name)