Skip to content

GH#4937: Fix wp-helper.sh SSH stdout capture#4940

Closed
alex-solovyev wants to merge 1 commit intomainfrom
bugfix/wp-helper-ssh-stdout
Closed

GH#4937: Fix wp-helper.sh SSH stdout capture#4940
alex-solovyev wants to merge 1 commit intomainfrom
bugfix/wp-helper-ssh-stdout

Conversation

@alex-solovyev
Copy link
Collaborator

@alex-solovyev alex-solovyev commented Mar 15, 2026

Summary

  • Root cause: bash -lc '...' _ path args passed as separate SSH arguments broke because SSH concatenates all remote-command arguments with spaces before the remote shell re-parses them. The local single quotes were stripped, so bash -c only received cd as its command — silently discarding the wp pipeline and its stdout.
  • Fix: New build_remote_wp_cmd() function constructs a single properly-quoted command string using printf %q. SSH sends it intact to the remote shell. No bash -lc wrapper needed — SSH already invokes the user's login shell.
  • Secondary fix: print_info in run_wp_command() now goes to stderr (>&2) so callers can capture just the WP-CLI stdout without the [INFO] prefix mixed in.

Changes

  • .agents/scripts/wp-helper.sh: Add build_remote_wp_cmd() helper, replace broken bash -lc SSH pattern in both key-based and password-based paths, redirect INFO line to stderr.

Testing

  • ShellCheck: zero violations (only SC1091 external source info, expected)
  • Requires live SSH server to fully verify — the broken pattern was discovered during t005.18.1 migration where direct SSH worked but wp-helper.sh returned empty stdout

Closes #4937

Summary by CodeRabbit

  • Bug Fixes
    • Fixed remote command execution reliability across multiple hosting platforms (Hostinger, Closte, Hetzner, Cloudways, and Cloudron).
    • Improved command output clarity by separating informational messages from operational results.

)

The bash -lc '...' _ path args pattern passed as separate SSH arguments
broke because SSH concatenates all remote-command arguments with spaces
before the remote shell re-parses them. The single quotes were stripped
locally, so bash -c only received 'cd' as its command — silently
discarding the rest of the pipeline including wp output.

Replace with build_remote_wp_cmd() that constructs a single properly-
quoted command string using printf %q. SSH sends it intact to the remote
shell. No bash -lc wrapper needed — SSH already invokes the user's login
shell.

Also redirect the run_wp_command INFO line to stderr so callers can
capture just the WP-CLI stdout without the [INFO] prefix mixed in.
@github-actions github-actions bot added the bug Auto-created from TODO.md tag label Mar 15, 2026
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug in wp-helper.sh where WP-CLI command output was being lost due to incorrect SSH argument parsing. It introduces a robust method for constructing remote shell commands, ensuring proper execution and argument handling. Additionally, it refines logging output to separate informational messages from command results, improving script usability and output parsing.

Highlights

  • SSH Command Parsing Fix: Resolved an issue where bash -lc '...' arguments were incorrectly parsed by SSH, leading to WP-CLI command truncation and swallowed output. The root cause was SSH concatenating arguments before the remote shell re-parsed them, stripping local quotes.
  • New build_remote_wp_cmd Function: Introduced build_remote_wp_cmd to construct a single, properly-quoted remote command string using printf %q, ensuring SSH sends it intact to the remote shell and correctly executes WP-CLI commands.
  • print_info Output Redirection: Modified print_info in run_wp_command to output informational messages to stderr instead of stdout, allowing callers to capture only the WP-CLI command's output without interference.
Changelog
  • .agents/scripts/wp-helper.sh
    • Added build_remote_wp_cmd function to safely construct remote SSH commands.
    • Replaced the problematic bash -lc SSH command pattern with calls to the new build_remote_wp_cmd function for both password-based and key-based SSH authentication.
    • Redirected print_info output within run_wp_command to stderr.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 15, 2026

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Review skipped — only excluded labels are configured. (1)
  • no-review

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ea27d201-5f9f-469e-8cef-e0356fa56e09

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Added build_remote_wp_cmd() function to construct properly quoted remote SSH commands, replacing array-based argument passing with single command strings. Redirected INFO messages to stderr. Fixes remote WP-CLI output being swallowed across SSH-based hosting providers.

Changes

Cohort / File(s) Summary
SSH Remote Command Handling
.agents/scripts/wp-helper.sh
Added build_remote_wp_cmd() function to construct single, properly escaped remote command strings for SSH. Updated Hostinger/Closte, Hetzner/Cloudways/Cloudron invocation paths to use the new function instead of array-based arguments. Redirected INFO status messages to stderr to separate command output from status information.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🚀 A single string now flows through SSH's door,
Where once array chaos left output deplored,
No more swallowed stdout on Cloudways' shore,
INFO to stderr, the bytes restored,
Remote commands clean — DevOps equilibrium restored! 📦

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix/wp-helper-ssh-stdout
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@alex-solovyev
Copy link
Collaborator Author

Closing — duplicate of PR #4938 which was already merged for issue #4937. This PR conflicts because the fix is already on main.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively resolves a critical bug where remote SSH commands were being truncated due to improper argument quoting. The introduction of the build_remote_wp_cmd function is a robust solution that correctly handles shell escaping. Additionally, redirecting informational logs to stderr is a great improvement for script usability. The changes are well-implemented and clearly documented. I have one minor suggestion to make the new helper function even more concise.

Comment on lines +292 to +296
local escaped_args=""
local arg
for arg in "${wp_args[@]}"; do
escaped_args+=" $(printf '%q' "$arg")"
done

Choose a reason for hiding this comment

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

medium

This loop for building escaped_args can be made more concise and efficient. The printf built-in can process an entire array of arguments at once, avoiding the need for a for loop and string concatenation.

Suggested change
local escaped_args=""
local arg
for arg in "${wp_args[@]}"; do
escaped_args+=" $(printf '%q' "$arg")"
done
local escaped_args
escaped_args=$(printf ' %q' "${wp_args[@]}")
References
  1. Use bash arrays for dynamic command construction to avoid duplicating argument expansion patterns and ensure safe handling of arguments, especially when constructing commands from arrays.

marcusquinn added a commit that referenced this pull request Mar 15, 2026
…itter

Root cause: multiple pulse runners evaluating the same issue simultaneously
create duplicate PRs. Process-based dedup (has_worker_for_repo_issue,
is-duplicate) only sees local processes — invisible across machines.

Fix 1: Add is-assigned command to dispatch-dedup-helper.sh that queries
GitHub assignees before dispatch. If another runner already self-assigned,
skip the issue. This is the primary cross-machine dedup guard.

Fix 2: Add 0-30s random startup jitter to pulse-wrapper.sh so concurrent
launchd-triggered pulses don't evaluate issues at the same instant.
Configurable via PULSE_JITTER_MAX (set to 0 to disable).

Fix 3: Update pulse.md dispatch instructions to enforce the assignee
check as a mandatory step alongside existing local process dedup.

Observed: PR #4940 duplicated PR #4938 for issue #4937 because
alex-solovyev's pulse dispatched 2 min after marcusquinn self-assigned,
interpreting the in-progress worker as 'failed'.
marcusquinn added a commit that referenced this pull request Mar 15, 2026
…tter (#4948)

* fix: prevent duplicate dispatch across runners via assignee check + jitter

Root cause: multiple pulse runners evaluating the same issue simultaneously
create duplicate PRs. Process-based dedup (has_worker_for_repo_issue,
is-duplicate) only sees local processes — invisible across machines.

Fix 1: Add is-assigned command to dispatch-dedup-helper.sh that queries
GitHub assignees before dispatch. If another runner already self-assigned,
skip the issue. This is the primary cross-machine dedup guard.

Fix 2: Add 0-30s random startup jitter to pulse-wrapper.sh so concurrent
launchd-triggered pulses don't evaluate issues at the same instant.
Configurable via PULSE_JITTER_MAX (set to 0 to disable).

Fix 3: Update pulse.md dispatch instructions to enforce the assignee
check as a mandatory step alongside existing local process dedup.

Observed: PR #4940 duplicated PR #4938 for issue #4937 because
alex-solovyev's pulse dispatched 2 min after marcusquinn self-assigned,
interpreting the in-progress worker as 'failed'.

* fix: validate PULSE_JITTER_MAX as numeric, use read -ra for assignee parsing

Address Gemini review feedback:
- Validate PULSE_JITTER_MAX is numeric before arithmetic (prevents
  set -e failures from non-integer env var values)
- Use read -ra for comma-separated assignee parsing instead of IFS
  word splitting (more robust against whitespace edge cases)
@marcusquinn marcusquinn added the already-fixed Already fixed by another change label Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

already-fixed Already fixed by another change bug Auto-created from TODO.md tag

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wp-helper.sh: SSH stdout swallowed — remote WP-CLI output not returned

2 participants