From 63fd260b030cd717edcc991396e8a336584c27fa Mon Sep 17 00:00:00 2001 From: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com> Date: Tue, 18 Mar 2025 10:00:04 -0700 Subject: [PATCH] Fix github actions to specific commit hashes --- .github/workflows/backport.yml | 2 +- .github/workflows/benchmark.yml | 16 ++-- .github/workflows/ci.yml | 96 ++++++++++------------- .github/workflows/danger.yml | 6 +- .github/workflows/icu-book.yml | 14 ++-- .github/workflows/notes.yml | 2 +- .github/workflows/release-notes.yml | 2 +- .github/workflows/stories.yml | 12 +-- ts/scripts/update-gha.ts | 117 ++++++++++++++++++++++++++++ 9 files changed, 184 insertions(+), 83 deletions(-) create mode 100644 ts/scripts/update-gha.ts diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 73efa00da..4d8ce3094 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: token: ${{ secrets.AUTOMATED_GITHUB_PAT }} repository: signalapp/Signal-Backport-Action-Private diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 7af00e4b6..21c3d8c4d 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -25,27 +25,27 @@ jobs: run: uname -a - name: Clone Desktop repo - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - name: Restore sccache - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 id: cache-sccache with: path: ${{ env.SCCACHE_PATH }} key: sccache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'patches/**') }} - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' cache: 'pnpm' cache-dependency-path: 'pnpm-lock.yaml' - name: Cache .electron-gyp - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ~/.electron-gyp key: electron-gyp-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} @@ -201,13 +201,13 @@ jobs: - name: Upload benchmark logs on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 with: name: logs path: artifacts - name: Clone benchmark repo - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: repository: 'signalapp/Signal-Desktop-Benchmarks-Private' path: 'benchmark-results' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eeb6c6bec..80a0b458d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,31 +18,31 @@ jobs: steps: - run: lsb_release -a - run: uname -a - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' cache: 'pnpm' cache-dependency-path: 'pnpm-lock.yaml' - name: Cache .electron-gyp - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ~/.electron-gyp key: electron-gyp-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - name: Restore sccache - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ${{ env.SCCACHE_PATH }} key: sccache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'patches/**') }} - name: Restore cached .eslintcache and tsconfig.tsbuildinfo - uses: actions/cache/restore@v4 + uses: actions/cache/restore@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 id: cache-lint with: path: | @@ -71,7 +71,7 @@ jobs: - run: git diff --exit-code - name: Update cached .eslintcache and tsconfig.tsbuildinfo - uses: actions/cache/save@v4 + uses: actions/cache/save@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 if: github.ref == 'refs/heads/main' with: path: | @@ -87,25 +87,25 @@ jobs: steps: - run: uname -a - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' cache: 'pnpm' cache-dependency-path: 'pnpm-lock.yaml' - name: Cache .electron-gyp - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ~/.electron-gyp key: electron-gyp-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - name: Restore sccache - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ${{ env.SCCACHE_PATH }} key: sccache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'patches/**') }} @@ -149,7 +149,7 @@ jobs: - name: Upload artifacts on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 with: path: artifacts @@ -161,17 +161,17 @@ jobs: steps: - run: lsb_release -a - run: uname -a - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' cache: 'pnpm' cache-dependency-path: 'pnpm-lock.yaml' - name: Cache .electron-gyp - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ~/.electron-gyp key: electron-gyp-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} @@ -180,9 +180,9 @@ jobs: run: sudo apt-get install xvfb libpulse0 || (sudo apt-get update && sudo apt-get install xvfb libpulse0) - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - name: Restore sccache - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ${{ env.SCCACHE_PATH }} key: sccache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'patches/**') }} @@ -231,7 +231,7 @@ jobs: - run: xvfb-run --auto-servernum pnpm run test-node - name: Clone backup integration tests - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: repository: 'signalapp/Signal-Message-Backup-Tests' ref: 'a743fbf8e3adc2f1a700577dd8a470beff60db3f' @@ -251,7 +251,7 @@ jobs: - name: Upload artifacts on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 with: path: artifacts @@ -260,44 +260,28 @@ jobs: runs-on: windows-2019 timeout-minutes: 30 - env: - BUILD_LOCATION: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Tools\\MSVC\\14.29.30133\\lib\\x86\\store\\references\\" - SDK_LOCATION: "C:\\Program Files (x86)\\Windows Kits\\10\\UnionMetadata\\10.0.17134.0" - steps: - run: systeminfo - run: git config --global core.autocrlf false - run: git config --global core.eol lf - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' + cache: 'pnpm' + cache-dependency-path: 'pnpm-lock.yaml' - name: Cache .electron-gyp - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ${{ env.SCCACHE_PATH }}\.electron-gyp key: electron-gyp-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - run: pnpm install -g node-gyp@10.0.1 - # Set things up so @nodert-win10-rs4 dependencies build properly - - run: dir "$env:BUILD_LOCATION" - - run: dir "$env:SDK_LOCATION" - - run: "copy \"$env:BUILD_LOCATION\\platform.winmd\" \"$env:SDK_LOCATION\"" - - run: dir "$env:SDK_LOCATION" - - - name: Cache Desktop node_modules - id: cache-desktop-modules - uses: actions/cache@v4 - with: - path: node_modules - key: ${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'patches/**') }} - - name: Install Desktop node_modules - if: steps.cache-desktop-modules.outputs.cache-hit != 'true' run: pnpm install env: CHILD_CONCURRENCY: 1 @@ -344,7 +328,7 @@ jobs: - name: Upload artifacts on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 with: path: artifacts @@ -358,11 +342,11 @@ jobs: working-directory: sticker-creator steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' @@ -397,18 +381,18 @@ jobs: run: uname -a - name: Clone Desktop repo - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' cache: 'pnpm' cache-dependency-path: 'pnpm-lock.yaml' - name: Cache .electron-gyp - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ~/.electron-gyp key: electron-gyp-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} @@ -417,9 +401,9 @@ jobs: run: sudo apt-get install xvfb libpulse0 || (sudo apt-get update && sudo apt-get install xvfb libpulse0) - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - name: Restore sccache - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ${{ env.SCCACHE_PATH }} key: sccache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'patches/**') }} @@ -453,7 +437,7 @@ jobs: - name: Upload mock server test logs on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 with: name: logs path: artifacts diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml index 184f482be..c0d12f2fb 100644 --- a/.github/workflows/danger.yml +++ b/.github/workflows/danger.yml @@ -10,13 +10,13 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 # fetch all history - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' - name: Install danger node_modules diff --git a/.github/workflows/icu-book.yml b/.github/workflows/icu-book.yml index a882030ef..98e245b7d 100644 --- a/.github/workflows/icu-book.yml +++ b/.github/workflows/icu-book.yml @@ -13,25 +13,25 @@ jobs: if: ${{ github.repository == 'signalapp/Signal-Desktop-Private' }} timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' cache: 'pnpm' cache-dependency-path: 'pnpm-lock.yaml' - name: Cache .electron-gyp - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ~/.electron-gyp key: electron-gyp-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - name: Restore sccache - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 id: cache-sccache with: path: ${{ env.SCCACHE_PATH }} @@ -53,7 +53,7 @@ jobs: - run: pnpm run build:esbuild - run: node ts/scripts/compile-stories-icu-lookup.js stories - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 with: name: desktop-${{ github.ref_name }}-icu path: stories diff --git a/.github/workflows/notes.yml b/.github/workflows/notes.yml index 18f870aa2..e4c7741b0 100644 --- a/.github/workflows/notes.yml +++ b/.github/workflows/notes.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: token: ${{ secrets.AUTOMATED_GITHUB_PAT }} repository: signalapp/Signal-Notes-Action-Private diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml index aea3569c6..128e46809 100644 --- a/.github/workflows/release-notes.yml +++ b/.github/workflows/release-notes.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: token: ${{ secrets.AUTOMATED_GITHUB_PAT }} repository: signalapp/Signal-Release-Notes-Action-Private diff --git a/.github/workflows/stories.yml b/.github/workflows/stories.yml index ab444728e..09c717999 100644 --- a/.github/workflows/stories.yml +++ b/.github/workflows/stories.yml @@ -13,25 +13,25 @@ jobs: runs-on: ubuntu-latest-8-cores timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4 - name: Setup node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4 with: node-version-file: '.nvmrc' cache: 'pnpm' cache-dependency-path: 'pnpm-lock.yaml' - name: Cache .electron-gyp - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 with: path: ~/.electron-gyp key: electron-gyp-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - name: Restore sccache - uses: actions/cache@v4 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 id: cache-sccache with: path: ${{ env.SCCACHE_PATH }} diff --git a/ts/scripts/update-gha.ts b/ts/scripts/update-gha.ts new file mode 100644 index 000000000..e4e7c39ac --- /dev/null +++ b/ts/scripts/update-gha.ts @@ -0,0 +1,117 @@ +// Copyright 2025 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { join } from 'node:path'; +import { readFile, readdir, writeFile } from 'node:fs/promises'; +import z from 'zod'; +import semver from 'semver'; + +import { drop } from '../util/drop'; +import { strictAssert } from '../util/assert'; + +const { GITHUB_TOKEN } = process.env; + +const WORKFLOWS_DIR = join(__dirname, '..', '..', '.github', 'workflows'); + +const REGEXP = + /uses:\s*(?[^\s]+)@(?[^\s#]+)(?:\s*#\s*(?[^\n]+))?/g; + +const CACHE = new Map(); + +const TagsSchema = z + .object({ + name: z.string(), + commit: z.object({ + sha: z.string(), + }), + }) + .array(); + +async function updateAction(fullPath: string): Promise { + const source = await readFile(fullPath, 'utf8'); + + for (const { groups } of source.matchAll(REGEXP)) { + strictAssert(groups != null, 'Expected regexp to fully match'); + const { path, ref, originalRef } = groups; + + // Skip local actions + if (path.startsWith('.')) { + continue; + } + + // Skip internal actions + if (path.startsWith('signalapp/')) { + continue; + } + + const cacheKey = `${path}@${originalRef}`; + if (CACHE.has(cacheKey)) { + continue; + } + + const [org, repo] = path.split('/', 2); + + const url = + `https://api.github.com/repos/${encodeURIComponent(org)}/` + + `${encodeURIComponent(repo)}/tags`; + + // eslint-disable-next-line no-await-in-loop + const res = await fetch(url, { + headers: { + authorization: GITHUB_TOKEN ? `Bearer ${GITHUB_TOKEN}` : '', + 'user-agent': + 'Mozilla/5.0 (Macintosh; ' + + 'Intel Mac OS X 10.15; rv:136.0) Gecko/20100101 Firefox/136.0', + }, + }); + if (!res.ok) { + throw new Error(`Failed to fetch ${url}, status: ${res.status}`); + } + + // eslint-disable-next-line no-await-in-loop + const tags = TagsSchema.parse(await res.json()) + // Filter out invalid tags + .filter(tag => semver.valid(tag.name)) + // Sort by latest release first + .sort((a, b) => semver.compare(b.name, a.name)); + + const targetRef = originalRef ?? ref; + let range = targetRef; + + // Pad tag to be valid semver range + if (/^v\d+$/.test(range)) { + range = `^${range}.0.0`; + } else if (/^v\d+\.d+$/.test(range)) { + range = `^${range}.0`; + } + + // Pick first match + const match = tags.find(tag => semver.satisfies(tag.name, range)); + if (!match) { + throw new Error(`Tag ${targetRef} not found for ${path}`); + } + + CACHE.set(cacheKey, `uses: ${path}@${match.commit.sha} # ${targetRef}`); + } + + const result = source.replace( + REGEXP, + (match, _p1, _p2, _p3, _offset, _string, groups) => { + const { path, originalRef } = groups; + + const cacheKey = `${path}@${originalRef}`; + return CACHE.get(cacheKey) || match; + } + ); + await writeFile(fullPath, result); +} + +async function main(): Promise { + const actions = await readdir(WORKFLOWS_DIR); + + for (const name of actions) { + // eslint-disable-next-line no-await-in-loop + await updateAction(join(WORKFLOWS_DIR, name)); + } +} +drop(main());