If you don't want to spend hours debugging GitHub CI jobs, avoid using job outputs that may contain secrets inside. Job outputs will not be passed to dependent jobs if they contain secrets in any part of output value.
There is a tiny note about this behavior in docs.
Job outputs containing expressions are evaluated on the runner at the end of each job. Outputs containing secrets are redacted on the runner and not sent to GitHub Actions.
You can test this by setting GitHub secret MY_SECRET
and using it in workflow like this:
name: 06 - Debug
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
demo1:
runs-on: ubuntu-latest
outputs:
my_output: ${{ steps.set_output.outputs.my_output }}
steps:
- id: set_output
run: echo 'my_output=${{ secrets.MY_SECRET }}' >> "$GITHUB_OUTPUT"
demo2:
runs-on: ubuntu-latest
needs: [demo1]
steps:
- run: echo 'MY_SECRET=${{ needs.demo1.outputs.my_secret }}'
- run: echo 'MY_SECRET=${{ secrets.MY_SECRET }}'
You will see a warning annotation at workflow run summary page:
Skip output 'my_output' since it may contain secret.
In the workflow run log you will see that trying to use demo1
job output will result in empty string.
I learned this the hard way. I was using secrets like DB_NAME=my-app
and then in output of build
job I tried to return output like image_tag: ghcr.io/${{ github.repository }}:my-app-${{ github.run_id }}
. It did not show up as output from this job because it contained my-app
inside. I should have used GitHub variables for storing non-sensitive values like database name and similar.