Skip to content

Commit 3db3b86

Browse files
merge: synchronize workflow audit base
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2 parents a18d325 + 0d604a3 commit 3db3b86

1 file changed

Lines changed: 55 additions & 54 deletions

File tree

docs/content/reference/process-workflow-fleet-standard.md

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ The uniform wrapper is a strong starting point, but it predates the two latest b
5757
- `v8.0.0` moves stable publication to a default-branch `push`, adds `unlabeled` routing, and requires non-cancelling
5858
pull-request-or-ref concurrency.
5959

60-
The observed absence of additional jobs is inventory context, not a conformance requirement. The candidate standardizes
61-
the Process-PSModule reusable-workflow call and the shared top-level controls that govern that call, rather than the
62-
repository owner's entire workflow.
63-
6460
No current caller has the `v8.0.0` trigger and concurrency contract. The fleet spans nine older versions:
6561

6662
| Version | Repositories |
@@ -129,19 +125,29 @@ jobs:
129125
GitHubAppPrivateKey: ${{ secrets.SHELLY_PRIVATE_KEY }}
130126
```
131127
128+
Modules whose local tests require repository-specific data may add the optional secret mapping:
129+
130+
```yaml
131+
TestData: >-
132+
{"secrets":{"TOKEN":"${{ secrets.TEST_TOKEN }}"},"variables":{"ENDPOINT":"${{ vars.TEST_ENDPOINT }}"}}
133+
```
134+
135+
The reusable workflow exports only the declared entries to module-local test setup, tests, and teardown. Callers omit
136+
`TestData` when no module-local test data is required.
137+
132138
This YAML is a recommendation derived from the v8 interface and fleet evidence. It is not an approved standard.
133139
Issue [#514](https://github.com/PSModule/Process-PSModule/issues/514) must record agreement on the following structural
134140
decisions before canonical guides, templates, or consumer workflows adopt it:
135141

136142
| Decision | Candidate | Alternatives still open |
137143
| --- | --- | --- |
138-
| Wrapper scope | Exactly one conforming Process-PSModule reusable-workflow call job plus the shared top-level controls that govern it. Repository-owned jobs may coexist in the same file or separate workflows when they do not weaken or bypass that boundary. | Decide only the placement of repository-owned jobs. |
144+
| Contract scope | Standardize the `Process-PSModule` caller job and its shared workflow controls, not every job in the file. | Selected for the candidate; repository-owned jobs remain outside the caller contract. |
139145
| Trigger ownership | The caller owns manual, schedule, default-branch push, and pull-request triggers. | Move some trigger policy into separate workflows or omit selected event classes. |
140146
| Pull-request activities | Keep all six listed activity types. | Reduce the activity list if a v8 behavior is intentionally unsupported. |
141-
| Concurrency | Use the PR-number-or-ref key and cancel only superseded pull-request runs. | Use separate groups per event class or disable cancellation for all runs. |
142-
| Permissions | Set top-level permissions to empty and grant only `contents: read`, `pages: write`, and `id-token: write` to the caller job. | Define a narrower profile for repositories that do not publish Pages. |
143-
| Fork behavior | Invoke the reusable workflow unconditionally; Plan classifies normal fork `pull_request` events into restricted read-only validation and rejects `pull_request_target` until separately designed. | Omit fork validation or design a separate `pull_request_target` trust boundary. |
144-
| Credentials | Explicitly map `PSGALLERY_API_KEY`, `GitHubAppClientId`, and `GitHubAppPrivateKey`; `secrets: inherit` is nonconforming. | Define a narrower profile only for repositories with an approved non-publication contract. |
147+
| Concurrency | Use the workflow plus PR-number-or-full-ref key and cancel only pull-request runs. | Selected for the candidate: PR reconciliation must be resumable; non-PR runs serialize by full ref. |
148+
| Permissions | Default deny at workflow level, then grant the caller job `contents: read`, `pages: write`, and `id-token: write`. | Selected for the candidate: use `GITHUB_TOKEN` for repository-local, non-user-facing platform operations and App tokens for user-facing or otherwise unsupported operations. |
149+
| Fork behavior | Keep the caller unconditional; classify fork pull requests as restricted read-only validation in `Plan`. | Selected for the candidate; execution policy belongs to Process-PSModule rather than every consumer. |
150+
| Credentials | Explicitly map the three v8 credentials; optionally map `TestData` when module-local tests need it. | Define a narrower credential profile for repositories that cannot publish. |
145151
| Optional surface | Permit only documented `TestData`, workflow inputs, schedule timing, and presentation metadata. | Allow additional extension points after naming and compatibility rules are agreed. |
146152

147153
The `v8` reference is the controlled moving major tag for this PSModule-owned workflow. On 2026-08-15, `v8`, `v8.0`,
@@ -154,6 +160,11 @@ Release automation is therefore the operational owner, but actors with sufficien
154160
from moving the major tag manually. Enforce release-identity-only governance for moving tags before migrating the fleet
155161
to `@v8`; until then, consumers must retain immutable SHA references.
156162

163+
The reusable workflow remains at `.github/workflows/workflow.yml`. A private cross-repository experiment on 2026-08-15
164+
confirmed that GitHub rejects a root-level reusable workflow reference with
165+
`references to workflows must be rooted in '.github/workflows'`, even when the provider repository grants the caller
166+
the required Actions access.
167+
157168
### Owned and external references
158169

159170
| Automation source | Standard reference | Update model |
@@ -173,76 +184,66 @@ fleet campaign. Branch names, `latest`, floating minor tags, and unqualified tar
173184
| Default-branch push | Keep `push.branches: [main]`. | `v8` authorizes stable releases from the tested default-branch push. |
174185
| Manual dispatch | Keep `workflow_dispatch`. | Provides the documented default-branch manual release and recovery path. |
175186
| Schedule | Keep a scheduled health run. | Exercises current dependencies even when repository code is unchanged. |
176-
| Concurrency | Use the PR-number-or-ref key and cancel only pull-request runs. | Pull-request changes converge promptly while non-pull-request runs serialize by ref. |
177-
| Permissions | Use empty top-level permissions and the three caller-job permissions shown above. | Repository-local reads and Pages/OIDC stay narrow; App tokens provide broader authority. |
178-
| Fork authorization | Leave the caller job unconditional. | Plan grants normal fork `pull_request` events only restricted read-only validation capabilities and rejects `pull_request_target` before credentials or repository-defined code run. |
187+
| Concurrency | Use the PR-number-or-ref key and cancel only pull-request runs. | New PR events supersede older declarative reconciliation runs; same-ref push, dispatch, and schedule runs serialize without cancellation. |
188+
| Permissions | Set top-level `permissions: {}` and grant only `contents: read`, `pages: write`, and `id-token: write` to the caller job. | Checkout and Pages remain repository-local built-in capabilities; user-facing interactions and operations outside the built-in token boundary use scoped GitHub App tokens. |
189+
| Event gate | Keep the caller unconditional and authorize capabilities in `Plan`. | The reusable workflow owns execution policy; fork pull requests may validate but cannot obtain App credentials, publish, deploy, clean up, or mutate repository state. |
179190
| Reference | Use the intended internal floating major tag (`v8`) after tag governance is enforced. | Compatible owned releases roll out centrally; breaking releases require a new major and campaign. |
180-
| Credentials | Explicitly map `PSGALLERY_API_KEY`, `GitHubAppClientId`, and `GitHubAppPrivateKey`; do not use `secrets: inherit`. | Satisfies the `v7+` contract and prevents unrelated secret inheritance. |
181-
| Scope | Require exactly one conforming Process-PSModule delegation job and its governing triggers, concurrency, permissions, Plan authorization, and credential boundary. | Repository-owned jobs may be reported for visibility but are not nonconforming merely by existing. |
191+
| Credentials | Explicitly map the three required secrets. | Satisfies the `v7+` contract and prevents unrelated secret inheritance. |
192+
| Scope | Require one conforming `Process-PSModule` delegation job. | Additional repository-owned jobs do not change caller conformance. |
182193

183194
## Candidate optional elements
184195

185196
These are evidence-based candidate variations, not approved policy.
186197

187198
| Option | When it is appropriate | Constraint |
188199
| --- | --- | --- |
189-
| `TestData` secret mapping | Module-local tests need caller-defined secrets or variables. | Map `TestData: ${{ secrets.TestData }}` only when used. Its value is a JSON object with separate `secrets` and `variables` maps; omit the mapping when unused. |
200+
| `TestData` secret | Module-local tests need caller-defined secrets or variables. | Optionally map the documented JSON object with separate `secrets` and `variables` maps, exposing only required values. |
190201
| `with.SettingsPath` | The settings file is not `.github/PSModule.yml`. | Prefer the standard path for normal module repositories. |
191202
| `with.WorkingDirectory` | The module is intentionally rooted below the repository root. | Keep the default `.` for the standard layout. |
192203
| `with.ImportantFilePatterns` | A caller must override change detection at the workflow boundary. | Prefer stable configuration in `.github/PSModule.yml`; the supplied list replaces all defaults. |
193204
| `with.Verbose`, `Version`, or `Prerelease` | A deliberate diagnostic or dependency-selection scenario needs it. | Do not hard-code temporary diagnostics into the fleet baseline. |
194205
| Schedule time | Health runs need staggering or a repository-specific maintenance window. | Keep at least one documented schedule unless the repository records why health runs are unnecessary. |
195206
| `run-name` | A repository needs clearer run presentation. | Presentation must not change job names or routing behavior. |
196207

208+
Conforming callers do not set `with.Debug: true`; the reusable workflow default remains `false`.
209+
197210
## Variations requiring a decision
198211

199-
The following are nonconforming with locked candidate decisions. They remain inventory classifications rather than
200-
approved organization policy until #514 records an approved structure:
212+
The following differ from the candidate. They are inventory classifications, not policy violations, until #514 records
213+
an approved structure:
201214

202-
- `secrets: inherit`, which is nonconforming because the candidate requires the three explicit baseline mappings;
215+
- `secrets: inherit`;
203216
- `APIKey` or `APIKEY` mappings from the pre-`v7` contract;
204217
- any Process-PSModule reference other than the intended major tag (`v8`), including a branch, `latest`, minor tag,
205218
exact patch tag, or full commit SHA;
206219
- missing `push` or `unlabeled` triggers;
207-
- a `cancel-in-progress` expression other than `github.event_name == 'pull_request'` or the old ref-only concurrency key;
220+
- a concurrency key other than workflow plus PR number or full ref, or cancellation behavior other than pull-request-only;
221+
- a caller-level fork or event-authorization condition;
208222
- trigger-level path filters that bypass Process-PSModule important-file evaluation;
209-
- omitted documented permissions without a verified settings-based least-privilege profile;
210-
- `with.Debug: true`, which is nonconforming because the reusable workflow default remains `false`.
211-
212-
When required, the optional test-data mapping extends the candidate baseline without broadening it:
213-
214-
```yaml
215-
secrets:
216-
PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
217-
GitHubAppClientId: ${{ secrets.SHELLY_CLIENT_ID }}
218-
GitHubAppPrivateKey: ${{ secrets.SHELLY_PRIVATE_KEY }}
219-
TestData: ${{ secrets.TestData }}
220-
```
221-
222-
`TestData` is a JSON object with separate `secrets` and `variables` maps, for example
223-
`{"secrets":{"Example":"value"},"variables":{"Feature":"enabled"}}`. Callers omit this mapping entirely when
224-
module-local tests do not need it. No conforming caller sets `with.Debug: true`; the reusable workflow's default remains
225-
`false`.
226-
227-
The candidate caller invokes the reusable workflow for fork-originated `pull_request` events. Plan classifies them into a
228-
restricted, read-only validation mode that permits only repository-local checkout, build, lint, and test with the
229-
least-privilege built-in token. It emits explicit capabilities that prohibit App-token creation, publication, mutation,
230-
Pages deployment, cleanup, and user-facing reporting. `pull_request_target` remains unsupported and Plan must reject it
231-
before credentials or repository-defined code run; issue [#514](https://github.com/PSModule/Process-PSModule/issues/514)
232-
must approve any separate trust boundary for that event.
233-
234-
The controlled upstream `v8` Plan implementation derives that restricted envelope first from immutable GitHub event
235-
metadata, including fork, base, and head identities. It may then use fork settings and checked-out files only as
236-
untrusted validation and build inputs; they cannot enable credentials, broaden permissions, or change the capability
237-
envelope. This permits ordinary fork contributors to receive the standard workflow green/red validation without
238-
configuring secrets.
239-
240-
The candidate requires exactly one conforming Process-PSModule reusable-workflow call job and the shared top-level triggers,
241-
concurrency, permissions, Plan authorization, and credential boundary that govern it. Repository-owned jobs may exist in
242-
the same file or in separate workflows and are reported only for visibility. Their existence is not nonconforming, but
243-
they MUST NOT weaken or bypass the Process-PSModule call's trigger, concurrency, permissions, Plan authorization, or
223+
- caller permissions beyond `contents: read`, `pages: write`, and `id-token: write`.
224+
225+
Use the built-in `GITHUB_TOKEN` for non-user-facing operations confined to the calling repository, including checkout
226+
and the standard GitHub Pages deployment. Create narrowly scoped GitHub App installation tokens for user-facing
227+
interactions such as pull-request comments, labels, statuses, releases, and release cleanup, and whenever the built-in
228+
token cannot provide the required repository or cross-repository access. Tokens remain step-scoped and must not fall
229+
back silently from App authorization to broader built-in-token authority.
230+
231+
The reusable workflow's Plan job classifies fork-originated `pull_request` events as restricted read-only validation.
232+
It may allow repository-local checkout, build, lint, and test with least-privilege built-in access, but must explicitly
233+
deny App-token creation, Gallery access, publication, Pages deployment, cleanup, and repository or user-facing
234+
mutations. The controlled upstream Plan implementation derives this security envelope from GitHub event metadata before
235+
it interprets repository settings or executes checked-out repository code. Fork-controlled files and settings remain
236+
untrusted build inputs and cannot broaden the planned capabilities. Every downstream job, including jobs using
237+
`always()`, must require a successful valid Plan and the planned capability for its operation before running or
238+
evaluating Settings. Privileged-context events such as
239+
`pull_request_target` remain unsupported unless separately designed to prevent untrusted code from crossing the
244240
credential boundary.
245241

242+
The contract applies to the shared workflow controls and the `Process-PSModule` delegation job shown above. Repositories
243+
may define additional jobs in the same file or separate workflows. The inventory reports those jobs for visibility, but
244+
the contract does not prescribe their implementation. Additional jobs must not weaken or bypass the permissions,
245+
authorization, trigger, or concurrency controls governing the Process-PSModule call.
246+
246247
## Rollout boundary
247248

248249
This research does not approve or change consumer repositories. If #514 approves the candidate, the campaign would use

0 commit comments

Comments
 (0)