Skip to content

mise.toml claims to mirror two files, and nothing checks either: golangci-lint and ruff are pinned twice, unguarded #749

Description

@stephrobert

Found while investigating a mise-action failure in another repository, then
checked here. The failure itself does not apply to feint, and that is worth
saying first because it is the reason this issue is narrow.

What does not apply

On 8 September 2026, mise.jdx.dev/VERSION announced 2026.9.3 while the
release carried no artefacts: the tag existed, the release did not, and any
action resolving "latest" composed a URL to a file that was never published.

feint is immune by construction: it does not install mise in CI at all, and
drift.yml says why in as many words, "Not mise run: mise is not installed on
a GitHub runner"
. There is nothing to fix there.

What does apply, and it is small

mise.toml promises, in its own comments, that two versions are mirrored
elsewhere:

golangci-lint = "2.12.2" # Go linters, mirrors .golangci.yml and the Go workflow
ruff = "0.14.9"          # Python lint + format, mirrors .pre-commit-config.yaml

Both mirrors exist, and both are currently correct:

tool mise.toml second copy agree today guarded
go 1.26.6 14 × go-version in workflows yes yes, TestTheGoWorkflowPinsTheVersionMiseDoes
uv 0.11.26 tools/ci/uv-requirements.txt yes yes, TestTheWorkflowsPinTheSameToolsAsMise
commitizen .pre-commit-config.yaml tools/ci/commitizen-requirements.txt yes yes, same test
golangci-lint 2.12.2 .github/workflows/go.yml:146, @v2.12.2 yes no
ruff 0.14.9 .pre-commit-config.yaml:65, rev: v0.14.9 yes no

Nothing is broken right now. What is missing is the thing that keeps it that
way, in a project that already built exactly that mechanism three times.

The comment in toolpins_test.go states the reason better than this issue
could:

A tool version written in two files drifts, and the failure is silent in the
worst direction: the workstation and the runner install different things, and
the artefacts the runner regenerates are produced by a tool nobody on the
project is using.

That argument holds for golangci-lint word for word: a linter whose CI version
differs from the workstation's reports findings a contributor cannot reproduce,
or misses ones they cannot see.

What this is not

Not a case for unpinning. The upstream incident argues the opposite: repos
that pinned did not fall. And feint already reasoned this through in
go.yml, where check-latest: true was tried and deliberately dropped because
it makes CI resolve a version the mise pin does not name.

Not python-version: '3.12' in commits.yml. It looks like the minor-pin
shape that go.yml's comment documents as having broken a morning of CI, but
the thing that matters there is commitizen, installed from a hash-pinned
requirements file whose version is guarded. The Python minor is not carrying a
promise.

Suggested shape

toolpins_test.go is already built for this: it takes an owner file, a pattern
to read the version there, and a list of repeats. Two entries added to the
owners and repeats maps would cover both, with mise.toml staying the
source, as its own comment says it is.

Done when

  • golangci-lint and ruff are compared between mise.toml and their second
    copy, and the test fails when the two disagree;
  • the test fails loudly when it can no longer find one of the versions,
    as the existing one already does, so it cannot pass while measuring nothing;
  • mise.toml's "mirrors …" comments name something a test verifies.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions