Skip to content

Commit 89d3d9b

Browse files
docs: scope workflow token authority
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 8825edc commit 89d3d9b

2 files changed

Lines changed: 33 additions & 30 deletions

File tree

docs/content/reference/process-workflow-lifecycle-design.md

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The confirmed reusable workflow runs a `Plan` job, enriches one settings object
1515

1616
The version resolver treats non-pull-request events, including `workflow_dispatch` and `schedule`, as events without a release decision. The workflow's concurrency identity contains either the pull request number or the Git ref, and its runs are not canceled. The documented scenario matrix also identifies closed-pull-request cleanup as non-stable behavior.
1717

18-
The current code detects an existing published version, resumes GitHub Release creation, and repeats GitHub Release and tag cleanup. Full reconciliation of immutable PowerShell Gallery prereleases is a design gap: it requires implementation and cancellation-boundary tests. Current reusable jobs create App tokens after checkout, and the Pages workflow declares `pages: write` and `id-token: write`; the permissionless-caller candidate is therefore not confirmed behavior. These facts establish the starting point. They do not implement the scheduled validation or manual recovery behavior proposed below.
18+
The current code detects an existing published version, resumes GitHub Release creation, and repeats GitHub Release and tag cleanup. Full reconciliation of immutable PowerShell Gallery prereleases is a design gap: it requires implementation and cancellation-boundary tests. Current reusable jobs create App tokens after checkout; that sequencing does not satisfy the candidate App-token boundary for user-facing operations. The Pages workflow's `pages: write` and `id-token: write` permissions align with the candidate's standard Pages/OIDC path. These facts establish the starting point. They do not implement the scheduled validation or manual recovery behavior proposed below.
1919

2020
## Candidate event routing
2121

@@ -58,19 +58,25 @@ One general module release action or reusable workflow consumes enriched Setting
5858

5959
## Candidate repository authorization
6060

61-
The caller remains permissionless:
61+
The caller sets no top-level default and grants its Process-PSModule job only the built-in permissions needed for repository-local reads and standard Pages/OIDC deployment:
6262

6363
```yaml
6464
permissions: {}
65+
jobs:
66+
Process-PSModule:
67+
permissions:
68+
contents: read
69+
pages: write
70+
id-token: write
6571
```
6672
67-
It grants no job permissions. Every reusable-workflow job creates a narrowly scoped GitHub App installation token before checkout and passes that token explicitly to checkout. The same explicit App token authorizes `gh` and API requests, linter statuses and comments, releases, and cleanup. Downstream jobs do not rely on built-in `GITHUB_TOKEN` authority.
73+
Built-in `GITHUB_TOKEN` authorization is permitted for checkout, repository-local reads, and standard Pages/OIDC deployment within that job boundary. GitHub App installation tokens are step-scoped and authorize every user-facing interaction and every operation that needs broader reach or permissions: pull-request comments and labels, commit statuses and check-facing reporting, releases, tags, assets, and cleanup.
6874

69-
Each job requests only the App installation permissions required for its operation. A missing App token is an authorization failure: the job stops before checkout or its repository operation, without falling back to the built-in workflow token.
75+
Each App-token step requests only the installation permissions required for its operation. A missing App token is an authorization failure for App-required work: that operation stops before its API request or mutation, without silently falling back to the built-in workflow token. Built-in-token reads and Pages deployment remain available only within the explicit caller job permissions.
7076

71-
## Candidate Pages deployment boundary
77+
## Candidate Pages authorization
7278

73-
The current Pages deployment uses `actions/deploy-pages`, which requires `pages: write` and `id-token: write`. This is a design gap under the permissionless-caller candidate. The implementation must either replace it with an App-authenticated supported deployment path or document an explicit, unavoidable Pages/OIDC exception. It MUST NOT silently grant caller or job `GITHUB_TOKEN` permissions.
79+
The standard `actions/deploy-pages` path uses the built-in token's `pages: write` and `id-token: write` permissions granted only to the caller's Process-PSModule job. It remains inside the candidate's repository-local, non-user-facing boundary and does not require an App token.
7480

7581
## Candidate stable Plan aggregation
7682

@@ -146,9 +152,9 @@ The lifecycle contract is exercised with event payload fixtures and publication
146152
| Pull-request convergence | Canceled prerelease-publication and cleanup fixtures followed by synchronize, label, unlabel, and close events that prove the latest pull-request state is reconciled. |
147153
| Gallery immutability | Deterministic pull-request identity, existing-version detection, supported-unlist, and retained-version fixtures across the cancellation boundary. |
148154
| Stable aggregation | Bursts of main-push, manual-dispatch, and scheduled fixtures that replace an intermediate pending run and prove the later stable target aggregates all unreleased merged pull requests. |
149-
| Permissionless caller | Empty caller permissions and no job grants with explicit App-token checkout, API, status, comment, release, and cleanup verification. |
150-
| Authorization failure | Missing-App-token fixtures that prove each repository job fails closed without built-in token fallback. |
151-
| Pages boundary | A supported App-authenticated deployment-path test or an explicit Pages/OIDC exception test. |
155+
| Scoped caller permissions | Empty caller top-level permissions, the three job grants, built-in-token checkout/read, and standard Pages/OIDC verification. |
156+
| App authorization failure | Missing-App-token fixtures that prove user-facing operations fail closed without built-in token fallback. |
157+
| Token boundary | Fixtures that prove App tokens are step-scoped and built-in-token operations remain within the caller job's boundary. |
152158

153159
## Decisions requiring approval
154160

@@ -159,7 +165,6 @@ The candidate does not decide the following:
159165
- Which consumer-facing checks comprise scheduled published-artifact validation.
160166
- Whether removing prerelease eligibility cleans up existing prereleases immediately or leaves them until the abandoned-close cleanup route.
161167
- Whether the supported Gallery API can unlist obsolete prereleases; otherwise, how retained immutable versions are recorded.
162-
- Whether Pages can use a supported App-authenticated deployment path or requires an explicit Pages/OIDC exception.
163168
- Approval of the selected caller concurrency expression in [PSModule/Process-PSModule#514](https://github.com/PSModule/Process-PSModule/issues/514).
164169

165170
## Related

docs/content/reference/process-workflow-lifecycle-specification.md

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -209,25 +209,24 @@ Scenario: Recover a range of unreleased merged pull requests
209209
And the release notes use that aggregated range
210210
```
211211

212-
### FR11 — Repository operations MUST use explicit GitHub App authorization {#fr11}
212+
### FR11 — Repository operations MUST use scoped authorization {#fr11}
213213

214-
The caller MUST declare top-level `permissions: {}` and MUST NOT grant job permissions. The reusable workflow MUST create narrowly scoped GitHub App installation tokens before repository access and pass them explicitly to every repository operation. Built-in `GITHUB_TOKEN` authority MUST NOT authorize checkout, API access, status reporting, comments, releases, or cleanup.
214+
The caller MUST declare top-level `permissions: {}`. Its Process-PSModule job MUST grant only `contents: read`, `pages: write`, and `id-token: write`. Built-in `GITHUB_TOKEN` MAY authorize repository-local, non-user-facing work when those permissions are sufficient, including checkout, reads, and standard Pages/OIDC deployment. GitHub App installation tokens MUST authorize all user-facing interactions and any operation that exceeds the built-in token's reach or permissions, including pull-request comments and labels, commit statuses and check-facing reporting, releases, tags, assets, and cleanup. Tokens MUST remain scoped to the steps that require them.
215215

216216
#### Behavioral scenarios {#fr11-scenarios}
217217

218218
```gherkin
219-
Scenario: Run from a permissionless caller
219+
Scenario: Run with the caller's minimum permissions
220220
Given the caller declares top-level permissions as an empty object
221-
And the caller grants no job permissions
222-
When the reusable workflow runs with authorized GitHub App installation tokens
223-
Then checkout and repository operations use the explicit App tokens
224-
And the built-in workflow token does not authorize those operations
225-
226-
Scenario: Start a repository operation
227-
Given the reusable workflow requires repository access
228-
When the workflow begins
229-
Then it creates the required GitHub App token before checkout
230-
And it passes that token explicitly to checkout and subsequent repository operations
221+
And its Process-PSModule job grants only contents read, Pages write, and ID-token write
222+
When the reusable workflow performs checkout or standard Pages deployment
223+
Then it may use the built-in workflow token within that granted boundary
224+
225+
Scenario: Perform a user-facing repository operation
226+
Given the reusable workflow must create a pull-request comment or release
227+
When the operation requires authority beyond the built-in token boundary
228+
Then it creates a narrowly scoped GitHub App installation token
229+
And it uses the App token only for the steps that require that authority
231230
```
232231

233232
## Non-functional requirements
@@ -338,18 +337,17 @@ Scenario: Retain an immutable Gallery prerelease
338337
And it performs GitHub Release and tag cleanup independently
339338
```
340339

341-
### NFR7 — Missing App authorization MUST fail closed {#nfr7}
340+
### NFR7 — App-required operations MUST fail closed {#nfr7}
342341

343-
When the required GitHub App authorization is unavailable, every repository-mutating or reporting job MUST fail before performing an unauthorized checkout, API request, status update, comment, release, or cleanup. It MUST NOT fall back to built-in `GITHUB_TOKEN` authority.
342+
When an operation requires GitHub App authorization and the required App token is unavailable, the operation MUST fail before an unauthorized API request, status update, comment, release, tag or asset mutation, or cleanup. It MUST NOT silently fall back to built-in `GITHUB_TOKEN` authority. Repository-local reads and standard Pages/OIDC deployment MAY continue only within the caller job's explicit built-in-token permissions.
344343

345344
#### Behavioral scenarios {#nfr7-scenarios}
346345

347346
```gherkin
348-
Scenario: Reject a job without GitHub App authorization
349-
Given a caller with no granted token permissions
350-
And a reusable-workflow job cannot create its required GitHub App token
351-
When the job attempts repository access
352-
Then the job fails before the repository operation
347+
Scenario: Reject a user-facing operation without GitHub App authorization
348+
Given a reusable-workflow job cannot create its required GitHub App token
349+
When the job attempts to create a pull-request comment
350+
Then the operation fails before the API request
353351
And it does not use the built-in workflow token as a fallback
354352
```
355353

0 commit comments

Comments
 (0)