-
Notifications
You must be signed in to change notification settings - Fork 220
GitHub Actions Design Guidelines
Mike Harder edited this page Feb 11, 2025
·
26 revisions
# Dev Dependencies for VS Code intellisense in github-script JS files
.github/package.json
.github/package-lock.json (required for repeatable builds of check unit tests)
# Composite Actions
.github/actions/do-something/action.yaml
.github/actions/do-something/src/action.js
.github/actions/do-something/test/action.test.js
.github/actions/src/util.js (code shared between actions)
.github/actions/test/util.test.js (code shared between actions)
# Workflows
.github/workflows/test-something.yaml
.github/workflows/src/test-something.js
.github/workflows/test/test-something.test.js
.github/workflows/src/util.js (code shared between workflows)
.github/workflows/test/util.test.js (code shared between workflows)
# Shared JS Libraries
.github/src/util.js (code shared between action and workflows)
.github/test/util.test.js (code shared between action and workflows)For VS Code intellisense and tools:
- cd
.github npm ci
-
YAML syntax for Workflows - Files under
.github/workflows -
YAML syntax for Actions - Files under
.github/actions
- Workflows and Actions should use the
.yamlfile extension (not.yml) - Use pinned runner images like
ubuntu-24.04rather than floated images likeubuntu-latest- Updating all pinned images is a single search/replace, while floating causes distracting warnings during updates
- Less is more, but make things nice
- Don't set a property (like
idorshell) unless it's useful - Do set a property (like
name) if (and only if) it improves the log UI
- Don't set a property (like
- Sort properties approximately in the order listed in the documents above (and/or align with examples in GitHub docs)
- Log as much as you can, but within reason
- Do log anything you think might be useful to debug a problem in the future
- Don't log anything verbose, unless it's useful
- Consider grouping log chunks to improve UI
- Use
debugwhen appropriate for verbose logs, but remember it's only useful for repros (not the original failure)
- Before merging, run "Format Document" (will be enforced in the future)
- Goal is 100% branch coverage of all actions, workflows, and shared code
- For efficiency, trigger on the minimal number of events necessary, and aggressively filter based on the event payload to avoid allocating an agent unless necessary.
on:
issue_comment:
types:
- edited
pull_request:
types:
# Depends on labels, so must re-evaluate whenever a relevant label is manually added or removed.
- labeled
- unlabeled
# Depends on changed files and check_run status, so must re-evaluate whenever either could change
- opened
- reopened
- synchronize
jobs:
job:
# pull_request:labeled - filter to only the input and output labels
# issue_comment:edited - filter to only PR comments containing "next steps to merge",
# a signal that "Swagger LintDiff" status may have changed
if: |
(github.event_name == 'pull_request' &&
((github.event.action == 'opened' ||
github.event.action == 'reopened' ||
github.event.action == 'synchronize') ||
((github.event.action == 'labeled' ||
github.event.action == 'unlabeled') &&
(github.event.label.name == 'ARMReview' ||
github.event.label.name == 'NotReadyForARMReview' ||
github.event.label.name == 'SuppressionReviewRequired' ||
github.event.label.name == 'Suppression-Approved' ||
github.event.label.name == 'ARMAutoSignOffPreview')))) ||
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, 'next steps to merge'))
runs-on: ubuntu-24.04
- Security hardening for GitHub Actions
- Keeping your GitHub Actions and workflows secure: Preventing pwn requests
- Trigger
pull_requesthas a read-onlyGITHUB_TOKEN- Should be used whenever possible, like to run a test and return pass/fail
- Triggers like
pull_request_targetandworkflow_completedhave read-writeGITHUB_TOKEN- You must never do anything that could execute untrusted code from a fork PR
- Safest option is to never clone the PR source branch at all
- Perform most of the work in a safe
pull_requesttrigger, then use aworkflow_completedtrigger to execute the privileged tasks (e.g. adding a label) based on artifacts published by the first workflow - If you must clone the PR source branch, it can only be treated as text, never executed
- Don't log anything that might leak secrets
- GitHub has some built-in protections (e.g. masking secrets), but treat them as defense-in-depth
To follow the principle of least-privilege, all workflows should use the following top-level permissions by default:
permissions:
content: read
This allows the workflow to clone the repo (and upload artifacts, which appears to be always allowed). Additional privileges should be granted at the job level as needed. For example:
permissions:
contents: read
jobs:
update-labels:
name: Update Labels
permissions:
contents: read
pull-requests: write
- Use
workflow_dispatchwherever you can- Manually triggering a pipeline can make testing/debugging easier
- Beware the different context objects available to the pipeline and don't couple to a specific one
- Naming jobs in a matrix
- Matrix UI improvements
- Composite Actions behavior is different from DevOps templates
- Code is written in JavaScript instead of TypeScript
- Significantly improves startup time
- Recommended by
github-scriptaction - Encourages us to keep our code simple
- With type checking and intellisense, the editing experience is similar
- Before merging, run "Format Document" (will be enforced in the future)
- All JS files should start with header
// @ts-checkto enable type checking - Functions called from
github-scriptshould start with the following, to set the argument types:
/**
* @param {import('github-script').AsyncFunctionArguments} AsyncFunctionArguments
*/
module.exports = async ({ github, context, core }) => {- Additional type declarations can be added via JSDoc comments
const payload =
/** @type {import("@octokit/webhooks-types").WorkflowRunCompletedEvent} */ (
context.payload
);- Error logging in
pwsh- To
$ErrorActionPreferenceandWrite-Erroror not to$ErrorActionPreferenceandWrite-Host?
- To

