Skip to content

fix(cli): surface non-zero child exits in toolchain install/build - #2889

Merged
fakedev9999 merged 3 commits into
succinctlabs:mainfrom
MavenRain:fix/2856-toolchain-exit-status
Sep 10, 2026
Merged

fakedev9999 merged 3 commits into
succinctlabs:mainfrom
MavenRain:fix/2856-toolchain-exit-status

Conversation

@MavenRain

Copy link
Copy Markdown
Contributor

Motivation

Fixes #2856.

Several cargo prove toolchain commands treat child-process failures as success. Command::status() returns Err only when the process cannot be spawned or waited on — a process that runs and exits non-zero still returns Ok(status). The affected paths only checked the Ok/Err split, never ExitStatus::success():

  • crates/cli/src/commands/install_toolchain.rs — the tar -xzf ... extract and the rustup toolchain link ... calls used .status()? with no success check, so a failed extraction or link was ignored and the command still printed Successfully linked toolchain to rustup.
  • crates/cli/src/commands/build_toolchain.rs — the shared CommandExecutor::run() helper called .output().map(|_| ()), so git clone, git submodule update, python3 x.py build, rustup toolchain link, and tar were all considered successful as long as the process spawned, regardless of exit code.

The net effect is that a broken toolchain install/build can be reported as successful, surfacing later as confusing downstream failures instead of a clear error at the point of failure.

Solution

Check the exit status wherever these toolchain commands run to completion, and stop with a clear, command-tagged error on a non-zero exit:

  • build_toolchain.rs — CommandExecutor::run() now drives the command with .status() (stdio inheritance is unchanged) and returns an error unless status.success(). Because every command in that module goes through run(), this fixes all of them at once.
  • install_toolchain.rs — adds a small private run_checked(&mut Command) helper with the same success check, used for the two bare .status()? sites (tar extract, rustup toolchain link).

Intentionally left as-is: the "rustup toolchain remove" paths (which should tolerate "no toolchain installed") and the rustup --version / forge --version "is it installed?" probes, which legitimately only care whether the process could be spawned. I also audited the rest of crates/cli; the one other capturing call site (new.rs git clone) already checks output.status.success().

Regression tests (#[cfg(unix)], using sh -c "exit N") assert a non-zero child exit becomes an error and a zero exit returns Ok in both modules.

Behavior for the success path is unchanged; only genuinely failing commands now abort with an error instead of being silently ignored.

PR Checklist

  • Added Tests
  • Added Documentation (doc comment on the new run_checked helper)
  • Breaking changes

MavenRain and others added 3 commits July 15, 2026 17:46
`cargo prove` toolchain commands treated child-process failures as
success because only spawning/waiting was checked, never
`ExitStatus::success()`.  `Command::status()` returns `Err` only when the
process cannot be spawned or waited on; a process that runs and exits
non-zero still returns `Ok(status)`.  So a failed `tar` extraction,
`rustup toolchain link`, `git clone`, or `python3 x.py build` could be
ignored, and `install-toolchain` could still print
"Successfully linked toolchain to rustup." after a non-zero link exit.

- build_toolchain: `CommandExecutor::run()` now drives the command with
  `.status()` and returns an error unless the process exited
  successfully.  This covers every command routed through it (git clone,
  git reset/submodule, x.py build, rustup link, tar).
- install_toolchain: add a small `run_checked()` helper that reports a
  non-zero exit as an error, and use it for the `tar` extract and
  `rustup toolchain link` calls . .  . the only two bare `.status()?` sites.
  The deliberately-lenient "rustup toolchain remove" and "is rust
  installed" probes are left unchanged.

Add `#[cfg(unix)]` regression tests in both modules asserting that a
non-zero child exit becomes an error and a zero exit is `Ok`.

Closes succinctlabs#2856

Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>

@fakedev9999 fakedev9999 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @MavenRain, lgtm. I added a follow-up to exclude credentials from command errors, with tests covering nonzero exits and spawn failures.

@fakedev9999
fakedev9999 enabled auto-merge (squash) September 10, 2026 06:58
@fakedev9999
fakedev9999 merged commit a3f98a3 into succinctlabs:main Sep 10, 2026
21 of 22 checks passed
@MavenRain
MavenRain deleted the fix/2856-toolchain-exit-status branch September 10, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cargo prove toolchain commands can ignore non-zero child process exits

2 participants