Skip to content

GitHub App authentication#

The repository API operations in the Plan, Build-Module, and Publish-Module workflows use short-lived GitHub App installation tokens. These workflows do not use github.token as a fallback for those operations.

Caller secret contract#

The reusable workflow declares two required secrets at its workflow_call boundary:

Name Purpose
GitHubAppClientId The GitHub App client ID passed to the token action.
GitHubAppPrivateKey The GitHub App private key passed to the token action.

The names are the reusable workflow contract, not a requirement for the caller's repository or organization secret names. Map the caller's secrets explicitly:

jobs:
  Process-PSModule:
    uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5
    secrets:
      PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
      GitHubAppClientId: ${{ secrets.SHELLY_CLIENT_ID }}
      GitHubAppPrivateKey: ${{ secrets.SHELLY_PRIVATE_KEY }}

The root reusable workflow forwards these two values to the Plan, Build-Module, and Publish-Module reusable jobs. Do not use secrets: inherit as a substitute for this mapping.

Dependabot-triggered workflows cannot read regular Actions secrets. To run Process-PSModule on Dependabot pull requests, create SHELLY_CLIENT_ID and SHELLY_PRIVATE_KEY as Dependabot secrets in addition to Actions secrets. This is a deliberate trust boundary: review the App's installation scope and every dependency update carefully, because the workflow can mint a Shelly token before human review.

GitHub App installation permissions#

Install Shelly only on repositories that the process must manage. The complete permission baseline for the current Process-PSModule GitHub App path is:

Repository permission Access Why it is needed
Contents Write Read releases during version resolution; create, upload to, and delete releases during publish and cleanup.
Pull requests Write Read pull-request files and labels; add process and release comments to pull requests.
Metadata Read Read repository description, topics, and URL while building the module manifest. This permission is granted automatically to GitHub Apps.

Do not grant Shelly Actions, Issues, Statuses, Pages, Workflows, or administration permissions for the current Process-PSModule GitHub App path. Those permissions are not used by installation tokens minted here.

The caller workflow's permissions: block is separate: it scopes only github.token for non-App operations such as artifact handling, linting, and Pages deployment. It cannot expand or restrict Shelly's installation token.

Per-workflow token scope#

Each job mints its own token with the repository that triggered the workflow: ${{ github.event.repository.name }}.

Workflow Requested repository permissions GitHub operations
Plan contents: read, pull-requests: write Read repository settings and version data, inspect pull-request files and labels, and write planning comments or labels.
Build-Module metadata: read Read repository metadata while building the module manifest.
Publish-Module contents: write, pull-requests: write Create and upload releases, write pull-request comments, and clean up prereleases.

The GitHub App installation must grant the permissions requested by each job. Keep the installation and token scope limited to the repository set required by the workflow; add broader repository access only when a workflow explicitly needs cross-repository operations.

The scopes have separate ceilings:

  • permissions: on the caller workflow controls the default github.token; it does not expand an App installation token.
  • The App installation permissions are the maximum permissions any token from that installation can receive.
  • The repositories input limits the repositories available to the minted token.
  • Each permission-<scope> input requests only the subset needed by that job.

Token injection#

Use the latest released version of the token action, resolved to its full immutable commit SHA. Record the exact release tag in the trailing comment. The token action exposes its output only to the steps that need GitHub API access:

- name: Create GitHub App token
  id: App-Token
  uses: actions/create-github-app-token@<sha> # vx.y.z
  with:
    client-id: ${{ secrets.GitHubAppClientId }}
    private-key: ${{ secrets.GitHubAppPrivateKey }}
    repositories: ${{ github.event.repository.name }}
    permission-metadata: read

- name: Use the token
  env:
    GH_TOKEN: ${{ steps.App-Token.outputs.token }}
  run: gh repo view

Process-PSModule does not set this token as a job-wide environment variable. It injects GH_TOKEN on the Get-Settings and Resolve-Version steps in Plan, the Build-PSModule step in Build-Module, and the Publish-PSModule and cleanup steps in Publish-Module. Keep GitHub App tokens step-scoped when adding new API calls.