Skip to content

AntelopeIO/github-app-token-action

 
 

Repository files navigation

GitHub App Token

This JavaScript GitHub Action can be used to impersonate a GitHub App when secrets.GITHUB_TOKEN's limitations are too restrictive and a personal access token is not suitable.

For instance, from GitHub Actions' docs:

When you use the repository's GITHUB_TOKEN to perform tasks, events triggered by the GITHUB_TOKEN, with the exception of workflow_dispatch and repository_dispatch, will not create a new workflow run. This prevents you from accidentally creating recursive workflow runs. For example, if a workflow run pushes code using the repository's GITHUB_TOKEN, a new workflow will not run even when the repository contains a workflow configured to run when push events occur.

A workaround is to use a personal access token from a personal user/bot account. However, for organizations, GitHub Apps are a more appropriate automation solution.

Index

  1. Examples
    1. Cloning Private Submodules
  2. Release Process

Examples

Here is a generic example retrieving a token from a GitHub App using this action, then consuming that token in a subsequent step. You can see some of the optional inputs listed in comments, as well.

jobs:
  job:
    runs-on: ubuntu-latest
    steps:
      - name: Generate token
        id: generate_token
        uses: tibdex/github-app-token@v1
        with:
          app_id: ${{ secrets.APP_ID }}

          # Optional.
          # github_api_url: https://api.example.com

          # Optional.
          # installation_id: 1337

          # Optional.
          # Using a YAML multiline string to avoid escaping the JSON quotes.
          # permissions: >-
          #   {"members": "read"}

          private_key: ${{ secrets.PRIVATE_KEY }}

          # Optional.
          # repository: owner/repo

      - name: Use token
        env:
          TOKEN: ${{ steps.generate_token.outputs.token }}
        run: |
          echo "The generated token is masked: ${TOKEN}"

Another use case for this action can (or could) be found in GitHub's own docs.

Cloning Private Submodules

This action is a great way to securely clone private submodules, a common need that remains unsupported by GitHub Actions as described in actions/checkout issue 287. Using GitHub App integration to clone submodules does not consume a paid user seat with a service account, the secrets cannot be used to login to the GitHub web UI, and the token used for the clone expires after one hour.

Steps:

  1. Create a GitHub App.
    1. Profile > Your organizations > Organization Settings > GitHub Apps > New GitHub App
    2. Fill in the information for the app.
      1. GitHub App name:
        ${REPO_NAME}-ci-submodule-checkout
        
      2. Description:
        This GitHub application is used by the ${REPO_NAME} CICD pipeline(s) to clone private submodules by using a fork of the tibdex/github-app-token GitHub Action to obtain an ephemeral token from this app and assume its identity. This token expires after one hour.
        
      3. Homepage URL:
        ${REPO_URL}
        
      4. Ensure the Expire user authorization tokens checkbox is checked.
      5. Disable webhook notifications.
      6. Permissions > Repository permissions > Contents > Read-only
        • This will implicitly set Metadata to Read-only as well.
      7. For Where can this integration be installed? choose Only on this account.
    3. Click Create GitHub App.
  2. Obtain credentials to assume the identity of the app.
    1. Profile > Your organizations > Developer settings > GitHub Apps > ${REPO_NAME}-ci-submodule-checkout > Edit
    2. Private keys > Generate a private key
    3. A private key downloads to your computer as a *.pem file. Keep this secret.
    4. Note the app ID. Keep this secret.
  3. Install the app in the organization.
    1. Organization > Settings > GitHub Apps > ${REPO_NAME}-ci-submodule-checkout > Edit
    2. Install App
    3. Click Install for the desired organization.
    4. Install & Request on your organization > Only select repositories
      • If you are an org admin, the button may be labeled differently.
    5. Select the appropriate repos in the drop-down.
      • This must include both the submodules you wish to clone as well as the repo you are cloning them into!
        Ask me how I know, lol.
    6. Click Install & Request.
      • If you are an org admin, the button may be labeled differently.
  4. Create repo secrets for app integration.
    1. Repo > Settings > Secrets and variables > Actions
    2. Add two new secrets.
      ${REPO_NAME}_CI_APP_ID
      ${REPO_NAME}_CI_APP_KEY
      
  5. Use the GitHub App to clone private submodules in your GitHub Actions workflow(s).
    name: CI
    
    on: [push, workflow_dispatch]
    
    jobs:
      build:
        name: Build
        runs-on: ubuntu-latest
    
        steps:
          - name: Authenticate
            id: auth
            uses: AntelopeIO/github-app-token-action@v1
            with:
              app_id: ${{ secrets.${REPO_NAME}_CI_APP_ID }}
              private_key: ${{ secrets.${REPO_NAME}_CI_APP_KEY }}
    
          - name: Checkout Repo
            uses: actions/checkout@v3
            with:
              fetch-depth: 0
              submodules: 'recursive'
              token: ${{ steps.auth.outputs.token }}
    
          - name: Do a Thing
            run: tree -L 2

Don't forget to replace ${REPO_NAME} and ${REPO_URL} with the appropriate values if you copy/pasta these examples.

The author recommends using a different GitHub App integration for each repo cloning submodules. This allows you to follow the principle of least priviledge.

Credit to @petr-tichy for the idea, and @matthijskooijman for sharing detailed steps to accomplish this. Thank you both!

Release Process

When a commit is pushed to the base branch (main), the dylanvann/publish-github-action GitHub Action is invoked. If the version field in the package.json is new, then the action:

  1. Downloads dependencies.
  2. Builds the project.
  3. Packs the action as a minimal distributable.
  4. Puts these files on a branch named "releases/" with the version string appended to the end.
  5. Points tags corresponding to the major, minor, and patch versions at the HEAD of the new release* branch.

For example, if the version field in package.json is 1.1.1, the following refs will be created.

  • A branch named releases/v1.1.1 with the action built and other files removed.
  • A tag named v1.1.1 is created pointing at the HEAD of releases/v1.1.1.
  • A tag named v1.1 is moved or created, pointing at the HEAD of releases/v1.1.1.
  • A tag named v1 is moved or created, pointing at the HEAD of releases/v1.1.1.

It is important to note some repo protections will prevent this action from running.

  • Tag protections.
  • Branch protections matching the release pattern.
  • Code signing requirements.

If these are enforced, they must be disabled for the action to run.

About

Impersonate a GitHub App in a GitHub Action

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 63.2%
  • JavaScript 36.8%