Hive Hive
Sign in

fix(infra): stop mise hitting the GitHub API in CI (install via mise.lock with –locked)

GitHub issue · Closed

Metadata
Source
tuist/tuist #11347
Updated
Jun 25, 2026
Domains
Compute
Details

What

Make every meaningful mise install in CI use the pre-resolved mise.lock URLs instead of resolving/downloading through api.github.com, eliminating the recurring GitHub rate limit exceeded / 403 Forbidden failures (e.g. run 27743340122, server Test job on github:ClickHouse/ClickHouse).

Why it was happening

  • The lockfile records both a direct CDN url (github.com/.../releases/download/..., not rate-limited) and a url_api (api.github.com/.../releases/assets/<id>, rate-limited). Without --locked, mise downloads github-backend assets through url_api.
  • The repo’s shared GITHUB_TOKEN is ~1k req/hr; dozens of concurrent CI jobs each making GitHub API calls via mise exhaust it → 403.
  • mise only keeps off the GitHub/aqua API when installing with --locked (its own help: “This prevents API calls to GitHub, aqua registry, etc.”). Only 4 of ~48 mise workflows set it.
  • Several workflows passed no install_args, so mise installed the entire merged root toolset (~30 tools, building erlang from source) and resolved all of it through the API. Worse, mise run and mise x auto-install the full merged config, so scoping install_args alone doesn’t help those — they need MISE_AUTO_INSTALL=0.

Constraints (verified empirically)

  • --locked hard-fails for source-built / non-URL backends (erlang, elixir, ruby, rust, npm:, gem:, asdf:) — mise lock writes no URL for them.
  • A scoped mise install --locked <lockable tools> only enforces the named tools and just warns (exit 0) about unlockable ones in the merged config.
  • MISE_AUTO_INSTALL=0 stops mise run/mise x/shims from installing the full config, while pre-installed tools still work. MISE_CEILING_PATHS does not stop the project-tree merge. A subdir --locked install resolves root-tier tools from the root lockfile.

Changes

  • New .github/actions/mise-install — splits requested tools: source-built/registry backends install normally, everything else installs with --locked (direct CDN URL, zero GitHub API calls). Used by setup-server-mix and the mixed-install workflows.
  • Mixed erlang/rust + lockable PR-CI installs routed through the action: noora (aube), kura (bazel/shellspec/buck2), gradle-cache-acceptance (ClickHouse), blick, and server.yml (ClickHouse — the original failure).
  • Pure-lockable release/deploy installs get --locked prepended (git-cliff, jq, helm, kubectl, tuist, 1password-cli, bats).
  • No-install_args workflows scoped to their real tools + MISE_AUTO_INSTALL=0 where they use mise run/mise x: app.yml (tuist / tuist+1password-cli), grafana-datasource (go node), status/status-deploy (node aube wrangler), search/search-deploy (ruby kamal).
  • Lockfiles regenerated for all common platforms (root, server, cache, noora, handbook) and created for kura, grafana-datasource, status.

Erlang/elixir-only jobs (slack, tuist-ops, l10n, cache) are unchanged — they install only source-built backends, which never touch the rate-limited API.

Validation

  • actionlint on all changed workflows: no new errors (only pre-existing custom-runner-label noise).
  • Split logic unit-tested in bash for every install string in use; MISE_AUTO_INSTALL/--locked/cross-dir-lock behaviors verified in isolated runs.
  • Verified every locked tool has a linux-x64 entry in its applicable lockfile; lockfile diffs are additive (no tool version changes except an intended cache erlang/elixir sync).

Behavior when a tool isn’t locked

If a tool is added to mise.toml but mise.lock isn’t updated (e.g. forgetting to commit the lock), the --locked install fails fast with a clear “…is not in the lockfile” error and makes zero GitHub API calls — it’s a pre-flight check, like npm ci refusing a stale lockfile, not a silent fallback to API resolution. So a stale lock is a loud, cheap CI failure rather than a quiet regression back into rate-limit territory. (Source-built / npm: / gem: / asdf: backends are installed unlocked by design and need no lock entry; they don’t hit the rate-limited API anyway.)

The contributor workflow stays: add the tool → run mise install (or mise lock) locally → commit the updated mise.lock.

Deliberately left unchanged

  • The SLSA-tuned mise -C infra run platform-install in server-deployment (resolves the full infra toolset; rescoping a prod-deploy path is high-risk for low marginal gain).
  • The rust-only install in server-production-deployment (rust is source-built and uses no rate-limited GitHub API).
  • The image-build workflows (*-image) — they don’t use jdx/mise-action (they use actions/setup-go, or invoke oras/packer directly).

🤖 Generated with Claude Code

Flights

Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.

New Flights are paused Configure model inference, GitHub, and a sandbox provider to start another Flight. Existing results remain available below.
No Flights yet

Start a Flight and preserve its objective, outcome, and session here.

Comments
TA
tuist-atlas[bot] Jun 19, 2026

The fix to stop mise hitting the GitHub API in CI (install via mise.lock with –locked) is now available in grafana-datasource@0.1.3. Please update to this version to get the changes.