Skip to content
Fran Gonzalez
← Back to blog
·Clanker·2 min read

Hardcoded tool versions in a GitHub Actions step drift from mise.lock under Renovate

Renovate bumps mise.lock but a version pinned inside a workflow run step stays stale, and MISE_LOCKED=1 then aborts. Install tools by name and let the lockfile decide.

Some matmuls wrote this slop, sorry. My goal with this content is to document some work I (a real human bean) do while poking the Clanker, and try to learn something along the way.

A run: step in a GitHub Actions workflow pinned a tool inline:

# .github/workflows/quality.yml
- name: Install locked toolchain
  run: |
    tmpdir="$(mktemp -d)"
    trap 'rm -rf "$tmpdir"' EXIT
    MISE_CONFIG_DIR="$tmpdir" MISE_LOCKED=1 mise install node actionlint "github:zizmorcore/zizmor@v1.25.2"

Renovate’s mise manager bumped the same tool in mise.toml and mise.lock to 1.26.1 in its weekly PR. The two pins disagreed. MISE_LOCKED=1 enforces the lockfile, so it refused to resolve the inline @v1.25.2 against a lockfile that now said 1.26.1:

mise ERROR Failed to install github:zizmorcore/zizmor@v1.25.2: No lockfile URL found for github:zizmorcore/zizmor@1.25.2 on platform linux-x64 (--locked mode)
hint: Run `mise lock` to generate lockfile URLs, or disable locked mode

Same drift class as Corepack packageManager vs mise.toml: two sources of truth for one version, updated in different places.

Fix

Drop the version suffix and install by tool name. The lockfile is the only source of truth.

# .github/workflows/quality.yml
MISE_CONFIG_DIR="$tmpdir" MISE_LOCKED=1 mise install node actionlint "github:zizmorcore/zizmor"

Verified locally, and on the rebased PR with the lockfile at zizmor 1.26.1: the command resolves from mise.lock without error.

Notes

MISE_CONFIG_DIR="$tmpdir" points mise at an empty config directory so the install is driven by the repo’s mise.toml/mise.lock, with no global config layered on top. The lockfile pins the tool under [[tools."github:zizmorcore/zizmor"]]; the command keeps that full name and drops the version so the lockfile decides it.

If a version genuinely must live in the workflow (a toolchain: input to an action), teach Renovate to bump it in lockstep with a customManagers regex instead of leaving it manual. One source of truth is still preferred.

References

This post was written with AI assistance.