How to mask environment variables created in Github when running a workflow?

Question:

I created a Github workflow that runs a python script with a cron schedule. On every run of the workflow an access_token is generated, which is required during the next run.

To save the token the python script writes the token to the GITHUB_ENV file. In the next step, I use the hmanzur/[email protected] action to save the token to a Github secret. All works fine.

My only problem is, that the token gets displayed in the logs of the second step as an environment variable.

Here is a minimal version of the workflow file:

name: Tests
on:
  schedule:
    - cron: "0 1 * * *"
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python: ['3.9']
    steps:
      - uses: actions/checkout@v1
      - uses: actions/setup-python@v1
        with:
          python-version: ${{ matrix.python }}
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run tests
        working-directory: ./src
        run: python -m unittest
        env:
          ACCESS_TOKEN: ${{secrets.ACCESS_TOKEN}}
      - uses: hmanzur/[email protected]
        with:
          name: 'ACCESS_TOKEN'
          value: ${{env.ACCESS_TOKEN}}
          repository: Me/MyRepository
          token: ${{ secrets.REPO_ACCESS_TOKEN }}

I tried applying ::add-mask::. Adding echo "ACCESS_TOKEN=::add-mask::$ACCESS_TOKEN" >> $GITHUB_ENV only added ::add-mask:: to the string.

Is there a way of masking all environment variables in the GITHUB_ENV file I can apply in the first step? Can I apply the masking to the variable while writing to the GITHUB_ENV file in python? Or is there a way to disable the display of the environment variables during the workflow?

Asked By: Der Henning

||

Answers:

My solution, if someone is having the same problem.

There seems to be no direct solution. As a workaround I use the cryptocode library to encode and decode the access token in the python script. Only the encrypted token is send to the workflow environment and saved in the repos secret.

Here a minimal working example:

workflow.yml:

name: Test
on:
  push:
    branches:
      - main
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python: ['3.9']
    steps:
      - uses: actions/checkout@v1
      - uses: actions/setup-python@v1
        with:
          python-version: ${{ matrix.python }}
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run tests
        working-directory: ./
        run: python encrypt-secret.py
        env:
          ENCRYPTED_ACCESS_TOKEN: ${{secrets.ENCRYPTED_ACCESS_TOKEN}}
          INITIAL_ACCESS_TOKEN: ${{secrets.INITIAL_ACCESS_TOKEN}}
          PASS_KEY: ${{secrets.REPO_ACCESS_TOKEN}}
      - uses: hmanzur/[email protected]
        with:
          name: 'ENCRYPTED_ACCESS_TOKEN'
          value: ${{env.ENCRYPTED_NEW_ACCESS_TOKEN}}
          repository: Der-Henning/test-workflows
          token: ${{ secrets.REPO_ACCESS_TOKEN }}

encrypt-secret.py:

from os import environ
from random import random
import cryptocode

def main():
  ## Get Github environment file
  ## Only run this part when GITHUB_ENV is set -> workflow detection
  env_file = environ.get('GITHUB_ENV', None)
  if env_file:
    
    ## PASS_KEY to encrypt the secret
    passkey = environ.get("PASS_KEY", None)
    
    access_token = environ.get("INITIAL_ACCESS_TOKEN")

    ## get the encrypted token and decrypt with passkey
    encrypted_old_access_token = environ.get("ENCRYPTED_ACCESS_TOKEN", None)
    if encrypted_old_access_token and passkey: 
      old_access_token = cryptocode.decrypt(encrypted_old_access_token, passkey)
      if old_access_token:
        print("Access Token from secret: {}".format(old_access_token))
        print("Correct Token: {}".format(old_access_token.startswith('ThisIsASecret')))
        access_token = old_access_token
    else:
      print("No encrypted Access Token provided!")

    ######
    #
    # Do stuff here
    # Use old_access_token to access an API ...
    #
    #####
      
    ## Encrypt new access token from API for next run
    ## Save encrypted token to GITHUB_ENV
    new_access_token = "ThisIsASecret{}".format(random())
    print("New Token: {}".format(new_access_token))
    if passkey:
      encrypted_new_access_token = cryptocode.encrypt(new_access_token, passkey)
      with open(env_file, "a") as file:
        file.write("ENCRYPTED_NEW_ACCESS_TOKEN={}n".format(encrypted_new_access_token))

if __name__ == "__main__":
  main()
Answered By: Der Henning

Your usage of "::add-mask::" is wrong (not your fault, I hate GHA doc).

What you need to do is:

echo "::add-mask::$ACCESS_TOKEN" 
echo "ACCESS_TOKEN=$ACCESS_TOKEN" >> $GITHUB_ENV
Answered By: micguo