0

I have a makefile with this goal:

setup: 
    @GHE_TOKEN=$(shell vault read -field=value is/cloud/eng/ghe_token)
    @GHE_TOKEN=${GHE_TOKEN} pipenv install --dev 

What I'm doing here is getting a secret from HashiCorp vault and passing it on to the next command. This works fine if I'm already logged in to vault properly.

However if I'm not logged in the pipenv install command proceeds even though there was an error in vault read.

So what I'm looking for is the make goal to abort and display the error message if there is an error on the vault read call and also be able to capture the output of a successful shell command to read. I know how to do one or the other, but not both.

Thanks for any help!

1
  • 1
    I'm not entirely sure what you're trying to do but... the two commands in the make recipe will be executed in separate shells. So the value of GHE_TOKEN set in the first command will not be visible in the second. Commented Mar 5, 2021 at 19:31

1 Answer 1

1

It isn't working because what you're doing is not at all what you think you're doing :).

When make processes a recipe it works like this: first all make variables and functions in all commands in the recipe are expanded, then each command line in the recipe is invoked one at a time, in its own shell.

So, in your situation note that ${GHE_TOKEN} is a reference to a make variable named GHE_TOKEN, which I assume is not set in your makefile, so it's the empty string. Also the make $(shell ...) function is expanded before any command is run, and note that make doesn't care about the exit code of this; if it fails it won't cause the command to fail.

If we assume that the vault read -field=value is/cloud/engine/ghe_token returns the value mysecret, then make will substitute in that value and run these commands (basically):

/bin/sh -c 'GHE_TOKEN=mysecret'
/bin/sh -c 'GHE_TOKEN= pipenv install --dev'

This clearly isn't going to do what you want.

You need to do all the work in the shell; it's almost always a sign of something wrong if you are using make's shell function in a recipe; a recipe is already running in the shell, so using $(shell ...) just adds confusion.

You probably want this:

setup:
        @export GHE_TOKEN=$$(vault read -field=value is/cloud/eng/ghe_token) \
            && pipenv install --dev

so that pipenv is not run if the vault read command fails.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks..... your suggestion wasn't working so I simplified a little: ``` export a=$$(vault read -field=value is/cloud/eng/ghe_token) && echo ${a} ``` it echoes an empty string.... hmmm
Yes, that won't work because you wrote ${a} which is a make variable (see my first point above). You need to use $${a} to print a shell variable.
But to really mimic what you're doing with pipenv you should use the env program, something like: export myvar=$$(vault ...) && env | grep myvar= and see what it prints. What you're doing is subtly different because the shell is expanding $a from its local environment before invoking echo.
I tried your answer again, and it works! no telling why it didn't on first pass. The double $$ was tripping me up but your explanation cleared it up, thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.