Repository navigation
fix(node): verify GPG signatures for every node version - #14132
Conversation
The SHASUMS256.txt signature was only checked when the version string started with "2", so 18.x, 19.x, 16.x and older installs skipped GPG verification entirely even though nodejs.org publishes a signature for them. Check every version; releases that never published a signature still hit the existing 404 path and warn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Entire-Checkpoint: 01M4CVM0A4Y99VR20MP97HR2N6
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 58 minutes. View limit detailsLimit details: Youβve used all 10 included reviews currently available. Review configuration: βοΈ Run configuration
π Files selected for processing (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
<!-- entire-trail-link-start --> https://entire.io/gh/jdx/mise/trails/570 <!-- entire-trail-link-end --> The docs rewrite (#14096, #14097, #14098) merged after a batch of behavior fixes, so several rewritten pages still described the old behavior. For example, the paranoid mode page said a monorepo root trusted before paranoid mode was turned on still trusts every config below it, and the `mise run ./script` section told you to run from the project root or pass an absolute path. This PR updates the pages so they describe what mise does now. It only changes documentation and one schema description. ## Trust, safe mode and hooks - `paranoid.md`, `tasks/monorepo.md`: paranoid mode never lets a monorepo root stand in for a descendant's own trust, even for a root trusted in normal mode. The `MISE_PARANOID=0 mise trust --untrust` workaround is gone ([#14105](#14105)). - `hooks.md`, `security.md`: `--no-hooks`, `MISE_NO_HOOKS`, `no_hooks` and safe mode also skip `[[watch_files]]` commands and tasks ([#14108](#14108)). - `environments/secrets/index.md`: `mise env --redacted` leaves out variables that set `redact = false`, so CI masking does not mask them ([#14109](#14109)). - `mcp.md`: the `install_tool` result also includes the install log as `output` ([#14111](#14111)). - `schema/mise.json` (and the generated `mise-task.json`): the `allow_net` description says per-host filtering is not supported, so Linux and macOS reject it ([#14106](#14106)). `sandboxing.md` already described the #14106 and #14107 behavior. ## Tasks - `tasks/file-tasks.md`: `mise run ./build.sh` resolves the path from the current directory, and the script still runs in the config root ([#14120](#14120)). Only a script extension such as `.sh` or `.py` is dropped from a file task's name, so `mise-tasks/gen.proto` is `gen.proto` ([#14159](#14159)). - `tasks/running-tasks.md`: `MISE_TASK_NAME` is the name `mise tasks ls` shows, without a script extension ([#14159](#14159)). `mise watch` passes its watchexec flags on, and watchexec's `--env` and `--quiet` are spelled `--watchexec-env` and `--watchexec-quiet` ([#14115](#14115)): ```sh mise watch -E dev --watchexec-env LOG_LEVEL=debug build ``` - `tasks/task-discovery.md`, `mise-cookbook/presets.md`: file tasks in `$MISE_CONFIG_DIR/tasks` are global without a global config file. The cookbook no longer creates an empty `config.toml` ([#14122](#14122)). - `tasks/task-configuration.md`: mise warns when `sources` match no files. `tasks/architecture.md`: `mise tasks deps <task>` shows post-dependencies ([#14122](#14122)). - `tips-and-tricks.md`: `mise generate task-stubs` skips hidden and global tasks ([#14127](#14127)). ## Settings, plugins and environments - `configuration/settings.md`: `mise settings set` refuses early-init settings, and `--local` refuses global-only settings ([#14126](#14126)). - `configuration/environment-variables.md`: `--log-level` takes `warn` ([#14125](#14125)). - `directories.md`: on Windows, temporary files default to `%TEMP%\mise-tmp`, because `%TEMP%\mise` is the cache ([#14134](#14134)). - `plugins.md`: `mise plugins uninstall --purge` also purges a backend plugin's `plugin:tool` installs and leaves shared and system installs in place ([#14117](#14117)). A packslip source in `[plugins]` needs no `vfox:` prefix ([#14141](#14141)). - `env-plugin-development.md`, `environments/index.md`: an env plugin directive whose plugin is not installed and has no source is skipped with a warning, instead of failing every command ([#14119](#14119)). - `direnv.md`: `mise direnv` prints a deprecation warning and will be removed in 2027.10.4 ([#14113](#14113)). ## Tools - `dev-tools/backends/github.md`: `size` is checked without `checksum` ([#14128](#14128)). - `dev-tools/backends/spm.md`, `dev-tools/mise-lock.md`: an `owner/repo` package clones from the `api_url` host, and spm is exempt from the lockfile URL check in `mise install --locked` ([#14129](#14129)). - `lang/node.md`, `security.md`: mise checks the OpenPGP signature for every Node.js release that publishes one, not only 20 and later ([#14132](#14132)). - `ide-integration.md`, `mise-cookbook/docker.md`: `mise generate devcontainer` sets `postCreateCommand` to `mise install` ([#14145](#14145)). ## Bootstrap - `bootstrap.md`: the old part names in parentheses (`shell`, `defaults`, `launchd`, `systemd`) print a deprecation warning ([#14113](#14113)). A dry run prints a hook that calls `exec()`, or reads a var computed with it, unrendered, with a note ([#14136](#14136)). - `bootstrap/firewall.md`: on macOS and Windows, `mise bootstrap` and `mise bootstrap plan` skip the Linux firewall with a warning. The SSH lockout check refuses only a real apply, and read-only commands report `unknown`. The UFW dry run lists `ufw --force reset` ([#14137](#14137)). - `bootstrap/packages/index.md`, `bootstrap/packages/scoop.md`: one package manager's failure no longer skips the others. An `absent` entry on a manager that cannot remove packages is skipped with a warning in a whole-config apply ([#14138](#14138)). - `bootstrap/shell.md`, `bootstrap/setup.md`: a tracked startup file still gets mise's activation block ([#14135](#14135)). The fix PRs that are still open update their own docs: #14104, #14110, #14114, #14121, #14124, #14139, #14143 and #14146. Validation: the docs build passes, including the link and anchor checker, and prettier and markdownlint are clean on the changed files. `schema/mise-task.json` was regenerated with `mise run render:schema`. *AI-assisted β Tool: Claude Code; model: anthropic/claude-opus-5-5; version: claude-code_2-1-289_agent.* π€ Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Documentation and JSON schema description updates only; no runtime code changes in this diff. > > **Overview** > **Aligns the docs (and task schema descriptions) with behavior shipped in recent fixes**, after the large docs rewrite had still described older semantics. > > **Trust, hooks, and tooling:** Paranoid mode no longer inherits monorepo-root trust for child configs. `--no-hooks` / safe mode also skip `[[watch_files]]`. `mise env --redacted` omits entries with `redact = false`. MCP `install_tool` documents install log `output`. `allow_net` schema text notes it is unsupported on Linux/macOS. > > **Tasks:** `mise run ./script` resolves from the current directory; file-task names drop only script extensions (e.g. `gen.proto` stays). `mise watch` forwards watchexec flags with renamed `--watchexec-env` / `--watchexec-quiet`. Global file tasks under `$MISE_CONFIG_DIR/tasks` work without a global config file; `task-stubs` skips hidden/global tasks. `sources` warns on empty matches; `mise tasks deps` shows post-deps in single-task trees. > > **Settings & plugins:** `mise settings set` refuses early-init and blocks `--local` on global-only settings. Plugin uninstall `--purge` covers backend tools; missing env plugins warn/skip instead of failing all commands. > > **Bootstrap & packages:** Documents deprecation of old bootstrap part names, dry-run `exec()` behavior, firewall SSH lockout vs read-only commands, non-Linux skip, UFW dry-run output, and per-manager package apply failures continuing other managers. > > **Install/backends:** GitHub `size` without `checksum`; SPM `api_url` clone host and lockfile URL exemption; Node GPG for all releases that publish signatures; devcontainer `postCreateCommand`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d751198. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
<!-- entire-trail-link-start --> https://entire.io/gh/jdx/mise/trails/493 <!-- entire-trail-link-end --> ### π Features - **(bootstrap)** add an os filter to files and directories by @jdx in [#14058](#14058) - **(bootstrap)** add auto mode for fish shell activation by @jdx in [#14172](#14172) - **(config)** merge [bootstrap] from config includes by @jdx in [#14176](#14176) - **(doctor)** show dotfiles repo path and origin by @jdx in [#14173](#14173) - **(dotfiles)** give each machine its own tracked version with a machine variant by @jdx in [#14062](#14062) - **(dotfiles)** infer merge sources and keep app state when switching from symlink by @jdx in [#14076](#14076) - **(dotfiles)** add merge = "missing" to fill in defaults the app may change by @jdx in [#14081](#14081) - **(dotfiles)** add track-local for history that never leaves the machine by @jdx in [#14082](#14082) - **(dotfiles)** refuse to publish saved versions that look like secrets by @jdx in [#14171](#14171) - **(installs)** move installs that cannot be reinstalled into the identity layout during migrate by @jdx in [#14079](#14079) - **(java)** **breaking** default java versions to Temurin builds by @jdx in [#14146](#14146) - **(mcp)** implement install_tool and require a trusted project for run_task by @jdx in [#14111](#14111) - **(packslip)** add a workflow option to pin the signing workflow by @jdx in [#14075](#14075) - **(packslip)** accept a list of signing workflows by @jdx in [#14093](#14093) ### π Bug Fixes - **(backend)** respect disable_backends in ls-remote by @jdx in [#14130](#14130) - **(bootstrap)** keep applying other package managers after one fails by @jdx in [#14138](#14138) - **(bootstrap)** skip the firewall section where it is unsupported by @jdx in [#14137](#14137) - **(bootstrap)** keep shell activation when a dotfile is tracked by @jdx in [#14135](#14135) - **(bootstrap)** warn on legacy command spellings and mise direnv by @jdx in [#14113](#14113) - **(bootstrap)** show hooks that use exec() in dry runs by @jdx in [#14136](#14136) - **(bootstrap)** support absent and unapply for systemd units by @jdx in [#14139](#14139) - **(brew)** infer formula version from the GitHub release tag path by @JamBalaya56562 in [#14165](#14165) - **(brew)** detach a DMG left attached by an interrupted install by @jdx in [#14177](#14177) - **(cargo)** do not resolve dependencies to mise shims by @jdx in [#14070](#14070) - **(cli)** accept yes/no booleans, prefix: in latest, and warn log level by @jdx in [#14125](#14125) - **(cli)** print the invoked command name in help by @jdx in [#14123](#14123) - **(cli)** replace unimplemented!() in --monorepo flags with an error by @jdx in [#14116](#14116) - **(config)** report an invalid tool version in config ls instead of panicking by @JamBalaya56562 in [#14094](#14094) - **(config)** verify .monorepo markers in paranoid mode by @jdx in [#14105](#14105) - **(config)** apply config environment files in directory order by @jdx in [#14148](#14148) - **(config)** ignore project bootstrap and dotfiles config in safe mode by @jdx in [#14110](#14110) - **(daemons)** quote deferred daemon commands for cmd.exe on Windows by @JamBalaya56562 in [#14055](#14055) - **(daemons)** run argv and Windows readiness probes in the tool environment by @JamBalaya56562 in [#14080](#14080) - **(doctor)** recognize a `mise` entry in the dedicated shims dir by @jdx in [#14069](#14069) - **(dotfiles)** say when incoming history changes no files on this machine by @jdx in [#14066](#14066) - **(dotfiles)** let MISE_YES confirm rollback, undo, and recover by @jdx in [#14067](#14067) - **(dotfiles)** save files replaced when adopting a setup, and add --take-remote-all by @jdx in [#14065](#14065) - **(dotfiles)** don't require --yes without a TTY for recoverable confirmations by @jdx in [#14071](#14071) - **(dotfiles)** stop prompting for recoverable operations by @jdx in [#14077](#14077) - **(edit)** do not overwrite an existing config without a terminal by @jdx in [#14124](#14124) - **(env)** honor redact = false exclusions in mise env --redacted by @jdx in [#14109](#14109) - **(env)** skip watch_files runs in safe mode and with --no-hooks by @jdx in [#14108](#14108) - **(exec)** install exact versions when the version list times out by @jdx in [#14164](#14164) - **(generate)** update the GitHub Actions and devcontainer templates by @jdx in [#14145](#14145) - **(generate)** skip hidden and global tasks in task-stubs by @jdx in [#14127](#14127) - **(github)** check asset size without a checksum by @jdx in [#14128](#14128) - **(github)** percent-encode the tag in gitlab release lookups by @thespags in [#14102](#14102) - **(java)** key the version cache by vendor and keep release_type by @jdx in [#14131](#14131) - **(migrate)** keep an unwritable stderr from aborting mise during a migration by @JamBalaya56562 in [#14158](#14158) - **(node)** verify GPG signatures for every node version by @jdx in [#14132](#14132) - **(npm)** stop npm view from re-entering mise through a foreign shim by @jdx in [#14084](#14084) - **(packslip)** let a user signer option replace a registry workflow default by @jdx in [#14091](#14091) - **(plugins)** install git:: plugins from a subdirectory by @jdx in [#14140](#14140) - **(plugins)** install packslip entries in [plugins] as vfox plugins by @jdx in [#14141](#14141) - **(plugins)** stop mise plugins uninstall --purge from panicking by @jdx in [#14117](#14117) - **(plugins)** install and compare git:: subdirectory sources from [plugins] by @onokonem in [#14150](#14150) - **(prune)** skip a tracked config whose tool version no longer parses by @JamBalaya56562 in [#14103](#14103) - **(ruby)** expand {os} and {arch} in precompiled URLs correctly by @jdx in [#14133](#14133) - **(sandbox)** clear inherited variables for --deny-env on Windows by @jdx in [#14107](#14107) - **(sandbox)** reject allow_net on macOS instead of writing invalid rules by @jdx in [#14106](#14106) - **(settings)** reject settings set in places mise ignores them by @jdx in [#14126](#14126) - **(shim)** skip version lookups for lazy tools that are not installed by @jdx in [#14063](#14063) - **(shim)** stop system fallback cycles through wrappers by @jdx in [#14088](#14088) - **(shim)** match Windows lazy shim names regardless of ASCII case by @jdx in [#14090](#14090) - **(spm)** use a custom api_url for cloning and skip lockfile URLs by @jdx in [#14129](#14129) - **(task)** report unmatched sources, show depends_post, and load global tasks by @jdx in [#14122](#14122) - **(task)** resolve mise run ./script relative to the current directory by @jdx in [#14120](#14120) - **(task)** send mbx-cache headers to the remote task cache by @jdx in [#14147](#14147) - **(task)** strip script extensions only from file task names by @jdx in [#14159](#14159) - **(task)** skip fresh raw and interactive cached tasks when their cache key is unchanged by @jdx in [#14121](#14121) - **(task)** keep secret values out of remote cache keys by @jdx in [#14104](#14104) - **(use)** create config.toml instead of writing global tools to config.<env>.toml by @jdx in [#14179](#14179) - **(vfox)** do not fail every command for an env plugin with no source by @jdx in [#14119](#14119) - **(vfox)** resolve embedded plugin files from the manifest dir by @jdx in [#14167](#14167) - **(watch)** pass watchexec flags through to watchexec by @jdx in [#14115](#14115) - keep temporary files out of the cache directory by @jdx in [#14134](#14134) - point error hints at current commands by @jdx in [#14142](#14142) - replace panics on bad input with errors by @jdx in [#14118](#14118) - require experimental for remote task sources, OpenTelemetry and spinel by @jdx in [#14114](#14114) ### π Documentation - **(agents)** treat 12 months as the default deprecation window by @jdx in [#14100](#14100) - **(cli)** hide mise bootstrap dotfiles and mise tasks run from help by @jdx in [#14101](#14101) - restructure and rewrite the documentation site by @jdx in [#14097](#14097) - rewrite CLI help and settings descriptions by @jdx in [#14098](#14098) - update pages for behavior changed by recent fixes by @jdx in [#14163](#14163) ### π§ͺ Testing - **(backend)** give test_ubi a longer version-fetch timeout by @jdx in [#14162](#14162) - **(config)** don't rely on teleport plugins being absent in not-found test by @jdx in [#14059](#14059) - **(windows)** isolate install fixtures and wait for executable teardown by @jdx in [#14089](#14089) ### π¦οΈ Dependency Updates - update rust crate demand to v2.4.0 by @renovate[bot] in [#14054](#14054) - update aube to v2.7.0 by @renovate[bot] in [#14074](#14074) ### π¦ Registry - pin packslip tools to the workflow that signs their releases by @jdx in [#14092](#14092) - rename mprocs to dekit and keep mprocs as an alias by @jdx in [#14169](#14169) ### Chore - **(docs)** keep moved pages reachable and fail on dead anchors by @jdx in [#14096](#14096) - **(settings)** deprecate settings that have no effect by @jdx in [#14112](#14112) - run e2e tests from mise run test and fix the registry test example by @jdx in [#14143](#14143) ### Ci - install mold from its GitHub release instead of apt by @jdx in [#14085](#14085) - stop installing direnv for the e2e tests by @jdx in [#14170](#14170) ### Security - **(http)** redact URL credentials in debug logs by @jdx in [#14155](#14155) - **(npm)** redact credentials in Git-source diagnostics by @jdx in [#14057](#14057) - **(npm)** redact normalized SSH diagnostics by @jdx in [#14064](#14064) - **(worktrunk)** pin the registry default to the release workflow on tags by @max-sixty in [#14073](#14073) ### New Contributors - @onokonem made their first contribution in [#14150](#14150) - @max-sixty made their first contribution in [#14073](#14073) ## π¦ Aqua Registry Updates ### Updated Packages (2) - [`charmbracelet/skate`](https://github.com/charmbracelet/skate) - [`pvolok/dekit`](https://github.com/pvolok/dekit)
Instruction counts
No instruction-count regression above 1%. Only instruction counts gate. Wall clock is shown for context β on identical hardware it moves 4-20% run to run. Measured by tak β instruction-counted CLI benchmarks, stored in this repository's git notes.
|
https://entire.io/gh/jdx/mise/trails/551
mise is supposed to check node's signed
SHASUMS256.txtbefore it trusts a download's checksum, but it only did this when the version string started with2. So installing node 18, 19, 16 or any older release skipped signature verification without saying so, even though nodejs.org publishesSHASUMS256.txt.sigfor those releases. The same check would also have stopped working once node reached 30.x.Before:
After:
Now every node version is checked, unless
node.gpg_verify(or the globalgpg_verify) isfalse. The bundled node release keyring verifies real signatures from v0.10.48 through v25.0.0. A few early releases (for example 0.12.0, 4.0.0 and 5.12.0) never published a signature; those still install, with the existinggpg signature not found, skipping verificationwarning.Migration: you do not need to change anything. If you use a mirror that has no signatures, or that answers the
.sigrequest with something other than 404, older versions now behave the way 20+ already did. Setnode.gpg_verify = falseto turn the check off.Validation: a new e2e test (
e2e/core/test_node_gpg_verify) serves an 18.x mirror whose signature does not match. The install fails on main's behaviour and is now rejected at the signature check. I also did real installs of 18.20.8 and 5.12.0 from nodejs.org.AI-assisted β Tool: Claude Code; model: anthropic/claude-opus-5-5; version: claude-code_2-1-289_agent.
π€ Generated with Claude Code
Note
Medium Risk
Expands security-critical install verification to all Node versions; mirrors without valid signatures may now fail installs that previously succeeded.
Overview
Node installs now verify
SHASUMS256.txtGPG signatures for all release lines, not only versions whose string started with2. The mistaken prefix check meant 18.x/19.x and future 30.x would skip signature validation even though nodejs.org publishes.sigfiles; releases without a signature still skip via the existing 404 path inverify_with_gpg.A new e2e test (
e2e/core/test_node_gpg_verify) serves a fake 18.20.8 mirror with a mismatched signature and expects install failure; it also confirmsMISE_NODE_GPG_VERIFY=falsebypasses GPG and fails later on checksum lookup. Security metadata text no longer claims GPG is limited to v20+.Reviewed by Cursor Bugbot for commit 48087ca. Bugbot is set up for automated code reviews on this repo. Configure here.