Repository navigation
fix(cli): keep usage explain from running a spec's choices run= commands - #1503
Conversation
`usage explain` promises never to start another program: a spec file that arrived with a bug report should not run its commands on the machine of whoever explains a line against it. Mounts were already answered without running anything, but #1497's `choices run=` ran its command to check a value. Parser gains `without_running_commands()`, which explain now uses: a value the declared choices don't accept is bound unchecked, and help describes the command instead of listing its output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Central YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 4 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthroughThe parser now supports skipping ChangesChoice command execution
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix Sequence Diagram(s)sequenceDiagram
participant Parser
participant NoRunScope
participant run_choices
participant ChoiceValidation
Parser->>NoRunScope: Enter scope when command execution is disabled
Parser->>run_choices: Resolve run= choices
run_choices->>NoRunScope: Check whether runs are disabled
run_choices-->>ChoiceValidation: Return shell error without executing command
ChoiceValidation-->>Parser: Ignore choice-check failure for run= choices
Merge Risk: ⚪ Minimal · up to The reviewed change is mergeable after normal checks; no actionable risk remains identified. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
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/usage/trails/33 <!-- entire-trail-link-end --> ### 🚀 Features - **(cli)** publish a usage agent skill with packslip by [@jdx](https://github.com/jdx) in [#1509](#1509) - **(complete)** complete a wrapped command's arguments with its own shell completion via delegate= by [@jdx](https://github.com/jdx) in [#1498](#1498) - **(lib)** add getters that read FlagMeta, CommandMeta and ArgMeta fields wherever they live by [@jdx](https://github.com/jdx) in [#1491](#1491) - **(lib)** export the chosen subcommand to scripts as usage_cmd by [@jdx](https://github.com/jdx) in [#1505](#1505) - **(spec)** let a complete node sit inside the arg it completes by [@jdx](https://github.com/jdx) in [#1496](#1496) - **(spec)** list an arg's possible values from a command with `choices run=` by [@jdx](https://github.com/jdx) in [#1497](#1497) ### 🐛 Bug Fixes - **(bash)** complete `--flag=` values when the cursor sits after `=` by [@jdx](https://github.com/jdx) in [#1499](#1499) - **(cli)** run scripts passed to usage bash through a pipe or process substitution by [@jdx](https://github.com/jdx) in [#1494](#1494) - **(cli)** keep usage explain from running a spec's choices run= commands by [@jdx](https://github.com/jdx) in [#1503](#1503) - **(complete)** read --line=LINE in completion requests from typed completers by [@jdx](https://github.com/jdx) in [#1487](#1487) - **(complete)** show completion parse errors without garbling the prompt by [@jdx](https://github.com/jdx) in [#1495](#1495) - **(derive)** ignore closed pipes instead of panicking in generated parse() by [@jdx](https://github.com/jdx) in [#1484](#1484) - **(derive)** keep generated async dispatch from reserving stack for every command by [@jdx](https://github.com/jdx) in [#1488](#1488) - **(fish)** complete words the user has started quoting by [@jdx](https://github.com/jdx) in [#1500](#1500) - **(lib)** resolve inherited usage aliases after multiline workspace entries by [@jdx](https://github.com/jdx) in [#1507](#1507) - **(lib)** make published usage-rs tests self-contained by [@jdx](https://github.com/jdx) in [#1510](#1510) - **(zsh)** stop the completion-init handler from breaking file completion for other commands by [@jdx](https://github.com/jdx) in [#1493](#1493) ### 📚 Documentation - **(cli)** describe fig output as the legacy Fig format by [@jdx](https://github.com/jdx) in [2a1bef6](2a1bef6) - clarify CLI frameworks and generators on the homepage by [@jdx](https://github.com/jdx) in [#1482](#1482) ### 🛡️ Security - remove Entire trail runners by [@jdx](https://github.com/jdx) in [#1485](#1485) ### 🔍 Other Changes - float jdx tools and aube on latest without a release-age delay by [@jdx](https://github.com/jdx) in [#1486](#1486) - run cargo-semver-checks on every published crate by [@jdx](https://github.com/jdx) in [#1490](#1490) - fail pull requests that grow the usage CLI or a derived CLI by more than 1% by [@jdx](https://github.com/jdx) in [#1492](#1492) - make the binary-size check measure the pull request's own code by [@jdx](https://github.com/jdx) in [#1501](#1501) ### 📦️ Dependency Updates - bump jdx/renovate-config workflows to c736149 by [@jdx](https://github.com/jdx) in [06f2f1b](06f2f1b) - bump jdx/renovate-config workflows to aa49efc by [@jdx](https://github.com/jdx) in [9aaedef](9aaedef) - bump jdx/renovate-config workflows to 5b46432 by [@jdx](https://github.com/jdx) in [36f8681](36f8681) - pin jdx/renovate-config workflows to v1.0.0 by [@jdx](https://github.com/jdx) in [a31ae2f](a31ae2f) - update communique to 1.4.2 in mise.lock by [@jdx](https://github.com/jdx) in [805396f](805396f) - upgrade locked mise tools by [@jdx](https://github.com/jdx) in [d8b761d](d8b761d) - update jdx/packslip action to v1.4.0 by [@jdx](https://github.com/jdx) in [#1508](#1508)
https://entire.io/gh/jdx/usage/trails/51
usage explainanswers "what would this command line bind to?" without running anything, and it promises that in the code: a spec file that arrived with a bug report shouldn't be able to run its commands on the machine of whoever explains a line against it. Mounts were already answered from injected outputs instead of being run. Butchoices run=(#1497) runs its command during parse-time validation, sousage explainran it too:Before:
usage explain -f spec.kdl m nopecreated/tmp/ran. After: nothing runs, and the report shows<svc> = "nope"bound from argv with no error. The value is let through unchecked, because only the command could say whether it's valid, and explaining must not ask it. Values the declared choices list are still checked as usual.Library:
Parser::without_running_commands()is new. With it set, achoices run=command never starts duringparse,explainorexplain_refused. A value outside the declared choices is accepted unchecked, and a help page reached through the parse describes the command instead of listing its output. Parsing without it is unchanged.usage explainnow uses it. Mounts are unaffected; they keep their existing injected-output handling. The MCP server only describes commands and never parses a command line, so it never ran these commands.Tests:
a_parser_told_not_to_run_commands_never_does(lib) anda_choices_command_is_never_run_to_answer_a_report(usage explain) check with a marker file that the command never ran. Both fail without the fix. Both are Unix-only, like the other command-running tests.cargo test --all --all-featuresandmise run lintpass.This was raised by Greptile's review of #1498, which is where the merged #1497 code showed up in its view.
🤖 Generated with Claude Code
Note
Medium Risk
Changes parse-time validation semantics for callers using
without_running_commands(); default parsing behavior is unchanged, but explain now may report values as bound that a real run would reject.Overview
usage explainno longer executeschoices run=shell commands when building a binding report. It now parses throughParser::without_running_commands(), matching the existing mount policy: inspect a line without side effects from untrusted specs.The library adds
Parser::without_running_commands()and a thread-localNoRunScope. While active,run_choicesrefuses to spawn processes; strict validation skips errors that would require command output, so argv values outside the static choice list are accepted unchecked (help text describes the command instead of listing its output). Declared static choices and mount injection behavior are unchanged when the flag is not set.Tests (Unix): marker-file checks in
explainandchoices_runassert therun=command never runs under explain / no-run parsing.Reviewed by Cursor Bugbot for commit eb0f6d1. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
explaincommand can now report choice values without runningchoices run=commands, avoiding their side effects during explanations.