From 93e10580c6773248e738a3982ce0c5e22f35e9df Mon Sep 17 00:00:00 2001 From: Pheidon Date: Sun, 31 May 2026 15:12:00 +0000 Subject: [PATCH 1/3] ci: run workflows on self-hosted runners --- .github/workflows/ci.yml | 18 +++++++++++++++--- .github/workflows/claude.yml | 6 +++++- .github/workflows/pr-fast-ci.yml | 24 ++++++++++++++++++++---- .github/workflows/release-image.yml | 6 +++++- .github/workflows/rg-ci.yml | 6 +++++- .github/workflows/rg-release.yml | 6 +++++- .github/workflows/rg-security.yml | 6 +++++- .github/workflows/scorecard.yml | 6 +++++- .github/workflows/security.yml | 18 +++++++++++++++--- test/release-workflow.test.ts | 8 +++++--- test/security-workflow.test.ts | 10 ++++++---- test/workflow.test.ts | 23 +++++++++++++---------- 12 files changed, 104 insertions(+), 33 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3177d13..528a7bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,11 @@ jobs: test_self_hosted_trusted: name: test if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 15 steps: - uses: actions/checkout@v6 @@ -108,7 +112,11 @@ jobs: linux_docker_contract_trusted: name: linux docker contract if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 20 steps: - uses: actions/checkout@v6 @@ -165,7 +173,11 @@ jobs: lume_macos_contract_trusted: name: lume macos contract if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - runs-on: macos-latest + runs-on: + - self-hosted + - macOS + - ARM64 + - xcode timeout-minutes: 20 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 4355b52..c07192b 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -29,7 +29,11 @@ jobs: (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 30 permissions: contents: write diff --git a/.github/workflows/pr-fast-ci.yml b/.github/workflows/pr-fast-ci.yml index d2256a0..6b9a1da 100644 --- a/.github/workflows/pr-fast-ci.yml +++ b/.github/workflows/pr-fast-ci.yml @@ -23,7 +23,11 @@ defaults: jobs: changes: name: Detect Relevant Changes - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public outputs: app: ${{ steps.filter.outputs.app }} ci: ${{ steps.filter.outputs.ci }} @@ -57,7 +61,11 @@ jobs: fast-checks: name: Fast Checks - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 15 needs: changes if: >- @@ -83,7 +91,11 @@ jobs: validate-secrets: name: Validate Secrets - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 10 if: >- github.event.pull_request.draft == false && @@ -141,7 +153,11 @@ jobs: ci-gate: name: CI Gate - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public if: always() needs: - changes diff --git a/.github/workflows/release-image.yml b/.github/workflows/release-image.yml index 50523e0..d0680fa 100644 --- a/.github/workflows/release-image.yml +++ b/.github/workflows/release-image.yml @@ -25,7 +25,11 @@ concurrency: jobs: publish_and_verify: name: publish-and-verify - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} SYNOLOGY_RUNNER_BASE_DIR: /volume1/docker/github-runner-fleet diff --git a/.github/workflows/rg-ci.yml b/.github/workflows/rg-ci.yml index f3beb01..c7446ba 100644 --- a/.github/workflows/rg-ci.yml +++ b/.github/workflows/rg-ci.yml @@ -27,7 +27,11 @@ permissions: jobs: ci: name: rg-ci - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 20 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/rg-release.yml b/.github/workflows/rg-release.yml index 019e6fb..37f189a 100644 --- a/.github/workflows/rg-release.yml +++ b/.github/workflows/rg-release.yml @@ -29,7 +29,11 @@ permissions: jobs: release: name: rg-release - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 45 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/rg-security.yml b/.github/workflows/rg-security.yml index 9a92095..b627857 100644 --- a/.github/workflows/rg-security.yml +++ b/.github/workflows/rg-security.yml @@ -20,7 +20,11 @@ permissions: jobs: security: name: rg-security - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 20 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 2f5daf0..72b26a4 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -16,7 +16,11 @@ permissions: jobs: scorecard: name: openssf-scorecard - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 15 steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 97e7899..dfd42b1 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -18,7 +18,11 @@ permissions: jobs: codeql: name: codeql - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 20 steps: - uses: actions/checkout@v6 @@ -30,7 +34,11 @@ jobs: dependency_review: name: dependency-review if: github.event_name == 'pull_request' - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 10 steps: - uses: actions/checkout@v6 @@ -41,7 +49,11 @@ jobs: osv: name: osv - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux + - shell-only + - public timeout-minutes: 10 steps: - uses: actions/checkout@v6 diff --git a/test/release-workflow.test.ts b/test/release-workflow.test.ts index 4d68722..05da8ab 100644 --- a/test/release-workflow.test.ts +++ b/test/release-workflow.test.ts @@ -3,8 +3,10 @@ import path from "node:path"; import YAML from "yaml"; import { describe, expect, test } from "vitest"; +const shellSafePublicRunner = ["self-hosted", "linux", "shell-only", "public"]; + describe("release workflow", () => { - test("publishes on hosted runners, verifies the pushed tag, and can create a repo release from main", () => { + test("publishes on shell-safe self-hosted runners, verifies the pushed tag, and can create a repo release from main", () => { const workflow = YAML.parse( fs.readFileSync( path.resolve(".github/workflows/release-image.yml"), @@ -16,7 +18,7 @@ describe("release workflow", () => { jobs: Record< string, { - "runs-on": string; + "runs-on": string | string[]; env: Record; steps: Array>; } @@ -39,7 +41,7 @@ describe("release workflow", () => { "id-token": "write", attestations: "write" }); - expect(job["runs-on"]).toBe("ubuntu-latest"); + expect(job["runs-on"]).toEqual(shellSafePublicRunner); expect(job.env).toMatchObject({ GITHUB_PAT: "${{ secrets.GITHUB_TOKEN }}", SYNOLOGY_RUNNER_BASE_DIR: "/volume1/docker/github-runner-fleet" diff --git a/test/security-workflow.test.ts b/test/security-workflow.test.ts index 81ea726..4809344 100644 --- a/test/security-workflow.test.ts +++ b/test/security-workflow.test.ts @@ -3,8 +3,10 @@ import path from "node:path"; import YAML from "yaml"; import { describe, expect, test } from "vitest"; +const shellSafePublicRunner = ["self-hosted", "linux", "shell-only", "public"]; + describe("security and reusable workflows", () => { - test("keeps security scans on hosted runners with Security tab upload", () => { + test("keeps security scans on shell-safe self-hosted runners with Security tab upload", () => { const workflow = YAML.parse( fs.readFileSync(path.resolve(".github/workflows/security.yml"), "utf8") ) as { permissions: Record; jobs: Record> }; @@ -14,7 +16,7 @@ describe("security and reusable workflows", () => { "security-events": "write" }); for (const job of Object.values(workflow.jobs)) { - expect(job["runs-on"]).toBe("ubuntu-latest"); + expect(job["runs-on"]).toEqual(shellSafePublicRunner); } expect(String(JSON.stringify(workflow))).toContain("github/codeql-action/init"); expect(String(JSON.stringify(workflow))).toContain("dependency-review-action"); @@ -40,7 +42,7 @@ describe("security and reusable workflows", () => { "id-token": "write", "security-events": "write" }); - expect(workflow.jobs.scorecard["runs-on"]).toBe("ubuntu-latest"); + expect(workflow.jobs.scorecard["runs-on"]).toEqual(shellSafePublicRunner); expect(String(JSON.stringify(workflow))).toContain("publish_results"); }); @@ -52,7 +54,7 @@ describe("security and reusable workflows", () => { expect(workflow.on).toHaveProperty("workflow_call"); for (const job of Object.values(workflow.jobs)) { - expect(job["runs-on"]).toBe("ubuntu-latest"); + expect(job["runs-on"]).toEqual(shellSafePublicRunner); } } }); diff --git a/test/workflow.test.ts b/test/workflow.test.ts index 8499f8a..a98169c 100644 --- a/test/workflow.test.ts +++ b/test/workflow.test.ts @@ -3,6 +3,9 @@ import path from "node:path"; import YAML from "yaml"; import { describe, expect, test } from "vitest"; +const shellSafePublicRunner = ["self-hosted", "linux", "shell-only", "public"]; +const macosXcodeRunner = ["self-hosted", "macOS", "ARM64", "xcode"]; + describe("CI workflow", () => { test("runs mutation testing in extended validation and uploads the report", () => { const workflow = YAML.parse( @@ -92,7 +95,7 @@ describe("CI workflow", () => { expect(gateJob.needs).toContain("drift-detect"); }); - test("keeps required trusted CI on hosted runners when shell-safe capacity is absent", () => { + test("keeps required trusted CI on shell-safe self-hosted runners", () => { const workflow = YAML.parse( fs.readFileSync(path.resolve(".github/workflows/ci.yml"), "utf8") ) as { @@ -112,7 +115,7 @@ describe("CI workflow", () => { (step) => step.uses === "actions/setup-node@v6" ); - expect(trustedJob["runs-on"]).toBe("ubuntu-latest"); + expect(trustedJob["runs-on"]).toEqual(shellSafePublicRunner); expect(pnpmStep?.with).toMatchObject({ version: "10.32.1" }); @@ -186,7 +189,7 @@ describe("CI workflow", () => { expect(workflow.jobs.test_public_fork_pr["runs-on"]).toBe("ubuntu-latest"); }); - test("keeps PR fast checks on hosted runners and gates same-repo and fork paths", () => { + test("keeps PR fast checks on self-hosted runners and gates same-repo and fork paths", () => { const workflow = YAML.parse( fs.readFileSync(path.resolve(".github/workflows/pr-fast-ci.yml"), "utf8") ) as { @@ -198,7 +201,7 @@ describe("CI workflow", () => { workflow.jobs["validate-secrets"] ]; for (const job of selfHostedJobs) { - expect(job["runs-on"]).toBe("ubuntu-latest"); + expect(job["runs-on"]).toEqual(shellSafePublicRunner); expect(String(job.if)).toContain( "github.event.pull_request.head.repo.full_name == github.repository" ); @@ -209,7 +212,7 @@ describe("CI workflow", () => { ) ).toBe(true); - expect(workflow.jobs.changes["runs-on"]).toBe("ubuntu-latest"); + expect(workflow.jobs.changes["runs-on"]).toEqual(shellSafePublicRunner); expect(workflow.jobs["hosted-fork-fast-checks"]["runs-on"]).toBe( "ubuntu-latest" ); @@ -230,10 +233,10 @@ describe("CI workflow", () => { "hosted-fork-validate-secrets" ]) ); - expect(workflow.jobs["ci-gate"]["runs-on"]).toBe("ubuntu-latest"); + expect(workflow.jobs["ci-gate"]["runs-on"]).toEqual(shellSafePublicRunner); }); - test("renders the Linux Docker contract on hosted Linux before operators provision the pool", () => { + test("renders the Linux Docker contract on shell-safe self-hosted Linux", () => { const workflow = YAML.parse( fs.readFileSync(path.resolve(".github/workflows/ci.yml"), "utf8") ) as { @@ -246,7 +249,7 @@ describe("CI workflow", () => { (step) => step.name === "Render Linux Docker runner manifests" ); - expect(dockerJob["runs-on"]).toBe("ubuntu-latest"); + expect(dockerJob["runs-on"]).toEqual(shellSafePublicRunner); expect(String(renderStep?.run)).toContain("pnpm validate-linux-docker-config"); expect(String(renderStep?.run)).toContain("pnpm render-linux-docker-compose"); expect(String(renderStep?.run)).toContain( @@ -287,7 +290,7 @@ describe("CI workflow", () => { expect(String(syntaxStep?.run)).toContain("docker/runner-entrypoint.ps1"); }); - test("keeps the Lume macOS pool contract on hosted macOS runners", () => { + test("keeps the Lume macOS pool contract on self-hosted macOS runners", () => { const workflow = YAML.parse( fs.readFileSync(path.resolve(".github/workflows/ci.yml"), "utf8") ) as { @@ -306,7 +309,7 @@ describe("CI workflow", () => { (step) => step.name === "Validate Lume shell scripts" ); - expect(lumeJob["runs-on"]).toBe("macos-latest"); + expect(lumeJob["runs-on"]).toEqual(macosXcodeRunner); expect(String(renderStep?.run)).toContain("pnpm validate-lume-config"); expect(String(renderStep?.run)).toContain("pnpm render-lume-runner-manifest"); expect(String(lifecycleStep?.run)).toContain("pnpm install-lume-project"); From 6b0a476ddd73fef538ca5920a49d706d11f92bdc Mon Sep 17 00:00:00 2001 From: Pheidon Date: Sun, 31 May 2026 15:34:13 +0000 Subject: [PATCH 2/3] ci: harden self-hosted runner workflow bootstrap --- .github/workflows/ci.yml | 3 +++ .github/workflows/pr-fast-ci.yml | 1 + .github/workflows/release-image.yml | 21 ++++++++++++++++++ .github/workflows/rg-ci.yml | 3 +++ .github/workflows/rg-release.yml | 17 +++++++++++++++ .github/workflows/security.yml | 34 ++++++++++++++++++++++++----- docker/Dockerfile | 11 +++++++++- test/security-workflow.test.ts | 4 ++-- 8 files changed, 85 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 528a7bb..fe4b5e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,9 @@ on: permissions: contents: read +env: + SHELL: /bin/bash + concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true diff --git a/.github/workflows/pr-fast-ci.yml b/.github/workflows/pr-fast-ci.yml index 6b9a1da..d36a655 100644 --- a/.github/workflows/pr-fast-ci.yml +++ b/.github/workflows/pr-fast-ci.yml @@ -15,6 +15,7 @@ permissions: env: NODE_VERSION: '20' PYTHON_VERSION: '3.12' + SHELL: /bin/bash defaults: run: diff --git a/.github/workflows/release-image.yml b/.github/workflows/release-image.yml index d0680fa..61f4dfc 100644 --- a/.github/workflows/release-image.yml +++ b/.github/workflows/release-image.yml @@ -22,6 +22,9 @@ concurrency: group: release-image-${{ github.ref }} cancel-in-progress: false +env: + SHELL: /bin/bash + jobs: publish_and_verify: name: publish-and-verify @@ -63,6 +66,24 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Ensure envsubst is available + run: | + set -euo pipefail + if command -v envsubst >/dev/null 2>&1; then + exit 0 + fi + + if [[ "$(id -u)" == "0" ]] && command -v apt-get >/dev/null 2>&1; then + apt-get update + apt-get install -y --no-install-recommends gettext-base + elif command -v sudo >/dev/null 2>&1 && command -v apt-get >/dev/null 2>&1; then + sudo apt-get update + sudo apt-get install -y --no-install-recommends gettext-base + else + echo "envsubst is required by cosign-installer." >&2 + exit 1 + fi + - uses: sigstore/cosign-installer@v4 - id: release_meta diff --git a/.github/workflows/rg-ci.yml b/.github/workflows/rg-ci.yml index c7446ba..8e1bdaa 100644 --- a/.github/workflows/rg-ci.yml +++ b/.github/workflows/rg-ci.yml @@ -24,6 +24,9 @@ on: permissions: contents: read +env: + SHELL: /bin/bash + jobs: ci: name: rg-ci diff --git a/.github/workflows/rg-release.yml b/.github/workflows/rg-release.yml index 37f189a..be1b4ca 100644 --- a/.github/workflows/rg-release.yml +++ b/.github/workflows/rg-release.yml @@ -52,6 +52,23 @@ jobs: platforms: linux/amd64,linux/arm64 push: true tags: ${{ inputs.image-ref }} + - name: Ensure envsubst is available + run: | + set -euo pipefail + if command -v envsubst >/dev/null 2>&1; then + exit 0 + fi + + if [[ "$(id -u)" == "0" ]] && command -v apt-get >/dev/null 2>&1; then + apt-get update + apt-get install -y --no-install-recommends gettext-base + elif command -v sudo >/dev/null 2>&1 && command -v apt-get >/dev/null 2>&1; then + sudo apt-get update + sudo apt-get install -y --no-install-recommends gettext-base + else + echo "envsubst is required by cosign-installer." >&2 + exit 1 + fi - uses: sigstore/cosign-installer@v4 - run: cosign sign --yes ${{ inputs.image-ref }}@${{ steps.build.outputs.digest }} - uses: actions/attest-build-provenance@v3 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index dfd42b1..c0f1e66 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -15,6 +15,9 @@ permissions: pull-requests: read security-events: write +env: + OSV_SCANNER_VERSION: v2.3.8 + jobs: codeql: name: codeql @@ -57,13 +60,32 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v6 - - uses: google/osv-scanner-action/osv-scanner-action@v2.3.8 + - name: Install OSV Scanner + run: | + set -euo pipefail + case "$(uname -m)" in + x86_64) osv_arch="amd64" ;; + aarch64|arm64) osv_arch="arm64" ;; + *) + echo "Unsupported OSV Scanner architecture: $(uname -m)" >&2 + exit 1 + ;; + esac + + osv_asset="osv-scanner_linux_${osv_arch}" + curl -fsSLO "https://github.com/google/osv-scanner/releases/download/${OSV_SCANNER_VERSION}/${osv_asset}" + curl -fsSLO "https://github.com/google/osv-scanner/releases/download/${OSV_SCANNER_VERSION}/osv-scanner_SHA256SUMS" + grep " ${osv_asset}$" osv-scanner_SHA256SUMS | sha256sum -c - + chmod +x "${osv_asset}" + mkdir -p "${RUNNER_TEMP}/osv-scanner" + mv "${osv_asset}" "${RUNNER_TEMP}/osv-scanner/osv-scanner" + echo "${RUNNER_TEMP}/osv-scanner" >> "${GITHUB_PATH}" + - name: Run OSV Scanner continue-on-error: true - with: - scan-args: |- - --lockfile=pnpm-lock.yaml - --format=sarif - --output=osv-results.sarif + run: osv-scanner scan -L pnpm-lock.yaml --format=sarif > osv-results.sarif + - name: Require OSV SARIF output + if: always() + run: test -s osv-results.sarif - uses: github/codeql-action/upload-sarif@v4 if: always() with: diff --git a/docker/Dockerfile b/docker/Dockerfile index 909a9e2..6b36afb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -8,6 +8,7 @@ ARG NODE_VERSION=18.20.8 ARG TERRAFORM_VERSION=1.6.6 ENV DEBIAN_FRONTEND=noninteractive \ + SHELL=/bin/bash \ RUNNER_SOURCE_HOME=/actions-runner \ RUNNER_TEMP=/tmp/github-runner-temp \ RUNNER_TOOL_CACHE=/opt/hostedtoolcache \ @@ -18,7 +19,7 @@ RUN apt-get update \ bash \ ca-certificates \ curl \ - docker.io \ + gettext-base \ git \ gosu \ jq \ @@ -30,6 +31,14 @@ RUN apt-get update \ zstd \ && rm -rf /var/lib/apt/lists/* +RUN install -m 0755 -d /etc/apt/keyrings \ + && curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc \ + && chmod a+r /etc/apt/keyrings/docker.asc \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian bookworm stable" > /etc/apt/sources.list.d/docker.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends docker-ce-cli \ + && rm -rf /var/lib/apt/lists/* + RUN useradd --create-home --home-dir /home/runner --shell /bin/bash runner \ && mkdir -p "${RUNNER_TOOL_CACHE}" "${RUNNER_TEMP}" /opt/node18 \ && chown -R runner:runner /home/runner "${RUNNER_TOOL_CACHE}" "${RUNNER_TEMP}" /opt/node18 diff --git a/test/security-workflow.test.ts b/test/security-workflow.test.ts index 4809344..bce71cf 100644 --- a/test/security-workflow.test.ts +++ b/test/security-workflow.test.ts @@ -20,12 +20,12 @@ describe("security and reusable workflows", () => { } expect(String(JSON.stringify(workflow))).toContain("github/codeql-action/init"); expect(String(JSON.stringify(workflow))).toContain("dependency-review-action"); - expect(String(JSON.stringify(workflow))).toContain("osv-scanner-action"); + expect(String(JSON.stringify(workflow))).toContain("osv-scanner/releases/download"); expect(String(JSON.stringify(workflow))).toContain("upload-sarif"); expect(workflow.jobs.osv.steps).toEqual( expect.arrayContaining([ expect.objectContaining({ - uses: "google/osv-scanner-action/osv-scanner-action@v2.3.8", + name: "Run OSV Scanner", "continue-on-error": true }) ]) From 90acfb7a3e6178edac23aa67afcc7edc4d7e0f3a Mon Sep 17 00:00:00 2001 From: Pheidon Date: Sun, 31 May 2026 15:40:31 +0000 Subject: [PATCH 3/3] ci: setup node before pnpm on self-hosted runners --- .github/workflows/ci.yml | 35 +++++++++++++---------------- .github/workflows/pr-fast-ci.yml | 18 +++++++-------- .github/workflows/release-image.yml | 9 ++++---- .github/workflows/rg-ci.yml | 7 +++--- test/workflow.test.ts | 9 ++++---- 5 files changed, 35 insertions(+), 43 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe4b5e9..4253dfe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,13 +31,12 @@ jobs: timeout-minutes: 15 steps: - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v6 - with: - version: 10.32.1 - uses: actions/setup-node@v6 with: node-version: "24" - cache: pnpm + - uses: pnpm/action-setup@v6 + with: + version: 10.32.1 - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm test:coverage @@ -123,13 +122,12 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v6 - with: - version: 10.32.1 - uses: actions/setup-node@v6 with: node-version: "24" - cache: pnpm + - uses: pnpm/action-setup@v6 + with: + version: 10.32.1 - run: pnpm install --frozen-lockfile - name: Render Linux Docker runner manifests run: | @@ -151,13 +149,12 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v6 - with: - version: 10.32.1 - uses: actions/setup-node@v6 with: node-version: "24" - cache: pnpm + - uses: pnpm/action-setup@v6 + with: + version: 10.32.1 - run: pnpm install --frozen-lockfile - name: Render Windows Docker runner manifests shell: pwsh @@ -184,13 +181,12 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v6 - with: - version: 10.32.1 - uses: actions/setup-node@v6 with: node-version: "24" - cache: pnpm + - uses: pnpm/action-setup@v6 + with: + version: 10.32.1 - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm test @@ -223,13 +219,12 @@ jobs: timeout-minutes: 15 steps: - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v6 - with: - version: 10.32.1 - uses: actions/setup-node@v6 with: node-version: "24" - cache: pnpm + - uses: pnpm/action-setup@v6 + with: + version: 10.32.1 - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm test diff --git a/.github/workflows/pr-fast-ci.yml b/.github/workflows/pr-fast-ci.yml index d36a655..1b0be4e 100644 --- a/.github/workflows/pr-fast-ci.yml +++ b/.github/workflows/pr-fast-ci.yml @@ -78,14 +78,13 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - - uses: pnpm/action-setup@v6 - with: - version: 10.32.1 - - uses: actions/setup-node@v6 with: node-version: "24" - cache: pnpm + + - uses: pnpm/action-setup@v6 + with: + version: 10.32.1 - name: Run fast checks run: bash scripts/ci/run-fast-checks.sh @@ -123,14 +122,13 @@ jobs: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.sha }} - - uses: pnpm/action-setup@v6 - with: - version: 10.32.1 - - uses: actions/setup-node@v6 with: node-version: "24" - cache: pnpm + + - uses: pnpm/action-setup@v6 + with: + version: 10.32.1 - run: pnpm install --frozen-lockfile - run: pnpm lint diff --git a/.github/workflows/release-image.yml b/.github/workflows/release-image.yml index 61f4dfc..f430c3b 100644 --- a/.github/workflows/release-image.yml +++ b/.github/workflows/release-image.yml @@ -41,14 +41,13 @@ jobs: steps: - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v6 - with: - version: 10.32.1 - - uses: actions/setup-node@v6 with: node-version: "24" - cache: pnpm + + - uses: pnpm/action-setup@v6 + with: + version: 10.32.1 - run: pnpm install --frozen-lockfile diff --git a/.github/workflows/rg-ci.yml b/.github/workflows/rg-ci.yml index 8e1bdaa..b550c6e 100644 --- a/.github/workflows/rg-ci.yml +++ b/.github/workflows/rg-ci.yml @@ -38,13 +38,12 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v6 - - uses: pnpm/action-setup@v6 - with: - version: ${{ inputs.package-manager-version }} - uses: actions/setup-node@v6 with: node-version: ${{ inputs.node-version }} - cache: pnpm + - uses: pnpm/action-setup@v6 + with: + version: ${{ inputs.package-manager-version }} - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm test diff --git a/test/workflow.test.ts b/test/workflow.test.ts index a98169c..d4fa439 100644 --- a/test/workflow.test.ts +++ b/test/workflow.test.ts @@ -120,13 +120,14 @@ describe("CI workflow", () => { version: "10.32.1" }); expect(setupNodeStep?.with).toMatchObject({ - "node-version": "24", - cache: "pnpm" + "node-version": "24" }); expect(forkSetupNodeStep?.with).toMatchObject({ - "node-version": "24", - cache: "pnpm" + "node-version": "24" }); + expect(steps.indexOf(setupNodeStep ?? {})).toBeLessThan( + steps.indexOf(pnpmStep ?? {}) + ); }); test("verifies the broader shell-safe toolchain contract on self-hosted runners", () => {