GitHub Actions and CI/CD
GitHub Actions is GitHub’s built-in automation engine: YAML workflows in .github/workflows/ run jobs of steps on events like push, PR, schedule, or manual dispatch.
Why it matters
It is where “every PR must pass tests” becomes enforceable — wire a workflow into branch protection as a required check and unreviewed-or-failing code can’t merge. It also drives CD: build, sign, publish, and deploy on a tag or to main. Being co-located with the repo (no external CI to provision) makes it the default for most GitHub projects.
How it works
A workflow is a tree: on: (triggers) → jobs: (run in parallel by default) → steps: (sequential, reuse actions via uses: or run shell via run:).
| Concept | Scope | Notes |
|---|---|---|
| Workflow | one .yml file | one or more triggers in on: |
| Job | runs on one runner | parallel unless needs: orders them |
| Step | one command/action | uses: actions/checkout@v4 etc. |
| Runner | VM/container | ubuntu-latest = 4 vCPU / 16 GB |
- Cost — public repos run free; private repos bill by minute, and non-Linux is weighted: Linux x1, Windows x2, macOS x10. A 5-min macOS job costs 50 minutes of quota.
- Secrets —
${{ secrets.NAME }}is masked in logs; never echo them. Use tokens or OIDC for cloud auth. GITHUB_TOKEN— an auto-minted per-run token; setpermissions:to least privilege (default is read-only on newer repos).- Cache & matrix —
actions/cachekeyed by a lockfile hash skips reinstalls; astrategy.matrixfans one job across versions/OSes.
Example
name: ci
on: { pull_request: {}, push: { branches: [main] } }
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix: { node: [18, 20, 22] }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: ${{ matrix.node }}, cache: npm }
- run: npm ci && npm testThis runs three parallel jobs (Node 18/20/22); marking test required blocks merge until all pass.
Pitfalls
pull_request_targetwith checkout of the PR head — runs untrusted fork code with repo secrets; a classic exfiltration hole. Preferpull_request(no secrets on forks).- Unpinned tags —
uses: foo/bar@v2follows a moving tag; a compromised release runs in your pipeline. Pin to a full commit SHA for supply-chain safety. - Over-broad
permissions— leavingGITHUB_TOKENwithwritelets a malicious step push or open PRs; scope per workflow. - Forgetting
concurrency— rapid pushes pile up redundant runs; add aconcurrencygroup withcancel-in-progress: true.