From 5b2f24375e1572c3625c1240e903e343bd99adc5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 28 Jul 2026 15:27:56 +0400 Subject: [PATCH 1/2] ci: run build/lint/type-check/test on every pull request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repo previously had no general PR CI — the only pull_request workflow was the path-filtered dep-changeset check, so PRs (fork or internal) merged with zero automated verification. This mirrors the gates release.yml runs on develop, plus bun test. Fork-safe: pull_request runs from forks get no secrets and a read-only token; setup-repo needs neither. Linear: API-2963 Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4106dd0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,29 @@ +name: CI + +# Runs on every PR, including fork PRs. Safe for untrusted code by +# construction: pull_request-triggered runs from forks receive no secrets +# and a read-only GITHUB_TOKEN, and none of these jobs need either. +on: + pull_request: + +concurrency: + group: ci-${{ github.event.pull_request.number }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build-lint-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Repo + uses: ./tools/github/setup-repo + + - run: bun build:ci + - run: bun lint + - run: bun type-check:ci + - run: bun test From 226e877147f858ef0b75ed7d9264553b1234f20f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 28 Jul 2026 15:33:10 +0400 Subject: [PATCH 2/2] ci: harden PR workflow for untrusted fork code - timeout-minutes caps compute abuse - persist-credentials: false keeps the token out of .git config - pinned bun 1.3.13 (matches packageManager) instead of latest - bun install --frozen-lockfile so dependency resolution cannot shift without a visible lockfile diff Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4106dd0..e0af0b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,13 @@ name: CI -# Runs on every PR, including fork PRs. Safe for untrusted code by -# construction: pull_request-triggered runs from forks receive no secrets -# and a read-only GITHUB_TOKEN, and none of these jobs need either. +# Runs on every PR, including fork PRs — which means it executes untrusted +# code. Containment: pull_request-triggered fork runs receive no secrets and +# a read-only GITHUB_TOKEN, the runner is an ephemeral hosted VM, and the +# clamps below cap what a malicious PR can do with the run itself. +# +# Deliberately NOT using the setup-repo composite: it floats bun-version to +# `latest` and installs without a lockfile guarantee, which is fine for +# trusted release builds but not for untrusted PR code. on: pull_request: @@ -16,12 +21,28 @@ permissions: jobs: build-lint-test: runs-on: ubuntu-latest + # Cap compute abuse from a malicious or runaway PR. + timeout-minutes: 20 steps: - uses: actions/checkout@v4 + with: + # Don't leave the (read-only) token readable by build/test scripts. + persist-credentials: false - - name: Setup Repo - uses: ./tools/github/setup-repo + - uses: oven-sh/setup-bun@v2 + with: + # Keep in sync with "packageManager" in package.json. + bun-version: 1.3.13 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install dependencies (locked) + # Frozen lockfile: a PR cannot shift dependency resolution without + # the lockfile change showing up in the reviewed diff. + run: bun install --frozen-lockfile - run: bun build:ci - run: bun lint