Public: anyone can read this; nobody can change it.

A pull from a fork gets its check: the gate fetches refs/pull/<n>/head when the head is not on a branch, and the preview skips forks #40

Merged opened this view on origin

Check · Review · Land done · Live — Landed; nothing deploys from this branch, so this is the end of its path.

Merged

check.yml cloned this repository and checked out GITHUB_SHA. A fork's head commit is here only as refs/pull/<n>/head, which a clone does not fetch, so every gate shard of a fork pull died at "clone source at this ref" with "fatal: reference is not a tree" before running a test (PR #39, run 893).

shipped merged

opened this view on origin

check.yml cloned this repository and checked out GITHUB_SHA. A fork's head commit is here only as refs/pull/<n>/head, which a clone does not fetch, so every gate shard of a fork pull died at "clone source at this ref" with "fatal: reference is not a tree" before running a test (PR #39, run 893).

preview.yml cloned --branch "$GITHUB_HEAD_REF", a branch that exists only in the fork; a fork pull gets no secrets either, and a preview builds and pushes an image of the pull's code, so it now skips pulls from forks.

Why now

#39 (https://git.open-platform.sh/trevato-apps/forge/pulls/39) is the first pull from a fork, and it is blocked by this: all three gate shards fail at "clone source at this ref" with fatal: reference is not a tree: cf8de4df… (run 893), and preview fails with Remote branch fix/2171-flow-unused-imports not found in upstream origin (run 894). No test ran.

Security review

With this change, a fork pull's own code runs in check.yml (bun install, scripts/test-shards.ts, the tests). What that code can reach:

  • Secrets: none. check.yml references no secrets.*. Forgejo also leaves secrets empty for a pull_request whose head is a fork.
  • Token: read-only. The only credential is github.token, scoped to the "clone source" step env and embedded in src/.git/config by the clone. Fork code in later steps can read it from there, and the runner hands job tokens to steps in other ways too, so scrubbing the URL would not be a real boundary. What matters is Forgejo's rule that a pull_request run's automatic token has no write permission (read-only for forks). It can read this public repository, which anyone can already do.
  • No push, no publish. Neither gate nor check pushes git, builds or pushes images or charts, signs anything, or calls a write API (/ci/preview and the registry appear only in preview.yml and release.yml). No cache is shared with privileged workflows, so nothing can be poisoned.
  • Trigger is pull_request, not pull_request_target. The fork's code never runs with base-repository privileges. Fork pulls from users without elevated rights still need a maintainer's approval before Actions run them (Forgejo default).
  • The fetch adds no capability. refs/pull/<n>/head is fetched only when $GITHUB_SHA is not already in the clone (fork pulls). It is the same commit the event names; nothing else changes for pushes to main or same-repository pulls.
  • Preview stays off for forks. It needs REGISTRY_TOKEN/cosign secrets (empty for forks anyway) and builds and pushes an image of the pull's code, so the job is skipped when head.repo.full_name != github.repository. Teardown is skipped too; there is nothing to tear down.

Conclusion: no secret or write token reaches fork code in check.yml, and its jobs cannot push or publish. No extra gating needed beyond the preview skip.

Known baseline on main (not this change)

test/og-png.test.ts "median of three cold renders is within 300 ms" failed main's push gate shard 2 (run 889: 616 ms / 708 ms on the half-core, 512 MiB runner). Pulls whose fast tier includes it (e.g. #39) may hit it too.

<!-- pipeline:validation -->

Validation

pipeline/validate on a9797560: pass in 6s — bun 1.3.14, CI-shaped env (scrubbed vars, runner PATH), exact check.yml shard + forge.json commands.

stepresulttime
bun install --frozen-lockfileok (exit 0)0s
forge.json check.fastok (exit 0)3s
check.yml gate (1) pull_requestok (exit 0)0s
check.yml gate (2) pull_requestok (exit 0)0s
check.yml gate (3) pull_requestok (exit 0)3s
  • ⚠️ node v20.19.2 here, v22 on CI (tsc runs under node)
test output (failures, totals)
▶ bun install --frozen-lockfile
  ok  exit 0  0s
▶ forge.json check.fast
Ran 87 tests across 7 files in 2.0s (7 shards).
  ok  exit 0  3s
▶ check.yml gate (1) pull_request
Ran 12 tests across 2 files in 0.1s (2 shards).
  ok  exit 0  0s
▶ check.yml gate (2) pull_request
Ran 7 tests across 2 files in 0.1s (2 shards).
  ok  exit 0  0s
▶ check.yml gate (3) pull_request
Ran 68 tests across 3 files in 2.3s (3 shards).
  ok  exit 0  3s
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs