Skip to content

fix(ci): use locked mode to eliminate GitHub API calls from mise#1118

Open
palootcenas-outreach wants to merge 9 commits intomainfrom
palo/mise-locked-ci
Open

fix(ci): use locked mode to eliminate GitHub API calls from mise#1118
palootcenas-outreach wants to merge 9 commits intomainfrom
palo/mise-locked-ci

Conversation

@palootcenas-outreach
Copy link
Copy Markdown

@palootcenas-outreach palootcenas-outreach commented Mar 26, 2026

Summary

Eliminate GitHub API calls from mise tool resolution in CI by using --locked mode with MISE_CONFIG_DIR isolation. This is the single highest-impact fix for CI GitHub rate limit exhaustion.

Related fix

#1117

Problem

mise's github: backend tools (orc, ci, lintroller) call api.github.com/repos/.../releases on every mise install to resolve versions. With orc declared as "latest", this happens on every CI build. These calls consume the shared 15,000 req/hr GitHub App token pool across all concurrent CI builds org-wide.

devbase already has lockfiles (mise.lock, mise.devbase.lock) with pre-resolved download URLs and checksums. But without --locked, mise treats these as advisory — it still hits the API.

ℹ️ Failed attempt: MISE_LOCKED=1 as a global env var 👎

Setting MISE_LOCKED=1 as a global env var failed because locked mode validates all tools from all config sources against a single project lockfile:

  • .tool-versions tools (go, node, protoc) — not in any mise lockfile
  • Global orc-installed tools (~/.config/mise/config.toml) — no lockfile exists for these
  • Pre-existing conf.d tools (~/.config/mise/conf.d/devbase.toml) — in CI image from prior runs

This is confirmed as intentional behavior by the mise maintainer.

Solution

Three-part fix:

1. MISE_CONFIG_DIR isolation

Set MISE_CONFIG_DIR to a temp directory during mise install calls. This hides all global config (config.toml, conf.d/, ~/.tool-versions) from discovery. Project-level configs (mise.toml, mise.devbase.toml) are unaffected since they're found by directory walking, not via the config dir.

Restored after install so devbase_configure_global_tools writes to the real ~/.config/mise/ for shim setup.

2. Per-invocation --locked with existence guard

  • Downstream repos: --locked only if mise.lock exists. ~60%+ of repos already have lockfiles; repos without them get plain mise install (same as today).
  • Devbase tools: Always --lockedmise.devbase.lock is maintained by the stencil:post:mise hook.

3. Two-pass install for go: backend tools

go: backend tools (goimports, dlv, goveralls) compile from source via go install and cannot produce lockfile URLs — their lockfile entries contain only version and backend, with no platform-specific download URLs. This is a known mise limitation.

--locked always fails for these tools. Fix: two-pass install in devbase_install_mise_tools():

  1. MISE_DISABLE_BACKENDS=go mise install --locked — installs all lockable tools (zero GitHub API calls)
    • we use workaround with MISE_DISABLE_TOOLS till mise#8789 gets resolved
  2. mise install — the lockable tools are already installed so mise skips them; only installs the 3 go: tools via Go module proxy (proxy.golang.org), not GitHub API

What this fixes

  • orc "latest": Resolves from lockfile (pinned with direct URLs) — zero API calls
  • All github:/aqua: backend tools: No api.github.com calls for version resolution
  • go: backend tools: Handled separately — they never used GitHub API anyway
  • Lockfile immutability: --locked prevents lockfile mutation in CI

Failure modes

  • Repo with mise.toml but no mise.lock: Falls back to normal mise install without --locked — no change from today
  • Stale lockfile: mise install --locked fails with clear error ("tool X not found in lockfile"). Fix: run mise lock locally and commit

Related

Enable strict lockfile mode for mise in CI so all tools resolve from
pre-resolved URLs in lockfiles instead of hitting api.github.com for
version resolution. This is safe because:

- mise already ignores .tool-versions in CI (MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES=none)
- All devbase tools have entries in mise.devbase.lock
- The setting only applies to mise install calls, not to mise settings/activate

Repos can opt out by setting MISE_LOCKED=0 in their CircleCI project env.

Relates-to: DT-5157
Replace MISE_LOCKED=1 global env var which validated ALL config sources
(global, conf.d, .tool-versions) against a single project lockfile.

Instead:
- Set MISE_CONFIG_DIR to a temp dir during install to hide global config
- Pass --locked per-invocation: guarded by mise.lock existence for
  downstream repos, always-on for devbase (mise.devbase.lock)
- Restore MISE_CONFIG_DIR after install for devbase_configure_global_tools
@palootcenas-outreach palootcenas-outreach changed the title fix(ci): enable MISE_LOCKED=1 to eliminate GitHub API calls from mise fix(ci): use locked mode to eliminate GitHub API calls from mise Mar 26, 2026
The previous approach exported MISE_CONFIG_DIR globally, which broke
wait-for-gh-rate-limit (a mise shim) because the shim couldn't resolve
its tool version against the empty config dir.

Instead, pass _MISE_INSTALL_CONFIG_DIR through run_mise() and apply
MISE_CONFIG_DIR as an inline env var only on the mise binary invocation.
Shims and other helper tools still see the real global config.
go: backend tools (goimports, dlv, goveralls) compile from source via
`go install` and cannot produce lockfile URLs. --locked always fails
for them. Split devbase tool install into two passes:
1) MISE_DISABLE_BACKENDS=go with --locked for all lockable tools
2) Normal install for go: tools (they use Go module proxy, not GitHub API)
MISE_DISABLE_BACKENDS=go doesn't work for explicitly declared tools
(mise bug: get() in backend/mod.rs bypasses the disable_backends
filter by re-creating backends on demand). Use MISE_DISABLE_TOOLS
with dynamically extracted go: tool names from mise.devbase.toml.
@getoutreach-ci-1
Copy link
Copy Markdown
Contributor

Link to code coverage report (posted by coverbot 🤖)

@palootcenas-outreach palootcenas-outreach marked this pull request as ready for review March 27, 2026 00:11
@palootcenas-outreach palootcenas-outreach requested a review from a team as a code owner March 27, 2026 00:11
Pass 2 runs without --locked for go: backend tools (they compile from
source and can't use lockfiles). Without MISE_LOCKFILE=false, mise
could still write to mise.lock during this pass, causing dirty-tree
failures in the pre-release dry run step.

Pass 1 (--locked) is already read-only by definition. This ensures
neither pass can mutate lockfiles in CI.
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