diff --git a/.github/actions/setup-mux/action.yml b/.github/actions/setup-mux/action.yml index 4258e9e8b1..5ff11ceb9c 100644 --- a/.github/actions/setup-mux/action.yml +++ b/.github/actions/setup-mux/action.yml @@ -4,7 +4,7 @@ runs: using: "composite" steps: - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 with: bun-version: 1.3.5 @@ -15,7 +15,7 @@ runs: - name: Cache node_modules id: cache-node-modules - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: node_modules key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ steps.bun-version.outputs.version }}-node-modules-${{ hashFiles('**/bun.lock') }} @@ -37,7 +37,7 @@ runs: - name: Cache bun install cache if: steps.check-node-modules.outputs.exists != 'true' id: cache-bun-install - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.bun/install/cache key: ${{ runner.os }}-bun-cache-${{ hashFiles('**/bun.lock') }} @@ -58,7 +58,7 @@ runs: # Cache Electron binaries and electron-builder resources (NSIS, etc.) # These are downloaded during electron-builder and can be 200MB+ total - name: Cache Electron - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/.cache/electron @@ -69,7 +69,7 @@ runs: ${{ runner.os }}-${{ runner.arch }}-electron- - name: Cache electron-builder - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/.cache/electron-builder diff --git a/.github/actions/setup-ollama/action.yml b/.github/actions/setup-ollama/action.yml index 55db4e07bf..8031cb5f6e 100644 --- a/.github/actions/setup-ollama/action.yml +++ b/.github/actions/setup-ollama/action.yml @@ -6,14 +6,14 @@ runs: steps: - name: Cache Ollama binary id: cache-ollama-binary - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ./.ollama-install key: ${{ runner.os }}-ollama-binary-v2 - name: Cache Ollama models id: cache-ollama-models - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.ollama key: ${{ runner.os }}-ollama-models-v2 diff --git a/.github/actions/setup-playwright/action.yml b/.github/actions/setup-playwright/action.yml index 046d0f8a3c..d237110bc2 100644 --- a/.github/actions/setup-playwright/action.yml +++ b/.github/actions/setup-playwright/action.yml @@ -19,7 +19,7 @@ runs: - name: Cache Playwright browsers id: cache-playwright - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.cache/ms-playwright key: ${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.version }}-${{ inputs.browsers }} diff --git a/.github/workflows/auto-label.yml b/.github/workflows/auto-label.yml index b80c35c595..a14cc17c4c 100644 --- a/.github/workflows/auto-label.yml +++ b/.github/workflows/auto-label.yml @@ -19,10 +19,10 @@ jobs: runs-on: ubuntu-latest if: github.actor != 'dependabot[bot]' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 - name: Label with mux env: diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml index 340815d034..eaca9c5f6e 100644 --- a/.github/workflows/chromatic.yml +++ b/.github/workflows/chromatic.yml @@ -15,7 +15,7 @@ jobs: if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'push' steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 # Required for Chromatic to track changes persist-credentials: false @@ -32,7 +32,7 @@ jobs: run: bun x storybook build --stats-json - name: Run Chromatic - uses: chromaui/action@latest + uses: chromaui/action@07791f8243f4cb2698bf4d00426baf4b2d1cb7e0 # v13.3.5 with: projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} exitZeroOnChanges: true diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 567dba5d38..a23aa45ea5 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -35,10 +35,10 @@ jobs: backend: ${{ steps.filter.outputs.backend }} browser: ${{ steps.filter.outputs.browser }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false - - uses: dorny/paths-filter@v3 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: filter with: filters: | @@ -72,13 +72,13 @@ jobs: if: github.event_name != 'push' || github.actor != 'github-merge-queue[bot]' runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 persist-credentials: false - uses: ./.github/actions/setup-mux - run: ./scripts/generate-version.sh - - uses: actions/cache@v4 + - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.local/bin/shfmt key: ${{ runner.os }}-shfmt-latest @@ -101,7 +101,7 @@ jobs: set -euo pipefail sudo apt-get update sudo apt-get install -y shellcheck - - uses: cachix/install-nix-action@v27 + - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 with: extra_nix_config: | experimental-features = nix-command flakes @@ -120,7 +120,7 @@ jobs: if: ${{ (needs.changes.outputs.src == 'true' || needs.changes.outputs.config == 'true') && (github.event_name != 'push' || github.actor != 'github-merge-queue[bot]') }} runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false - uses: ./.github/actions/setup-mux @@ -128,7 +128,7 @@ jobs: # workflow_dispatch inputs are only triggerable by repo members, so direct # interpolation is acceptable and preserves shell quoting in the filter. - run: bun test --coverage --coverage-reporter=lcov ${{ github.event.inputs.test_filter || 'src' }} # zizmor: ignore[template-injection] - - uses: codecov/codecov-action@v5 + - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage/lcov.info @@ -142,7 +142,7 @@ jobs: timeout-minutes: 10 runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false - uses: ./.github/actions/setup-mux @@ -179,7 +179,7 @@ jobs: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} BACKEND: ${{ needs.changes.outputs.backend }} BROWSER: ${{ needs.changes.outputs.browser }} - - uses: codecov/codecov-action@v5 + - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage/lcov.info @@ -192,7 +192,7 @@ jobs: if: ${{ (needs.changes.outputs.src == 'true' || needs.changes.outputs.config == 'true') && github.event.inputs.test_filter == '' && (github.event_name != 'push' || github.actor != 'github-merge-queue[bot]') }} runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false - uses: ./.github/actions/setup-mux @@ -226,7 +226,7 @@ jobs: runner: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest' }} runs-on: ${{ matrix.runner }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false - uses: ./.github/actions/setup-mux @@ -251,7 +251,7 @@ jobs: if: ${{ (needs.changes.outputs.src == 'true' || needs.changes.outputs.config == 'true') && (github.event_name != 'push' || github.actor != 'github-merge-queue[bot]') }} runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 persist-credentials: false @@ -266,7 +266,7 @@ jobs: # shellcheck disable=SC2012 # ls is fine here - known filename pattern in controlled directory TARBALL=$(ls mux-*.tgz | head -1) PACKAGE_TARBALL="$TARBALL" ./scripts/smoke-test.sh - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: failure() with: name: smoke-server-logs @@ -280,12 +280,12 @@ jobs: if: github.event_name == 'merge_group' || (github.event_name == 'push' && github.actor != 'github-merge-queue[bot]') runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 persist-credentials: false - - uses: docker/setup-buildx-action@v3 - - uses: docker/build-push-action@v6 + - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: context: . load: true @@ -313,14 +313,14 @@ jobs: if: ${{ (needs.changes.outputs.src == 'true' || needs.changes.outputs.config == 'true') && (github.event_name != 'push' || github.actor != 'github-merge-queue[bot]') }} runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 persist-credentials: false - uses: ./.github/actions/setup-mux - run: bun run build - run: make dist-linux - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: build-linux path: release/*.AppImage @@ -333,7 +333,7 @@ jobs: if: ${{ needs.changes.outputs.src == 'true' || needs.changes.outputs.config == 'true' }} runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-15' || 'macos-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 persist-credentials: false @@ -348,13 +348,13 @@ jobs: AC_APIKEY_ID: ${{ secrets.AC_APIKEY_ID }} AC_APIKEY_ISSUER_ID: ${{ secrets.AC_APIKEY_ISSUER_ID }} - run: make dist-mac - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: build-macos-x64 path: release/*-x64.dmg retention-days: 30 if-no-files-found: error - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: build-macos-arm64 path: release/*-arm64.dmg @@ -368,7 +368,7 @@ jobs: if: ${{ (github.event_name == 'merge_group' || (github.event_name == 'push' && github.ref == 'refs/heads/main')) && (needs.changes.outputs.src == 'true' || needs.changes.outputs.config == 'true') }} runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 persist-credentials: false @@ -403,7 +403,7 @@ jobs: EV_KEY: ${{ vars.EV_KEY }} EV_TSA_URL: ${{ vars.EV_TSA_URL }} GCLOUD_ACCESS_TOKEN: ${{ steps.signing.outputs.gcloud_access_token }} - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: build-windows path: release/*.exe @@ -416,13 +416,13 @@ jobs: if: ${{ (needs.changes.outputs.src == 'true' || needs.changes.outputs.config == 'true') && (github.event_name != 'push' || github.actor != 'github-merge-queue[bot]') }} runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 persist-credentials: false - uses: ./.github/actions/setup-mux - uses: ./.github/actions/build-vscode-extension - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: build-vscode path: vscode/mux-*.vsix @@ -434,7 +434,7 @@ jobs: if: github.event_name == 'pull_request' runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index c5507dda5f..679bbb8636 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -29,7 +29,7 @@ jobs: id-token: write # Required for OIDC trusted publishing steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 # Required for git describe to find tags persist-credentials: false @@ -38,7 +38,7 @@ jobs: # Setup Node.js 24+ for npm v11+ required by OIDC trusted publishing. # Node 22 ships with npm 10.x which does NOT support OIDC. - - uses: actions/setup-node@v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" @@ -104,7 +104,7 @@ jobs: - name: Upload server logs on smoke test failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: smoke-test-logs path: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e906703036..2c9d7763eb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-15' || 'macos-latest' }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: ref: ${{ inputs.tag || github.ref }} fetch-depth: 0 # Required for git describe to find tags @@ -80,7 +80,7 @@ jobs: runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: ref: ${{ inputs.tag || github.ref }} fetch-depth: 0 # Required for git describe to find tags @@ -102,7 +102,7 @@ jobs: runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: ref: ${{ inputs.tag || github.ref }} fetch-depth: 0 # Required for git describe to find tags @@ -155,7 +155,7 @@ jobs: runs-on: windows-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: ref: ${{ inputs.tag || github.ref }} fetch-depth: 0 @@ -200,7 +200,7 @@ jobs: GCLOUD_ACCESS_TOKEN: ${{ steps.signing.outputs.gcloud_access_token }} - name: Upload Windows artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: windows-release path: | diff --git a/.github/workflows/terminal-bench.yml b/.github/workflows/terminal-bench.yml index ed76d7b1bb..7543b6f62e 100644 --- a/.github/workflows/terminal-bench.yml +++ b/.github/workflows/terminal-bench.yml @@ -102,7 +102,7 @@ jobs: timeout-minutes: 240 steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 # Required for git describe to find tags persist-credentials: false @@ -202,7 +202,7 @@ jobs: - name: Upload benchmark results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ${{ steps.artifact-name.outputs.name }} path: | diff --git a/.github/zizmor.yml b/.github/zizmor.yml index 8ea9a082e3..e23e42abdf 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -2,12 +2,6 @@ # https://docs.zizmor.sh/configuration/ rules: - # TODO: Pin all actions to SHA hashes instead of version tags. - # Version tags like @v4 can be moved by maintainers, which is a supply chain risk. - # Use a tool like pinact (https://github.com/suzuki-shunsuke/pinact) to auto-pin. - unpinned-uses: - disable: true - # TODO: Move these workflow-level permissions to job-level for least-privilege. # These permissions are documented in the workflow files with specific reasons. # Moving to job-level requires restructuring since multiple jobs need them. diff --git a/Makefile b/Makefile index ca83a2be4f..fe2adf17b9 100644 --- a/Makefile +++ b/Makefile @@ -294,6 +294,9 @@ SHELL_SRC_FILES := $(shell find . -not \( -path '*/.git/*' -o -path './node_modu lint-shellcheck: ## Run shellcheck on shell scripts shellcheck --external-sources $(SHELL_SRC_FILES) +pin-actions: ## Pin GitHub Actions to SHA hashes (requires GH_TOKEN or gh CLI) + ./scripts/pin-actions.sh .github/workflows/*.yml .github/actions/*/action.yml + ifeq ($(OS),Windows_NT) typecheck: node_modules/.installed src/version.ts $(BUILTIN_AGENTS_GENERATED) $(BUILTIN_SKILLS_GENERATED) ## Run TypeScript type checking (uses tsgo for 10x speedup) @# On Windows, use npm run because bun x doesn't correctly pass arguments diff --git a/docs/guides/github-actions.mdx b/docs/guides/github-actions.mdx index d274e6dec9..8df357bbc0 100644 --- a/docs/guides/github-actions.mdx +++ b/docs/guides/github-actions.mdx @@ -60,10 +60,10 @@ jobs: runs-on: ubuntu-latest if: github.actor != 'dependabot[bot]' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 - name: Label with mux env: diff --git a/scripts/pin-actions.sh b/scripts/pin-actions.sh new file mode 100755 index 0000000000..48c6648052 --- /dev/null +++ b/scripts/pin-actions.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# Downloads pinact and runs it to pin all GitHub Actions to SHA hashes. +# Usage: ./pin-actions.sh [files...] +# +# If no files are specified, defaults to all workflow and action files. + +set -euo pipefail + +VERSION="v3.8.0" +TMPDIR="$(mktemp -d)" +trap 'rm -rf "$TMPDIR"' EXIT + +# Detect OS and architecture +OS="$(uname -s | tr '[:upper:]' '[:lower:]')" +ARCH="$(uname -m)" +case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64 | arm64) ARCH="arm64" ;; +esac + +# Download pinact +TARBALL="pinact_${OS}_${ARCH}.tar.gz" +curl -sSfL "https://github.com/suzuki-shunsuke/pinact/releases/download/${VERSION}/${TARBALL}" | tar xz -C "$TMPDIR" + +# Run pinact with GitHub token +export GITHUB_TOKEN="${GH_TOKEN:-$(gh auth token)}" +"$TMPDIR/pinact" run "$@"