Skip to content

Add rustflags passthrough to setup-rust and rust-build-release - #391

Merged
leynos merged 26 commits into
mainfrom
add-rustflags-passthrough-inputs
Aug 2, 2026
Merged

Add rustflags passthrough to setup-rust and rust-build-release#391
leynos merged 26 commits into
mainfrom
add-rustflags-passthrough-inputs

Conversation

@leynos

@leynos leynos commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

This branch adds a rustflags passthrough to the setup-rust and rust-build-release composite actions so consumers can stop the nested actions-rust-lang/setup-rust-toolchain step from silently stripping flags their builds require.

That nested step exports RUSTFLAGS="-D warnings" into the job environment whenever the variable is unset, and an ambient RUSTFLAGS overrides Cargo's build.rustflags configuration. Projects whose source tree requires specific flags in .cargo/config.toml — netsuke's -Zpolonius=next borrow-checker flag being the motivating case (leynos/netsuke#465, leynos/netsuke#472) — therefore fail to compile in any step after setup unless every recipe re-states the flags.

  • setup-rust/action.yml gains a rustflags input forwarded to all three nested setup-rust-toolchain invocations. The default preserves the historical -D warnings; the empty string leaves RUSTFLAGS unset so the project's Cargo configuration applies.
  • rust-build-release/action.yml gains a rustflags input exported ahead of its internally pinned setup-rust step, through a GITHUB_ENV heredoc with env-var indirection (no template expansion inside the script). A pre-existing RUSTFLAGS still takes precedence. Implementing the export locally avoids bumping the internal setup-rust-v1 pin inside this pull request.

Review walkthrough

Validation

  • uv run --with pytest --with pyyaml pytest .github/actions/setup-rust/tests/ .github/actions/rust-build-release/tests/test_manifest_input_step.py -q: all pass (30 + 7).
  • uv tool run ruff check and ruff format --check on the changed test files: clean.
  • markdownlint-cli2 on the changed READMEs and changelogs: 0 errors.

Notes

Behaviour is unchanged for existing consumers: setup-rust defaults to the historical -D warnings, and rust-build-release defaults to not touching the environment. Netsuke currently works around the issue with job-level RUSTFLAGS env blocks; once this lands and the action tags move, it can adopt the inputs instead.

References

Summary by Sourcery

Add configurable RUSTFLAGS passthrough to the shared Rust setup and release build composite actions to avoid clobbering project-specific compiler flags while preserving default behaviour for existing consumers.

New Features:

  • Introduce a rustflags input to the setup-rust composite action to control the RUSTFLAGS value used by nested setup-rust-toolchain steps.
  • Expose a rustflags input in the rust-build-release composite action that can export caller-provided RUSTFLAGS before toolchain setup.

Enhancements:

  • Ensure the rust-build-release action only exports RUSTFLAGS when the rustflags input is set and defers to any pre-existing RUSTFLAGS environment variable.
  • Document the new rustflags inputs and defaults in the READMEs and changelogs for both setup-rust and rust-build-release actions.

Tests:

  • Add manifest-level tests to verify the rustflags input defaults and wiring in setup-rust and rust-build-release action manifests.

@coderabbitai

coderabbitai Bot commented Jul 29, 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

  • Add configurable rustflags inputs to setup-rust and rust-build-release.
  • Forward rustflags to all setup-rust toolchain paths.
  • Export rustflags safely before setup in rust-build-release.
  • Preserve inherited RUSTFLAGS, including inherited empty values.
  • Support multiline values with collision-safe heredoc delimiters and Bash 3.2-compatible detection.
  • Add manifest, wiring, precedence, round-trip, injection, retry, failure, ordering, and act-backed workflow tests.
  • Reduce _parse_env_file complexity without changing behaviour or error messages.
  • Update action documentation, changelogs, user guidance, pipeline documentation, developer guidance, formatting examples, typing, and coverage-file handling.
  • No new ExecPlan document was added.

Validation

  • 1,079 tests passed.
  • 7 tests were skipped.
  • Ruff, formatting, and Markdown linting passed.

Walkthrough

The changes add caller-controlled RUSTFLAGS support to two composite actions, add tests and documentation, update repository support code, and reformat Python examples and documentation snippets.

Changes

Rust flags configuration

Layer / File(s) Summary
Release action flag export
.github/actions/rust-build-release/*, docs/rust-build-release-pipeline.md
The release action accepts rustflags and exports RUSTFLAGS before toolchain setup. Inherited values take precedence. Multiline values use a validated generated delimiter.
Toolchain flag forwarding
.github/actions/setup-rust/*
setup-rust adds optional rustflags, defaults it to -D warnings, and forwards it through all installation paths.
Rust flags validation and guidance
.github/actions/rust-build-release/tests/*, .github/workflows/test-rustflags-export.yml, tests/workflows/*, docs/users-guide.md, docs/developers-guide.md
Tests validate wiring, precedence, payload handling, delimiter safety, retries, failure handling, and workflow propagation. Documentation describes the same behaviour.

Repository maintenance

Layer / File(s) Summary
Support code and metadata updates
.coverage, .gitignore, .github/actions/release-to-pypi-uv/tests/_helpers.py, .github/actions/linux-packages/scripts/package.py, workflow_scripts/graphql_client.py
Coverage files are ignored and metadata is updated. Helper paths derive from the helper location. OctalInt._octal_width receives an int annotation. JsonValue retains the same members.
Module-glob test correction
workflow_scripts/tests/test_mutation_properties.py
The property test derives expected module globs from input paths and retains uniqueness, suffix, and separator checks.

Documentation formatting

Layer / File(s) Summary
Python rule and guide examples
.rules/*, docs/cmd-mox-users-guide.md, docs/python-action-scripts.md, docs/scripting-standards.md, docs/local-validation-of-github-actions-with-act-and-pytest.md
Examples receive spacing and equivalent presentation-only formatting updates.
Execution-plan snippets
docs/execplans/*
Embedded snippets receive blank-line and equivalent string-quoting updates.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant rust-build-release
  participant GITHUB_ENV
  participant setup-rust
  participant Cargo
  Caller->>rust-build-release: provide rustflags
  rust-build-release->>GITHUB_ENV: export RUSTFLAGS
  rust-build-release->>setup-rust: start toolchain setup
  setup-rust->>Cargo: apply forwarded rustflags
Loading

Possibly related PRs

Suggested reviewers: codescene-access

Poem

Export Rust flags before setup,
Preserve inherited values.
Delimiters guard each payload,
Tests check every boundary.
Examples align in clear rows.


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (2 errors)

Check name Status Explanation Resolution
Module-Level Documentation ❌ Error A repository scan found 1 of 216 Python modules without a module docstring: .github/actions/rust-build-release/tests/_packaging_utils.py. Add a module-level docstring to _packaging_utils.py that explains its re-export relationship to the linux-packages test helpers.
Security And Privacy ❌ Error Reject: the new setup-rust input reaches the pinned action, which writes echo "RUSTFLAGS=$NEW_RUSTFLAGS" to GITHUB_ENV; newline input injects extra variables. Write RUSTFLAGS with a collision-safe heredoc, or reject CR/LF before forwarding it. Add a runtime test proving newline input cannot create extra GITHUB_ENV entries.
✅ Passed checks (18 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the added rustflags passthrough to both composite actions.
Description check ✅ Passed The description directly explains the rustflags changes, rationale, documentation, tests, and preserved behaviour.
Docstring Coverage ✅ Passed Docstring coverage is 93.94% 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.
Testing (Overall) ✅ Passed The tests execute the export shell fragment and cover exact round-trips, adversarial multiline payloads, inherited empty/non-empty precedence, collision retries, three-attempt failure, all setup-ru...
User-Facing Documentation ✅ Passed Accept this check: docs/users-guide.md documents both inputs, defaults, precedence, empty-string behaviour, toolchain ordering, and practical YAML examples consistent with the action manifests.
Developer Documentation ✅ Passed Pass this check: docs/developers-guide.md documents both inputs, precedence, Bash 3.2, heredoc safety, observability, tests, and links the design document.
Testing (Unit And Behavioural) ✅ Passed Accept the check: subprocess tests cover round-trip, arbitrary payloads, inherited values, delimiter collisions and failure; act jobs verify both actions at later workflow steps.
Testing (Property / Proof) ✅ Passed The change introduces payload round-tripping, delimiter-safety, collision-retry, and inherited-value invariants. Substantive Hypothesis tests generate varied payloads and inherited states, with bou...
Testing (Compile-Time / Ui) ✅ Passed Pass this check: the PR changes no Rust or TypeScript source; focused environment-file assertions and act-backed Rust builds cover the action behaviour, so trybuild and snapshots are not appropriate.
Unit Architecture ✅ Passed Preserve the boundaries: the named export step isolates environment writes and failure handling, while tests inject values through env/PATH stubs and verify the real runner boundary.
Domain Architecture ✅ Passed The diff changes only CI/composite actions, workflow scripts, tests, docs, and typing metadata; no domain/application model or repository code changes were found.
Observability ✅ Passed The export step logs inherited deferral, bounded delimiter retries, success, and fatal exhaustion to stderr without logging flag or delimiter values; tests assert these diagnostics.
Performance And Resource Use ✅ Passed Accept the change: the only new runtime loop has three attempts and fixed 16-byte entropy reads; other changes only forward flags or update types, docs, and bounded tests.
Concurrency And State ✅ Passed The change uses GitHub Actions' sequential step boundary for GITHUB_ENV, documents the export-before-setup ordering, preserves inherited RUSTFLAGS, and tests retries, failure, precedence, and later...
Architectural Complexity And Maintainability ✅ Passed Accept this change: it adds no production abstraction, keeps the export logic explicit, reuses test-local manifest helpers, and documents the pinned-action seam without new dependencies.
Rust Compiler Lint Integrity ✅ Passed The PR changes no Rust source or Cargo files, and its complete diff adds no Rust lint suppressions or clone calls; it only updates action inputs, tests, and documentation.
✨ 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 add-rustflags-passthrough-inputs

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

codescene-access[bot]

This comment was marked as outdated.

@sourcery-ai

sourcery-ai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds a configurable rustflags passthrough to the setup-rust and rust-build-release composite actions, including wiring into nested setup-rust-toolchain calls, a guarded export step in rust-build-release, tests, and documentation/changelog updates while preserving existing default behavior.

Sequence diagram for rustflags passthrough in setup-rust and rust-build-release

sequenceDiagram
    actor Workflow
    participant RustBuildRelease as rust-build-release
    participant SetupRust as setup-rust
    participant SetupRustToolchain as setup-rust-toolchain

    Workflow->>RustBuildRelease: run (inputs.rustflags)
    alt inputs.rustflags != ''
        RustBuildRelease->>RustBuildRelease: Export caller RUSTFLAGS
        alt env.RUSTFLAGS already set
            RustBuildRelease-->>RustBuildRelease: keep inherited RUSTFLAGS
        else env.RUSTFLAGS unset
            RustBuildRelease-->>RustBuildRelease: write RUSTFLAGS to GITHUB_ENV
        end
    else inputs.rustflags == ''
        RustBuildRelease-->>RustBuildRelease: environment untouched
    end

    RustBuildRelease->>SetupRust: Setup Rust toolchain (rustflags input)
    SetupRust->>SetupRustToolchain: call with rustflags: ${{ inputs.rustflags }}
    alt env.RUSTFLAGS unset in setup-rust-toolchain
        SetupRustToolchain-->>SetupRustToolchain: export RUSTFLAGS "-D warnings"
    else env.RUSTFLAGS set
        SetupRustToolchain-->>SetupRustToolchain: keep existing RUSTFLAGS
    end
Loading

File-Level Changes

Change Details Files
Add rustflags input to setup-rust and forward it to all nested setup-rust-toolchain steps while preserving the historical -D warnings default.
  • Introduce optional rustflags input with default '-D warnings' describing precedence and interaction with Cargo config.
  • Pass inputs.rustflags through the with block to each actions-rust-lang/setup-rust-toolchain step (explicit toolchain, rust-toolchain file, stable default).
  • Document the new rustflags input in setup-rust README and record it in the setup-rust changelog with a new version entry.
  • Add tests to assert rustflags input existence, default value, and forwarding in all install steps.
.github/actions/setup-rust/action.yml
.github/actions/setup-rust/tests/test_setup_rust_manifest.py
.github/actions/setup-rust/README.md
.github/actions/setup-rust/CHANGELOG.md
Add rustflags input to rust-build-release and export it into the job environment before invoking setup-rust, without changing existing behavior when unset.
  • Introduce optional rustflags input with empty-string default and detailed description of interaction with nested setup-rust and Cargo config.
  • Add 'Export caller RUSTFLAGS' bash step that runs before toolchain setup, conditionally writes a RUSTFLAGS heredoc to GITHUB_ENV via env-var indirection, and defers to a pre-existing RUSTFLAGS.
  • Ensure step ordering so the export runs before 'Setup Rust toolchain'.
  • Document the rustflags input in rust-build-release README and changelog, describing precedence and motivation.
  • Add tests to validate rustflags input declaration, export step wiring (if condition, env mapping, script content, lack of template expansion), and ordering before the toolchain setup step.
.github/actions/rust-build-release/action.yml
.github/actions/rust-build-release/tests/test_manifest_input_step.py
.github/actions/rust-build-release/README.md
.github/actions/rust-build-release/CHANGELOG.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos marked this pull request as ready for review July 29, 2026 12:40

@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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f667b1b631

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/actions/rust-build-release/action.yml Outdated
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Jul 29, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

.github/actions/rust-build-release/tests/test_manifest_input_step.py

Comment on lines +66 to +93

def _parse_env_file(text: str) -> dict[str, str]:
    """Parse ``GITHUB_ENV`` content, honouring heredoc-delimited values."""
    values: dict[str, str] = {}
    lines = text.splitlines()
    index = 0
    while index < len(lines):
        line = lines[index]
        index += 1
        if not line:
            continue
        name, separator, remainder = line.partition("=")
        if separator:
            values[name] = remainder
            continue
        name, separator, delimiter = line.partition("<<")
        if not separator:
            message = f"unparsable environment-file line: {line!r}"
            raise AssertionError(message)
        collected: list[str] = []
        while index < len(lines) and lines[index] != delimiter:
            collected.append(lines[index])
            index += 1
        if index >= len(lines):
            message = f"unterminated heredoc for {name}"
            raise AssertionError(message)
        index += 1
        values[name] = "\n".join(collected)
    return values

❌ New issue: Complex Method
_parse_env_file has a cyclomatic complexity of 10, threshold = 9

@coderabbitai

This comment was marked as resolved.

@leynos

leynos commented Jul 29, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please investigate the cause of the following issue using codegraph exploration and research, identify a fix and provide an AI coding agent prompt for the fix:

Run uv sync --group dev
  uv sync --group dev
  uv run pytest
  shell: /bin/bash --noprofile --norc -e -o pipefail {0}
  env:
    MERMAN_CLI_VERSION: 0.7.0
    WHITAKER_INSTALLER_VERSION: 0.2.6
    UV_PYTHON_INSTALL_DIR: /Users/runner/work/_temp/uv-python-dir
    UV_PYTHON: 3.13
    UV_CACHE_DIR: /Users/runner/work/_temp/setup-uv-cache
    PYTHONIOENCODING: utf-8
Using CPython 3.13.14 interpreter at: /usr/local/bin/python3.13
Creating virtual environment at: .venv
Resolved 48 packages in 203ms
   Building shared-actions @ file:///Users/runner/work/shared-actions/shared-actions
Downloading ty (10.8MiB)
Downloading lxml (8.2MiB)
Downloading pygments (1.2MiB)
 Downloaded ty
 Downloaded lxml
 Downloaded pygments
      Built shared-actions @ file:///Users/runner/work/shared-actions/shared-actions
Prepared 46 packages in 2.70s
Installed 46 packages in 94ms
 + annotated-doc==0.0.5
 + anyio==4.14.2
 + attrs==26.1.0
 + certifi==2026.7.22
 + cmd-mox==0.2.0
 + cyclopts==3.24.0
 + docstring-parser==0.18.0
 + docutils==0.23
 + gherkin-official==29.0.0
 + h11==0.16.0
 + httpcore==1.0.9
 + httpx==0.28.1
 + hypothesis==6.163.0
 + idna==3.18
 + iniconfig==2.3.0
 + jinja2==3.1.6
 + lxml==6.1.1
 + lxml-stubs==0.5.1
 + mako==1.3.12
 + markdown-it-py==4.2.0
 + markupsafe==3.0.3
 + mdurl==0.1.2
 + packaging==26.2
 + parse==1.22.1
 + parse-type==0.6.6
 + pathspec==1.1.1
 + pluggy==1.6.0
 + plumbum==1.10.0
 + polythene==0.1.0 (from git+https://github.com/leynos/polythene.git@61b4566130305fcb32f419f09ae8b3940ceb4107)
 + pygments==2.20.0
 + pytest==9.1.1
 + pytest-bdd==8.1.0
 + pyyaml==6.0.3
 + rich==15.0.0
 + rich-rst==1.3.2
 + shared-actions==1.2.2 (from file:///Users/runner/work/shared-actions/shared-actions)
 + shellingham==1.5.4
 + six==1.17.0
 + sortedcontainers==2.4.0
 + syrupy==5.5.3
 + syspath-hack==0.4.0
 + tenacity==9.1.4
 + ty==0.0.64
 + typer==0.27.0
 + typing-extensions==4.16.0
 + uuid6==2025.0.1
============================= test session starts ==============================
platform darwin -- Python 3.13.14, pytest-9.1.1, pluggy-1.6.0
rootdir: /Users/runner/work/shared-actions/shared-actions
configfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)
testpaths: .github/actions, workflow_scripts/tests
plugins: syrupy-5.5.3, hypothesis-6.163.0, anyio-4.14.2, bdd-8.1.0
collected 1090 items

.github/actions/determine-release-modes/tests/test_determine_release_modes.py . [  0%]
..........................                                               [  2%]
.github/actions/ensure-cargo-version/scripts/tests/test_ensure_cargo_version.py . [  2%]
..............                                                           [  3%]
.github/actions/export-cargo-metadata/tests/test_read_manifest.py ...... [  4%]
........                                                                 [  5%]
.github/actions/generate-coverage/scripts/tests/test_run_rust_windows.py . [  5%]
.                                                                        [  5%]
.github/actions/generate-coverage/tests/test_archive_masking.py ...      [  5%]
.github/actions/generate-coverage/tests/test_cmd_utils.py ..             [  5%]
.github/actions/generate-coverage/tests/test_cmd_utils_loader.py ...     [  6%]
.github/actions/generate-coverage/tests/test_common.py ................. [  7%]
.......................                                                  [  9%]
.github/actions/generate-coverage/tests/test_detect.py ................. [ 11%]
.......                                                                  [ 11%]
.github/actions/generate-coverage/tests/test_ratchet_baseline.py ....... [ 12%]
.....                                                                    [ 13%]
.github/actions/generate-coverage/tests/test_scripts.py ................ [ 14%]
........................................................................ [ 21%]
.......................................................................  [ 27%]
.github/actions/generate-coverage/tests/test_set_outputs.py ......       [ 28%]
.github/actions/linux-packages/tests/test_action_workdir.py .....        [ 28%]
.github/actions/linux-packages/tests/test_deb_package.py s               [ 28%]
.github/actions/linux-packages/tests/test_package_cli.py ............... [ 30%]
.........s..                                                             [ 31%]
.github/actions/linux-packages/tests/test_rpm_package.py s               [ 31%]
.github/actions/linux-packages/tests/test_script_utils_helpers.py ...... [ 31%]
.....                                                                    [ 32%]
.github/actions/macos-package/tests/test_build_component.py ..           [ 32%]
.github/actions/macos-package/tests/test_build_product.py ....           [ 32%]
.github/actions/macos-package/tests/test_check_platform.py ..            [ 33%]
.github/actions/macos-package/tests/test_compute_version.py .....        [ 33%]
.github/actions/macos-package/tests/test_prepare_license_resources.py .. [ 33%]
                                                                         [ 33%]
.github/actions/macos-package/tests/test_prepare_payload.py .....        [ 34%]
.github/actions/macos-package/tests/test_shared_utils.py .........       [ 34%]
.github/actions/macos-package/tests/test_sign_package.py ...             [ 35%]
.github/actions/release-to-pypi-uv/tests/test_action_python_version.py . [ 35%]
....                                                                     [ 35%]
.github/actions/release-to-pypi-uv/tests/test_check_github_release.py .. [ 35%]
..........                                                               [ 36%]
.github/actions/release-to-pypi-uv/tests/test_confirm_release.py ..      [ 36%]
.github/actions/release-to-pypi-uv/tests/test_determine_release.py ..... [ 37%]
......                                                                   [ 37%]
.github/actions/release-to-pypi-uv/tests/test_publish_release.py ....... [ 38%]
                                                                         [ 38%]
.github/actions/release-to-pypi-uv/tests/test_validate_toml_versions.py . [ 38%]
...................................................                      [ 43%]
.github/actions/release-to-pypi-uv/tests/test_write_summary.py ...       [ 43%]
.github/actions/rust-build-release/tests/test_action_setup.py .......... [ 44%]
...........                                                              [ 45%]
.github/actions/rust-build-release/tests/test_command_wrapper.py ...     [ 45%]
.github/actions/rust-build-release/tests/test_cross_install.py ......... [ 46%]
..                                                                       [ 46%]
.github/actions/rust-build-release/tests/test_features.py .............. [ 48%]
..                                                                       [ 48%]
.github/actions/rust-build-release/tests/test_linux_package_step.py .    [ 48%]
.github/actions/rust-build-release/tests/test_manifest_input_step.py ... [ 48%]
......FFFF.                                                              [ 49%]
.github/actions/rust-build-release/tests/test_manifest_path.py ......... [ 50%]
.......                                                                  [ 51%]
.github/actions/rust-build-release/tests/test_runtime.py ............... [ 52%]
.............................                                            [ 55%]
.github/actions/rust-build-release/tests/test_rust_toy_workflow.py ..    [ 55%]
.github/actions/rust-build-release/tests/test_setup_rust_reference.py .. [ 55%]
                                                                         [ 55%]
.github/actions/rust-build-release/tests/test_smoke.py s..ss             [ 56%]
.github/actions/rust-build-release/tests/test_stage_artefacts_step.py .. [ 56%]
..                                                                       [ 56%]
.github/actions/rust-build-release/tests/test_stage_script_behaviour.py . [ 56%]
.....                                                                    [ 56%]
.github/actions/rust-build-release/tests/test_target_install.py ........ [ 57%]
................................                                         [ 60%]
.github/actions/rust-build-release/tests/test_toolchain_helpers.py ..... [ 61%]
.....                                                                    [ 61%]
.github/actions/rust-build-release/tests/test_toolchain_sanitize.py s    [ 61%]
.github/actions/rust-build-release/tests/test_utils.py ....              [ 62%]
.github/actions/setup-rust/tests/test_copy_stdlib.py ...                 [ 62%]
.github/actions/setup-rust/tests/test_setup_rust_manifest.py ........... [ 63%]
..........                                                               [ 64%]
.github/actions/setup-rust/tests/test_validate_workspaces.py ......      [ 64%]
.github/actions/stage-release-artefacts/tests/test_binstall_bdd.py .     [ 64%]
.github/actions/stage-release-artefacts/tests/test_config.py ........... [ 65%]
....                                                                     [ 66%]
.github/actions/stage-release-artefacts/tests/test_environment.py ...    [ 66%]
.github/actions/stage-release-artefacts/tests/test_output.py ..........  [ 67%]
.github/actions/stage-release-artefacts/tests/test_resolution.py ...     [ 67%]
.github/actions/stage-release-artefacts/tests/test_stage_binstall.py ... [ 67%]
........                                                                 [ 68%]
.github/actions/stage-release-artefacts/tests/test_stage_cli.py ....     [ 69%]
.github/actions/stage-release-artefacts/tests/test_stage_core.py ....... [ 69%]
......                                                                   [ 70%]
.github/actions/stage-release-artefacts/tests/test_stage_path_safety.py . [ 70%]
.......                                                                  [ 71%]
.github/actions/stage-release-artefacts/tests/test_stage_powershell.py . [ 71%]
........                                                                 [ 71%]
.github/actions/tests/test_actions_common.py ....                        [ 72%]
.github/actions/upload-release-assets/tests/test_upload_release_assets.py . [ 72%]
..................................                                       [ 75%]
.github/actions/validate-linux-packages/tests/deb/test_validate_packages.py . [ 75%]
...                                                                      [ 75%]
.github/actions/validate-linux-packages/tests/locators/test_locators.py . [ 75%]
...                                                                      [ 76%]
.github/actions/validate-linux-packages/tests/metadata/test_metadata_validators.py . [ 76%]
.....                                                                    [ 76%]
.github/actions/validate-linux-packages/tests/rpm/test_validate_packages.py . [ 76%]
......                                                                   [ 77%]
.github/actions/validate-linux-packages/tests/test_action_manifest.py .. [ 77%]
                                                                         [ 77%]
.github/actions/validate-linux-packages/tests/test_validate_architecture.py . [ 77%]
..                                                                       [ 77%]
.github/actions/validate-linux-packages/tests/test_validate_cli.py ..... [ 78%]
...........................                                              [ 80%]
.github/actions/validate-linux-packages/tests/test_validate_commands.py . [ 80%]
...                                                                      [ 81%]
.github/actions/validate-linux-packages/tests/test_validate_exceptions.py . [ 81%]
                                                                         [ 81%]
.github/actions/validate-linux-packages/tests/test_validate_helpers.py . [ 81%]
...                                                                      [ 81%]
.github/actions/validate-linux-packages/tests/test_validate_metadata.py . [ 81%]
...                                                                      [ 81%]
.github/actions/validate-linux-packages/tests/test_validate_normalize.py . [ 82%]
......                                                                   [ 82%]
.github/actions/validate-linux-packages/tests/test_validate_packages_diagnostics.py . [ 82%]
..                                                                       [ 82%]
.github/actions/validate-linux-packages/tests/test_validate_polythene.py . [ 82%]
...............                                                          [ 84%]
.github/actions/windows-package/tests/test_manifest.py ..                [ 84%]
.github/actions/windows-package/tests/test_plaintext_to_rtf.py ......... [ 85%]
.........                                                                [ 86%]
.github/actions/windows-package/tests/test_resolve_version_ps1.py ...... [ 86%]
.............                                                            [ 87%]
.github/actions/windows-package/tests/test_validate_inputs_ps1.py ...... [ 88%]
.........                                                                [ 89%]
.github/actions/windows-package/tests/test_windows_installer_template.py . [ 89%]
..............                                                           [ 90%]
workflow_scripts/tests/test_dependabot_automerge.py .................... [ 92%]
...................                                                      [ 94%]
workflow_scripts/tests/test_mutation_detect_changes.py ..............    [ 95%]
workflow_scripts/tests/test_mutation_properties.py ......                [ 96%]
workflow_scripts/tests/test_mutation_run_cargo.py ..............         [ 97%]
workflow_scripts/tests/test_mutation_run_mutmut.py ...........           [ 98%]
workflow_scripts/tests/test_mutation_summarize_cargo.py ........         [ 99%]
workflow_scripts/tests/test_mutation_testing_caller.py ......            [ 99%]
workflow_scripts/tests/test_mutation_workflow_shape.py ....              [100%]

=================================== FAILURES ===================================
________________ test_export_rustflags_writes_single_line_value ________________

tmp_path = PosixPath('/private/var/folders/pd/2_nlvl1s4k121pdk4d5_2c8m0000gn/T/pytest-of-runner/pytest-0/test_export_rustflags_writes_s0')

    def test_export_rustflags_writes_single_line_value(tmp_path: Path) -> None:
        """An ordinary value round-trips through the environment file."""
        result, env_text = _run_export_script(tmp_path, "-Zpolonius=next")
    
>       assert result.returncode == 0, result.stderr
E       AssertionError: /bin/bash: -c: line 1: conditional binary operator expected
E         
E       assert 2 == 0
E        +  where 2 = CompletedProcess(args=['/bin/bash', '-c', 'set -euo pipefail\nif [[ -v RUSTFLAGS ]]; then\n  echo "RUSTFLAGS already s... >> "$GITHUB_ENV"\n'], returncode=2, stdout='', stderr='/bin/bash: -c: line 1: conditional binary operator expected\n').returncode

.github/actions/rust-build-release/tests/test_manifest_input_step.py:207: AssertionError
______________ test_export_rustflags_contains_delimiter_lookalike ______________

tmp_path = PosixPath('/private/var/folders/pd/2_nlvl1s4k121pdk4d5_2c8m0000gn/T/pytest-of-runner/pytest-0/test_export_rustflags_contains0')

    def test_export_rustflags_contains_delimiter_lookalike(tmp_path: Path) -> None:
        """A value carrying the old fixed marker must not escape its heredoc."""
        result, env_text = _run_export_script(tmp_path, INJECTED_RUSTFLAGS)
    
>       assert result.returncode == 0, result.stderr
E       AssertionError: /bin/bash: -c: line 1: conditional binary operator expected
E         
E       assert 2 == 0
E        +  where 2 = CompletedProcess(args=['/bin/bash', '-c', 'set -euo pipefail\nif [[ -v RUSTFLAGS ]]; then\n  echo "RUSTFLAGS already s... >> "$GITHUB_ENV"\n'], returncode=2, stdout='', stderr='/bin/bash: -c: line 1: conditional binary operator expected\n').returncode

.github/actions/rust-build-release/tests/test_manifest_input_step.py:215: AssertionError
_____________ test_export_rustflags_delimiter_differs_between_runs _____________

tmp_path = PosixPath('/private/var/folders/pd/2_nlvl1s4k121pdk4d5_2c8m0000gn/T/pytest-of-runner/pytest-0/test_export_rustflags_delimite0')

    def test_export_rustflags_delimiter_differs_between_runs(tmp_path: Path) -> None:
        """Delimiters are generated per run so callers cannot predict them."""
        _, first = _run_export_script(tmp_path / "first", "-Zpolonius=next")
        _, second = _run_export_script(tmp_path / "second", "-Zpolonius=next")
    
>       assert first.splitlines()[0] != second.splitlines()[0]
               ^^^^^^^^^^^^^^^^^^^^^
E       IndexError: list index out of range

.github/actions/rust-build-release/tests/test_manifest_input_step.py:228: IndexError
_______________ test_export_rustflags_defers_to_inherited_value ________________

tmp_path = PosixPath('/private/var/folders/pd/2_nlvl1s4k121pdk4d5_2c8m0000gn/T/pytest-of-runner/pytest-0/test_export_rustflags_defers_t0')

    def test_export_rustflags_defers_to_inherited_value(tmp_path: Path) -> None:
        """An inherited RUSTFLAGS wins and nothing is written to the env file."""
        result, env_text = _run_export_script(
            tmp_path, "-Zpolonius=next", inherited="-D warnings"
        )
    
>       assert result.returncode == 0, result.stderr
E       AssertionError: /bin/bash: -c: line 1: conditional binary operator expected
E         
E       assert 2 == 0
E        +  where 2 = CompletedProcess(args=['/bin/bash', '-c', 'set -euo pipefail\nif [[ -v RUSTFLAGS ]]; then\n  echo "RUSTFLAGS already s... >> "$GITHUB_ENV"\n'], returncode=2, stdout='', stderr='/bin/bash: -c: line 1: conditional binary operator expected\n').returncode

.github/actions/rust-build-release/tests/test_manifest_input_step.py:237: AssertionError
--------------------------- snapshot report summary ----------------------------
4 snapshots passed.
=========================== short test summary info ============================
FAILED .github/actions/rust-build-release/tests/test_manifest_input_step.py::test_export_rustflags_writes_single_line_value - AssertionError: /bin/bash: -c: line 1: conditional binary operator expected
  
assert 2 == 0
 +  where 2 = CompletedProcess(args=['/bin/bash', '-c', 'set -euo pipefail\nif [[ -v RUSTFLAGS ]]; then\n  echo "RUSTFLAGS already s... >> "$GITHUB_ENV"\n'], returncode=2, stdout='', stderr='/bin/bash: -c: line 1: conditional binary operator expected\n').returncode
FAILED .github/actions/rust-build-release/tests/test_manifest_input_step.py::test_export_rustflags_contains_delimiter_lookalike - AssertionError: /bin/bash: -c: line 1: conditional binary operator expected
  
assert 2 == 0
 +  where 2 = CompletedProcess(args=['/bin/bash', '-c', 'set -euo pipefail\nif [[ -v RUSTFLAGS ]]; then\n  echo "RUSTFLAGS already s... >> "$GITHUB_ENV"\n'], returncode=2, stdout='', stderr='/bin/bash: -c: line 1: conditional binary operator expected\n').returncode
FAILED .github/actions/rust-build-release/tests/test_manifest_input_step.py::test_export_rustflags_delimiter_differs_between_runs - IndexError: list index out of range
FAILED .github/actions/rust-build-release/tests/test_manifest_input_step.py::test_export_rustflags_defers_to_inherited_value - AssertionError: /bin/bash: -c: line 1: conditional binary operator expected
  
assert 2 == 0
 +  where 2 = CompletedProcess(args=['/bin/bash', '-c', 'set -euo pipefail\nif [[ -v RUSTFLAGS ]]; then\n  echo "RUSTFLAGS already s... >> "$GITHUB_ENV"\n'], returncode=2, stdout='', stderr='/bin/bash: -c: line 1: conditional binary operator expected\n').returncode
================== 4 failed, 1079 passed, 7 skipped in 55.08s ==================
Error: Process completed with exit code 1.

@coderabbitai

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as resolved.

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 4

🤖 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 @.coverage:
- Around line 52-53: Remove the machine-specific .coverage artifact from the
change, add .coverage to the repository’s ignore configuration, and leave
coverage generation to CI. Do not retain the absolute worktree path; only
preserve repository-relative coverage data if intentionally versioned.

In @.github/actions/rust-build-release/action.yml:
- Around line 81-84: The inherited RUSTFLAGS check in
.github/actions/rust-build-release/action.yml lines 81-84 must use the Bash
3.2-compatible set-variable form [[ -n ${RUSTFLAGS+x} ]] instead of [[ -v
RUSTFLAGS ]]; update the corresponding assertion in
.github/actions/rust-build-release/tests/test_manifest_input_step.py line 197 to
expect the new guard.

In @.github/actions/rust-build-release/tests/test_manifest_input_step.py:
- Around line 55-56: Update the subprocess.run call in the test to pass
check=False explicitly, preserving the existing manual returncode assertion and
command execution behavior.

In @.github/actions/setup-rust/action.yml:
- Around line 44-46: Insert a comma before “so” in the RUSTFLAGS description at
.github/actions/setup-rust/action.yml lines 44-46 and the corresponding README
text at .github/actions/setup-rust/README.md line 23; make no other wording
changes.
🪄 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: 3d36f68c-9f28-483d-abf7-bcb8dd8380d8

📥 Commits

Reviewing files that changed from the base of the PR and between dca6131 and 42e70a8.

📒 Files selected for processing (25)
  • .coverage
  • .github/actions/linux-packages/scripts/package.py
  • .github/actions/release-to-pypi-uv/tests/_helpers.py
  • .github/actions/rust-build-release/CHANGELOG.md
  • .github/actions/rust-build-release/README.md
  • .github/actions/rust-build-release/action.yml
  • .github/actions/rust-build-release/tests/test_manifest_input_step.py
  • .github/actions/setup-rust/CHANGELOG.md
  • .github/actions/setup-rust/README.md
  • .github/actions/setup-rust/action.yml
  • .github/actions/setup-rust/tests/test_setup_rust_manifest.py
  • .rules/python-00.md
  • .rules/python-context-managers.md
  • .rules/python-exception-design-raising-handling-and-logging.md
  • .rules/python-generators.md
  • .rules/python-return.md
  • .rules/python-typing.md
  • docs/cmd-mox-users-guide.md
  • docs/execplans/2-4-5-extend-architecture-enforcement-to-orchestration-code.md
  • docs/execplans/add-mutation-testing-workflows.md
  • docs/execplans/support-cranelift-codegen.md
  • docs/local-validation-of-github-actions-with-act-and-pytest.md
  • docs/python-action-scripts.md
  • docs/scripting-standards.md
  • workflow_scripts/graphql_client.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • leynos/polythene (auto-detected)
🛑 Comments failed to post (1)
.coverage (1)

52-53: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Information Disclosure (CWE-200): Exposure of Sensitive Information to an Unauthorized Actor

Remove the machine-specific coverage database from the change.

Line 52-53 records an absolute /home/leynos/.../worktrees/... path, exposing local filesystem metadata and making the generated coverage artefact stale and non-portable. Remove .coverage from the patch, ignore it, and regenerate coverage in CI; retain only repository-relative data if versioning is intentional.

🤖 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 @.coverage around lines 52 - 53, Remove the machine-specific .coverage
artifact from the change, add .coverage to the repository’s ignore
configuration, and leave coverage generation to CI. Do not retain the absolute
worktree path; only preserve repository-relative coverage data if intentionally
versioned.

@pandalump

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

The shell-fragment tests run the export step against a fake GITHUB_ENV, so
nothing checked that the heredoc it writes is one a real runner accepts, nor
that the resulting RUSTFLAGS reaches a later step. Add two opt-in act tests
covering propagation and inherited-value precedence.

The workflow runs on the release event because the nested setup-rust skips
sccache for releases, and the sccache post-step fails under act.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Code Duplication

.github/actions/rust-build-release/tests/test_rustflags_export.py:

What lead to degradation?

The module contains 2 functions with similar structure: test_export_rustflags_defers_to_inherited_empty_value,test_export_rustflags_defers_to_inherited_value

Why does this problem occur?

Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health.

How to fix it?

A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

codescene-access[bot]

This comment was marked as outdated.

@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

The empty and non-empty cases differed only in the inherited value, so fold
them into one parametrized test. Each case gets its own temporary directory,
since the helper truncates the environment file per invocation.

The property test stays separate: it asserts the same precedence across
generated payloads rather than the two worked examples.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@coderabbitai

This comment was marked as resolved.

@leynos

leynos commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

.github/actions/rust-build-release/tests/test_manifest_input_step.py (1)

150-466: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Split this file: it now exceeds the 400-logical-line cap.
This file has grown to roughly 466 lines through this PR's additions (new imports, _parse_heredoc_value, the od stub, and nine new test functions). Move the delimiter-generation, collision-retry, and property-based round-trip tests into a separate module, for example test_manifest_input_step_heredoc.py, and keep manifest-structure assertions in this file. Share _load_action_manifest, _find_step, and _export_rustflags_run_script via a small local fixtures module or conftest.py.
As per path instructions, **/*.py files "must not exceed 400 logical lines: Decompose large modules into subpackages."

🤖 Detailed instructions

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/rust-build-release/tests/test_manifest_input_step.py around
lines 150 - 466, Split the oversized test module by moving delimiter-generation,
collision-retry, and property-based round-trip coverage—including tests using
_parse_env_file and _run_export_script—into a dedicated heredoc test module.
Keep manifest-structure assertions in the current module, and centralize shared
helpers such as _load_action_manifest, _find_step, and
_export_rustflags_run_script in a local fixtures module or conftest.py so each
Python file remains under 400 logical lines.

Source: Path instructions

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

test_dir=".github/actions/rust-build-release/tests"
main_test="$test_dir/test_manifest_input_step.py"

printf '%s\n' '--- current relevant files ---'
fd -t f . "$test_dir" | sort | rg 'test_manifest_input_step|heredoc|conftest|fixture|rustflags'

printf '%s\n' '--- physical and logical line counts ---'
for file in $(fd -t f -e py . "$test_dir" | sort); do
  case "$file" in
    *test_manifest_input_step*.py|*heredoc*.py|*/conftest.py|*fixture*.py)
      physical=$(wc -l < "$file")
      logical=$(awk 'NF && $1 !~ /^`#/`' "$file" | wc -l)
      printf '%s: physical=%s logical_noncomment=%s\n' "$file" "$physical" "$logical"
      ;;
  esac
done

printf '%s\n' '--- main module outline ---'
ast-grep outline "$main_test" --items all --view expanded

printf '%s\n' '--- helper definitions and relevant test definitions ---'
rg -n -C 2 \
  '^(def (_load_action_manifest|_find_step|_export_rustflags_run_script|_run_export_script|_parse_env_file|_parse_heredoc_value|_write_od_stub)|def test_.*(heredoc|delimiter|collision|round_trip|export_rustflags))' \
  "$test_dir" --glob '*.py' || true

printf '%s\n' '--- current main module boundaries ---'
nl -ba "$main_test" | sed -n '1,520p'

Length of output: 10348


🏁 Script executed:

#!/bin/bash
set -euo pipefail

test_dir=".github/actions/rust-build-release/tests"

printf '%s\n' '--- line counts for split-related Python modules ---'
for file in \
  "$test_dir/test_manifest_input_step.py" \
  "$test_dir/test_rustflags_export.py" \
  "$test_dir/rust_build_release_test_helpers.py" \
  "$test_dir/conftest.py"
do
  if [ -f "$file" ]; then
    physical=$(wc -l < "$file")
    logical=$(awk 'NF && $1 !~ /^`#/`' "$file" | wc -l)
    printf '%s: physical=%s logical_noncomment=%s\n' "$file" "$physical" "$logical"
  else
    printf '%s: absent\n' "$file"
  fi
done

printf '%s\n' '--- extracted test module outline ---'
ast-grep outline "$test_dir/test_rustflags_export.py" --items all --view expanded

printf '%s\n' '--- shared helper module outline ---'
if [ -f "$test_dir/rust_build_release_test_helpers.py" ]; then
  ast-grep outline "$test_dir/rust_build_release_test_helpers.py" --items all --view expanded
fi

printf '%s\n' '--- imports shared by the split modules ---'
sed -n '1,45p' "$test_dir/test_manifest_input_step.py"
sed -n '1,65p' "$test_dir/test_rustflags_export.py"
if [ -f "$test_dir/rust_build_release_test_helpers.py" ]; then
  sed -n '1,180p' "$test_dir/rust_build_release_test_helpers.py"
fi

printf '%s\n' '--- changed test-directory Python files in PR ---'
git diff --name-status origin/main...HEAD -- "$test_dir" -- '*.py' 2>/dev/null || true

printf '%s\n' '--- conftest diff summary ---'
git diff --numstat origin/main...HEAD -- "$test_dir/conftest.py" 2>/dev/null || true

Length of output: 9735


@leynos .github/actions/rust-build-release/tests/test_manifest_input_step.py — resolved

The current codegraph satisfies the reported requirement.

  • test_manifest_input_step.py is now 147 physical lines and 123 logical non-comment lines.
  • It now contains manifest-structure assertions only.
  • test_rustflags_export.py contains the extracted runtime coverage:
    • generated delimiters;
    • heredoc parsing;
    • inherited-value precedence;
    • property-based round trips;
    • delimiter-collision retries;
    • failure after three unsafe delimiters.
  • rust_build_release_test_helpers.py centralizes load_action_manifest, find_step, and export_rustflags_run_script.
  • The extracted module is 340 physical lines.
  • The helper module is 37 physical lines.

No further change is required for this finding.

conftest.py is currently 608 physical lines. It is outside this reported split. The available inspection did not establish whether this PR changed it. Assess that file separately before raising a new PR finding.

The sandbox could inspect the codegraph but could not run tests. Test execution remains unverified.

You are interacting with an AI system.

rust-build-release pins a remote setup-rust revision, so the existing act jobs
never ran the action this branch changes. Add two jobs that use the local
action directly, with an explicit toolchain so exactly one of its three
install paths is taken.

The first shows the input reaching a later step. The second pins the deferral
to an inherited value: setup-rust forwards the input unconditionally, so that
behaviour belongs to the nested setup-rust-toolchain and a version bump could
otherwise change it silently. Both were observed under act before the
assertions were written.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/test-rustflags-export.yml (1)

81-83: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the trailing blank line.

YAMLlint flags an extra blank line at the end of the file (empty-lines). Trim it.

🤖 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/workflows/test-rustflags-export.yml around lines 81 - 83, Remove the
trailing blank line at the end of the workflow after the
setup_rust_inherited_rustflags step, leaving the file ending immediately after
the final content line so YAML lint passes.

Source: Linters/SAST tools

🤖 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/workflows/test-rustflags-export.yml:
- Around line 8-11: Add a concurrency block to the workflow trigger
configuration so runs are grouped consistently and newer workflow_dispatch or
release runs cancel superseded in-progress runs. Preserve the existing triggers
and configure cancellation for in-progress executions.
- Around line 1-12: Add a workflow-level permissions block to the “Test
rustflags export” workflow, granting only contents: read. Do not add write
permissions or change the existing triggers and job behavior.
- Line 18: Update all four actions/checkout@v4 uses in the workflow to the
pinned commit 11d5960a326750d5838078e36cf38b85af677262 with the # v4 annotation,
and set persist-credentials to false for each checkout step.

In `@docs/developers-guide.md`:
- Around line 519-520: Update the prose in the heredoc explanation to remove the
comma before “because” in the phrase “as a plain assignment because the value
may contain newlines,” preserving the rest of the wording and meaning.

---

Outside diff comments:
In @.github/workflows/test-rustflags-export.yml:
- Around line 81-83: Remove the trailing blank line at the end of the workflow
after the setup_rust_inherited_rustflags step, leaving the file ending
immediately after the final content line so YAML lint passes.
🪄 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: adb7e1e6-7d06-47db-b5b5-ecd4f5167785

📥 Commits

Reviewing files that changed from the base of the PR and between 35d4919 and 07e4440.

📒 Files selected for processing (8)
  • .github/actions/rust-build-release/action.yml
  • .github/actions/rust-build-release/tests/rust_build_release_test_helpers.py
  • .github/actions/rust-build-release/tests/test_manifest_input_step.py
  • .github/actions/rust-build-release/tests/test_rustflags_export.py
  • .github/workflows/test-rustflags-export.yml
  • docs/developers-guide.md
  • tests/workflows/fixtures/release.event.json
  • tests/workflows/test_rustflags_export_workflow.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • leynos/polythene (auto-detected)

Comment thread .github/workflows/test-rustflags-export.yml
Comment thread .github/workflows/test-rustflags-export.yml
Comment thread .github/workflows/test-rustflags-export.yml Outdated
Comment thread docs/developers-guide.md Outdated
leynos and others added 3 commits August 2, 2026 15:24
The pinned setup-rust-toolchain writes its rustflags input to GITHUB_ENV as
`echo "RUSTFLAGS=$NEW_RUSTFLAGS"`, a plain assignment. Before this branch that
value was the action's own hardcoded default; adding the rustflags input made
it caller-controlled, so a line break in it would append further
environment-file entries and set variables the caller never asked for.

The nested action cannot be changed, so reject CR and LF before forwarding.
The rejected value is never echoed. Tests cover the three line-break forms and
pin the guard to the sink it protects by reproducing that echo and showing it
does create a second entry.

Move the rustflags tests into their own module to stay within the file size
limit, with the manifest lookups they share in a sibling helper.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pin the checkouts to the SHA the rest of the repository uses, drop their
credentials, restrict the token to contents: read, and cancel superseded runs.
The workflow was the only one of eighteen with no permissions block at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No quality gates enabled for this code.

@leynos

leynos commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

.github/workflows/test-rustflags-export.yml (1)

81-83: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the trailing blank line.
YAMLlint flags an extra blank line at the end of the file (empty-lines). Trim it.

🤖 Detailed instructions

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/workflows/test-rustflags-export.yml around lines 81 - 83, Remove the
trailing blank line at the end of the workflow after the
setup_rust_inherited_rustflags step, leaving the file ending immediately after
the final content line so YAML lint passes.

Source: Linters/SAST tools

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

workflow=".github/workflows/test-rustflags-export.yml"

printf '%s\n' '--- final numbered lines ---'
tail -n 12 "$workflow" | cat -n

printf '%s\n' '--- final bytes ---'
tail -c 32 "$workflow" | od -An -tx1c

printf '%s\n' '--- blank-line check after final content ---'
python3 - "$workflow" <<'PY'
from pathlib import Path
import sys

path = Path(sys.argv[1])
data = path.read_bytes()
print(f"ends_with_single_lf={data.endswith(b'\\n') and not data.endswith(b'\\n\\n')}")
print(f"trailing_lf_count={len(data) - len(data.rstrip(b'\\n'))}")
print(f"last_nonempty_line={next(line for line in reversed(data.decode('utf-8').splitlines()) if line.strip())!r}")
PY

printf '%s\n' '--- YAML lint configuration candidates ---'
fd -a -i '.yamllint*' . || true
rg -n -C 3 'empty-lines|yamllint' .yamllint* pyproject.toml Makefile .github 2>/dev/null || true

Length of output: 1856


🏁 Script executed:

#!/bin/bash
set -euo pipefail

workflow=".github/workflows/test-rustflags-export.yml"

printf '%s\n' '--- final lines with end-of-line markers ---'
tail -n 4 "$workflow" | sed -n 'l'

printf '%s\n' '--- terminal newline structure ---'
python3 - "$workflow" <<'PY'
from pathlib import Path
import sys

data = Path(sys.argv[1]).read_bytes()
trailing_newlines = len(data) - len(data.rstrip(b"\n"))
print(f"trailing_newlines={trailing_newlines}")
print(f"has_extra_terminal_blank_line={trailing_newlines > 1}")
print(f"ends_with_newline={data.endswith(b'\n')}")
PY

printf '%s\n' '--- whitespace errors in current diff ---'
git diff --check

printf '%s\n' '--- YAML lint configuration ---'
fd -a -i '.yamllint*' . || true
rg -n -C 3 'empty-lines|yamllint' \
  .yamllint .yamllint.yaml .yamllint.yml pyproject.toml Makefile \
  .github 2>/dev/null || true

Length of output: 1679


🏁 Script executed:

#!/bin/bash
set -euo pipefail

workflow=".github/workflows/test-rustflags-export.yml"

python3 - "$workflow" <<'PY'
from pathlib import Path
import sys

data = Path(sys.argv[1]).read_bytes()
trailing_newlines = len(data) - len(data.rstrip(b"\n"))
ends_with_newline = data.endswith(b"\n")
print(f"trailing_newlines={trailing_newlines}")
print(f"has_extra_terminal_blank_line={trailing_newlines > 1}")
print(f"ends_with_newline={ends_with_newline}")
PY

printf '%s\n' '--- whitespace errors in current diff ---'
git diff --check

printf '%s\n' '--- YAML lint configuration references ---'
rg -n -C 3 'empty-lines|yamllint' \
  .yamllint .yamllint.yaml .yamllint.yml pyproject.toml Makefile \
  .github 2>/dev/null || true

Length of output: 1056


@leynos .github/workflows/test-rustflags-export.yml — resolved

Do not make a change for this finding.

The current file ends after:

run: echo "setup_rust_inherited_rustflags=[${RUSTFLAGS-unset}]"

The file has exactly one terminal newline and no trailing blank line:

  • trailing_newlines=1
  • has_extra_terminal_blank_line=False
  • ends_with_newline=True

git diff --check reports no whitespace errors. The YAMLlint empty-lines diagnostic does not apply to the current codegraph.

You are interacting with an AI system.

@leynos

leynos commented Aug 2, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai please create new GitHub issues for the following:

❌ Failed checks (2 errors)

Check name Status Explanation Resolution
Module-Level Documentation ❌ Error A repository scan found 1 of 216 Python modules without a module docstring: .github/actions/rust-build-release/tests/_packaging_utils.py. Add a module-level docstring to _packaging_utils.py that explains its re-export relationship to the linux-packages test helpers.
Security And Privacy ❌ Error Reject: the new setup-rust input reaches the pinned action, which writes echo "RUSTFLAGS=$NEW_RUSTFLAGS" to GITHUB_ENV; newline input injects extra variables. Write RUSTFLAGS with a collision-safe heredoc, or reject CR/LF before forwarding it. Add a runtime test proving newline input cannot create extra GITHUB_ENV entries.

@leynos
leynos merged commit 47b337e into main Aug 2, 2026
29 checks passed
@leynos
leynos deleted the add-rustflags-passthrough-inputs branch August 2, 2026 13:50
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- affected helper module ---'
helper='.github/actions/rust-build-release/tests/_packaging_utils.py'
if [[ -f "$helper" ]]; then
  sed -n '1,120p' "$helper"
else
  printf 'Missing: %s\n' "$helper"
fi

printf '%s\n' '--- setup-rust RustFLAGS forwarding ---'
setup='.github/actions/setup-rust/action.yml'
rg -n -C 8 'rustflags|RUSTFLAGS|GITHUB_ENV|NEW_RUSTFLAGS' "$setup" || true

printf '%s\n' '--- candidate runtime tests ---'
rg -n -C 5 'RUSTFLAGS|rustflags|GITHUB_ENV|NEW_RUSTFLAGS' \
  .github/actions/setup-rust/tests \
  .github/actions/rust-build-release/tests \
  --glob '*.py' || true

printf '%s\n' '--- potentially duplicate open issues ---'
gh issue list --repo leynos/shared-actions --state open --limit 100 \
  --search '("packaging_utils" OR "module docstring" OR "RUSTFLAGS" OR "rustflags" OR "GITHUB_ENV" OR "newline injection") in:title,body' \
  --json number,title,url,body,assignees

Length of output: 65743


@leynos Do not create GitHub issues for these findings. Both findings are resolved in the current codegraph.

  • .github/actions/rust-build-release/tests/_packaging_utils.py now has a module docstring. The docstring states that it re-exports the linux-packages packaging test helpers for the rust-build-release test suite.
  • .github/actions/setup-rust/action.yml now rejects \n and \r in rustflags before it forwards the input to actions-rust-lang/setup-rust-toolchain. This prevents the pinned action’s plain GITHUB_ENV assignment from creating additional environment entries.
  • .github/actions/setup-rust/tests/test_rustflags_input.py covers LF, CRLF, and CR rejection. It also verifies the protected sink and confirms that the rejected payload is not logged.

Creating issues now would record already completed work as open defects.


✏️ Learnings added
Learnt from: leynos
URL: https://github.com/leynos/shared-actions/pull/391

Timestamp: 2026-08-02T13:50:24.377Z
Learning: In `leynos/shared-actions`, `.github/actions/rust-build-release/tests/_packaging_utils.py` is intentionally a path-loaded re-export module for the `linux-packages` packaging test helpers and has a module-level docstring that documents this relationship.

Learnt from: leynos
URL: https://github.com/leynos/shared-actions/pull/391

Timestamp: 2026-08-02T13:50:24.377Z
Learning: In `leynos/shared-actions`, `.github/actions/setup-rust/action.yml` validates the `rustflags` input before forwarding it to `actions-rust-lang/setup-rust-toolchain`. The `Validate rustflags` step rejects LF, CRLF, and CR because the nested action writes `RUSTFLAGS` to `GITHUB_ENV` as a plain assignment. `.github/actions/setup-rust/tests/test_rustflags_input.py` covers this newline-injection mitigation.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants