From 69a8a7c7d174ef5edd538025d0e20eeeeff39877 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 20:52:47 +0200 Subject: [PATCH 01/10] Add generic GitHub App secret mapping Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/Workflow-Test-Default.yml | 2 ++ .github/workflows/Workflow-Test-WithManifest.yml | 2 ++ .github/workflows/workflow.yml | 11 +++++++++++ 3 files changed, 15 insertions(+) diff --git a/.github/workflows/Workflow-Test-Default.yml b/.github/workflows/Workflow-Test-Default.yml index 511b4b1c..c7ebccf1 100644 --- a/.github/workflows/Workflow-Test-Default.yml +++ b/.github/workflows/Workflow-Test-Default.yml @@ -30,6 +30,8 @@ jobs: uses: ./.github/workflows/workflow.yml secrets: APIKey: ${{ secrets.APIKey }} + GitHubAppClientId: ${{ secrets.PSMODULE_CLIENT_ID }} + GitHubAppPrivateKey: ${{ secrets.PSMODULE_PRIVATE_KEY }} TestData: >- { "secrets": { diff --git a/.github/workflows/Workflow-Test-WithManifest.yml b/.github/workflows/Workflow-Test-WithManifest.yml index 82f80f55..ad048a79 100644 --- a/.github/workflows/Workflow-Test-WithManifest.yml +++ b/.github/workflows/Workflow-Test-WithManifest.yml @@ -30,6 +30,8 @@ jobs: uses: ./.github/workflows/workflow.yml secrets: APIKey: ${{ secrets.APIKey }} + GitHubAppClientId: ${{ secrets.PSMODULE_CLIENT_ID }} + GitHubAppPrivateKey: ${{ secrets.PSMODULE_PRIVATE_KEY }} TestData: >- { "secrets": { diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 099afc34..789bef75 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -6,6 +6,12 @@ on: APIKey: description: The API key for the PowerShell Gallery. required: true + GitHubAppClientId: + description: Generic GitHub App client ID secret for caller mapping. + required: true + GitHubAppPrivateKey: + description: Generic GitHub App private key secret for caller mapping. + required: true TestData: description: | Optional single-line JSON object carrying all data the module test jobs @@ -77,6 +83,9 @@ jobs: # - ✅ Manual run - Always runs to load configuration Plan: uses: ./.github/workflows/Plan.yml + secrets: + GitHubAppClientId: ${{ secrets.GitHubAppClientId }} + GitHubAppPrivateKey: ${{ secrets.GitHubAppPrivateKey }} with: SettingsPath: ${{ inputs.SettingsPath }} Debug: ${{ inputs.Debug }} @@ -246,6 +255,8 @@ jobs: uses: ./.github/workflows/Publish-Module.yml secrets: APIKey: ${{ secrets.APIKey }} + GitHubAppClientId: ${{ secrets.GitHubAppClientId }} + GitHubAppPrivateKey: ${{ secrets.GitHubAppPrivateKey }} needs: - Plan - Get-TestResults From ac2caa122b3fa6d75c978cfa1f0d98c2041a7b7e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 20:52:49 +0200 Subject: [PATCH 02/10] Document reusable GitHub App secrets Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index db35db76..1230fb72 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,21 @@ The full documentation lives on the MSX / Docs site: 📖 **[Process-PSModule documentation](https://msxorg.github.io/docs/Frameworks/Process-PSModule/)** It covers getting started, the pipeline stages, usage, configuration, repository structure, and the principles behind the framework. + +## Reusable workflow secrets (GitHub App auth) + +When calling `./.github/workflows/workflow.yml`, pass GitHub App credentials using these generic reusable-workflow secret names: + +- `GitHubAppClientId` +- `GitHubAppPrivateKey` + +Consumer repositories can keep their own secret names and map them in the caller workflow, for example: + +```yaml +jobs: + ProcessPSModule: + uses: ./.github/workflows/workflow.yml + secrets: + GitHubAppClientId: ${{ secrets.PSMODULE_CLIENT_ID }} + GitHubAppPrivateKey: ${{ secrets.PSMODULE_PRIVATE_KEY }} +``` From b5cbfe31b06fdb4d66b9442825c82b448744bc67 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 20:53:05 +0200 Subject: [PATCH 03/10] Use GitHub App token in Plan workflow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/Plan.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/Plan.yml b/.github/workflows/Plan.yml index 3fad50eb..65e6e48c 100644 --- a/.github/workflows/Plan.yml +++ b/.github/workflows/Plan.yml @@ -9,6 +9,13 @@ name: Plan on: workflow_call: + secrets: + GitHubAppClientId: + description: The client ID of the GitHub App used for repository API calls. + required: true + GitHubAppPrivateKey: + description: The private key of the GitHub App used for repository API calls. + required: true inputs: SettingsPath: type: string @@ -80,9 +87,19 @@ jobs: path: _wf persist-credentials: false + - 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 }} + - name: Get-Settings uses: ./_wf/.github/actions/Get-PSModuleSettings id: Get-Settings + env: + GH_TOKEN: ${{ steps.App-Token.outputs.token }} + GITHUB_TOKEN: ${{ steps.App-Token.outputs.token }} with: SettingsPath: ${{ inputs.SettingsPath }} Debug: ${{ inputs.Debug }} @@ -96,7 +113,8 @@ jobs: uses: ./_wf/.github/actions/Resolve-PSModuleVersion id: Resolve-Version env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.App-Token.outputs.token }} + GITHUB_TOKEN: ${{ steps.App-Token.outputs.token }} with: Settings: ${{ steps.Get-Settings.outputs.Settings }} Name: ${{ fromJson(steps.Get-Settings.outputs.Settings).Name }} From eec3b8440393cdd7a2fa50a004a997fc3953dfbc Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 20:53:07 +0200 Subject: [PATCH 04/10] Use GitHub App token in publish workflow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/Publish-Module.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Publish-Module.yml b/.github/workflows/Publish-Module.yml index ee1bbcb6..81d02fe7 100644 --- a/.github/workflows/Publish-Module.yml +++ b/.github/workflows/Publish-Module.yml @@ -6,6 +6,12 @@ on: APIKey: description: The API key for the PowerShell Gallery. required: true + GitHubAppClientId: + description: The client ID of the GitHub App used for repository API calls. + required: true + GitHubAppPrivateKey: + description: The private key of the GitHub App used for repository API calls. + required: true inputs: Settings: type: string @@ -37,11 +43,19 @@ jobs: path: _wf persist-credentials: false + - 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 }} + - name: Publish module if: fromJson(inputs.Settings).Publish.Module.Resolution.ReleaseType != 'None' uses: ./_wf/.github/actions/Publish-PSModule env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.App-Token.outputs.token }} + GITHUB_TOKEN: ${{ steps.App-Token.outputs.token }} with: Name: ${{ fromJson(inputs.Settings).Name }} ModulePath: outputs/module @@ -56,7 +70,8 @@ jobs: if: fromJson(inputs.Settings).Publish.Module.Resolution.ReleaseType != 'Prerelease' uses: ./_wf/.github/actions/Cleanup-PSModulePrereleases env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.App-Token.outputs.token }} + GITHUB_TOKEN: ${{ steps.App-Token.outputs.token }} with: WhatIf: ${{ github.repository == 'PSModule/Process-PSModule' }} AutoCleanup: ${{ fromJson(inputs.Settings).Publish.Module.AutoCleanup }} From 4b47a32dcb4ed934511a5bf9b0843c81b0717c9a Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 20:53:08 +0200 Subject: [PATCH 05/10] Adjust action token env precedence Prefer caller-provided GH_TOKEN/GITHUB_TOKEN for GitHub API/CLI calls while keeping github.token fallback for compatibility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/actions/Cleanup-PSModulePrereleases/action.yml | 2 ++ .github/actions/Get-PSModuleSettings/action.yml | 2 ++ .github/actions/Publish-PSModule/action.yml | 2 ++ .github/actions/Resolve-PSModuleVersion/action.yml | 3 ++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/actions/Cleanup-PSModulePrereleases/action.yml b/.github/actions/Cleanup-PSModulePrereleases/action.yml index 3c076b45..cf6b97c4 100644 --- a/.github/actions/Cleanup-PSModulePrereleases/action.yml +++ b/.github/actions/Cleanup-PSModulePrereleases/action.yml @@ -27,6 +27,8 @@ runs: shell: pwsh working-directory: ${{ inputs.WorkingDirectory }} env: + GH_TOKEN: ${{ env.GH_TOKEN || env.GITHUB_TOKEN || github.token }} + GITHUB_TOKEN: ${{ env.GITHUB_TOKEN || env.GH_TOKEN || github.token }} PSMODULE_CLEANUP_PSMODULEPRERELEASES_INPUT_WhatIf: ${{ inputs.WhatIf }} PSMODULE_CLEANUP_PSMODULEPRERELEASES_CONTEXT_ReleaseTag: ${{ env.PSMODULE_PUBLISH_PSMODULE_CONTEXT_ReleaseTag }} run: ${{ github.action_path }}/src/cleanup.ps1 diff --git a/.github/actions/Get-PSModuleSettings/action.yml b/.github/actions/Get-PSModuleSettings/action.yml index 86a49b3a..3597f8fe 100644 --- a/.github/actions/Get-PSModuleSettings/action.yml +++ b/.github/actions/Get-PSModuleSettings/action.yml @@ -53,6 +53,8 @@ runs: uses: PSModule/GitHub-Script@8083ec1f733f00357ee4d0db0c6056686e483bc0 # v1.9.0 id: Get-PSModuleSettings env: + GH_TOKEN: ${{ env.GH_TOKEN || env.GITHUB_TOKEN || github.token }} + GITHUB_TOKEN: ${{ env.GITHUB_TOKEN || env.GH_TOKEN || github.token }} PSMODULE_GET_SETTINGS_INPUT_Name: ${{ inputs.Name }} PSMODULE_GET_SETTINGS_INPUT_SettingsPath: ${{ inputs.SettingsPath }} PSMODULE_GET_SETTINGS_INPUT_Debug: ${{ inputs.Debug }} diff --git a/.github/actions/Publish-PSModule/action.yml b/.github/actions/Publish-PSModule/action.yml index 0ff0a534..1e7ffd0d 100644 --- a/.github/actions/Publish-PSModule/action.yml +++ b/.github/actions/Publish-PSModule/action.yml @@ -58,6 +58,8 @@ runs: shell: pwsh working-directory: ${{ inputs.WorkingDirectory }} env: + GH_TOKEN: ${{ env.GH_TOKEN || env.GITHUB_TOKEN || github.token }} + GITHUB_TOKEN: ${{ env.GITHUB_TOKEN || env.GH_TOKEN || github.token }} PSMODULE_PUBLISH_PSMODULE_INPUT_Name: ${{ inputs.Name }} PSMODULE_PUBLISH_PSMODULE_INPUT_ModulePath: ${{ inputs.ModulePath }} PSMODULE_PUBLISH_PSMODULE_INPUT_APIKey: ${{ inputs.APIKey }} diff --git a/.github/actions/Resolve-PSModuleVersion/action.yml b/.github/actions/Resolve-PSModuleVersion/action.yml index 20b41883..c3a399c4 100644 --- a/.github/actions/Resolve-PSModuleVersion/action.yml +++ b/.github/actions/Resolve-PSModuleVersion/action.yml @@ -65,7 +65,8 @@ runs: shell: pwsh working-directory: ${{ inputs.WorkingDirectory }} env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ env.GH_TOKEN || env.GITHUB_TOKEN || github.token }} + GITHUB_TOKEN: ${{ env.GITHUB_TOKEN || env.GH_TOKEN || github.token }} PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_Settings: ${{ inputs.Settings }} PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_Name: ${{ inputs.Name }} PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_EventJson: ${{ inputs.EventJson }} From a339e4dd615283aaabf2cf6f8d00ba1d83893c08 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 20:52:34 +0200 Subject: [PATCH 06/10] Prefer app token in Get-PSModuleSettings Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/actions/Get-PSModuleSettings/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/Get-PSModuleSettings/action.yml b/.github/actions/Get-PSModuleSettings/action.yml index 3597f8fe..208a4b00 100644 --- a/.github/actions/Get-PSModuleSettings/action.yml +++ b/.github/actions/Get-PSModuleSettings/action.yml @@ -65,6 +65,8 @@ runs: PSMODULE_GET_SETTINGS_INPUT_ImportantFilePatterns: ${{ inputs.ImportantFilePatterns }} with: Name: Get-PSModuleSettings + # Prefer a caller-provided GitHub App token when available. + Token: ${{ env.PSMODULE_GITHUB_APP_TOKEN || env.GITHUB_APP_TOKEN || env.GH_APP_TOKEN || env.GH_TOKEN || github.token }} ShowInfo: false ShowOutput: true Debug: ${{ inputs.Debug }} From f7ded053debd13d329c6094dfe3461027769c3fd Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 21:07:38 +0200 Subject: [PATCH 07/10] Make GitHub App token wiring strict Remove github.token fallbacks from GitHub-facing composite actions so reusable workflow paths require explicit app-token env wiring. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/actions/Cleanup-PSModulePrereleases/action.yml | 4 ++-- .github/actions/Get-PSModuleSettings/action.yml | 7 +++---- .github/actions/Publish-PSModule/action.yml | 4 ++-- .github/actions/Resolve-PSModuleVersion/action.yml | 4 ++-- README.md | 2 ++ 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/actions/Cleanup-PSModulePrereleases/action.yml b/.github/actions/Cleanup-PSModulePrereleases/action.yml index cf6b97c4..2e46f71e 100644 --- a/.github/actions/Cleanup-PSModulePrereleases/action.yml +++ b/.github/actions/Cleanup-PSModulePrereleases/action.yml @@ -27,8 +27,8 @@ runs: shell: pwsh working-directory: ${{ inputs.WorkingDirectory }} env: - GH_TOKEN: ${{ env.GH_TOKEN || env.GITHUB_TOKEN || github.token }} - GITHUB_TOKEN: ${{ env.GITHUB_TOKEN || env.GH_TOKEN || github.token }} + GH_TOKEN: ${{ env.GH_TOKEN }} + GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} PSMODULE_CLEANUP_PSMODULEPRERELEASES_INPUT_WhatIf: ${{ inputs.WhatIf }} PSMODULE_CLEANUP_PSMODULEPRERELEASES_CONTEXT_ReleaseTag: ${{ env.PSMODULE_PUBLISH_PSMODULE_CONTEXT_ReleaseTag }} run: ${{ github.action_path }}/src/cleanup.ps1 diff --git a/.github/actions/Get-PSModuleSettings/action.yml b/.github/actions/Get-PSModuleSettings/action.yml index 208a4b00..70e2e703 100644 --- a/.github/actions/Get-PSModuleSettings/action.yml +++ b/.github/actions/Get-PSModuleSettings/action.yml @@ -53,8 +53,8 @@ runs: uses: PSModule/GitHub-Script@8083ec1f733f00357ee4d0db0c6056686e483bc0 # v1.9.0 id: Get-PSModuleSettings env: - GH_TOKEN: ${{ env.GH_TOKEN || env.GITHUB_TOKEN || github.token }} - GITHUB_TOKEN: ${{ env.GITHUB_TOKEN || env.GH_TOKEN || github.token }} + GH_TOKEN: ${{ env.GH_TOKEN }} + GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} PSMODULE_GET_SETTINGS_INPUT_Name: ${{ inputs.Name }} PSMODULE_GET_SETTINGS_INPUT_SettingsPath: ${{ inputs.SettingsPath }} PSMODULE_GET_SETTINGS_INPUT_Debug: ${{ inputs.Debug }} @@ -65,8 +65,7 @@ runs: PSMODULE_GET_SETTINGS_INPUT_ImportantFilePatterns: ${{ inputs.ImportantFilePatterns }} with: Name: Get-PSModuleSettings - # Prefer a caller-provided GitHub App token when available. - Token: ${{ env.PSMODULE_GITHUB_APP_TOKEN || env.GITHUB_APP_TOKEN || env.GH_APP_TOKEN || env.GH_TOKEN || github.token }} + Token: ${{ env.GITHUB_TOKEN }} ShowInfo: false ShowOutput: true Debug: ${{ inputs.Debug }} diff --git a/.github/actions/Publish-PSModule/action.yml b/.github/actions/Publish-PSModule/action.yml index 1e7ffd0d..18b1811d 100644 --- a/.github/actions/Publish-PSModule/action.yml +++ b/.github/actions/Publish-PSModule/action.yml @@ -58,8 +58,8 @@ runs: shell: pwsh working-directory: ${{ inputs.WorkingDirectory }} env: - GH_TOKEN: ${{ env.GH_TOKEN || env.GITHUB_TOKEN || github.token }} - GITHUB_TOKEN: ${{ env.GITHUB_TOKEN || env.GH_TOKEN || github.token }} + GH_TOKEN: ${{ env.GH_TOKEN }} + GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} PSMODULE_PUBLISH_PSMODULE_INPUT_Name: ${{ inputs.Name }} PSMODULE_PUBLISH_PSMODULE_INPUT_ModulePath: ${{ inputs.ModulePath }} PSMODULE_PUBLISH_PSMODULE_INPUT_APIKey: ${{ inputs.APIKey }} diff --git a/.github/actions/Resolve-PSModuleVersion/action.yml b/.github/actions/Resolve-PSModuleVersion/action.yml index c3a399c4..072f2d47 100644 --- a/.github/actions/Resolve-PSModuleVersion/action.yml +++ b/.github/actions/Resolve-PSModuleVersion/action.yml @@ -65,8 +65,8 @@ runs: shell: pwsh working-directory: ${{ inputs.WorkingDirectory }} env: - GH_TOKEN: ${{ env.GH_TOKEN || env.GITHUB_TOKEN || github.token }} - GITHUB_TOKEN: ${{ env.GITHUB_TOKEN || env.GH_TOKEN || github.token }} + GH_TOKEN: ${{ env.GH_TOKEN }} + GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_Settings: ${{ inputs.Settings }} PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_Name: ${{ inputs.Name }} PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_EventJson: ${{ inputs.EventJson }} diff --git a/README.md b/README.md index 1230fb72..052b35b1 100644 --- a/README.md +++ b/README.md @@ -29,3 +29,5 @@ jobs: GitHubAppClientId: ${{ secrets.PSMODULE_CLIENT_ID }} GitHubAppPrivateKey: ${{ secrets.PSMODULE_PRIVATE_KEY }} ``` + +This is a required contract for GitHub operations in the reusable workflow path; `github.token` fallback is intentionally not used. From 83568fb790c9f1e6e11c42f3ccb84962ea08bdd0 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 21:12:48 +0200 Subject: [PATCH 08/10] Use only GH_TOKEN for app-auth steps For GitHub App-enabled workflow/action paths, remove dual-token env usage and keep explicit GH_TOKEN-only wiring with no github.token fallback. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/actions/Cleanup-PSModulePrereleases/action.yml | 1 - .github/actions/Get-PSModuleSettings/action.yml | 3 +-- .github/actions/Publish-PSModule/action.yml | 1 - .github/actions/Resolve-PSModuleVersion/action.yml | 1 - .github/workflows/Plan.yml | 2 -- .github/workflows/Publish-Module.yml | 2 -- README.md | 2 +- 7 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/actions/Cleanup-PSModulePrereleases/action.yml b/.github/actions/Cleanup-PSModulePrereleases/action.yml index 2e46f71e..5bba40c0 100644 --- a/.github/actions/Cleanup-PSModulePrereleases/action.yml +++ b/.github/actions/Cleanup-PSModulePrereleases/action.yml @@ -28,7 +28,6 @@ runs: working-directory: ${{ inputs.WorkingDirectory }} env: GH_TOKEN: ${{ env.GH_TOKEN }} - GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} PSMODULE_CLEANUP_PSMODULEPRERELEASES_INPUT_WhatIf: ${{ inputs.WhatIf }} PSMODULE_CLEANUP_PSMODULEPRERELEASES_CONTEXT_ReleaseTag: ${{ env.PSMODULE_PUBLISH_PSMODULE_CONTEXT_ReleaseTag }} run: ${{ github.action_path }}/src/cleanup.ps1 diff --git a/.github/actions/Get-PSModuleSettings/action.yml b/.github/actions/Get-PSModuleSettings/action.yml index 70e2e703..1a209701 100644 --- a/.github/actions/Get-PSModuleSettings/action.yml +++ b/.github/actions/Get-PSModuleSettings/action.yml @@ -54,7 +54,6 @@ runs: id: Get-PSModuleSettings env: GH_TOKEN: ${{ env.GH_TOKEN }} - GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} PSMODULE_GET_SETTINGS_INPUT_Name: ${{ inputs.Name }} PSMODULE_GET_SETTINGS_INPUT_SettingsPath: ${{ inputs.SettingsPath }} PSMODULE_GET_SETTINGS_INPUT_Debug: ${{ inputs.Debug }} @@ -65,7 +64,7 @@ runs: PSMODULE_GET_SETTINGS_INPUT_ImportantFilePatterns: ${{ inputs.ImportantFilePatterns }} with: Name: Get-PSModuleSettings - Token: ${{ env.GITHUB_TOKEN }} + Token: ${{ env.GH_TOKEN }} ShowInfo: false ShowOutput: true Debug: ${{ inputs.Debug }} diff --git a/.github/actions/Publish-PSModule/action.yml b/.github/actions/Publish-PSModule/action.yml index 18b1811d..badd74b8 100644 --- a/.github/actions/Publish-PSModule/action.yml +++ b/.github/actions/Publish-PSModule/action.yml @@ -59,7 +59,6 @@ runs: working-directory: ${{ inputs.WorkingDirectory }} env: GH_TOKEN: ${{ env.GH_TOKEN }} - GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} PSMODULE_PUBLISH_PSMODULE_INPUT_Name: ${{ inputs.Name }} PSMODULE_PUBLISH_PSMODULE_INPUT_ModulePath: ${{ inputs.ModulePath }} PSMODULE_PUBLISH_PSMODULE_INPUT_APIKey: ${{ inputs.APIKey }} diff --git a/.github/actions/Resolve-PSModuleVersion/action.yml b/.github/actions/Resolve-PSModuleVersion/action.yml index 072f2d47..5192f28f 100644 --- a/.github/actions/Resolve-PSModuleVersion/action.yml +++ b/.github/actions/Resolve-PSModuleVersion/action.yml @@ -66,7 +66,6 @@ runs: working-directory: ${{ inputs.WorkingDirectory }} env: GH_TOKEN: ${{ env.GH_TOKEN }} - GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_Settings: ${{ inputs.Settings }} PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_Name: ${{ inputs.Name }} PSMODULE_RESOLVE_PSMODULEVERSION_INPUT_EventJson: ${{ inputs.EventJson }} diff --git a/.github/workflows/Plan.yml b/.github/workflows/Plan.yml index 65e6e48c..19a0d866 100644 --- a/.github/workflows/Plan.yml +++ b/.github/workflows/Plan.yml @@ -99,7 +99,6 @@ jobs: id: Get-Settings env: GH_TOKEN: ${{ steps.App-Token.outputs.token }} - GITHUB_TOKEN: ${{ steps.App-Token.outputs.token }} with: SettingsPath: ${{ inputs.SettingsPath }} Debug: ${{ inputs.Debug }} @@ -114,7 +113,6 @@ jobs: id: Resolve-Version env: GH_TOKEN: ${{ steps.App-Token.outputs.token }} - GITHUB_TOKEN: ${{ steps.App-Token.outputs.token }} with: Settings: ${{ steps.Get-Settings.outputs.Settings }} Name: ${{ fromJson(steps.Get-Settings.outputs.Settings).Name }} diff --git a/.github/workflows/Publish-Module.yml b/.github/workflows/Publish-Module.yml index 81d02fe7..3b54e6b6 100644 --- a/.github/workflows/Publish-Module.yml +++ b/.github/workflows/Publish-Module.yml @@ -55,7 +55,6 @@ jobs: uses: ./_wf/.github/actions/Publish-PSModule env: GH_TOKEN: ${{ steps.App-Token.outputs.token }} - GITHUB_TOKEN: ${{ steps.App-Token.outputs.token }} with: Name: ${{ fromJson(inputs.Settings).Name }} ModulePath: outputs/module @@ -71,7 +70,6 @@ jobs: uses: ./_wf/.github/actions/Cleanup-PSModulePrereleases env: GH_TOKEN: ${{ steps.App-Token.outputs.token }} - GITHUB_TOKEN: ${{ steps.App-Token.outputs.token }} with: WhatIf: ${{ github.repository == 'PSModule/Process-PSModule' }} AutoCleanup: ${{ fromJson(inputs.Settings).Publish.Module.AutoCleanup }} diff --git a/README.md b/README.md index 052b35b1..2773f83d 100644 --- a/README.md +++ b/README.md @@ -30,4 +30,4 @@ jobs: GitHubAppPrivateKey: ${{ secrets.PSMODULE_PRIVATE_KEY }} ``` -This is a required contract for GitHub operations in the reusable workflow path; `github.token` fallback is intentionally not used. +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. From 3b4410a3f6b6a5fdd7c5d1c812a0125f091f22ba Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 21:19:24 +0200 Subject: [PATCH 09/10] Use GitHub App token in Build-Module workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mint an installation token in Build-Module.yml (same pinned actions/create-github-app-token@fee1f7d... as Plan and Publish-Module) and inject it as GH_TOKEN on the Build-PSModule step. This covers the three gh repo view calls in Build-PSModuleManifest.ps1 that read repo description, topics, and URL — all of which go through the gh CLI and therefore consume GH_TOKEN. The job-level GH_TOKEN: github.token fallback is removed. workflow.yml is updated to pass the GitHubAppClientId and GitHubAppPrivateKey secrets into the Build-Module reusable workflow. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/Build-Module.yml | 18 ++++++++++++++++-- .github/workflows/workflow.yml | 3 +++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Build-Module.yml b/.github/workflows/Build-Module.yml index 411d7ed6..e8e77495 100644 --- a/.github/workflows/Build-Module.yml +++ b/.github/workflows/Build-Module.yml @@ -2,6 +2,13 @@ name: Build-Module on: workflow_call: + secrets: + GitHubAppClientId: + description: The client ID of the GitHub App used for repository API calls. + required: true + GitHubAppPrivateKey: + description: The private key of the GitHub App used for repository API calls. + required: true inputs: Settings: type: string @@ -20,8 +27,6 @@ jobs: Build-Module: name: Build-Module runs-on: ubuntu-latest - env: - GH_TOKEN: ${{ github.token }} steps: - name: Checkout Code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -37,8 +42,17 @@ jobs: path: _wf persist-credentials: false + - 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 }} + - name: Build module uses: ./_wf/.github/actions/Build-PSModule + env: + GH_TOKEN: ${{ steps.App-Token.outputs.token }} with: Name: ${{ fromJson(inputs.Settings).Name }} Version: ${{ fromJson(inputs.Settings).Publish.Module.Resolution.Version != '' && fromJson(inputs.Settings).Publish.Module.Resolution.Version || '999.0.0' }} diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 789bef75..4cea1a27 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -116,6 +116,9 @@ jobs: Build-Module: if: fromJson(needs.Plan.outputs.Settings).Build.Module.Enabled uses: ./.github/workflows/Build-Module.yml + secrets: + GitHubAppClientId: ${{ secrets.GitHubAppClientId }} + GitHubAppPrivateKey: ${{ secrets.GitHubAppPrivateKey }} needs: - Plan with: From 61be8788130af699d70e3cacb6f51e62746f6adb Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 23 Jul 2026 21:55:00 +0200 Subject: [PATCH 10/10] Scope GitHub App tokens to repo and minimum permissions Each token-minting step now requests only the permissions the job actually exercises and restricts the token to the current repository. Plan: repositories: current repo permission-contents: read (gh release list in Resolve-Version) permission-pull-requests: write (label/comment via Get-PSModuleSettings) Publish-Module: repositories: current repo permission-contents: write (gh release create/upload/delete) permission-pull-requests: write (gh pr comment) Build-Module: repositories: current repo (no permission-* needed - only gh repo view which uses metadata:read, auto-granted to all GitHub App installations) This limits blast radius: even if a compromised step obtained GH_TOKEN, it could only act on the one repository and only with the declared permission level, not on every repo in the installation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/Build-Module.yml | 1 + .github/workflows/Plan.yml | 3 +++ .github/workflows/Publish-Module.yml | 3 +++ 3 files changed, 7 insertions(+) diff --git a/.github/workflows/Build-Module.yml b/.github/workflows/Build-Module.yml index e8e77495..360c2797 100644 --- a/.github/workflows/Build-Module.yml +++ b/.github/workflows/Build-Module.yml @@ -48,6 +48,7 @@ jobs: with: app-id: ${{ secrets.GitHubAppClientId }} private-key: ${{ secrets.GitHubAppPrivateKey }} + repositories: ${{ github.event.repository.name }} - name: Build module uses: ./_wf/.github/actions/Build-PSModule diff --git a/.github/workflows/Plan.yml b/.github/workflows/Plan.yml index 19a0d866..d57300d8 100644 --- a/.github/workflows/Plan.yml +++ b/.github/workflows/Plan.yml @@ -93,6 +93,9 @@ jobs: with: app-id: ${{ secrets.GitHubAppClientId }} private-key: ${{ secrets.GitHubAppPrivateKey }} + repositories: ${{ github.event.repository.name }} + permission-contents: read + permission-pull-requests: write - name: Get-Settings uses: ./_wf/.github/actions/Get-PSModuleSettings diff --git a/.github/workflows/Publish-Module.yml b/.github/workflows/Publish-Module.yml index 3b54e6b6..757e1c9e 100644 --- a/.github/workflows/Publish-Module.yml +++ b/.github/workflows/Publish-Module.yml @@ -49,6 +49,9 @@ jobs: with: app-id: ${{ secrets.GitHubAppClientId }} private-key: ${{ secrets.GitHubAppPrivateKey }} + repositories: ${{ github.event.repository.name }} + permission-contents: write + permission-pull-requests: write - name: Publish module if: fromJson(inputs.Settings).Publish.Module.Resolution.ReleaseType != 'None'