actions / create-github-app-token

GitHub Action for creating a GitHub App Installation Access Token
https://github.com/marketplace/actions/create-github-app-token
MIT License
344 stars 47 forks source link

output token cannot be used across jobs #66

Closed unicornware closed 10 months ago

unicornware commented 10 months ago

Current behavior

Output tokens cannot be used across jobs. This causes jobs that depend on said token to fail.

  1. Unless the skip-token-revoke input is set to a truthy value, the token is revoked in the post step of the action, which means it cannot be passed to another job.

Using skip-token-revoke does not allow a token to be used across jobs, which is what this wording seems to imply.

Possible solutions

Additional context

Action summary screenshot

Screen Shot 2023-10-22 at 4 31 32 AM

smockle commented 10 months ago

Hi, thanks for reporting this!

This is a “necessity and sufficiency” issue: Setting skip-token-revoke to a truthy value is necessary for cross-job token usage, but that alone is not sufficient for cross-job token usage. I’m open to updating the docs to make that more clear—is there specific phrasing you’d suggest?

I don’t think masking should be optional. Instead, we should document how to use tokens across jobs. There are a few workable techniques, such as ‘storing the token as a repository secret’ or ‘encrypting the token and outputting the (unmasked) encrypted value’. In your case, implementing one of these techniques would required you to add another step to your preflight job.

gr2m commented 10 months ago

I think it would be great to document a working example of "use token across jobs" usecase in the README. And yes we should make clear that tokens cannot be passed as job output in clear text. I think the GitHub Actions documentation mentions it somewhere and suggests to use a secrets service, but I couldn't find it right now

MarkIannucci commented 10 months ago

We're running into the same frustration. Our use case is to pass the token from one job to a reusable workflow which consumes it downstream. Our reusable workflow is a wrapper around terraform, so refactoring it to get the token for itself reduces the genericity of the workflow which is currently configured to take in a generic secret. We're currently working around this using a classic PAT which GH suggests shouldn't be neceessary.

Here's the documentation that @gr2m is likely thinking about. It recommends sending the secret to hashicorp's vault and then fetching from it, which is not a light-weight approach for a secret which by definition is only valid for ten minutes.

As a customer of GitHub Enterprise, I'd like to see GH relax the ::add-mask:: functionality so that we can decide for ourselves if we want to be able to use the output in future workflow steps.

In the meantime, reading #55, it seems like @smockle may have a workable solution. Can you share how you're using the token you skip revoking?

gr2m commented 10 months ago

I think even when the token is not masked by our action, and not revoked in the post job, GitHub will still not permit you to set an output to token that it recognizes as such, I ran into this before. There is some kind of automated masking in place for tokens.

MarkIannucci commented 10 months ago

I realized I didn't say thank you to everyone who has contributed to this action. We're beginning to eliminate our PATs in our org, and this is trusted and helpful, which is exactly what we need.

Another use case we have is building container images. We have a reusable workflow for that, it needs to check out multiple internal repos to build the stuff and it can't because we can't pass the token from the job that fetches it to a build argument in the job that builds the stuff.

Elaborating on the ask to relax the ::add-mask:: and GITHUB_TOKEN sniffing and dropping functionality, I completely understand why the runner would do that in public repositories. Where I'm a bit confused is why GH wouldn't give the engineers working in internal repos the ability to make the decision on how to manage secret things in their workflows.

While I'm sure GH would prefer that there not be any tokens getting accidentally written to logs or exfiltrated, I suspect GH would be happier to have an app's 10 minute token get leaked than an individual or machine account's long lived PAT get leaked.

gr2m commented 10 months ago

can you try writing the token to an environment variable and see if that environment variable is accessible in other jobs?

MarkIannucci commented 10 months ago

I assume by environment variable you're talking about using GITHUB_ENV? I tested that out in this repo using clear text data so it'd be easier to follow and I wasn't able to update an environment variable's value in one job and have it persist to the second :( Stepping through my test bench, I initially set environment variables for the workflow as a whole:

env:
  foo: bar

Then update it:

      - run: |
          echo "foo before we change it using the env command: $foo"
          echo "foo=baz" >> "$GITHUB_ENV"
          echo "foo after we change it using the env command -- note it is still what it was: $foo"
          echo "foo if we reference it in the env object: ${{env.foo}}"

Then echo it in a second step to validate that it was updated:

      - run: |
          echo "foo if we reference it in a second step: $foo"
          echo "foo if we reference it using the env object in a second step: ${{env.foo}}"

And finally I echo it in a second job to see if I can pass the value down the line:

  second-job:
    runs-on: ubuntu-latest
    needs: [first-job]
    steps:
      - run: |
          echo "foo in job two after it was updated by job one: $foo"

And unfortunately, I find that in the second job, $foo's value is bar

gr2m commented 10 months ago

Thank you for testing this.

I reached out to the actions team, and unfortunately there is not a simple and safe solution to this problem. Feedback I got is

Not easily no, you'd need to store it in an artifact. You'd want to delete the artifact and ensure you're revoking token before the run ends.

The only way I can think is to re-run the create-github-app-token for each follow up job.

What exactly is your use case?

unicornware commented 10 months ago

@smockle

thanks for the feedback! my computer was down for a little bit, so i'm still getting caught up :sweat_smile:

This is a “necessity and sufficiency” issue: Setting skip-token-revoke to a truthy value is necessary for cross-job token usage, but that alone is not sufficient for cross-job token usage. I’m open to updating the docs to make that more clear—is there specific phrasing you’d suggest?

the bit before the phrasing question (adjusted for context, if necessary) would be perfect haha

I don’t think masking should be optional. Instead, we should document how to use tokens across jobs. There are a few workable techniques, such as ‘storing the token as a repository secret’ or ‘encrypting the token and outputting the (unmasked) encrypted value’. In your case, implementing one of these techniques would required you to add another step to your preflight job.

would it be possible to incorporate one of those suggestions into this action?

gr2m commented 10 months ago

would it be possible to incorporate one of those suggestions into this action?

I would rather not. This is not working for a reason. I would rather document a workaround and explain why it is necessary. I think in many cases I would recommend to use the action in each job, instead of passing the token via jobs outputs.

unicornware commented 10 months ago

i'm not a fan of copying one of those techniques from repo to repo, and there are a few cases where i'd rather not use the action in each job, so i'll most likely implement an action that suits more of my needs. this issue can be closed. thanks though!

acuD1 commented 2 months ago

Hi everyone,

I ran into this exact situation where I need to set up a token that can write to the registry. Before migrating to an organization, I used my own PAT, but now it's a bit more tricky, so we need a GitHub App.

After reading these topics, I would like to confirm that for now the only viable solution is to call this action before each job that needs a token ?

Thank you.

gr2m commented 2 months ago

the only viable solution is to call this action before each job that needs a token

Yes, that is correct.