Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/ci-template-overhaul.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@bradygaster/squad-cli': patch
'@bradygaster/squad-sdk': patch
---

CI template overhaul: add caching, timeouts, concurrency groups, SHA-pinned actions, token documentation, and security hardening across all 11 shipped workflow templates. Closes #886.
31 changes: 29 additions & 2 deletions .squad-templates/workflows/squad-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,46 @@ on:
types: [opened, synchronize, reopened]
push:
branches: [dev, insider]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
changes:
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
src: ${{ steps.filter.outputs.src }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: filter
with:
filters: |
src:
- '!docs/**'
- '!*.md'
- '!.squad/*.md'
- '!.squad/decisions/**'

test:
needs: changes
if: needs.changes.outputs.src == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- uses: actions/setup-node@v4
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 22
cache: npm # REQUIRES: package-lock.json (npm). For pnpm: cache: pnpm. For yarn: cache: yarn.

- name: Run tests
run: node --test test/*.test.cjs
14 changes: 9 additions & 5 deletions .squad-templates/workflows/squad-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ on:
permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
Expand All @@ -20,10 +19,11 @@ concurrency:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- uses: actions/setup-node@v4
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '22'
cache: npm
Expand All @@ -38,17 +38,21 @@ jobs:
run: npm run build

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0
with:
path: docs/dist

deploy:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
23 changes: 17 additions & 6 deletions .squad-templates/workflows/squad-heartbeat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,18 @@ permissions:
contents: read
pull-requests: read

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

jobs:
heartbeat:
runs-on: ubuntu-latest
timeout-minutes: 15
env:
HAS_COPILOT_TOKEN: ${{ secrets.COPILOT_ASSIGN_TOKEN != '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Check triage script
id: check-script
Expand All @@ -48,7 +55,7 @@ jobs:

- name: Ralph — Apply triage decisions
if: steps.check-script.outputs.has_script == 'true' && hashFiles('triage-results.json') != ''
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('fs');
Expand Down Expand Up @@ -97,12 +104,16 @@ jobs:

core.info(`🔄 Ralph triaged ${results.length} issue(s)`);

# Copilot auto-assign step (uses PAT if available)
# COPILOT_ASSIGN_TOKEN: A fine-grained GitHub PAT with 'Issues: Write' permission.
# Used to assign the @copilot coding agent to issues. Optional — if not set,
# @copilot assignment is skipped.
# Create at: Settings > Developer settings > Fine-grained tokens
# Required permission: Issues (Read and Write) on this repository only.
- name: Ralph — Assign @copilot issues
if: success()
uses: actions/github-script@v7
if: success() && env.HAS_COPILOT_TOKEN == 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN || secrets.GITHUB_TOKEN }}
github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN }}
script: |
const fs = require('fs');

Expand Down
10 changes: 8 additions & 2 deletions .squad-templates/workflows/squad-insider-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,23 @@ on:
permissions:
contents: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

- uses: actions/setup-node@v4
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 22
cache: npm # REQUIRES: package-lock.json (npm). For pnpm: cache: pnpm. For yarn: cache: yarn.

- name: Run tests
run: node --test test/*.test.cjs
Expand Down
24 changes: 19 additions & 5 deletions .squad-templates/workflows/squad-issue-assign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,25 @@ permissions:
issues: write
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.issue.number }}
cancel-in-progress: false

jobs:
assign-work:
# Only trigger on squad:{member} labels (not the base "squad" label)
if: startsWith(github.event.label.name, 'squad:')
if: startsWith(github.event.label.name, 'squad:') && github.actor != 'github-actions[bot]' && github.actor != 'dependabot[bot]'
runs-on: ubuntu-latest
timeout-minutes: 10
env:
HAS_COPILOT_TOKEN: ${{ secrets.COPILOT_ASSIGN_TOKEN != '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Identify assigned member and trigger work
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('fs');
Expand Down Expand Up @@ -113,10 +122,15 @@ jobs:

core.info(`Issue #${issue.number} assigned to ${assignedMember.name} (${assignedMember.role})`);

# COPILOT_ASSIGN_TOKEN: A fine-grained GitHub PAT with 'Issues: Write' permission.
# Used to assign the @copilot coding agent to issues. Optional — if not set,
# @copilot assignment is skipped.
# Create at: Settings > Developer settings > Fine-grained tokens
# Required permission: Issues (Read and Write) on this repository only.
# Separate step: assign @copilot using PAT (required for coding agent)
- name: Assign @copilot coding agent
if: github.event.label.name == 'squad:copilot'
uses: actions/github-script@v7
if: github.event.label.name == 'squad:copilot' && env.HAS_COPILOT_TOKEN == 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN }}
script: |
Comment thread
diberry marked this conversation as resolved.
Expand Down
12 changes: 10 additions & 2 deletions .squad-templates/workflows/squad-label-enforce.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,22 @@ permissions:
issues: write
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.issue.number }}
cancel-in-progress: false

jobs:
enforce:
if: github.actor != 'github-actions[bot]' && github.actor != 'dependabot[bot]'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Enforce mutual exclusivity
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const issue = context.payload.issue;
Expand Down
10 changes: 8 additions & 2 deletions .squad-templates/workflows/squad-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@ on:
permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- uses: actions/setup-node@v4
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 22
cache: npm # REQUIRES: package-lock.json (npm). For pnpm: cache: pnpm. For yarn: cache: yarn.

- name: Validate version consistency
run: |
Expand Down
10 changes: 8 additions & 2 deletions .squad-templates/workflows/squad-promote.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@ on:
permissions:
contents: write

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

jobs:
dev-to-preview:
name: Promote dev → preview
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
Expand Down Expand Up @@ -69,8 +74,9 @@ jobs:
name: Promote preview → main (release)
needs: dev-to-preview
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
10 changes: 8 additions & 2 deletions .squad-templates/workflows/squad-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,23 @@ on:
permissions:
contents: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

- uses: actions/setup-node@v4
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 22
cache: npm # REQUIRES: package-lock.json (npm). For pnpm: cache: pnpm. For yarn: cache: yarn.

- name: Run tests
run: node --test test/*.test.cjs
Expand Down
13 changes: 10 additions & 3 deletions .squad-templates/workflows/squad-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@ permissions:
issues: write
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.issue.number }}
cancel-in-progress: false

jobs:
triage:
if: github.event.label.name == 'squad'
if: github.event.label.name == 'squad' && github.actor != 'github-actions[bot]' && github.actor != 'dependabot[bot]'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Triage issue via Lead agent
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('fs');
Expand Down
9 changes: 7 additions & 2 deletions .squad-templates/workflows/sync-squad-labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ permissions:
issues: write
contents: read

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true

jobs:
sync-labels:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Parse roster and sync labels
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('fs');
Expand Down
Loading
Loading