diff --git a/src/docs/Modules/Process-PSModule/build-test-pack-publish.md b/src/docs/Modules/Process-PSModule/build-test-pack-publish.md index 9b499cd..dfa4f56 100644 --- a/src/docs/Modules/Process-PSModule/build-test-pack-publish.md +++ b/src/docs/Modules/Process-PSModule/build-test-pack-publish.md @@ -18,4 +18,8 @@ Version progression is label-driven in pull requests and resolved in the plan st Test and lint stages run before publish gates, and publish is blocked when required checks fail. +## GitHub API authentication + +GitHub API interactions in Process-PSModule workflows use GitHub App installation tokens (not `github.token`). For the full permission and scoping model, see [GitHub App Authentication](github-app-authentication.md). + For complete cross-org release capability docs, use [MSX Capabilities](https://msxorg.github.io/docs/Capabilities/). diff --git a/src/docs/Modules/Process-PSModule/github-app-authentication.md b/src/docs/Modules/Process-PSModule/github-app-authentication.md new file mode 100644 index 0000000..e0f1427 --- /dev/null +++ b/src/docs/Modules/Process-PSModule/github-app-authentication.md @@ -0,0 +1,86 @@ +# GitHub App Authentication + +Process-PSModule uses GitHub App installation tokens for GitHub API operations in the pipeline instead of `github.token`. + +## Secret contract at reusable workflow boundary + +The root reusable workflow (`workflow.yml`) requires two caller-provided secrets: + +- `GitHubAppClientId`: GitHub App Client ID (identifier, not a secret) +- `GitHubAppPrivateKey`: GitHub App RSA private key (sensitive) + +Callers map their repository or organization secret names into this contract: + +```yaml +secrets: + GitHubAppClientId: ${{ secrets.PSMODULE_CLIENT_ID }} + GitHubAppPrivateKey: ${{ secrets.PSMODULE_PRIVATE_KEY }} +``` + +## Token minting model + +Each workflow that needs GitHub API access mints its own short-lived installation token with a pinned action: + +```yaml +- uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 +``` + +### Plan.yml (settings, version resolution, PR labels) + +```yaml +- uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 + with: + app-id: ${{ secrets.GitHubAppClientId }} + private-key: ${{ secrets.GitHubAppPrivateKey }} + repositories: ${{ github.event.repository.name }} + permission-contents: read + permission-pull-requests: write +``` + +### Publish-Module.yml (release creation, artifacts, PR comments, prerelease cleanup) + +```yaml +- uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 + with: + app-id: ${{ secrets.GitHubAppClientId }} + private-key: ${{ secrets.GitHubAppPrivateKey }} + repositories: ${{ github.event.repository.name }} + permission-contents: write + permission-pull-requests: write +``` + +### Build-Module.yml (repository metadata for module manifest) + +```yaml +- uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 + with: + app-id: ${{ secrets.GitHubAppClientId }} + private-key: ${{ secrets.GitHubAppPrivateKey }} + repositories: ${{ github.event.repository.name }} + # no permission-* inputs required here + # gh repo view relies on metadata: read (auto-granted to GitHub Apps) +``` + +## Token injection pattern + +Inject the minted token as `GH_TOKEN` only on steps that call GitHub APIs (for example, `gh` CLI steps). Do not set it job-wide unless every step requires GitHub API access. + +## Why GitHub App tokens are used + +- identity is app-scoped, not tied to an individual user +- pipeline automation can write where `github.token` is constrained in reusable-workflow fork scenarios +- each token mint is repository-scoped and permission-scoped +- effective permission ceiling is enforced at app installation level + +Required installation permissions for Process-PSModule use cases: + +- `contents: write` +- `pull-requests: write` +- `metadata: read` (auto-granted) + +## Permission model distinctions + +1. **Workflow `permissions:` block** controls only `github.token`; it does not change GitHub App installation tokens. +2. **GitHub App installation permissions** are the hard ceiling for any token minted by that app. +3. **`repositories:` input** scopes token reach. Default to `${{ github.event.repository.name }}` unless cross-repo access is intentionally required. +4. **`permission-:` inputs** request a per-token subset of installation permissions; request only the minimum needed by that workflow. diff --git a/src/docs/Modules/Process-PSModule/index.md b/src/docs/Modules/Process-PSModule/index.md index 3194648..c079e30 100644 --- a/src/docs/Modules/Process-PSModule/index.md +++ b/src/docs/Modules/Process-PSModule/index.md @@ -9,6 +9,7 @@ This section documents how module repositories are formed and how they move from - [Repository Structure](repository-structure.md) - [Module Anatomy](module-anatomy.md) - [Build, Test, Pack, Publish](build-test-pack-publish.md) +- [GitHub App Authentication](github-app-authentication.md) - [Template Quickstart](template-quickstart.md) For broader framework context, see [MSX Frameworks / Process-PSModule](https://msxorg.github.io/docs/Frameworks/Process-PSModule/). diff --git a/src/zensical.toml b/src/zensical.toml index 5990c31..b98fea1 100644 --- a/src/zensical.toml +++ b/src/zensical.toml @@ -32,6 +32,7 @@ nav = [ {"Repository Structure" = "Modules/Process-PSModule/repository-structure.md"}, {"Module Anatomy" = "Modules/Process-PSModule/module-anatomy.md"}, {"Build, Test, Pack, Publish" = "Modules/Process-PSModule/build-test-pack-publish.md"}, + {"GitHub App Authentication" = "Modules/Process-PSModule/github-app-authentication.md"}, {"Template Quickstart" = "Modules/Process-PSModule/template-quickstart.md"}, ]}, ]},