diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml index 4110266d..92aacaf6 100644 --- a/.github/linters/.markdown-lint.yml +++ b/.github/linters/.markdown-lint.yml @@ -12,7 +12,7 @@ MD004: false # Unordered list style MD007: indent: 2 # Unordered list indentation MD013: - line_length: 3000 # Line length +line_length: 3000 # Line length MD025: false # Allow front-matter title + visible H1 on docs pages MD026: punctuation: '.,;:!。,;:' # List of not allowed diff --git a/.github/workflows/Build-Module.yml b/.github/workflows/Build-Module.yml index 37af18f3..1924f2a3 100644 --- a/.github/workflows/Build-Module.yml +++ b/.github/workflows/Build-Module.yml @@ -48,6 +48,7 @@ jobs: app-id: ${{ secrets.GitHubAppClientId }} private-key: ${{ secrets.GitHubAppPrivateKey }} repositories: ${{ github.event.repository.name }} + permission-metadata: read - name: Build module uses: ./_wf/.github/actions/Build-PSModule diff --git a/README.md b/README.md index 128c37ba..385bafef 100644 --- a/README.md +++ b/README.md @@ -31,3 +31,5 @@ jobs: ``` This is a required contract for GitHub operations in the reusable workflow path; a GitHub App installation token is minted and used for those steps via `GH_TOKEN`, and `github.token` fallback is intentionally not used. + +See the [GitHub App authentication guide](https://psmodule.io/docs/guides/github-app-authentication/) for the caller mapping, per-workflow permissions and repository scoping, and token injection details. diff --git a/docs/content/guides/github-app-authentication.md b/docs/content/guides/github-app-authentication.md new file mode 100644 index 00000000..e600e6aa --- /dev/null +++ b/docs/content/guides/github-app-authentication.md @@ -0,0 +1,81 @@ +--- +title: GitHub App authentication +description: Configure the GitHub App secrets and understand token scope and injection in Process-PSModule workflows. +--- + +# 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: + +```yaml +jobs: + Process-PSModule: + uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5 + secrets: + APIKey: ${{ secrets.APIKey }} + 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. + +## 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-` input requests only the subset needed by that job. + +## Token injection + +The token action is pinned and exposes its output only to the steps that need GitHub API access: + +```yaml +- name: Create GitHub App token + id: App-Token + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2 + with: + app-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.