feat: add WordPress config templates and wp-helper.sh script#263
Conversation
- Add mainwp-config.json.txt template (fixes #260) - Add wordpress-sites.json.txt template (fixes #261) - Add wp-helper.sh script for multi-site WP-CLI operations (fixes #262) - Update wp-admin.md with setup instructions and wp-helper.sh reference The wp-helper.sh script reads from ~/.config/aidevops/wordpress-sites.json and supports multiple hosting types: LocalWP, Hostinger, Hetzner, Cloudways, Closte, and Cloudron. It can run WP-CLI commands on individual sites, by category, or on all configured sites.
Summary of ChangesHello @marcusquinn, 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 significantly enhances WordPress management capabilities by providing structured configuration templates and a powerful command-line utility. The new templates offer a standardized way to define MainWP and individual WordPress site settings, while the Highlights
Using Gemini Code AssistThe 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
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 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
|
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. WalkthroughAdds two JSON config templates for MainWP and WordPress sites, a new wp-helper.sh Bash script to run WP‑CLI across configured sites/hosting types, and updates WordPress docs with setup and usage examples. No runtime library/API changes. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Helper as wp-helper.sh
participant Config as ~/.config/aidevops/wordpress-sites.json
participant Remote as Remote Host (SSH / Local)
User->>Helper: invoke command (--list / <site> <wp-cli> / --all)
Helper->>Config: read & parse registry
Helper-->>Helper: select targets (single / category / all)
Helper->>Remote: run (local exec or SSH + WP‑CLI)
Remote-->>Helper: return output/status
Helper-->>User: aggregate & print results
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Fri Jan 30 21:00:59 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
There was a problem hiding this comment.
Code Review
This pull request introduces two new JSON configuration templates for MainWP and WordPress sites, along with a wp-helper.sh script to streamline WP-CLI operations across multiple WordPress installations. The documentation (wp-admin.md) has been updated to reflect these new tools and their usage. The wp-helper.sh script is a valuable addition, offering multi-site WP-CLI capabilities and supporting various hosting types. However, the script contains critical command injection vulnerabilities that must be addressed before merging. Additionally, there are opportunities to improve code clarity and security best practices.
.agent/scripts/wp-helper.sh
Outdated
| echo "cd \"$expanded_path\" && wp $wp_command" | ||
| ;; |
There was a problem hiding this comment.
The use of eval echo "$local_path" is a critical command injection vulnerability. If the path value in wordpress-sites.json contains malicious shell commands (e.g., ~/Local Sites/my-site/app/public; rm -rf /), they will be executed on the local machine. It's crucial to avoid eval with untrusted input.
Additionally, the wp_command should be explicitly quoted when passed to wp to prevent shell injection if wp_command itself contains shell metacharacters.
| echo "cd \"$expanded_path\" && wp $wp_command" | |
| ;; | |
| local expanded_path="${local_path/#\~/$HOME}" | |
| local quoted_local_path | |
| quoted_local_path=$(printf %q "$expanded_path") | |
| echo "cd $quoted_local_path && wp \"$wp_command\"" |
.agent/scripts/wp-helper.sh
Outdated
| # Hostinger/Closte - sshpass with password file | ||
| local expanded_password_file | ||
| if [[ -n "$password_file" ]]; then | ||
| expanded_password_file=$(eval echo "$password_file") | ||
| else | ||
| # Default password file locations | ||
| if [[ "$site_type" == "hostinger" ]]; then | ||
| expanded_password_file="${HOME}/.ssh/hostinger_password" | ||
| else | ||
| expanded_password_file="${HOME}/.ssh/closte_password" | ||
| fi | ||
| fi | ||
|
|
||
| if [[ ! -f "$expanded_password_file" ]]; then | ||
| print_error "Password file not found: $expanded_password_file" | ||
| print_info "Create the password file with your SSH password" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "sshpass -f \"$expanded_password_file\" ssh -p $ssh_port $ssh_user@$ssh_host \"cd $wp_path && wp $wp_command\"" |
There was a problem hiding this comment.
The use of sshpass for Hostinger and Closte sites, while functional, is generally discouraged due to security concerns. Passwords can be exposed in memory or in process lists, making them vulnerable. SSH key-based authentication is a more secure alternative. If sshpass is absolutely necessary due to hosting provider limitations, ensure the password files have strict permissions (e.g., chmod 600).
Furthermore, there is a critical command injection vulnerability here. The wp_path and wp_command are directly interpolated into the remote SSH command string without proper quoting for the remote shell. This allows for arbitrary command execution on the remote server if these values in wordpress-sites.json or the CLI arguments contain shell metacharacters.
# Hostinger/Closte - sshpass with password file
local expanded_password_file
if [[ -n "$password_file" ]]; then
expanded_password_file=$(eval echo "$password_file")
else
# Default password file locations
if [[ "$site_type" == "hostinger" ]]; then
expanded_password_file="${HOME}/.ssh/hostinger_password"
else
expanded_password_file="${HOME}/.ssh/closte_password"
fi
fi
if [[ ! -f "$expanded_password_file" ]]; then
print_error "Password file not found: $expanded_password_file"
print_info "Create the password file with your SSH password"
exit 1
fi
local quoted_wp_path
quoted_wp_path=$(printf %q "$wp_path")
echo "sshpass -f \"$expanded_password_file\" ssh -p $ssh_port $ssh_user@$ssh_host \"cd $quoted_wp_path && wp \\\"$wp_command\\\"\""
.agent/scripts/wp-helper.sh
Outdated
| ;; | ||
| hetzner|cloudways|cloudron) | ||
| # SSH key-based authentication | ||
| echo "ssh -p $ssh_port $ssh_user@$ssh_host \"cd $wp_path && wp $wp_command\"" |
There was a problem hiding this comment.
Similar to the hostinger|closte case, there is a critical command injection vulnerability here. The wp_path and wp_command are directly interpolated into the remote SSH command string without proper quoting for the remote shell. This allows for arbitrary command execution on the remote server if these values in wordpress-sites.json or the CLI arguments contain shell metacharacters.
| echo "ssh -p $ssh_port $ssh_user@$ssh_host \"cd $wp_path && wp $wp_command\"" | |
| local quoted_wp_path | |
| quoted_wp_path=$(printf %q "$wp_path") | |
| echo "ssh -p $ssh_port $ssh_user@$ssh_host \"cd $quoted_wp_path && wp \\\"$wp_command\\\"\"" |
.agent/scripts/wp-helper.sh
Outdated
| @@ -0,0 +1,445 @@ | |||
| #!/bin/bash | |||
| # shellcheck disable=SC2034,SC2155 | |||
There was a problem hiding this comment.
The shellcheck disable=SC2034 directive is used, but the HELP_SHOW_MESSAGE variable (line 25) is indeed unused. It's better to remove unused variables to keep the code clean and avoid unnecessary disables, or ensure they are used if intended.
| # shellcheck disable=SC2034,SC2155 | |
| #!/bin/bash | |
| # shellcheck disable=SC2155 |
.agent/scripts/wp-helper.sh
Outdated
| readonly ERROR_SITE_NOT_FOUND="Site not found in configuration" | ||
| readonly ERROR_SITE_REQUIRED="Site identifier is required" | ||
| readonly ERROR_COMMAND_REQUIRED="WP-CLI command is required" | ||
| readonly HELP_SHOW_MESSAGE="Show this help" |
🤖 Augment PR SummarySummary: This PR adds WordPress admin configuration templates and a multi-site WP-CLI helper script to simplify repeated maintenance tasks across multiple WordPress installs. Changes:
Technical Notes: The helper script reads 🤖 Was this summary useful? React with 👍 or 👎 |
.agent/scripts/wp-helper.sh
Outdated
| localwp) | ||
| # LocalWP - direct local access | ||
| local expanded_path | ||
| expanded_path=$(eval echo "$local_path") |
There was a problem hiding this comment.
eval is used to expand values sourced from wordpress-sites.json (e.g., path/password_file), which can execute arbitrary shell code if those fields contain substitutions; this is a risky footgun even for local tooling.
Other Locations
.agent/scripts/wp-helper.sh:153.agent/scripts/wp-helper.sh:208
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| run_wp_command() { | ||
| local site_key="$1" | ||
| shift | ||
| local wp_command="$*" |
There was a problem hiding this comment.
| } | ||
|
|
||
| # Check dependencies | ||
| check_dependencies() { |
.agent/scripts/wp-helper.sh
Outdated
| exit 1 | ||
| fi | ||
|
|
||
| echo "sshpass -f \"$expanded_password_file\" ssh -p $ssh_port $ssh_user@$ssh_host \"cd $wp_path && wp $wp_command\"" |
There was a problem hiding this comment.
For SSH-based site types, there’s no validation that required fields like ssh_host, ssh_user, and wp_path are present; if any are empty, the constructed ssh ... "cd ..." command will be malformed or run in an unexpected directory.
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
.agent/scripts/wp-helper.sh
Outdated
| print_info "Available categories:" | ||
| jq -r '.sites[].category // "uncategorized"' "$CONFIG_FILE" | sort -u | while read -r cat; do | ||
| local count | ||
| count=$(jq -r "[.sites[] | select(.category == \"$cat\")] | length" "$CONFIG_FILE") |
There was a problem hiding this comment.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.agent/scripts/wp-helper.sh:
- Around line 237-248: The post-increment arithmetic ((success_count++)) and
((fail_count++)) can return 0 and trigger a set -e exit; change these to use
pre-increment or explicit addition so the expression returns a non-zero
value—e.g., replace ((success_count++)) with ((++success_count)) or
((success_count+=1)) and do the same for fail_count; also apply the identical
fix to the increments inside the run_on_all loop (the other occurrence
referenced) so both success_count and fail_count updates never evaluate to zero.
🧹 Nitpick comments (3)
.agent/scripts/wp-helper.sh (2)
84-86: Consider using jq's--argfor safer variable interpolation.Embedding shell variables directly in jq filters (e.g.,
.sites.\"$site_key\") can behave unexpectedly if the variable contains special characters. While this is a local CLI tool with limited attack surface, using--argis more robust.♻️ Safer jq pattern
- site_config=$(jq -r ".sites.\"$site_key\"" "$CONFIG_FILE") + site_config=$(jq -r --arg key "$site_key" '.sites[$key]' "$CONFIG_FILE")Similar changes would apply to lines 101, 115, 230, 273, 311, and 313.
144-147: Consider safer tilde expansion withouteval.Using
eval echofor tilde expansion works but can be risky if the path contains unexpected shell metacharacters. A safer alternative is parameter expansion.♻️ Safer tilde expansion
- local expanded_path - expanded_path=$(eval echo "$local_path") + local expanded_path="${local_path/#\~/$HOME}"Apply similarly to line 153 for
password_fileexpansion..agent/configs/mainwp-config.json.txt (1)
4-4: Setup instruction could include the full destination path.For consistency with the wordpress-sites.json.txt template and to provide clearer guidance, consider specifying the full path in the
_setupfield.📝 Suggested improvement
- "_setup": "Copy to mainwp-config.json and fill in your credentials", + "_setup": "Copy to ~/.config/aidevops/mainwp-config.json and fill in your credentials (chmod 600)",Based on learnings: "Store Service Configurations in ~/Git/aidevops/configs/[service]-config.json with file permissions set to 600"
- Remove eval usage to prevent command injection - Use safe tilde expansion with parameter substitution - Quote paths with printf %q for safe shell execution - Remove unused HELP_SHOW_MESSAGE constant - Add note about sshpass security and chmod 600 recommendation Addresses CodeRabbit security review feedback.
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Fri Jan 30 21:05:04 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @.agent/scripts/wp-helper.sh:
- Around line 218-220: The eval "$ssh_command" call still allows command
injection; replace it by building the SSH invocation as a Bash array and
executing it without eval (e.g., construct ssh_command as an array variable and
run it as "${ssh_command[@]}"), and ensure the wp_command pieces are properly
escaped or passed as separate array elements instead of interpolating into a
single string; update any code that sets ssh_command or wp_command so they push
safe, quoted tokens into the array rather than concatenating raw strings.
- Around line 121-192: The build_ssh_command function embeds the unescaped
parameter wp_command directly into constructed shell strings (used later with
eval), creating a command injection risk; fix by shell-quoting/escaping
wp_command the same way paths are handled (use printf %q "$wp_command" and
reference the resulting variable) in every branch that constructs a command
(localwp, hostinger|closte, hetzner|cloudways|cloudron) so the echoed strings
use the quoted wp_command variable rather than raw $wp_command.
🧹 Nitpick comments (4)
.agent/scripts/wp-helper.sh (4)
78-89: Usejq --argto safely pass user-provided site keys.The current jq query interpolates
$site_keydirectly into the filter string. If a site key contains characters like"or\, the query could malfunction or produce unexpected results. Using--argis the robust approach for passing external variables to jq.♻️ Proposed fix using --arg for safe variable passing
local site_config - site_config=$(jq -r ".sites.\"$site_key\"" "$CONFIG_FILE") + site_config=$(jq -r --arg key "$site_key" '.sites[$key]' "$CONFIG_FILE") if [[ "$site_config" == "null" ]]; then
107-119: Apply--argpattern for category filtering as well.Similar to the site key issue, the
$categoryvariable is interpolated directly into the jq filter at line 114. For consistency and robustness, use--arg.♻️ Proposed fix
- jq -r ".sites | to_entries[] | select(.value.category == \"$category\") | \"\(.key)|\(.value.name)|\(.value.type)|\(.value.url // .value.path)\"" "$CONFIG_FILE" | \ + jq -r --arg cat "$category" '.sites | to_entries[] | select(.value.category == $cat) | "\(.key)|\(.value.name)|\(.value.type)|\(.value.url // .value.path)"' "$CONFIG_FILE" | \
240-241: Apply--argpattern for category in jq query.♻️ Proposed fix
local site_keys - site_keys=$(jq -r ".sites | to_entries[] | select(.value.category == \"$category\") | .key" "$CONFIG_FILE") + site_keys=$(jq -r --arg cat "$category" '.sites | to_entries[] | select(.value.category == $cat) | .key' "$CONFIG_FILE")
318-328: Apply--arginlist_categoriescount query.Line 324 interpolates
$catinto the jq filter. Use--argfor consistency.♻️ Proposed fix
jq -r '.sites[].category // "uncategorized"' "$CONFIG_FILE" | sort -u | while read -r cat; do local count - count=$(jq -r "[.sites[] | select(.category == \"$cat\")] | length" "$CONFIG_FILE") + count=$(jq -r --arg c "$cat" '[.sites[] | select(.category == $c)] | length' "$CONFIG_FILE") echo " - $cat ($count sites)" done
| # Execute the command | ||
| eval "$ssh_command" | ||
| return $? |
There was a problem hiding this comment.
eval usage persists despite commit message claiming removal.
The commit messages summary states "removed use of eval to prevent command injection," but eval "$ssh_command" remains at line 219. Combined with the unescaped wp_command noted above, this creates the injection pathway.
Consider refactoring to avoid eval entirely by using Bash arrays for command construction, or at minimum ensure all interpolated values are properly escaped before the eval.
🤖 Prompt for AI Agents
In @.agent/scripts/wp-helper.sh around lines 218 - 220, The eval "$ssh_command"
call still allows command injection; replace it by building the SSH invocation
as a Bash array and executing it without eval (e.g., construct ssh_command as an
array variable and run it as "${ssh_command[@]}"), and ensure the wp_command
pieces are properly escaped or passed as separate array elements instead of
interpolating into a single string; update any code that sets ssh_command or
wp_command so they push safe, quoted tokens into the array rather than
concatenating raw strings.
- Use pre-increment ((++count)) to avoid set -e exit on zero - Add sshpass dependency check for Hostinger/Closte sites - Add ssh dependency check - Use jq --arg for safer variable interpolation - Fix uncategorized count in list_categories Addresses CodeRabbit and Augment review feedback.
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Fri Jan 30 21:09:42 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
- Add printf %q quoting for wp_command in build_ssh_command - Apply to all hosting types (localwp, hostinger, closte, hetzner, cloudways, cloudron) Addresses final CodeRabbit security feedback.
|
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Fri Jan 30 21:12:54 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |



Summary
mainwp-config.json.txttemplate (fixes Missing mainwp-config.json.txt template in configs folder #260)wordpress-sites.json.txttemplate (fixes Missing wordpress-sites.json.txt template in configs folder #261)wp-helper.shscript for multi-site WP-CLI operations (fixes Feature: WP-CLI helper script that reads wordpress-sites.json #262)wp-admin.mdwith setup instructions and wp-helper.sh referenceChanges
New Files
.agent/configs/mainwp-config.json.txt.agent/configs/wordpress-sites.json.txt.agent/scripts/wp-helper.shModified Files
.agent/tools/wordpress/wp-admin.mdwp-helper.sh Features
The new script reads from
~/.config/aidevops/wordpress-sites.jsonand supports:Usage Examples
Testing
Closes #260, #261, #262
Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.