Skip to content

Cap what a single fork pull request can spend - #4

Merged
gvonnessi merged 1 commit into
mainfrom
ci/limit-fork-pr-runs
Aug 20, 2026
Merged

gvonnessi merged 1 commit into
mainfrom
ci/limit-fork-pr-runs

Conversation

@gvonnessi

Copy link
Copy Markdown
Contributor

Cap what a single fork pull request can spend

This workflow is reachable from a fork pull request and had neither a
concurrency group nor a job timeout, so it inherited GitHub's defaults for
both: unlimited concurrent runs and six hours per job. Counting the
matrix that is 3 job runs per push, so the ceiling was 3x6 = 18
compute-hours for one push — and with no concurrency group a contributor
pushing five times held five complete sets at once rather than superseding
the previous one.

Unlike the Blacksmith repos this one runs on hosted minutes and the repo is
public, so those hours are free rather than billed. The reason to bound it
anyway is that "free" describes the invoice and not the behaviour: an
unbounded job is still a job nobody can tell from a hung one, and the
repository-level protection this pairs with — approval now required for
every external contributor, not merely first-timers — is only half a
control if an approved run has no ceiling.

Sized against measurement. Over the last six runs the slowest job here is
2m07s, so 20 minutes is generous headroom while removing the runaway. A job
that hits 20 minutes is not a slow job, it is a stuck one.

Change

  • concurrency group keyed on workflow + ref, with cancel-in-progress: true
  • timeout-minutes: 20 on every job definition

Worst case per push

before after
3 job runs at the ceiling 18 compute-hours ~1 compute-hours
repeated pushes accumulate superseded

Test plan

  • YAML parses; triggers unchanged; step count identical to main
  • Every job definition carries timeout-minutes
  • This PR's own run passes well inside 20 min

This workflow is reachable from a fork pull request and had neither a
concurrency group nor a job timeout, so it inherited GitHub's defaults for
both: unlimited concurrent runs and **six hours** per job. Counting the
matrix that is 3 job runs per push, so the ceiling was 3x6 = 18
compute-hours for one push — and with no concurrency group a contributor
pushing five times held five complete sets at once rather than superseding
the previous one.

Unlike the Blacksmith repos this one runs on hosted minutes and the repo is
public, so those hours are free rather than billed. The reason to bound it
anyway is that "free" describes the invoice and not the behaviour: an
unbounded job is still a job nobody can tell from a hung one, and the
repository-level protection this pairs with — approval now required for
every external contributor, not merely first-timers — is only half a
control if an approved run has no ceiling.

Sized against measurement. Over the last six runs the slowest job here is
2m07s, so 20 minutes is generous headroom while removing the runaway. A job
that hits 20 minutes is not a slow job, it is a stuck one.
@gvonnessi
gvonnessi merged commit c010394 into main Aug 20, 2026
3 checks passed
@gvonnessi
gvonnessi deleted the ci/limit-fork-pr-runs branch August 20, 2026 11:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant