18

I am trying to publish a Python package to PyPI, from a Github workflow, but the authentication fails for "Test PyPI". I successfully published to Test PyPI from the command line, so my API token must be correct. I also checked for leading and trailing spaces in the secret value (i.e., on GitHub).

As the last commits show, I tried a few things without success.

I first tried to inline simple bash commands into the workflow as follows, but I have not been able to get my secrets into environment variables. Nothing showed up in the logs when I printed these variables.

- name: Publish on Test PyPI 
  env:
     TWINE_USERNAME: __token__
     TWINE_PASSWORD: ${{ secrets.PYPI_TEST_TOKEN }}
     TWINE_REPOSITORY_URL: "https://test.pypi.org/legacy/"
  run: |
     echo "$TWINE_PASSWORD"
     pip install twine
     twine check dist/*
     twine upload dist/*

I also tried to use a dedicated GitHub Action as follows, but it does not work either. I guess the problem comes from the secrets not being available in my workflow. What puzzled me is that my workflow uses another token/secret just fine! Though, if I put it in an environment variable, nothing is printed out. I also recreated my secrets under different names (PYPI_TEST_TOKEN and TEST_PYPI_API_TOKEN) but to no avail.

- name: Publish to Test PyPI
  uses: pypa/gh-action-pypi-publish@release/v1
  with:
    user: __token__
    password: ${{ secrets.TEST_PYPI_API_TOKEN }}
    repository_url: https://test.pypi.org/legacy/

I guess I miss something obvious (as usual). Any help is highly appreciated.

fchauvel
  • 763
  • 1
  • 6
  • 14
  • Do the secret variables show up on https://github.com/username/repo/settings/secrets/actions? – Julia Mar 07 '21 at 22:10
  • 1
    As for [this run](https://github.com/fchauvel/flap/runs/2052152834?check_suite_focus=true) using the dedicated action: the "Publish to Test PyPI" step doesn't show `password` as an input, so I'd ask as well, how do you set the secret? – Benjamin W. Mar 07 '21 at 23:52
  • Yes, I do see the secrets under `settings/secrets/actions`. They are listed as variables of the 'CI' environment, which I created and where I added the variables. If I create secrets at the repository level it works, I can put them in environment variables and I see '***' in the logs. – fchauvel Mar 08 '21 at 05:02

2 Answers2

38

I eventually figured it out. My mistake was that I defined my secrets within an environment and, by default, workflows do not run in any specific environment. For this to happen, I have to explicitly name the environment in the job description as follows:

jobs:
  publish:
    environment: CI    # <--- /!\ Here is the link to the environment
    needs: build
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
    - uses: actions/checkout@v2
    # Some more steps here ...
    - name: Publish to Test PyPI
      env:
        TWINE_USERNAME: "__token__"
        TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
        TWINE_REPOSITORY_URL: "https://test.pypi.org/legacy/"
      run: |
        echo KEY: '${TWINE_PASSWORD}'
        twine check dist/*
        twine upload --verbose --skip-existing dist/*

The documentation mentions it actually.

Thanks to those who commented for pointing me in the right direction.

fchauvel
  • 763
  • 1
  • 6
  • 14
  • 2
    It seems there is a part I am missing about this. What if you have a secret `FOO` that is present in multiple environments. You want to be able to access `FOO`, which will vary depending on the branch you are on.. For that, you will not want to create different jobs just to be able to refer to the secrets within that environment... I wonder how that could be done. – Rose Aug 20 '21 at 21:29
  • thank you! this also applies for manually-executed `workflow_dispatch` workflows that have an `inputs: env: type: environment` which still requires an explicit `environment: ${{ inputs.env }}` on the job – hotzen Jan 03 '23 at 10:29
2

This is the problem I struggled with, since I am working with multiple environments and they all share same named secrets with different values the following solution worked for me. Isolated pieces are described here and there, but it wasn't obvious how to piece it together.

At first I define that environment is selected during workflow_dispatch event:

on:
  workflow_dispatch:
    inputs:
      environment:
        type: choice
        description: Select the environment
        required: true
        options:
          - TEST
          - UAT

I then reference it in jobs context:

jobs:
  run-portal-tests:
    runs-on: ubuntu-latest
    environment: ${{ github.event.inputs.environment }}

Finally to be used in the step I need them in:

- name: Run tests
    env:
      ENDPOINT: ${{ secrets.ENDPOINT }}
      TEST_USER: ${{ secrets.TEST_USER }}
      TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
      CLIENT_ID: ${{ secrets.CLIENT_ID }}
      CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
    run: python3 main.py
  • Thank you for this! It put me on the right track. But instead of `${{ github.events.inputs.environment }}` I had to use just `${{ inputs.environment }}` per [this page](https://github.com/orgs/community/discussions/37686). – James Frank Apr 27 '23 at 20:24