Problem
The security/lint scanner toolchain is pinned to floating latest in mise.toml [tools], so a scanner release can silently change findings between runs. This makes the scheduled security suite non-reproducible and hard to triage — a run can go red with no repo change (e.g. #542's masking count and #593's failing subtask both shifted over time as tools moved).
Current unpinned tools (mise.toml [tools]):
prek = "latest"
gitleaks = "latest"
semgrep = "latest"
osv-scanner = "latest"
grype = "latest"
"aqua:zizmorcore/zizmor" = "latest"
All surfaces are governed by mise.toml (good news)
CI installs these via jdx/mise-action (see security.yml, security-pr.yml, build.yml, etc.), so pinning in mise.toml propagates to all three surfaces at once: local dev, mise run, and CI. No per-workflow duplication to chase. (Exception: build.yml sets MISE_DISABLE_TOOLS=aqua:aquasecurity/trivy,grype,semgrep for that job — those simply aren't installed there; the pins still govern where they DO run.)
Requirements
1. Pin the 6 scanner tools to exact versions in mise.toml [tools] (mirror how knip and the Cedar engines are already exact-pinned). Capture the currently-known-good versions, e.g. at time of writing: semgrep 1.157.0, gitleaks 8.30.1, osv-scanner (current), grype (current), zizmor (current), prek (current) — verify each against a green run before committing.
2. Pin mise itself. Today mise.toml only sets min_version = "2026.2.6" (a floor, not an exact version) — local and CI can drift to different mise releases. Decide and implement one of: (a) tighten to an exact min_version cadence, or (b) document the intended mise version and how it is bumped. Note the existing constraint context: minimum_release_age interplay called out in mise.toml (#320) and jdx/mise#10279 — preserve that reasoning.
3. Bump jdx/mise-action — Dependabot appears to have MISSED this. All workflows pin jdx/mise-action@e6a8b39… # v4.2.0, but latest is v4.2.4 (2026-08-01). .github/dependabot.yml does cover github-actions (package-ecosystem: "github-actions", directory: "/"), so this should have been flagged. As part of this issue: bump the action to v4.2.4 (by pinned SHA) across all workflows, AND investigate why Dependabot didn't open a PR (grouping? schedule? SHA-pin handling?) — fix the config gap so future action drift is caught automatically.
Gotchas
Acceptance criteria
References
#329 (prek↔CI toolchain SoT — likely overlap, reconcile), #320 (mise release-age), #542/#721/#593 (the non-reproducibility symptoms), ADR-003 (governance).
Problem
The security/lint scanner toolchain is pinned to floating
latestinmise.toml[tools], so a scanner release can silently change findings between runs. This makes the scheduled security suite non-reproducible and hard to triage — a run can go red with no repo change (e.g. #542's masking count and #593's failing subtask both shifted over time as tools moved).Current unpinned tools (
mise.toml[tools]):All surfaces are governed by
mise.toml(good news)CI installs these via
jdx/mise-action(seesecurity.yml,security-pr.yml,build.yml, etc.), so pinning inmise.tomlpropagates to all three surfaces at once: local dev,mise run, and CI. No per-workflow duplication to chase. (Exception:build.ymlsetsMISE_DISABLE_TOOLS=aqua:aquasecurity/trivy,grype,semgrepfor that job — those simply aren't installed there; the pins still govern where they DO run.)Requirements
1. Pin the 6 scanner tools to exact versions in
mise.toml[tools](mirror howknipand the Cedar engines are already exact-pinned). Capture the currently-known-good versions, e.g. at time of writing:semgrep 1.157.0,gitleaks 8.30.1,osv-scanner(current),grype(current),zizmor(current),prek(current) — verify each against a green run before committing.2. Pin
miseitself. Todaymise.tomlonly setsmin_version = "2026.2.6"(a floor, not an exact version) — local and CI can drift to different mise releases. Decide and implement one of: (a) tighten to an exactmin_versioncadence, or (b) document the intended mise version and how it is bumped. Note the existing constraint context:minimum_release_ageinterplay called out inmise.toml(#320) and jdx/mise#10279 — preserve that reasoning.3. Bump
jdx/mise-action— Dependabot appears to have MISSED this. All workflows pinjdx/mise-action@e6a8b39… # v4.2.0, but latest is v4.2.4 (2026-08-01)..github/dependabot.ymldoes covergithub-actions(package-ecosystem: "github-actions",directory: "/"), so this should have been flagged. As part of this issue: bump the action to v4.2.4 (by pinned SHA) across all workflows, AND investigate why Dependabot didn't open a PR (grouping? schedule? SHA-pin handling?) — fix the config gap so future action drift is caught automatically.Gotchas
semgrepinstall ordering:uvmust be on PATH beforesemgrepinstalls (see the existing comment inmise.toml). Preserve tool ordering/comments.prekmay interact with thecore.hooksPathhook-manager conflict noted in CONTRIBUTING.md — verifymise run hooks:installstill works after pinning.mise-actionby SHA: update BOTH the SHA and the trailing# v4.2.4comment in every workflow (7 files); a mismatch is a lint/readability trap.Acceptance criteria
= "latest"remains for the 6 scanners inmise.toml; each is an exact version.miseversion strategy is explicit (exact pin or documented bump path), preserving the#320release-age reasoning.jdx/mise-actionreferences are at the same pinned newer version (SHA + comment), and.github/dependabot.ymlis confirmed/fixed to catch action updates going forward.mise run securityreproduces the same findings on two consecutive runs (reproducibility check).References
#329 (prek↔CI toolchain SoT — likely overlap, reconcile), #320 (mise release-age), #542/#721/#593 (the non-reproducibility symptoms), ADR-003 (governance).