github jdx/usage v3.5.6
v3.5.6: Private completion cache and Markdown code-block escaping

11 hours ago

A security-focused patch release that moves the shell-completion spec cache out of world-writable /tmp into a private per-user cache dir, plus a Markdown renderer fix that stops mangling < inside fenced code blocks.

Fixed

  • Completion spec cache is no longer written to world-writable tmp (#727, fixes #722). The generated bash, zsh, fish, and nu completion scripts previously cached the usage spec at a predictable path under ${TMPDIR:-/tmp}. Because /tmp is typically world-writable and the filename is guessable, another local user could pre-plant a symlink there and have the completion script's >| / save -f overwrite an arbitrary file owned by the invoking user. Caches now live in a per-user directory created with mode 700:

    • bash / zsh / fish: ${XDG_CACHE_HOME:-$HOME/.cache}/usage
    • nu: ($env.XDG_CACHE_HOME? | default (home-dir | path join ".cache") | path join "usage")

    Because ~/.cache persists across reboots (unlike /tmp), version-keyed cache files are now reaped on a cache miss if they haven't been regenerated in 30 days. The prune is age-based and scoped to the current bin, so running two versions of the same tool concurrently no longer thrashes the cache. Users who regenerate their completion scripts will pick up the fix; the cache location change is otherwise transparent.

  • nu: completion cache dir permissions and nushell 0.110+ compatibility (#731). Nushell's builtin mkdir has no mode flag, so the initial fix in #727 created the nu cache dir at the process umask (usually 755, world-readable). The generator now runs ^chmod 0700 on the dir at creation time (non-Windows only) to match bash/zsh/fish. Separately, $nu.home-path was renamed to $nu.home-dir in nushell 0.110.0, which broke the completer on any recent nushell even when XDG_CACHE_HOME was set (because default's argument is evaluated eagerly). The lookup now uses optional access with a fallback that works on both old and new nushell:

    let spec_dir = ($env.XDG_CACHE_HOME? | default ($nu.home-dir? | default $nu.home-path? | path join ".cache") | path join "usage")
  • markdown: preserve HTML inside fenced code blocks (#720) — thanks @risu729. The Markdown renderer's HTML-escape filter processed lines independently and would turn < into &lt; even inside multiline fenced code blocks, corrupting examples like echo <value>. It now tracks fenced-block state across lines and leaves content between column-zero triple-backtick fences untouched, while still escaping < in surrounding prose. Addresses the escaping problem reported in jdx/mise#6949.

  • cli: avoid trailing semicolon in macro expression position (#729). The two miette::bail!("unsupported shell: ...") match arms in complete_word and usage_spec were wrapped in a block so the macro expands in statement position. This clears the semicolon_in_expressions_from_macros lint that is already a hard error on nightly Rust. Runtime behavior is unchanged.

  • lib: remove needless borrows in format! args (#726) — minor cleanup for newer clippy.

Full Changelog: v3.5.5...v3.5.6

💚 Sponsor usage

usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.

If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.

Don't miss a new usage release

NewReleases is sending notifications on new releases.