diff --git a/changelogs/fragments/50603-tty-check.yaml b/changelogs/fragments/50603-tty-check.yaml new file mode 100644 index 00000000000..9acc5351fbf --- /dev/null +++ b/changelogs/fragments/50603-tty-check.yaml @@ -0,0 +1,4 @@ +--- +minor_changes: + - "ansible-vault create: Now raises an error when opening the editor without + tty. The flag --skip-tty-check restores previous behaviour." diff --git a/lib/ansible/cli/vault.py b/lib/ansible/cli/vault.py index 870cb11c7fc..f7fb5ee01da 100755 --- a/lib/ansible/cli/vault.py +++ b/lib/ansible/cli/vault.py @@ -82,6 +82,8 @@ class VaultCLI(CLI): create_parser = subparsers.add_parser('create', help='Create new vault encrypted file', parents=[vault_id, common]) create_parser.set_defaults(func=self.execute_create) create_parser.add_argument('args', help='Filename', metavar='file_name', nargs='*') + create_parser.add_argument('--skip-tty-check', default=False, help='allows editor to be opened when no tty attached', + dest='skip_tty_check', action='store_true') decrypt_parser = subparsers.add_parser('decrypt', help='Decrypt vault encrypted file', parents=[output, common]) decrypt_parser.set_defaults(func=self.execute_decrypt) @@ -447,8 +449,11 @@ class VaultCLI(CLI): if len(context.CLIARGS['args']) != 1: raise AnsibleOptionsError("ansible-vault create can take only one filename argument") - self.editor.create_file(context.CLIARGS['args'][0], self.encrypt_secret, - vault_id=self.encrypt_vault_id) + if sys.stdout.isatty() or context.CLIARGS['skip_tty_check']: + self.editor.create_file(context.CLIARGS['args'][0], self.encrypt_secret, + vault_id=self.encrypt_vault_id) + else: + raise AnsibleOptionsError("not a tty, editor cannot be opened") def execute_edit(self): ''' open and decrypt an existing vaulted file in an editor, that will be encrypted again when closed''' diff --git a/test/units/cli/test_vault.py b/test/units/cli/test_vault.py index 2304f4d5cd1..1be29d9ca1f 100644 --- a/test/units/cli/test_vault.py +++ b/test/units/cli/test_vault.py @@ -171,7 +171,28 @@ class TestVaultCli(unittest.TestCase): mock_setup_vault_secrets.return_value = [('default', TextVaultSecret('password'))] cli = VaultCLI(args=['ansible-vault', 'create', '/dev/null/foo']) cli.parse() + self.assertRaisesRegexp(errors.AnsibleOptionsError, + "not a tty, editor cannot be opened", + cli.run) + + @patch('ansible.cli.vault.VaultCLI.setup_vault_secrets') + @patch('ansible.cli.vault.VaultEditor') + def test_create_skip_tty_check(self, mock_vault_editor, mock_setup_vault_secrets): + mock_setup_vault_secrets.return_value = [('default', TextVaultSecret('password'))] + cli = VaultCLI(args=['ansible-vault', 'create', '--skip-tty-check', '/dev/null/foo']) + cli.parse() + cli.run() + + @patch('ansible.cli.vault.VaultCLI.setup_vault_secrets') + @patch('ansible.cli.vault.VaultEditor') + def test_create_with_tty(self, mock_vault_editor, mock_setup_vault_secrets): + mock_setup_vault_secrets.return_value = [('default', TextVaultSecret('password'))] + self.tty_stdout_patcher = patch('ansible.cli.sys.stdout.isatty', return_value=True) + self.tty_stdout_patcher.start() + cli = VaultCLI(args=['ansible-vault', 'create', '/dev/null/foo']) + cli.parse() cli.run() + self.tty_stdout_patcher.stop() @patch('ansible.cli.vault.VaultCLI.setup_vault_secrets') @patch('ansible.cli.vault.VaultEditor')