Skip to content

Ensure cargo-binstall before coverage tool installs#296

Open
leynos wants to merge 1 commit into
mainfrom
fix/generate-coverage-binstall-order
Open

Ensure cargo-binstall before coverage tool installs#296
leynos wants to merge 1 commit into
mainfrom
fix/generate-coverage-binstall-order

Conversation

@leynos

@leynos leynos commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Summary

This branch ensures the generate-coverage action installs cargo-binstall before it installs Rust coverage tools. That prevents fresh Linux and Windows runners from failing when cargo-llvm-cov invokes cargo binstall, while still reusing the binary that setup-rust normally provides.

No linked issue or execplan was identified for this regression fix.

Review walkthrough

Validation

  • make test: 934 passed, 14 skipped.
  • make check-fmt: passed.
  • make typecheck: passed.
  • make lint: passed.
  • git diff --check: passed.

Notes

The branch was renamed from session/a758c119 to fix/generate-coverage-binstall-order before the pull request was created, so no PR branch rename was required.

Install `cargo-binstall` before `cargo-llvm-cov` is installed so Rust
coverage runs can use `cargo binstall` on fresh runners. Keep the step
idempotent so `setup-rust` can continue to provide the binary when it is
already present.

Cover the action ordering and guard condition in the generate-coverage
manifest tests.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary

This pull request addresses a regression in the generate-coverage action where fresh Linux and Windows runners fail when cargo-llvm-cov attempts to invoke cargo binstall. The fix introduces an idempotent "Ensure cargo-binstall" step that executes before the Install cargo-llvm-cov step, ensuring the tool is available on all runners.

Changes

.github/actions/generate-coverage/action.yml

Added a new "Ensure cargo-binstall" step that:

  • Runs only for Rust and mixed-language projects (guarded by the same condition as cargo-llvm-cov installation)
  • Implements idempotent behaviour by checking if cargo-binstall is already available via command -v cargo-binstall, exiting immediately if found
  • Downloads the cargo-binstall installer from GitHub (pinned to v1.16.6) and verifies its SHA256 checksum before execution
  • Updates GITHUB_PATH to include the expected Cargo binary directory for immediate availability
  • Verifies that the installed cargo-binstall version matches the pinned version before proceeding

The step is placed before the existing Install cargo-llvm-cov step to ensure dependencies are available.

.github/actions/generate-coverage/tests/test_scripts.py

Extended test coverage by:

  • Introducing _generate_coverage_steps() helper to extract and type-check the runs.steps list from the action manifest
  • Introducing _generate_coverage_step(step_name) helper to locate a named step by its name field
  • Adding integration-style tests that verify:
    • "Ensure cargo-binstall" runs before "Install cargo-llvm-cov"
    • The step's if condition depends on Rust/mixed language detection and does not include use-cargo-nextest
    • The step is idempotent by validating the run script contains both command -v cargo-binstall and the success message
  • Refactoring _python_step_env_contract() to reuse the new _generate_coverage_steps() helper

Validation

All validation checks passed:

  • 934 tests passed, 14 skipped
  • Code formatting check passed
  • Type checking passed
  • Linting passed
  • Git diff whitespace check passed

Walkthrough

The generate-coverage composite action gains an idempotent "Ensure cargo-binstall" step that skips installation when the binary is already present, exports the Cargo bin directory to GITHUB_PATH, and asserts the installed version matches the pinned BINSTALL_VERSION. Three new tests and two shared helpers are added to verify step ordering, if-condition scope, and idempotent behaviour.

Changes

Idempotent cargo-binstall setup and tests

Layer / File(s) Summary
Idempotent binstall step and PATH/version verification
.github/actions/generate-coverage/action.yml
Adds an "Ensure cargo-binstall" early-check block that exits the step if the binary is already present, computes and exports the Cargo bin directory to GITHUB_PATH, and asserts the installed version matches BINSTALL_VERSION before proceeding to install cargo-llvm-cov.
Test helpers and new step-contract tests
.github/actions/generate-coverage/tests/test_scripts.py
Introduces _generate_coverage_steps() and _generate_coverage_step() helpers; adds test_generate_coverage_ensures_binstall_before_llvm_cov, test_generate_coverage_binstall_is_not_nextest_only, and test_generate_coverage_binstall_install_is_idempotent; refactors _python_step_env_contract() to use the shared helper.

Suggested Reviewers

  • codescene-delta-analysis

Poem

🦀 cargo-binstall knocks at the door,
Checks if it's home — no need to install more.
The PATH is exported, the version confirmed,
Idempotent habits have finally been learned.
Tests stand on guard to keep order in line —
Install once, verify twice, and all shall be fine! ✅


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (2 errors, 4 warnings)

Check name Status Explanation Resolution
Testing (Overall) ❌ Error Tests are vacuous: they only check for string presence in YAML and script text, not actual behaviour. The idempotent test would pass even if version verification were removed from the fast path, di... Strengthen tests to verify version checking logic executes in both fast and slow paths through integration tests or mock-based behavioural assertions, not just string presence checks.
Unit Architecture ❌ Error The "Ensure cargo-binstall" step violates unit architecture: fast path bypasses version verification (asymmetric fallibility contracts), tests verify source syntax not execution semantics. Restructure the step to invoke version verification BEFORE the early exit, ensuring both paths enforce identical validation contracts. Augment tests with integration-style execution or shell-script mocking.
Developer Documentation ⚠️ Warning The PR adds a new pinned tooling requirement (cargo-binstall v1.16.6) to generate-coverage but lacks documentation in CHANGELOG.md, developers-guide.md, and design documents. Add entry to CHANGELOG.md Unreleased section, create "generate-coverage cargo-binstall Pinning" section in developers-guide.md, and add design decision to generate-coverage-design.md for the new idempotent binstall installation step.
Testing (Unit And Behavioural) ⚠️ Warning The three new tests are manifest-only checks (YAML parsing and string assertions) disguised as behavioural tests. They never execute the shell script logic, verify functional boundaries, test error... Add integration tests that execute the Ensure cargo-binstall step with actual shell invocation, testing: (1) version mismatch detection in both fast and slow paths; (2) idempotency verification via actual command invocation; (3) hash ver...
Observability ⚠️ Warning Fast-path version verification is missing. The script logs when cargo-binstall exists (line 126) but exits (line 128) before performing the version check required in the slow path (lines 164-169),... Move the version check before the fast-path exit to ensure version verification always occurs, providing observability for version mismatches in both paths.
Concurrency And State ⚠️ Warning The idempotent fast path (lines 125-128) bypasses the version verification that the slow path enforces (lines 164-169). State transitions violate the version-pinning contract, and tests only check... Move the version verification check (lines 164-169) before the fast-path exit. Verify BINSTALL_VERSION immediately after the early-exit check, before line 128. Add integration tests that exercise both paths: success with correct version,...
✅ Passed checks (14 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main change: adding a cargo-binstall installation step before coverage tool installation.
Description check ✅ Passed The description is directly related to the changeset, providing context about the cargo-binstall ordering fix and the implementation approach.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
User-Facing Documentation ✅ Passed This PR modifies only the internal implementation of the generate-coverage action (adding an "Ensure cargo-binstall" step) without changing inputs, outputs, or user-facing behaviour documented in R...
Module-Level Documentation ✅ Passed The PR introduced no new Python modules. The only module modified (test_scripts.py) retains its comprehensive module-level docstring explaining purpose, utility, and relationships to other components.
Testing (Property / Proof) ✅ Passed Property-based testing or formal proof is not applicable here. The PR introduces simple step-ordering and conditional-logic invariants in YAML and Bash, not mathematically-ranged or state-space pro...
Testing (Compile-Time / Ui) ✅ Passed Check does not apply: PR modifies a GitHub Action manifest and adds contract tests validating YAML structure (step ordering, conditional expressions, shell script content), not compile-time Rust co...
Domain Architecture ✅ Passed This PR modifies GitHub Actions YAML and related tests—inherently infrastructure code. No domain logic exists to segregate from infrastructure concerns. The changes ensure cargo-binstall is install...
Security And Privacy ✅ Passed The pull request introduces no security or privacy risks. The new "Ensure cargo-binstall" step safely downloads, verifies and executes a third-party installer with SHA256 checksum validation. All c...
Performance And Resource Use ✅ Passed The PR introduces no algorithmic regressions, unbounded loops, memory leaks, or resource growth issues. The new "Ensure cargo-binstall" step executes a linear sequence of operations (PATH check, si...
Architectural Complexity And Maintainability ✅ Passed Abstractions introduced are proportional to the problem: three modest test helpers enable three focused tests validating step ordering, condition logic, and idempotent fast-path behaviour. No specu...
Rust Compiler Lint Integrity ✅ Passed PR modifies only YAML (.github/actions/generate-coverage/action.yml) and Python (.github/actions/generate-coverage/tests/test_scripts.py) files; no Rust source code (.rs) is present, so Rust Compil...
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/generate-coverage-binstall-order

Comment @coderabbitai help to get the list of available commands.

@pandalump pandalump marked this pull request as ready for review June 23, 2026 23:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/actions/generate-coverage/action.yml:
- Around line 121-128: The early exit in the Ensure cargo-binstall step accepts
any pre-existing cargo-binstall and exits immediately without verifying that its
version matches the pinned BINSTALL_VERSION. The version check must be performed
before the early exit succeeds. Restructure the logic to verify the version of
the existing cargo-binstall (using the same grep pattern that checks if the
version output matches the expected version string) before exiting; only exit
successfully if both the binary exists and the version matches, otherwise fall
through to the installation path to download the correct pinned version.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f8918c33-65b6-4a20-b3a8-2bacb145cf03

📥 Commits

Reviewing files that changed from the base of the PR and between 7da7c6d and 8c1b9e2.

📒 Files selected for processing (2)
  • .github/actions/generate-coverage/action.yml
  • .github/actions/generate-coverage/tests/test_scripts.py

Comment on lines +121 to +128
- name: Ensure cargo-binstall
if: steps.detect.outputs.lang == 'rust' || steps.detect.outputs.lang == 'mixed'
run: uv run --script "${{ github.action_path }}/scripts/install_cargo_llvm_cov.py"
shell: bash
- name: Install cargo-binstall
if: (steps.detect.outputs.lang == 'rust' || steps.detect.outputs.lang == 'mixed') && inputs.use-cargo-nextest == 'true'
run: |
set -euo pipefail
if command -v cargo-binstall >/dev/null 2>&1; then
echo "cargo-binstall already installed: $(cargo-binstall -V)"
exit 0
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect setup-rust's pinned cargo-binstall version for drift against generate-coverage.
fd -t f 'action.yml' .github/actions/setup-rust --exec rg -n 'BINSTALL_VERSION' {}
rg -n 'BINSTALL_VERSION' .github/actions/generate-coverage/action.yml

Repository: leynos/shared-actions

Length of output: 795


🏁 Script executed:

# Inspect the slow path in generate-coverage that allegedly enforces the pin
sed -n '159,170p' .github/actions/generate-coverage/action.yml

# Check if setup-rust installs or provides cargo-binstall
sed -n '1,200p' .github/actions/setup-rust/action.yml | grep -A 5 -B 5 'cargo-binstall\|cargo.*install'

Repository: leynos/shared-actions

Length of output: 3990


Move the pinned-version assertion ahead of the early exit; the fast path bypasses the version check.

The early-exit branch (lines 121–128) accepts any pre-existing cargo-binstall on PATH and exits immediately, but it never verifies the version matches BINSTALL_VERSION. The slow path (lines 164–169) enforces this: if ! "$cargo_binstall" -V | grep -qF "$binstall_ver" exits with status 1 on mismatch. This asymmetry violates the documented contract—the version check exists to fail when the installed binary drifts from the pinned release, yet the fast path silently bypasses it.

Both setup-rust and generate-coverage currently pin v1.16.6, so immediate practical risk is low. However, a runner with a pre-existing cargo-binstall (sourced from a previous workflow, system installation, or version drift in future updates) could bypass the version enforcement entirely. Restructure the fast path to verify the version before exiting.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/actions/generate-coverage/action.yml around lines 121 - 128, The
early exit in the Ensure cargo-binstall step accepts any pre-existing
cargo-binstall and exits immediately without verifying that its version matches
the pinned BINSTALL_VERSION. The version check must be performed before the
early exit succeeds. Restructure the logic to verify the version of the existing
cargo-binstall (using the same grep pattern that checks if the version output
matches the expected version string) before exiting; only exit successfully if
both the binary exists and the version matches, otherwise fall through to the
installation path to download the correct pinned version.

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.

1 participant