Skip to content

ci(runners): move every job to the 1-vCPU ubuntu-slim runner - #1190

Merged
potiuk merged 3 commits into
apache:mainfrom
potiuk:worktree-curious-hugging-hinton
Sep 9, 2026
Merged

ci(runners): move every job to the 1-vCPU ubuntu-slim runner#1190
potiuk merged 3 commits into
apache:mainfrom
potiuk:worktree-curious-hugging-hinton

Conversation

@potiuk

@potiuk potiuk commented Sep 9, 2026

Copy link
Copy Markdown
Member

Nothing this repository runs in CI is heavy. Measured on the current
4-vCPU image:

Job Runtime
prek 131s
analyze (python) / (actions) 99s / 41s
sandbox-lint ~88s
rat 60s
pytest (dev) / (vetted-ops) 20s / 18s
validate skills and tool contracts 18s
list-workspace-members 6s
tests-ok 3s

Paying for four cores to run a YAML linter and a 20-second pytest suite
is waste on infrastructure the foundation shares.

ubuntu-slim is GitHub-hosted (1 vCPU, 5 GB) rather than an ASF
self-hosted label, so it needs no Infra ticket — and 114 workflow files
across the apache org already use it. Jobs run in a container instead of
a dedicated VM and are killed at 15 minutes; the slowest job here uses 15%
of that budget, so the headroom survives the single-core slowdown.

Two jobs needed a fix to survive the move

zizmor ran through a Docker action. zizmorcore/zizmor-action's
action.sh runs the tool with docker pull + docker run and aborts
with "Cannot run this action without Docker"; ubuntu-slim jobs are
themselves containers with no Docker daemon, so the job failed before
zizmor was ever invoked. The CLI now comes from the root uv workspace's
dev group, which also puts its version under the lockfile and the
[tool.uv] exclude-newer cooldown, same as prek. This supersedes #1167's
pin bump of that action, which the rebase dropped.

typos was OOM-killed. It reported a bare - exit code: 1 with no
output, which reads like a hook that lost its error message — but prek has
no exit code to report for a signal-killed process. typos' peak RSS scales
with the number of paths handed to a single invocation (~1.2 MB each), and
prek splits the file list across roughly cpu_count invocations. Measured
on this repo's ~4.9k tracked files, in a 1-vCPU ubuntu:24.04 container
(which is what ubuntu-slim is):

paths in one invocation peak RSS
610 422 MB
1,219 (the 4-vCPU chunk) 925 MB
2,438 2,514 MB
4,876 (the 1-vCPU chunk) 5,754 MB
walk mode, no paths passed 21 MB

So the hook fit comfortably on four cores and went past the runner's
memory on one. pass_filenames: false plus a trailing . makes typos
walk the repo itself — the shape the lychee hook already uses — for a
flat ~21 MB whatever the core count. Coverage is unchanged: typos honours
.gitignore while walking, and this checkout has no untracked non-ignored
files. .venv/ joins .gitignore for the same reason.

Three consequences worth flagging for review:

  • codeql.yml gives up its ubuntu-24.04 pin along with the four
    cores. Its Python analysis is the one genuinely CPU- and memory-bound
    job here, so it's the first place to look if a run starts timing out.
    Happy to leave that workflow pinned and on the fat runner if reviewers
    prefer.
  • No workflow sets timeout-minutes, so slim's 15-minute kill becomes
    the effective timeout everywhere — stricter than the 6-hour default it
    replaces, and appropriate for a repo where every job finishes inside two
    minutes.
  • uv tool install prek is unpinned, so pre-commit.yml tracks
    whatever prek is latest at run time. Not introduced here, but the typos
    diagnosis leaned on knowing the version, so it's worth a follow-up.

🤖 Generated with Claude Code

https://claude.ai/code/session_01R3wLTXcKFLKiZE992K5UHr

Nothing this repository runs in CI is heavy. The slowest job on the
4-vCPU image is `prek` at 131s; the rest land between 3s and 99s. Paying
for four cores to run a YAML linter and a 20-second pytest suite is waste
on infrastructure the foundation shares.

`ubuntu-slim` is GitHub-hosted (1 vCPU, 5 GB), not an ASF self-hosted
label, so it needs no Infra ticket — and 114 workflow files across the
`apache` org already use it. Jobs run in a container rather than a
dedicated VM and are killed at 15 minutes. Measured against that budget
the slowest job here uses 15% of it, so the headroom is real even after
the single-core slowdown.

Two consequences worth recording. `codeql.yml` gives up its
`ubuntu-24.04` pin along with the four cores; its Python analysis is the
one job here that is genuinely CPU- and memory-bound, so it is the first
place to look if a run starts timing out. And no workflow sets
`timeout-minutes`, which makes slim's 15-minute kill the effective
timeout everywhere — stricter than the 6-hour default it replaces, and
appropriate for a repo where every job finishes inside two minutes.

Generated-by: Claude Code (Opus 5)
`zizmorcore/zizmor-action` is a composite action whose `action.sh` runs
the tool with `docker pull` + `docker run`, and it aborts outright —
"Cannot run this action without Docker" — when the daemon is absent.
`ubuntu-slim` jobs are themselves containers and have no daemon, so the
job died before zizmor was ever invoked.

Declaring `zizmor` in the root `[dependency-groups] dev` and calling
`uv run zizmor` removes the dependency on Docker entirely, and brings
three things the action could not:

- the version is resolved into the root `uv.lock` (1.30.0) and governed
  by the `[tool.uv] exclude-newer` cooldown, like every other pinned
  tool here, instead of being a floating tag inside a container image;
- `uv run zizmor --config .zizmor.yml .` reproduces CI locally, which
  the Docker path only did for contributors with a working daemon;
- one fewer third-party action in a workflow whose entire purpose is
  auditing third-party actions.

Behaviour is unchanged where it matters. `--persona regular` is the
action's default, and `advanced-security: false` already meant no SARIF
upload, so the console-plus-exit-code contract is the same. The action
defaults its `token` input to `github.token`, so online audits were
already enabled; `GH_TOKEN` in the run step keeps them enabled rather
than silently dropping to offline mode.

`uv sync` uses `--no-install-workspace`: zizmor imports nothing from
this repo, so building ~34 member packages to run it would be pure cost
on a 1-vCPU runner.

Verified locally against the whole tree — no findings, 15 suppressed.

Generated-by: Claude Code (Opus 5)
@potiuk
potiuk force-pushed the worktree-curious-hugging-hinton branch from a17f7dc to 1b41144 Compare September 9, 2026 23:07
The `typos` hook was the one job that would not survive the move to
`ubuntu-slim`. It failed as a bare `- exit code: 1` with no output,
which reads like a hook that lost its error message; it is really an
OOM kill, and prek has no exit code to report for a signal-killed
process.

typos' peak RSS scales with the number of paths handed to a single
invocation — about 1.2 MB each — and prek splits the file list across
roughly `cpu_count` invocations. Measured on this repo's ~4.9k tracked
files, in a 1-vCPU `ubuntu:24.04` container (what `ubuntu-slim` is):

  610 paths    422 MB
  1219 paths   925 MB   <- the 4-vCPU chunk; fits, hence green on
                           ubuntu-latest
  2438 paths  2514 MB
  4876 paths  5754 MB   <- the 1-vCPU chunk; over the runner's memory,
                           SIGKILL, no stdout, no stderr
  walk mode     21 MB

`pass_filenames: false` plus a trailing `.` makes the hook walk the
repo itself — the shape the `lychee` hook below already uses — for a
flat ~21 MB whatever the core count. Coverage is unchanged: typos
honours .gitignore while walking, and this checkout has no untracked
non-ignored files. `.venv/` joins .gitignore for the same reason;
uv already writes a `*` .gitignore inside it, so git behaved either
way, but the walk should not depend on that.

Note that this busts the prek hook-env cache key. The `prek-Linux-`
restore-key prefix still restores the previous archive, so no hook env
is rebuilt from scratch.

Generated-by: Claude Code (Opus 5)
@potiuk
potiuk merged commit 35a3457 into apache:main Sep 9, 2026
45 checks passed
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