From 82f550e8cd640dd364e6c0707614d039a5619add Mon Sep 17 00:00:00 2001 From: Adrian Likins Date: Thu, 10 Aug 2017 09:34:16 -0400 Subject: [PATCH] Add prompt formats for 2.3 compat ask-vault-pass (#27974) The prompt_formats dict didn't get the 'prompt_ask_vault_pass' item added for interactive --ask-vault-pass, which caused "KeyError: u'prompt_ask_vault_pass'" Fixes #27885 --- lib/ansible/cli/__init__.py | 3 + test/units/cli/test_cli.py | 144 ++++++++++++++++++++++++++++++++++-- 2 files changed, 141 insertions(+), 6 deletions(-) diff --git a/lib/ansible/cli/__init__.py b/lib/ansible/cli/__init__.py index 353186f86a9..fa77d0e0acd 100644 --- a/lib/ansible/cli/__init__.py +++ b/lib/ansible/cli/__init__.py @@ -218,6 +218,9 @@ class CLI(with_metaclass(ABCMeta, object)): if create_new_password: prompt_formats['prompt'] = ['New vault password (%(vault_id)s): ', 'Confirm vew vault password (%(vault_id)s): '] + # 2.3 format prompts for --ask-vault-pass + prompt_formats['prompt_ask_vault_pass'] = ['New Vault password: ', + 'Confirm New Vault password: '] else: prompt_formats['prompt'] = ['Vault password (%(vault_id)s): '] # The format when we use just --ask-vault-pass needs to match 'Vault password:\s*?$' diff --git a/test/units/cli/test_cli.py b/test/units/cli/test_cli.py index 4692f128baa..706eea08b0f 100644 --- a/test/units/cli/test_cli.py +++ b/test/units/cli/test_cli.py @@ -46,6 +46,9 @@ class TestCliVersion(unittest.TestCase): class TestCliSetupVaultSecrets(unittest.TestCase): + def setUp(self): + self.fake_loader = DictDataLoader({}) + def test(self): res = cli.CLI.setup_vault_secrets(None, None) self.assertIsInstance(res, list) @@ -56,8 +59,7 @@ class TestCliSetupVaultSecrets(unittest.TestCase): mock_file_secret.return_value = MagicMock(bytes=b'file1_password', vault_id='file1', filename=filename) - fake_loader = DictDataLoader({}) - res = cli.CLI.setup_vault_secrets(loader=fake_loader, + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, vault_ids=['secret1@%s' % filename, 'secret2'], vault_password_files=[filename]) self.assertIsInstance(res, list) @@ -71,15 +73,145 @@ class TestCliSetupVaultSecrets(unittest.TestCase): mock_prompt_secret.return_value = MagicMock(bytes=b'prompt1_password', vault_id='prompt1') - fake_loader = DictDataLoader({}) - res = cli.CLI.setup_vault_secrets(loader=fake_loader, + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, vault_ids=['prompt1@prompt'], ask_vault_pass=True) self.assertIsInstance(res, list) matches = vault.match_secrets(res, ['prompt1']) self.assertIn('prompt1', [x[0] for x in matches]) - # self.assertIn('prompt1', res) - # self.assertIn('secret1', res) match = matches[0][1] self.assertEqual(match.bytes, b'prompt1_password') + + def _assert_ids(self, vault_id_names, res, password=b'prompt1_password'): + self.assertIsInstance(res, list) + len_ids = len(vault_id_names) + matches = vault.match_secrets(res, vault_id_names) + self.assertEqual(len(res), len_ids) + self.assertEqual(len(matches), len_ids) + for index, prompt in enumerate(vault_id_names): + self.assertIn(prompt, [x[0] for x in matches]) + # simple mock, same password/prompt for each mock_prompt_secret + self.assertEqual(matches[index][1].bytes, password) + + @patch('ansible.cli.PromptVaultSecret') + def test_multiple_prompts(self, mock_prompt_secret): + mock_prompt_secret.return_value = MagicMock(bytes=b'prompt1_password', + vault_id='prompt1') + + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, + vault_ids=['prompt1@prompt', + 'prompt2@prompt'], + ask_vault_pass=False) + + vault_id_names = ['prompt1', 'prompt2'] + self._assert_ids(vault_id_names, res) + + @patch('ansible.cli.PromptVaultSecret') + def test_multiple_prompts_and_ask_vault_pass(self, mock_prompt_secret): + mock_prompt_secret.return_value = MagicMock(bytes=b'prompt1_password', + vault_id='prompt1') + + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, + vault_ids=['prompt1@prompt', + 'prompt2@prompt', + 'prompt3@prompt_ask_vault_pass'], + ask_vault_pass=True) + + vault_id_names = ['prompt1', 'prompt2', 'prompt3', 'default'] + self._assert_ids(vault_id_names, res) + + @patch('ansible.cli.C', name='MockConfig') + @patch('ansible.cli.get_file_vault_secret') + @patch('ansible.cli.PromptVaultSecret') + def test_default_file_vault(self, mock_prompt_secret, + mock_file_secret, + mock_config): + mock_prompt_secret.return_value = MagicMock(bytes=b'prompt1_password', + vault_id='default') + mock_file_secret.return_value = MagicMock(bytes=b'file1_password', + vault_id='default') + mock_config.DEFAULT_VAULT_PASSWORD_FILE = '/dev/null/faux/vault_password_file' + mock_config.DEFAULT_VAULT_IDENTITY = 'default' + + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, + vault_ids=[], + create_new_password=False, + ask_vault_pass=True) + + self.assertIsInstance(res, list) + matches = vault.match_secrets(res, ['default']) + # --vault-password-file/DEFAULT_VAULT_PASSWORD_FILE is higher precendce than prompts + # if the same vault-id ('default') regardless of cli order since it didn't matter in 2.3 + self.assertEqual(matches[0][1].bytes, b'file1_password') + self.assertEqual(matches[1][1].bytes, b'prompt1_password') + + @patch('ansible.cli.PromptVaultSecret') + def test_prompt_just_ask_vault_pass(self, mock_prompt_secret): + mock_prompt_secret.return_value = MagicMock(bytes=b'prompt1_password', + vault_id='default') + + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, + vault_ids=[], + create_new_password=False, + ask_vault_pass=True) + + self.assertIsInstance(res, list) + match = vault.match_secrets(res, ['default'])[0][1] + self.assertEqual(match.bytes, b'prompt1_password') + + @patch('ansible.cli.PromptVaultSecret') + def test_prompt_new_password_ask_vault_pass(self, mock_prompt_secret): + mock_prompt_secret.return_value = MagicMock(bytes=b'prompt1_password', + vault_id='default') + + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, + vault_ids=[], + create_new_password=True, + ask_vault_pass=True) + + self.assertIsInstance(res, list) + match = vault.match_secrets(res, ['default'])[0][1] + self.assertEqual(match.bytes, b'prompt1_password') + + @patch('ansible.cli.PromptVaultSecret') + def test_prompt_new_password_vault_id_prompt(self, mock_prompt_secret): + mock_prompt_secret.return_value = MagicMock(bytes=b'prompt1_password', + vault_id='some_vault_id') + + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, + vault_ids=['some_vault_id@prompt'], + create_new_password=True, + ask_vault_pass=False) + + self.assertIsInstance(res, list) + match = vault.match_secrets(res, ['some_vault_id'])[0][1] + self.assertEqual(match.bytes, b'prompt1_password') + + @patch('ansible.cli.PromptVaultSecret') + def test_prompt_new_password_vault_id_prompt_ask_vault_pass(self, mock_prompt_secret): + mock_prompt_secret.return_value = MagicMock(bytes=b'prompt1_password', + vault_id='default') + + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, + vault_ids=['some_vault_id@prompt_ask_vault_pass'], + create_new_password=True, + ask_vault_pass=False) + + self.assertIsInstance(res, list) + match = vault.match_secrets(res, ['some_vault_id'])[0][1] + self.assertEqual(match.bytes, b'prompt1_password') + + @patch('ansible.cli.PromptVaultSecret') + def test_prompt_new_password_vault_id_prompt_ask_vault_pass_ask_vault_pass(self, mock_prompt_secret): + mock_prompt_secret.return_value = MagicMock(bytes=b'prompt1_password', + vault_id='default') + + res = cli.CLI.setup_vault_secrets(loader=self.fake_loader, + vault_ids=['some_vault_id@prompt_ask_vault_pass'], + create_new_password=True, + ask_vault_pass=True) + + self.assertIsInstance(res, list) + match = vault.match_secrets(res, ['some_vault_id'])[0][1] + self.assertEqual(match.bytes, b'prompt1_password')