Skip to content
Draft
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
20 changes: 20 additions & 0 deletions .github/actions/setup-pnpm-node/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Setup pnpm + Node.js (cached)
description: >-
Install pnpm, then Node.js with the pnpm store cache wired in
(pnpm must be on PATH before actions/setup-node's cache: pnpm probe runs).
inputs:
node-version:
description: Node.js version to install
required: false
default: '22'
runs:
using: composite
steps:
- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: ${{ inputs.node-version }}
cache: pnpm
43 changes: 16 additions & 27 deletions .github/workflows/build-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ jobs:
steps:
- id: set
# PRs build the cheap linux-x64 target only (catches the vast majority
# of compile errors on the self-hosted runner). Full cross-platform
# validation runs on push to main and on manually pushed
# cachekit-core-ts-v* tags — the validation a (currently manual, see
# header) publish relies on — keeping the macOS/Windows cost off the
# PR review loop without losing coverage where it matters.
# of compile errors fast). Full cross-platform validation runs on
# push to main and on manually pushed cachekit-core-ts-v* tags — the
# validation a (currently manual, see header) publish relies on —
# keeping the macOS/Windows cost off the PR review loop without
# losing coverage where it matters.
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
builds='[{"target":"x86_64-unknown-linux-gnu","os":"cachekit-lean"}]'
builds='[{"target":"x86_64-unknown-linux-gnu","os":"ubuntu-latest"}]'
else
builds='[
{"target":"x86_64-unknown-linux-gnu","os":"cachekit-lean"},
{"target":"x86_64-unknown-linux-gnu","os":"ubuntu-latest"},
{"target":"aarch64-unknown-linux-gnu","os":"ubuntu-latest"},
{"target":"x86_64-apple-darwin","os":"macos-latest"},
{"target":"aarch64-apple-darwin","os":"macos-latest"},
Expand All @@ -78,26 +78,20 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Configure Rust paths (self-hosted)
if: matrix.os == 'cachekit-lean'
run: |
echo "RUSTUP_HOME=/tmp/rustup" >> "$GITHUB_ENV"
echo "CARGO_HOME=/tmp/cargo" >> "$GITHUB_ENV"

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '22'

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2
- uses: ./.github/actions/setup-pnpm-node

- name: Setup Rust
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # stable
with:
toolchain: stable
targets: ${{ matrix.target }}

- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: packages/cachekit-core-ts
shared-key: ${{ matrix.target }}

- name: Install aarch64 cross-compiler
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
Expand Down Expand Up @@ -125,16 +119,14 @@ jobs:
needs: build
strategy:
matrix:
os: [cachekit-lean]
node: [22, 24]

runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
- uses: ./.github/actions/setup-pnpm-node
with:
node-version: ${{ matrix.node }}

Expand All @@ -144,9 +136,6 @@ jobs:
name: bindings-x86_64-unknown-linux-gnu
path: packages/cachekit-core-ts

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2

- name: Install dependencies
run: pnpm install

Expand Down
16 changes: 2 additions & 14 deletions .github/workflows/build-wasm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,11 @@ env:

jobs:
build:
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'cachekit-lean' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Configure Rust paths (self-hosted)
if: ${{ !github.event.pull_request.head.repo.fork }}
run: |
echo "RUSTUP_HOME=/tmp/rustup" >> "$GITHUB_ENV"
echo "CARGO_HOME=/tmp/cargo" >> "$GITHUB_ENV"

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '22'

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2
- uses: ./.github/actions/setup-pnpm-node

- name: Setup Rust
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # stable
Expand Down
133 changes: 64 additions & 69 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,11 @@ permissions:

jobs:
lint:
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'cachekit-lean' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '22'

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2
- uses: ./.github/actions/setup-pnpm-node

- name: Install dependencies
run: pnpm install --frozen-lockfile
Expand All @@ -33,7 +27,7 @@ jobs:
run: pnpm type-check

test:
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'cachekit-lean' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
Expand All @@ -42,14 +36,10 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Setup Node.js ${{ matrix.node }}
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
- uses: ./.github/actions/setup-pnpm-node
with:
node-version: ${{ matrix.node }}

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2

- name: Install dependencies
run: pnpm install --frozen-lockfile

Expand All @@ -60,13 +50,7 @@ jobs:
run: pnpm test

test-integration:
# Fork PRs fall back to ubuntu-latest (GHA disables self-hosted runners
# for fork PRs by security policy). Internal/push runs use 'cachekit'
# (NOT 'cachekit-lean') because the redis service container below
# requires Docker on the host: cachekit-lean is a locked-down rootless
# pod with no DOCKER_HOST and no docker socket, so services would fail
# to start. ubuntu-latest has Docker preinstalled.
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'cachekit' }}
runs-on: ubuntu-latest
services:
redis:
image: redis:7-alpine
Expand All @@ -81,13 +65,7 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '22'

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2
- uses: ./.github/actions/setup-pnpm-node

- name: Install dependencies
run: pnpm install --frozen-lockfile
Expand All @@ -102,17 +80,11 @@ jobs:
CI: true

coverage:
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'cachekit-lean' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '22'

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2
- uses: ./.github/actions/setup-pnpm-node

- name: Install dependencies
run: pnpm install --frozen-lockfile
Expand All @@ -130,17 +102,11 @@ jobs:
fail_ci_if_error: false

security:
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'cachekit-lean' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '22'
- uses: ./.github/actions/setup-pnpm-node

- name: Install dependencies
run: pnpm install --frozen-lockfile
Expand Down Expand Up @@ -198,7 +164,7 @@ jobs:

workers:
name: Workers lane (wasm + workerd)
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'cachekit-lean' }}
runs-on: ubuntu-latest
env:
# Must match the wasm-bindgen version pinned in the crate's Cargo.lock;
# scripts/build.sh fails loudly on drift.
Expand All @@ -211,19 +177,7 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Configure Rust paths (self-hosted)
if: ${{ !github.event.pull_request.head.repo.fork }}
run: |
echo "RUSTUP_HOME=/tmp/rustup" >> "$GITHUB_ENV"
echo "CARGO_HOME=/tmp/cargo" >> "$GITHUB_ENV"

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '22'

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2
- uses: ./.github/actions/setup-pnpm-node

- name: Setup Rust
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # stable
Expand All @@ -234,6 +188,11 @@ jobs:
toolchain: 1.97.1
targets: wasm32-unknown-unknown

- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: packages/cachekit-core-wasm

- name: Install wasm-bindgen + wasm-opt (pinned prebuilts, checksummed)
run: |
mkdir -p "$HOME/.local/bin"
Expand Down Expand Up @@ -264,18 +223,12 @@ jobs:

smoke-test:
name: Package smoke test (ESM + CJS)
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'cachekit-lean' }}
runs-on: ubuntu-latest
needs: [test]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Setup Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '22'

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v2
- uses: ./.github/actions/setup-pnpm-node

- name: Install dependencies
run: pnpm install --frozen-lockfile
Expand Down Expand Up @@ -323,10 +276,51 @@ jobs:
console.log('CJS: all exports verified');
"

self-hosted-drift-guard:
name: Self-hosted runner drift guard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

# Drift protection for maintainers only: a fork PR runs its own copy of
# this workflow (a fork can't remove its own guard), so this catches an
# accidental self-hosted `runs-on` creeping back onto main/push, not a
# malicious fork PR. The server-side control for fork PRs lives in
# repository and org runner settings, outside this file.
#
# This is a line-oriented heuristic (case-insensitive grep over
# runs-on:/os:/runner: keys and JSON "os": values), not a schema-aware
# YAML parse — a determined bypass via a renamed matrix key or a YAML
# anchor/multi-line block scalar would slip past it. That tradeoff is
# deliberate: closing it properly means defeating a determined bypass,
# which is what the settings-level runner controls are for, not this
# maintainer sanity check.
- name: Fail if any workflow still targets a self-hosted runner
run: |
set -euo pipefail
hits=$(grep -rnE '^[[:space:]]*runs-on:|^[[:space:]]*(os|runner):|"os":' .github/workflows/ \
| grep -iE 'cachekit|self-hosted' || true)
if [ -n "$hits" ]; then
echo "::error::self-hosted runner reference(s) found in .github/workflows/ (LAB-3503 drift guard):"
echo "$hits"
exit 1
fi
echo "no self-hosted runner references found in .github/workflows/"

ci-success:
name: CI Success
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'cachekit-lean' }}
needs: [lint, test, test-integration, coverage, security, smoke-test, workers]
runs-on: ubuntu-latest
needs:
[
lint,
test,
test-integration,
coverage,
security,
smoke-test,
workers,
self-hosted-drift-guard,
]
if: always()
steps:
- name: Check all jobs succeeded
Expand All @@ -337,7 +331,8 @@ jobs:
[[ "${{ needs.coverage.result }}" != "success" ]] || \
[[ "${{ needs.security.result }}" != "success" ]] || \
[[ "${{ needs.smoke-test.result }}" != "success" ]] || \
[[ "${{ needs.workers.result }}" != "success" ]]; then
[[ "${{ needs.workers.result }}" != "success" ]] || \
[[ "${{ needs.self-hosted-drift-guard.result }}" != "success" ]]; then
echo "One or more jobs failed"
exit 1
fi
Expand Down
Loading