From 216ab5cf419fb08fb8842ba2e0d1e5d0b2fe559b Mon Sep 17 00:00:00 2001 From: Chris Church Date: Tue, 19 Nov 2013 13:18:04 -0500 Subject: [PATCH] AC-672 Fixed responding to passphrase prompts for project updates, re-added tests removed in earlier update. --- awx/main/tasks.py | 34 ++++++++++++++---------------- awx/main/tests/projects.py | 43 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index d1d3cfe2a4..b31268d90b 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -27,6 +27,7 @@ from celery import Task # Django from django.conf import settings from django.db import transaction +from django.utils.datastructures import SortedDict from django.utils.timezone import now # AWX @@ -152,10 +153,7 @@ class BaseTask(Task): Return a dictionary of prompt regular expressions and password lookup keys. ''' - return { - r'Enter passphrase for .*:': 'ssh_key_unlock', - r'Bad passphrase, try again for .*:': '', - } + return SortedDict() def run_pexpect(self, instance, args, cwd, env, passwords, output_replacements=None): @@ -180,6 +178,7 @@ class BaseTask(Task): expect_list.extend([pexpect.TIMEOUT, pexpect.EOF]) while child.isalive(): result_id = child.expect(expect_list, timeout=pexpect_timeout) + #print 'pexpect result_id', result_id, expect_list[result_id], expect_passwords.get(result_id, None) if result_id in expect_passwords: child.sendline(expect_passwords[result_id]) updates = {'status': 'running', @@ -407,11 +406,11 @@ class RunJob(BaseTask): def get_password_prompts(self): d = super(RunJob, self).get_password_prompts() - d.update({ - r'sudo password.*:': 'sudo_password', - r'SSH password:': 'password', - r'Password:': 'password', - }) + d[re.compile(r'^Enter passphrase for .*:\s*?$', re.M)] = 'ssh_key_unlock' + d[re.compile(r'^Bad passphrase, try again for .*:\s*?$', re.M)] = '' + d[re.compile(r'^sudo password.*:\s*?$', re.M)] = 'sudo_password' + d[re.compile(r'^SSH password:\s*?$', re.M)] = 'password' + d[re.compile(r'^Password:\s*?$', re.M)] = 'password' return d def pre_run_check(self, job, **kwargs): @@ -663,15 +662,14 @@ class RunProjectUpdate(BaseTask): def get_password_prompts(self): d = super(RunProjectUpdate, self).get_password_prompts() - d.update({ - re.compile(r'^Username for.*:\s*?$', re.M): 'scm_username', - re.compile(r'^Password for.*:\s*?$', re.M): 'scm_password', - re.compile(r'^Password:\s*?$', re.M): 'scm_password', - re.compile(r'^\S+?@\S+?\'s\s+?password:\s*?$', re.M): 'scm_password', - re.compile(r'^Enter passphrase for .*:\s*?$', re.M): 'scm_key_unlock', - # FIXME: Configure whether we should auto accept host keys? - re.compile(r'^Are you sure you want to continue connecting \(yes/no\)\?\s*?$', re.M): 'yes', - }) + d[re.compile(r'^Username for.*:\s*?$', re.M)] = 'scm_username' + d[re.compile(r'^Password for.*:\s*?$', re.M)] = 'scm_password' + d[re.compile(r'^Password:\s*?$', re.M)] = 'scm_password' + d[re.compile(r'^\S+?@\S+?\'s\s+?password:\s*?$', re.M)] = 'scm_password' + d[re.compile(r'^Enter passphrase for .*:\s*?$', re.M)] = 'scm_key_unlock' + d[re.compile(r'^Bad passphrase, try again for .*:\s*?$', re.M)] = '' + # FIXME: Configure whether we should auto accept host keys? + d[re.compile(r'^Are you sure you want to continue connecting \(yes/no\)\?\s*?$', re.M)] = 'yes' return d def get_idle_timeout(self): diff --git a/awx/main/tests/projects.py b/awx/main/tests/projects.py index 7f6116df18..a833fffeae 100644 --- a/awx/main/tests/projects.py +++ b/awx/main/tests/projects.py @@ -1220,6 +1220,49 @@ class ProjectUpdatesTest(BaseTransactionTest): self.check_project_update(project2, should_fail=None)#, #should_error=should_error) + def test_scm_key_unlock_on_project_update(self): + scm_url = 'git@github.com:ansible/ansible.github.com.git' + project = self.create_project( + name='my git project over ssh with encrypted key', + scm_type='git', + scm_url=scm_url, + scm_key_data=TEST_SSH_KEY_DATA_LOCKED, + scm_key_unlock=TEST_SSH_KEY_DATA_UNLOCK, + ) + url = reverse('api:project_update_view', args=(project.pk,)) + with self.current_user(self.super_django_user): + response = self.get(url, expect=200) + self.assertTrue(response['can_update']) + with self.current_user(self.super_django_user): + response = self.post(url, {}, expect=202) + project_update = project.project_updates.order_by('-pk')[0] + self.check_project_update(project, should_fail=None, + project_update=project_update) + # Verify that we responded to ssh-agent prompt. + self.assertTrue('Identity added' in project_update.result_stdout, + project_update.result_stdout) + # Try again with a bad unlock password. + project = self.create_project( + name='my git project over ssh with encrypted key and bad pass', + scm_type='git', + scm_url=scm_url, + scm_key_data=TEST_SSH_KEY_DATA_LOCKED, + scm_key_unlock='not the right password', + ) + with self.current_user(self.super_django_user): + response = self.get(url, expect=200) + self.assertTrue(response['can_update']) + with self.current_user(self.super_django_user): + response = self.post(url, {}, expect=202) + project_update = project.project_updates.order_by('-pk')[0] + self.check_project_update(project, should_fail=None, + project_update=project_update) + # Verify response to ssh-agent prompt, did not accept password. + self.assertTrue('Bad passphrase' in project_update.result_stdout, + project_update.result_stdout) + self.assertFalse('Identity added' in project_update.result_stdout, + project_update.result_stdout) + def create_local_git_repo(self): repo_dir = tempfile.mkdtemp() self._temp_project_dirs.append(repo_dir)