.NET: Harden dotnet-format workflow shell handling#6796
Conversation
Minor robustness improvements to how the dotnet-format workflow passes values to the shell. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR improves the robustness of the .github/workflows/dotnet-format.yml workflow by reducing direct expression interpolation into shell code and by invoking dotnet format in Docker without an intermediate /bin/sh -c, improving quoting and avoiding shell parsing of constructed command strings.
Changes:
- Pass workflow outputs into the shell via
env:variables (ADDED_MODIFIED,CSPROJ_FILES) instead of embedding them directly in the script. - Update the Docker invocation to avoid
/bin/sh -cand improve quoting for the bind mount andcsprojargument.
There was a problem hiding this comment.
Automated Code Review
Reviewers: 5 | Confidence: 95%
✓ Correctness
The PR correctly hardens the dotnet-format workflow by moving GitHub expression interpolations into environment variables (preventing script injection), quoting $(pwd) in the docker volume mount (preventing word-splitting on paths with spaces), quoting $csproj (handling paths with spaces), and removing the unnecessary /bin/sh -c wrapper inside the container (the dotnet/sdk image has no ENTRYPOINT, so the command executes directly via exec form). All changes preserve the existing behavior while improving robustness.
✓ Security Reliability
This PR correctly hardens the dotnet-format workflow against shell injection by moving step outputs into environment variables (preventing direct
${{ }} interpolation in run blocks), quoting $ (pwd) and $csproj to avoid word-splitting issues, and removing the unnecessary /bin/sh -c wrapper in the docker command. These are well-established GitHub Actions security best practices. No security or reliability issues found.
✓ Test Coverage
This PR hardens shell handling in the dotnet-format GitHub Actions workflow by moving step output expressions into environment variables (preventing shell injection/word-splitting issues) and properly quoting command arguments. These are CI configuration changes to a YAML workflow file, which is inherently not unit-testable—the workflow validates itself when it runs on PRs. No test coverage gap exists here as there is no testing infrastructure for workflow files in this repository, nor would adding one be appropriate for this type of change.
✓ Failure Modes
The PR correctly hardens shell handling by moving user-controlled outputs into environment variables (preventing injection), quoting command substitutions (preventing word-splitting on paths with spaces), and removing the unnecessary /bin/sh -c wrapper in the docker command (avoiding double shell interpretation). The remaining direct ${{ }} interpolation on line 62 (steps.changed-files.outcome) is safe because 'outcome' is a system-controlled enum value (success/failure/cancelled/skipped), not user data. No failure modes are introduced.
✓ Design Approach
The overall direction of removing the inner
/bin/sh -cis good, and I did not find a blocking design regression in the formatter invocation itself. The remaining issue is that the workflow still relies on shell word-splitting for path lists, so the hardening is incomplete: whitespace-containing paths would still be silently misparsed before they ever reach the now-quoteddotnet formatargument.
Suggestions
- The shell-hardening is only partial:
.github/workflows/dotnet-format.yml:63still iteratesADED_MODIFIEDwith shell word-splitting, and.github/workflows/dotnet-format.yml:84/:96serializes and reparsescsproj_filesthe same way. Consider switching both transfers to newline-delimited output pluswhile IFS= read -rormapfileso paths are preserved exactly.
Automated review by SergeyMenshykh's agents
Adjust shell settings around workflow path iteration for more predictable behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Minor robustness and hygiene improvements to how the
dotnet-formatworkflow passes values to the shell. No functional change to the formatting behavior.