Repository: ansible/ansible
Pull request: ansible-vault: add newline to the output of the 'encrypt_string' command
##### SUMMARY
Adds newline to the `ansible-vault encrypt_string ...` output.
Fixes #78932, more details here.

##### ISSUE TYPE
- Bugfix Pull Request

##### COMPONENT NAME
<!--- Write the short name of the module, plugin, task or feature below -->
Ansible-vault: `encrypt_string` output

Problem statement:
ansible-vault encrypt_string output is missing a new line, causing broken output on copy
### Summary

```
$ ansible-vault encrypt_string secret
Encryption successful
!vault |
          $ANSIBLE_VAULT;1.1;AES256
          61633966613365393435663962393261376338336136313065376437373838636336623565363239
          6630383564363634636364613830613561316333623739380a653764333864666363663539363363
          65316331636165353761626461386166633330623835316362393361343333396234663638653666
          3163373561623331340a633161373437343563333135343933376634643638613332643964313135
          3430%                                                                                                                    
 
```
If you look at the end of the printed data, it contains a `%`, which is a character that is added by the terminal in order to inform user that the executed command did not end-up with a newline.

Now you can easily guess that when user will copy/paste that yaml block, their will have a surprise, as decoding will not work,.... because of the extra `%` at the end.


This bug can easily be avoided by ensuring that we add a newline at the end of the dumped data, as this will not affect the validity of the dumped YAML, but will avoid having the terminal add the `%` character at the end of the last line, a character which will render the entire block invalid for decryption.

### Issue Type

Bug Report

### Component Name

encrypt

### Ansible Version

```console
$ ansible --version
ansible [core 2.14.0b1]
  config file = /Users/ssbarnea/.ansible.cfg
  configured module search path = ['/Users/ssbarnea/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/ssbarnea/.pyenv/versions/3.11-dev/lib/python3.11/site-packages/ansible
  ansible collection location = /Users/ssbarnea/.ansible/collections:/usr/share/ansible/collections
  executable location = /Users/ssbarnea/.pyenv/versions/3.11-dev/bin/ansible
  python version = 3.11.0rc2+ (heads/3.11:8e2bda8227, Sep 19 2022, 10:59:25) [Clang 14.0.0 (clang-1400.0.29.102)] (/Users/ssbarnea/.pyenv/versions/3.11-dev/bin/python3.11)
  jinja version = 3.1.2
  libyaml = True
```


### Configuration

```console
-
```


### OS / Environment

MacOS

### Steps to Reproduce

Just configure a ANSIBLE_VAULT_PASSWORD_FILE=.vault_pass and put a password inside the vault file, so you can easily encrypt and decypt.

Try to encrypt a secret like `ansible-vault encrypt_string secret`, select the output and paste it inside a playbook for use.

### Expected Results

Be able to copy/paste the output and be able to use it.

### Actual Results

```console
Vault format unhexlify error: Odd-length string
```


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct

Hints from issue discussion:
Files identified in the description:
* [`lib/ansible/utils/encrypt.py`](https://github.com/ansible/ansible/blob/devel/lib/ansible/utils/encrypt.py)

If these files are incorrect, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
Hi @ssbarnea, 
  I would like to contribute to this issue.  
@karthiknatarajan-27558 Feel free to make a PR for it, it should be easy. IMHO, it will not be hard to get approval to merge it. I wasted almost an hour trying to figure-out what was not working and it was this trailing `%`. That being a good shell feature, until you discover an issue like this. Some programs do need to not add extra newline at the end, but that is not the case for something that just dumps YAML on console.

Commit message: ansible-vault: add newline to the output of the 'encrypt_string' command

Patch to review:
diff --git a/lib/ansible/cli/vault.py b/lib/ansible/cli/vault.py
index 3e60329de608a2..7dcd213d6040dd 100755
--- a/lib/ansible/cli/vault.py
+++ b/lib/ansible/cli/vault.py
@@ -384,7 +384,7 @@ def execute_encrypt_string(self):
                 sys.stderr.write(err)
             b_outs.append(to_bytes(out))
 
-        self.editor.write_data(b'\n'.join(b_outs), context.CLIARGS['output_file'] or '-')
+        self.editor.write_data(b'\n'.join(b_outs) + b'\n', context.CLIARGS['output_file'] or '-')
 
         if sys.stdout.isatty():
             display.display("Encryption successful", stderr=True)


Code review comments:
diff_hunk: @@ -384,7 +384,7 @@ def execute_encrypt_string(self):
                 sys.stderr.write(err)
             b_outs.append(to_bytes(out))
 
-        self.editor.write_data(b'\n'.join(b_outs), context.CLIARGS['output_file'] or '-')
+        self.editor.write_data(b'\n'.join(b_outs) + b'\n', context.CLIARGS['output_file'] or '-')
path: lib/ansible/cli/vault.py
text: @user1:
I think a more elegant solution would be to add one more list element and `str.join()` will do the rest:
```suggestion
        b_outs.append(b'')
        self.editor.write_data(b'\n'.join(b_outs), context.CLIARGS['output_file'] or '-')
```

@author:
@user1 Done