Skip to content

Commit e76da44

Browse files
πŸ“– [Docs]: Coding style guides now live in the docs site (#43)
The PSModule coding style guides now live in the documentation site under a new **Style Guides** menu section. Contributors and agents can browse the GitHub Actions, Markdown, and PowerShell conventions directly on the docs site instead of digging through editor instruction files in another repository. ## New: Style Guides section in the docs A new **Style Guides** entry appears in the top navigation, containing: - **GitHub Actions** β€” workflow and composite action authoring conventions: job/step naming, quoting, SHA pinning, minimal permissions, OIDC and secrets handling, untrusted-input safety, trigger isolation, runner pinning, and a zizmor security checklist. - **Markdown** β€” headings, lists, code blocks, links, tables, emphasis, whitespace, and filename conventions. - **PowerShell** β€” One True Brace Style, naming, parameters, error handling, pipeline design, performance, and Pester testing conventions. Each guide states the rule, shows good and bad examples, and explains how to apply it. The Markdown and PowerShell guides are migrated verbatim from the editor instruction files that previously lived in the `Process-PSModule` repository; the GitHub Actions guide is new and aligns with the existing GitHub Actions Standard. ## Technical Details - Added `src/docs/Style-Guides/` with `index.md`, `GitHub-Actions.md`, `Markdown.md`, and `PowerShell.md`. - Editor-specific frontmatter (`applyTo`) was replaced with docs frontmatter (`title`/`description`). - Registered the new `Style Guides` section in the `nav` array in `src/zensical.toml`, placed between **GitHub Actions** and **Solutions**. - Companion PR: `PSModule/Process-PSModule#349` removes the now-migrated instruction files. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent 5cc80d4 commit e76da44

5 files changed

Lines changed: 1425 additions & 0 deletions

File tree

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
---
2+
title: GitHub Actions
3+
description: GitHub Actions style guidelines for consistency and security across workflows and composite actions.
4+
---
5+
6+
## GitHub Actions style guidelines
7+
8+
This document defines the GitHub Actions style guidelines for all workflow files (`.github/workflows/*.yml`), composite actions (`action.yml`), and reusable workflows in PSModule repositories. These rules follow GitHub Actions best practices and the security guidance enforced by [zizmor](https://github.com/woodruffw/zizmor).
9+
10+
## Scope
11+
12+
- Applies to `.github/workflows/*.{yml,yaml}`, `action.yml`, `.github/dependabot.yml`, and `CODEOWNERS` entries for workflows.
13+
- Application source code stays out of scope. If a fix requires changes outside `.github/`, surface it as a recommendation instead.
14+
15+
## Naming
16+
17+
- Give every job and every step a `name:` field
18+
- Use short, human-readable names that describe what the job or step does, not how
19+
- Keep naming consistent with existing workflows in the repository
20+
21+
**Good:**
22+
23+
```yaml
24+
jobs:
25+
build:
26+
name: Build module
27+
steps:
28+
- name: Checkout repository
29+
uses: actions/checkout@<sha> # vX.Y.Z
30+
```
31+
32+
**Bad:**
33+
34+
```yaml
35+
jobs:
36+
build:
37+
steps:
38+
- uses: actions/checkout@<sha> # vX.Y.Z
39+
```
40+
41+
## Quoting
42+
43+
- Only quote scalar values when YAML would otherwise misinterpret them
44+
- Quote values starting with `{`, containing `:`, boolean-like strings (`true`/`false`), or numeric strings
45+
- Omit quotes everywhere else
46+
47+
**Good:**
48+
49+
```yaml
50+
run-name: Release ${{ github.ref_name }}
51+
concurrency:
52+
group: ${{ github.workflow }}-${{ github.ref }}
53+
```
54+
55+
**Bad:**
56+
57+
```yaml
58+
run-name: 'Release ${{ github.ref_name }}'
59+
concurrency:
60+
group: '${{ github.workflow }}-${{ github.ref }}'
61+
```
62+
63+
## Pinning actions
64+
65+
- Pin every `uses:` to a full 40-character commit SHA
66+
- Add a patch-level version comment (`# vX.Y.Z`) so Dependabot can update SHA and comment together
67+
- Applies to reusable workflows too (`uses: org/repo/.github/workflows/foo.yml@<sha>`)
68+
- Exception: first-party actions in the same repository (`uses: ./.github/actions/...`)
69+
- Resolve SHAs via `gh api` β€” never invent or guess a commit SHA. Always use the commit SHA, never the annotated-tag object SHA.
70+
71+
**Good:**
72+
73+
```yaml
74+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
75+
```
76+
77+
**Bad:**
78+
79+
```yaml
80+
- uses: actions/checkout@v4
81+
- uses: actions/checkout@main
82+
```
83+
84+
Resolving SHAs:
85+
86+
```bash
87+
gh api repos/<owner>/<repo>/git/refs/tags/<vX.Y.Z> --jq '.object.sha'
88+
# If .object.type == "tag", dereference:
89+
gh api repos/<owner>/<repo>/git/tags/<sha> --jq '.object.sha'
90+
```
91+
92+
## Permissions
93+
94+
- Declare workflow-level `permissions:` set to the strictest needed (default `contents: read`)
95+
- Override per-job when one job needs more
96+
- Never use `permissions: write-all` or omit `permissions:` entirely
97+
- Add an inline comment justifying any non-`read` grant
98+
99+
**Good:**
100+
101+
```yaml
102+
permissions:
103+
contents: read
104+
105+
jobs:
106+
deploy:
107+
permissions:
108+
contents: read
109+
id-token: write # OIDC federation to AWS
110+
```
111+
112+
## Secrets and configuration
113+
114+
- Use `vars.*` for configuration: region, account ID, role ARN, environment name
115+
- Use `secrets.*` for credentials: API tokens, passwords, signing keys
116+
- Never hardcode account IDs, role ARNs, or region names
117+
- Authenticate to cloud providers with OIDC, never long-lived keys
118+
- In reusable workflows, pass secrets explicitly β€” never use `secrets: inherit`
119+
120+
**Good:**
121+
122+
```yaml
123+
permissions:
124+
id-token: write
125+
contents: read
126+
127+
steps:
128+
- name: Configure AWS credentials
129+
uses: aws-actions/configure-aws-credentials@<sha> # vX.Y.Z
130+
with:
131+
aws-region: ${{ vars.AWS_REGION }}
132+
role-to-assume: ${{ vars.AWS_ROLE_ARN_CONTINUOUS_DEPLOYMENT }}
133+
```
134+
135+
**Bad:**
136+
137+
```yaml
138+
jobs:
139+
call:
140+
uses: ./.github/workflows/reusable.yml
141+
secrets: inherit
142+
```
143+
144+
## Untrusted input
145+
146+
- Never interpolate untrusted context directly into shell commands
147+
- Untrusted contexts include `github.event.issue.title`, `.body`, `.comment.body`, `.pull_request.title`, `.pull_request.body`, `.pull_request.head.ref`, `.head_commit.message`, `.review.body`, `.review_comment.body`, and `.head_ref`
148+
- Pass untrusted values through an `env:` variable and quote them in the shell
149+
150+
**Good:**
151+
152+
```yaml
153+
- run: echo "Title: $TITLE"
154+
env:
155+
TITLE: ${{ github.event.issue.title }}
156+
```
157+
158+
**Bad:**
159+
160+
```yaml
161+
- run: echo "Title: ${{ github.event.issue.title }}"
162+
```
163+
164+
## Triggers and isolation
165+
166+
- Default to `pull_request` for PR validation
167+
- Avoid `pull_request_target` and `workflow_run` unless required β€” they run with write tokens and secrets while potentially checking out attacker-controlled code
168+
- If `pull_request_target` is unavoidable, never check out the PR head, or check out into a sandbox without secrets
169+
- Use `actions/checkout` with `persist-credentials: false` unless the job pushes commits
170+
171+
**Good:**
172+
173+
```yaml
174+
- uses: actions/checkout@<sha> # vX.Y.Z
175+
with:
176+
persist-credentials: false
177+
```
178+
179+
## Runners and concurrency
180+
181+
- Pin `runs-on:` to a specific OS version (`ubuntu-24.04`) over a floating label (`ubuntu-latest`)
182+
- Add `concurrency:` to deploy and release workflows
183+
- Use `cancel-in-progress: true` for CI and `false` for deploys
184+
185+
**Good:**
186+
187+
```yaml
188+
concurrency:
189+
group: ${{ github.workflow }}-${{ github.ref }}
190+
cancel-in-progress: false
191+
```
192+
193+
## Operating protocol
194+
195+
Before writing or reviewing a workflow:
196+
197+
1. Read existing workflows and match shell choice, naming, job structure, and comment style
198+
1. Check `.github/dependabot.yml` for `package-ecosystem: github-actions` and propose adding it if absent
199+
1. Check `CODEOWNERS` for `.github/workflows/` ownership and recommend it if absent
200+
1. Resolve SHAs via `gh api` β€” never invent a commit SHA
201+
202+
## Security checklist
203+
204+
Run mentally (and via [zizmor](https://github.com/woodruffw/zizmor) when available) before declaring done.
205+
206+
### High severity β€” must fix
207+
208+
- `template-injection` β€” no `${{ ... }}` from untrusted context inside `run:` or `script:`
209+
- `dangerous-triggers` β€” `pull_request_target` / `workflow_run` justified and hardened
210+
- `unpinned-uses` β€” every `uses:` has a 40-char SHA and `# vX.Y.Z` comment
211+
- `excessive-permissions` β€” workflow- and job-level `permissions:` minimal
212+
- `secrets-inherit` β€” no `secrets: inherit`
213+
- `known-vulnerable-actions` β€” no pinned versions in GHSA
214+
- `github-env` β€” no untrusted writes to `$GITHUB_ENV` / `$GITHUB_PATH`
215+
216+
### Medium severity β€” fix unless justified
217+
218+
- `overprovisioned-secrets` β€” no `${{ toJSON(secrets) }}` or wholesale `${{ secrets }}`
219+
- `cache-poisoning` β€” no `actions/cache` (or `setup-*` cache) in tag-triggered release workflows
220+
- `ref-confusion` β€” pinned ref is not a name shared by both a tag and a branch
221+
- `ref-version-mismatch` β€” the `# vX.Y.Z` comment matches what the SHA actually is
222+
223+
### Low severity β€” fix when reasonable
224+
225+
- `stale-action-refs` β€” pinned commit corresponds to a real tag
226+
- `impostor-commit` β€” pinned SHA exists in the action repo's history
227+
228+
## Related resources
229+
230+
- [GitHub Actions documentation](https://docs.github.com/en/actions)
231+
- [zizmor β€” static analysis for GitHub Actions](https://github.com/woodruffw/zizmor)
232+
- [GitHub Actions Standard](../GitHub-Actions/Standards.md)

0 commit comments

Comments
Β (0)