From ca4eb462a89b3e2dbbbb9ad63b1e3018bbefc12a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:19:31 +0000 Subject: [PATCH 1/3] Initial plan From ab81325af975d93f95fb5d12e3f3057bf869a7bb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:24:51 +0000 Subject: [PATCH 2/3] Initial planning for GitHub Actions SHA pinning Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/release.lock.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index e459c176fb4..184dd51541d 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -5968,19 +5968,19 @@ jobs: - name: Download Go modules run: go mod download - name: Generate SBOM (SPDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 with: artifact-name: sbom.spdx.json format: spdx-json output-file: sbom.spdx.json - name: Generate SBOM (CycloneDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 with: artifact-name: sbom.cdx.json format: cyclonedx-json output-file: sbom.cdx.json - name: Upload SBOM artifacts - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: sbom-artifacts path: | From 2c78f8d9e95813e0752972869f25e01d3b33c111 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:30:11 +0000 Subject: [PATCH 3/3] Pin all GitHub Actions to SHA commits and update documentation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/ci.yml | 48 +++--- .../workflows/close-old-bot-discussions.yml | 4 +- .github/workflows/codeql.yml | 8 +- .github/workflows/copilot-setup-steps.yml | 6 +- .github/workflows/copilot.yml | 4 +- .github/workflows/docs.yml | 8 +- .github/workflows/format-and-commit.yml | 6 +- .github/workflows/install.yml | 8 +- .github/workflows/integration-agentics.yml | 4 +- .github/workflows/release.lock.yml | 6 +- .github/workflows/security-scan.yml | 6 +- .github/workflows/smoke-isolated-srt.yml | 4 +- .../test-copilot-github-integration.yml | 4 +- .../github-actions-security-best-practices.md | 149 +++++++++++++++++- 14 files changed, 203 insertions(+), 62 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3a87d4e780..e8a44b6d157 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,11 +21,11 @@ jobs: cancel-in-progress: true steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Go id: setup-go - uses: actions/setup-go@v6 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version-file: go.mod cache: true @@ -48,7 +48,7 @@ jobs: # Coverage reports for recent builds only - 7 days is sufficient for debugging recent changes - name: Upload coverage report - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: coverage-report path: coverage.html @@ -87,11 +87,11 @@ jobs: name: "Integration: ${{ matrix.test-group.name }}" steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Go id: setup-go - uses: actions/setup-go@v6 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version-file: go.mod cache: true @@ -125,10 +125,10 @@ jobs: cancel-in-progress: true steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Node.js id: setup-node - uses: actions/setup-node@v6 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 with: node-version: "24" cache: npm @@ -142,7 +142,7 @@ jobs: fi - name: Set up Go id: setup-go - uses: actions/setup-go@v6 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version-file: go.mod cache: true @@ -173,10 +173,10 @@ jobs: cancel-in-progress: true steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Node.js id: setup-node - uses: actions/setup-node@v6 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 with: node-version: "24" cache: npm @@ -202,11 +202,11 @@ jobs: cancel-in-progress: true steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Go id: setup-go - uses: actions/setup-go@v6 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version-file: go.mod cache: true @@ -227,7 +227,7 @@ jobs: # Benchmark results for performance trend analysis - 14 days allows comparison across multiple runs - name: Save benchmark results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: benchmark-results path: bench_results.txt @@ -243,11 +243,11 @@ jobs: cancel-in-progress: true steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Node.js id: setup-node - uses: actions/setup-node@v6 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 with: node-version: "24" cache: npm @@ -263,7 +263,7 @@ jobs: - name: Set up Go id: setup-go - uses: actions/setup-go@v6 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version-file: go.mod cache: true @@ -295,11 +295,11 @@ jobs: cancel-in-progress: true steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Go id: setup-go - uses: actions/setup-go@v6 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version-file: go.mod cache: true @@ -330,11 +330,11 @@ jobs: cancel-in-progress: true steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Go id: setup-go - uses: actions/setup-go@v6 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version-file: go.mod cache: true @@ -374,11 +374,11 @@ jobs: name: "Security Scan: ${{ matrix.tool.name }}" steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Go id: setup-go - uses: actions/setup-go@v6 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version-file: go.mod cache: true @@ -407,11 +407,11 @@ jobs: cancel-in-progress: true steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Go id: setup-go - uses: actions/setup-go@v6 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version-file: go.mod cache: true diff --git a/.github/workflows/close-old-bot-discussions.yml b/.github/workflows/close-old-bot-discussions.yml index 0bf14bb8c2f..cdd45f67cc5 100644 --- a/.github/workflows/close-old-bot-discussions.yml +++ b/.github/workflows/close-old-bot-discussions.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Close discussions older than 3 days - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 with: script: | const THREE_DAYS_MS = 3 * 24 * 60 * 60 * 1000; @@ -136,7 +136,7 @@ jobs: issues: write steps: - name: Close issues labeled smoke-claude older than 1 hour - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 with: script: | const ONE_HOUR_MS = 60 * 60 * 1000; diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index baf4101a4ae..9aa4fcfb0fe 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -22,17 +22,17 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@4248455a6f2335bc3b7a8a62932f000050ec8f13 # v3 with: languages: ${{ matrix.language }} queries: security-and-quality - name: Set up Go if: matrix.language == 'go' - uses: actions/setup-go@v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version-file: go.mod cache: true @@ -42,6 +42,6 @@ jobs: run: make build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@4248455a6f2335bc3b7a8a62932f000050ec8f13 # v3 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 22b42e8efe3..081b924844d 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -26,17 +26,17 @@ jobs: # If you do not check out your code, Copilot will do this for you. steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 with: node-version: "24" cache: npm cache-dependency-path: pkg/workflow/js/package-lock.json - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version-file: go.mod cache: true diff --git a/.github/workflows/copilot.yml b/.github/workflows/copilot.yml index a890af25d60..6625e1fa091 100644 --- a/.github/workflows/copilot.yml +++ b/.github/workflows/copilot.yml @@ -12,7 +12,7 @@ jobs: pull-requests: read steps: - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 with: node-version: '22' - name: Install GitHub Copilot CLI @@ -63,7 +63,7 @@ jobs: done - name: Upload execution logs if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: copilot-logs path: /tmp/logs/ diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 776706dfb89..a0e24c368ba 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -30,10 +30,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 with: node-version: '24' cache: 'npm' @@ -51,7 +51,7 @@ jobs: - name: Upload build artifacts if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3 with: path: ./docs/dist @@ -66,4 +66,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 \ No newline at end of file + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 \ No newline at end of file diff --git a/.github/workflows/format-and-commit.yml b/.github/workflows/format-and-commit.yml index a0a678c9702..6c337a56791 100644 --- a/.github/workflows/format-and-commit.yml +++ b/.github/workflows/format-and-commit.yml @@ -19,14 +19,14 @@ jobs: exit 78 - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version-file: go.mod cache: true - name: Set up Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 with: cache: npm cache-dependency-path: pkg/workflow/js/package-lock.json diff --git a/.github/workflows/install.yml b/.github/workflows/install.yml index 12dde6d32fa..cb720e515ba 100644 --- a/.github/workflows/install.yml +++ b/.github/workflows/install.yml @@ -31,7 +31,7 @@ jobs: - windows-latest steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Test install script detection logic shell: bash @@ -100,7 +100,7 @@ jobs: - name: Upload test results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: install-test-${{ matrix.os }} path: install-output.log @@ -116,10 +116,10 @@ jobs: issues: write steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Create issue on failure - uses: actions/github-script@v7 + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 with: script: | const workflowUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; diff --git a/.github/workflows/integration-agentics.yml b/.github/workflows/integration-agentics.yml index 8c1a4d5e61e..acd958fbfef 100644 --- a/.github/workflows/integration-agentics.yml +++ b/.github/workflows/integration-agentics.yml @@ -15,10 +15,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version-file: go.mod cache: true diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 184dd51541d..e459c176fb4 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -5968,19 +5968,19 @@ jobs: - name: Download Go modules run: go mod download - name: Generate SBOM (SPDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 with: artifact-name: sbom.spdx.json format: spdx-json output-file: sbom.spdx.json - name: Generate SBOM (CycloneDX format) - uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0 + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 with: artifact-name: sbom.cdx.json format: cyclonedx-json output-file: sbom.cdx.json - name: Upload SBOM artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 with: name: sbom-artifacts path: | diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index a989a959205..dd21e152f07 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -30,7 +30,7 @@ jobs: gosec -fmt sarif -out gosec-results.sarif -exclude-generated ./... - name: Upload Gosec SARIF - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@4248455a6f2335bc3b7a8a62932f000050ec8f13 # v3 if: always() with: sarif_file: gosec-results.sarif @@ -56,7 +56,7 @@ jobs: output-file: govulncheck-results.sarif - name: Upload govulncheck SARIF - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@4248455a6f2335bc3b7a8a62932f000050ec8f13 # v3 if: always() with: sarif_file: govulncheck-results.sarif @@ -80,7 +80,7 @@ jobs: exit-code: '1' - name: Upload Trivy SARIF - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@4248455a6f2335bc3b7a8a62932f000050ec8f13 # v3 if: always() with: sarif_file: trivy-results.sarif diff --git a/.github/workflows/smoke-isolated-srt.yml b/.github/workflows/smoke-isolated-srt.yml index 1aed84cf4c5..38812312cc7 100644 --- a/.github/workflows/smoke-isolated-srt.yml +++ b/.github/workflows/smoke-isolated-srt.yml @@ -18,10 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: '20' diff --git a/.github/workflows/test-copilot-github-integration.yml b/.github/workflows/test-copilot-github-integration.yml index 4b9946a485e..f53902a9c2d 100644 --- a/.github/workflows/test-copilot-github-integration.yml +++ b/.github/workflows/test-copilot-github-integration.yml @@ -12,7 +12,7 @@ jobs: pull-requests: read steps: - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6 with: node-version: '22' @@ -79,7 +79,7 @@ jobs: - name: Upload execution logs if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: agent-logs path: | diff --git a/specs/github-actions-security-best-practices.md b/specs/github-actions-security-best-practices.md index 32ded6c4dde..9cb38b16f92 100644 --- a/specs/github-actions-security-best-practices.md +++ b/specs/github-actions-security-best-practices.md @@ -310,12 +310,60 @@ steps: #### Finding SHA for Actions +There are several ways to find the SHA commit for a specific action version: + +**Method 1: Using git ls-remote (Recommended)** ```bash # Get SHA for a specific tag git ls-remote https://github.com/actions/checkout v4.1.1 +# Output: abc123def456... refs/tags/v4.1.1 + +# For actions with subpaths (like codeql-action) +git ls-remote https://github.com/github/codeql-action v3 +``` + +**Method 2: Using GitHub API** +```bash +# Get SHA for a tag +curl -s https://api.github.com/repos/actions/checkout/git/refs/tags/v4.1.1 | jq -r '.object.sha' + +# Get the latest release +curl -s https://api.github.com/repos/actions/checkout/releases/latest | jq -r '.tag_name' +``` + +**Method 3: Using GitHub Web UI** +1. Navigate to the action's GitHub repository (e.g., https://github.com/actions/checkout) +2. Click on the "Releases" or "Tags" section +3. Find the version tag you want (e.g., v4.1.1) +4. Click on the tag to see the commit +5. Copy the full SHA from the commit page + +**Method 4: Automated Script** +```bash +#!/bin/bash +# pin-action.sh - Get SHA for an action -# Or use GitHub API -curl -s https://api.github.com/repos/actions/checkout/git/refs/tags/v4.1.1 +get_sha() { + local action=$1 + local version=$2 + local repo=$(echo "$action" | cut -d'/' -f1-2) + + sha=$(git ls-remote "https://github.com/$repo" "refs/tags/$version" 2>/dev/null | awk '{print $1}') + + if [ -z "$sha" ]; then + sha=$(git ls-remote "https://github.com/$repo" "$version" 2>/dev/null | awk '{print $1}') + fi + + if [ -n "$sha" ]; then + echo "$action@$sha # $version" + else + echo "ERROR: Could not find SHA for $action@$version" >&2 + return 1 + fi +} + +# Usage: get_sha "actions/checkout" "v4.1.1" +get_sha "$1" "$2" ``` ### Verify Action Creators @@ -392,16 +440,109 @@ jobs: scan-ref: '.' ``` +### Maintaining Pinned Actions + +Once actions are pinned to SHA commits, they need to be updated periodically to get bug fixes and security updates. + +#### When to Update Pinned Actions + +- **Security advisories**: Immediately update when a security vulnerability is announced +- **Major releases**: Review and update when a new major version is released +- **Regular maintenance**: Update quarterly or semi-annually for bug fixes and improvements +- **Breaking changes**: Test thoroughly before updating to avoid CI/CD disruptions + +#### Update Process + +1. **Check for updates**: + ```bash + # List current versions in your workflows + grep -r "uses:.*# v" .github/workflows/ + + # Check for newer versions on GitHub + # Visit: https://github.com/actions/checkout/releases + ``` + +2. **Get new SHA**: + ```bash + # Get SHA for new version + git ls-remote https://github.com/actions/checkout v4.2.0 + ``` + +3. **Update workflow file**: + ```yaml + # Old + - uses: actions/checkout@abc123... # v4.1.1 + + # New + - uses: actions/checkout@def456... # v4.2.0 + ``` + +4. **Test the changes**: + - Run the workflow in a test branch + - Verify all jobs complete successfully + - Check for any behavioral changes + +5. **Document changes**: + - Note why the update was made (security fix, new feature, etc.) + - Update any related documentation + +#### Automated Update Tools + +**Dependabot** (Recommended for GitHub repositories): +```yaml +# .github/dependabot.yml +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + # Auto-merge minor and patch updates + open-pull-requests-limit: 10 +``` + +**Renovate Bot**: +```json +{ + "extends": ["config:base"], + "github-actions": { + "enabled": true, + "pinDigests": true + } +} +``` + +#### Finding All Unpinned Actions + +Use this command to identify any remaining unpinned actions: + +```bash +# Find all unpinned actions (not using SHA) +grep -r "uses:" .github/workflows/*.yml .github/workflows/*.yaml | \ + grep -v "@[0-9a-f]\{40\}" | \ + grep -v "^#" | \ + grep -v ".lock.yml" + +# Count pinned vs unpinned +echo "Pinned actions:" +grep -r "uses:" .github/workflows/*.yml | grep "@[0-9a-f]\{40\}" | wc -l + +echo "Unpinned actions:" +grep -r "uses:" .github/workflows/*.yml | grep -v "@[0-9a-f]\{40\}" | grep -v "^#" | wc -l +``` + ### Supply Chain Security Checklist - ✅ Pin all actions to immutable SHA references -- ✅ Add version comments to pinned SHAs +- ✅ Add version comments to pinned SHAs (format: `@sha # v1.2.3`) - ✅ Review action source code before first use - ✅ Use actions from verified creators when possible - ✅ Regularly update pinned actions (but review changes) - ✅ Scan dependencies for vulnerabilities - ✅ Monitor security advisories for used actions - ✅ Use Dependabot or Renovate for automated updates +- ✅ Document update procedures for your team +- ✅ Test updated actions before merging to main branch --- @@ -875,6 +1016,6 @@ Use this checklist when creating or reviewing GitHub Actions workflows: --- -**Last Updated**: 2025-11-06 +**Last Updated**: 2025-12-06 **Status**: ✅ Documented **Implementation**: See workflow examples in `.github/workflows/` and `pkg/cli/workflows/`