3

The travis encryption docs mention that I have to bash-escape my password before encrypting it:

Note on escaping certain symbols

When you use travis encrypt to encrypt sensitive data, it is important to note that it will be processed as a bash statement. This means that secret you are encrypting should not cause errors when bash parses it. Having incomplete data will cause bash to dump the error statement to the log, which contains portions of your sensitive data.

Thus, you need to escape special characters such as braces, parentheses, backslashes, and pipe symbols. For example, when you want to assign the string 6&a(5!1Ab\ to FOO, you need to execute:

travis encrypt "FOO=6\\&a\\(5\\!1Ab\\\\"

The answer for bash seems to revolve around printf "%q", but it's still too complicated to figure out how to wire printf with the travis cli.

What's the bash one-liner for having travis encrypt do what it's supposed to do?

I mean, I want to paste my variable name and its value and be sure that it will be encrypted properly, without having to worry about bash escaping. We can stay with the example above, assuming I want to assign the string 6&a(5!1Ab\ to the variable FOO.

And while we're at it, what would be the corresponding one-liner for travis env set? That would help those fighting with the data too large error.

Community
  • 1
  • 1
Pierre F
  • 1,332
  • 15
  • 33
  • 1
    I think all you need is `printf -v esc_foo '%q' "$foo"` and now `esc_foo` contains properly escaped string – Inian Feb 05 '19 at 15:59
  • "Processed as a `bash` statement" makes me think that it's just invoking `eval` on the argument, which means I would think long and hard about using it *at all*. – chepner Feb 05 '19 at 17:03
  • 2
    Also, why would they suggest that backslash-infested nightmare instead of `travis encrypt "FOO='6&a(5!1Ab\'"`? – chepner Feb 05 '19 at 17:05

3 Answers3

4

Based on Armali's answer:

read -r && travis encrypt "$(printf %q "$REPLY")"

then paste your variable and its value:

FOO=6&a(5!1Ab\
Pierre F
  • 1,332
  • 15
  • 33
2

What's the bash one-liner for having travis encrypt do what it's supposed to do?

I mean, I want to paste my variable name and its value and be sure that it will be encrypted properly, without having to worry about bash escaping.

This is generally impossible, because if the value is to be inserted into the command line, some kind of quoting is indispensable, hence at least one quoting character (if allowed to occur in the value) must be handled specially and cannot simply be pasted in; that's the reason why enclosing the value in ' ' doesn't work if ' occurs in the value (and surely ' shall be allowed in a password). Thus, the requirement of being able to paste the value can only be met if the requirement of a one-liner is dropped and the value is supplied as input.
Then, since the travis encrypt command needs extra quoting of the argument (perhaps because, as chepner thinks, eval is invoked), we can provide this quoting with printf %q, e. g.

read -r
6&a(5!1Ab\
travis encrypt "$(printf %q "FOO=$REPLY")"
(the bold line to be pasted).

How about putting VAR=VALUE in the read statement to put everything together? read -r, paste FOO=6&a(5!1Ab\ and finally travis encrypt "$(printf %q "$REPLY")".

Of course that would also work.

Furthermore, is there really no way to pipe the result of read -r to travis encrypt?

If you mean literally to pipe, then no, there's no way to pipe something to a command that only expects arguments. But if you just wonder if we can concatenate the commands, then yes, we can as well write e. g.

read -r; travis encrypt "$(printf %q "$REPLY")"
FOO=6&a(5!1Ab\
Armali
  • 18,255
  • 14
  • 57
  • 171
  • Thanks a lot! How about putting `VAR=VALUE` in the `read` statement to put everything together? `read -r`, paste `FOO=6&a(5!1Ab\ ` and finally `travis encrypt "$(printf %q "$REPLY")"`. Furthermore, is there really no way to pipe the result of `read -r` to `travis encrypt`? – Pierre F Feb 06 '19 at 13:28
  • 1
    How about chaining the statements with `&&`? That would be: `read -r && travis encrypt "$(printf %q "$REPLY")"`, then paste `FOO=6&a(5!1Ab\ `. That would satisfy the one-liner requirement for me. Anything I'm missing? – Pierre F Feb 06 '19 at 13:39
  • @Pierre F - I just incorporated the questions from your first comment into my answer. Your idea of using `&&` is even better than my `;`. – Armali Feb 06 '19 at 13:51
  • Thanks for the update @Armali. Regarding your argument about handling the quoting character specially: Would this solution always work, even when the line contains the character `"`, or do we need to escape this character one more time to be on the safe side? – Pierre F Feb 06 '19 at 13:56
  • @Pierre F - This works also with `"`, as a contained quote is not interpreted during the expansion of `$REPLY`, and is thereafter escaped by `printf %q` just like other special characters. – Armali Feb 06 '19 at 14:02
  • Perfect! Then I guess we have the solution. Problem solved! – Pierre F Feb 07 '19 at 09:40
  • It may be a good idea to run `unset REPLY` after the encryption step. – sylvain Dec 12 '19 at 05:05
2

it is so much easier to just base64 the string and decode it in your build. saves all the faffing about with the escaping in travis.

Travis, and any other CI/CD service, allows for secret environment variables to be stored secretly to be used for every build. In setting for your projects build, add environment variable option. To echo the the password in cli to use for base64 youd still need to escape the string as it needs to be evaluated by bash. create a temp file with your password. Then:

cat /tmp/secret | base64 -w 0

copy the string and paste it in the value field for travis ci env var setting

in .travis.yaml file to retrieve the secret simply:

echo $SECRET | base64 -d

There may be edge cases, though, but this should solve most use cases.

Erik K
  • 471
  • 5
  • 12
  • That's a fair idea as well, thanks. I guess the answer would be even more useful for the other stack overflow users with the corresponding commands: How to base64-encode & encrypt in the command-line, and how to decrypt & base64-decode the environment variable in `.travis.yml` – Pierre F Mar 05 '19 at 09:58
  • Thanks for updating the answer with the `base64` command. I'm not sure how this could be used e.g. to encrypt a variable that is meant to be used directly like a deploy password. With Armali's answer, you could directly `travis encrypt --add deploy.password`. – Pierre F Apr 16 '19 at 09:13