Skip to content

GH#2947: Harden setup.sh plist/cron generation against injection and improve debuggability#2996

Merged
marcusquinn merged 2 commits intomainfrom
bugfix/t2947-setup-quality-debt
Mar 6, 2026
Merged

GH#2947: Harden setup.sh plist/cron generation against injection and improve debuggability#2996
marcusquinn merged 2 commits intomainfrom
bugfix/t2947-setup-quality-debt

Conversation

@marcusquinn
Copy link
Owner

Summary

  • Add _xml_escape() function to sanitize paths embedded in XML/plist heredocs, preventing plist injection via crafted directory names containing &, <, >, ", or '
  • Apply XML escaping to all variable interpolations in both pulse and guard launchd plists
  • Remove blanket 2>/dev/null from launchctl load/unload calls — || true already prevents script abort, but suppressing stderr hid diagnostic errors
  • Quote all variables in cron entries and add explicit PATH to prevent command-not-found errors in minimal cron environments
  • Add /bin/bash wrapper to guard plist ProgramArguments for consistency with pulse plist pattern

Findings Addressed

Severity Source Finding Fix
HIGH Gemini Cron entry command injection via unquoted vars (line ~1046) Already quoted on main; added explicit PATH
MEDIUM Gemini Plist injection via unsanitized ${guard_script} in XML Added _xml_escape() for all plist vars
MEDIUM Gemini 2>/dev/null on launchctl unload hides errors Removed from all launchctl load/unload calls
MEDIUM Gemini Hardcoded PATH in guard plist Already ${PATH} on main (was fixed previously)
MEDIUM Gemini 2>/dev/null on launchctl load hides errors Removed
NITPICK CodeRabbit Guard plist missing /bin/bash wrapper Added for consistency with pulse plist
NITPICK CodeRabbit Dynamic PATH + HOME env parity Already on main; XML-escaped HOME now

Supersedes #2964 (stale branch based on older main).

Closes #2947

@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 significantly enhances the security and reliability of the setup script by addressing potential injection vulnerabilities in launchd plist and crontab configurations. It also improves the script's debuggability by ensuring that errors from system commands are no longer silently suppressed. These changes collectively make the system more robust against malicious input and easier to troubleshoot.

Highlights

  • Security Hardening: Implemented XML escaping for all variable interpolations within launchd plist files (both pulse and guard) to prevent plist injection vulnerabilities from crafted directory names containing special XML characters.
  • Improved Debuggability: Removed 2>/dev/null from launchctl load/unload commands and crontab operations, allowing diagnostic errors to be visible instead of being suppressed.
  • Cron Job Robustness: Enhanced cron entries by quoting all variables and explicitly setting the PATH environment variable, preventing command-not-found errors in minimal cron environments and improving injection resistance.
  • Consistency in Launchd Configuration: Added a /bin/bash wrapper to the guard plist's ProgramArguments for consistency with the existing pulse plist pattern.
Changelog
  • setup.sh
    • Added a new _xml_escape() function to safely embed strings in XML, preventing injection.
    • Removed 2>/dev/null from launchctl unload and launchctl load commands for the pulse agent, improving error visibility.
    • Applied XML escaping to wrapper_script, HOME, opencode_bin, and _aidevops_dir variables when generating the pulse launchd plist.
    • Updated the pulse cron entry to include an explicit PATH and quoted all interpolated variables for enhanced security and reliability.
    • Removed 2>/dev/null from crontab - operations when managing pulse cron entries.
    • Applied XML escaping to guard_script and HOME variables when generating the guard launchd plist.
    • Added /bin/bash as a wrapper to the ProgramArguments array in the guard launchd plist for consistency.
    • Updated the guard cron entry to include an explicit PATH and quoted guard_script and log path for enhanced security and reliability.
Activity
  • No human activity (comments, reviews) was detected on this pull request.
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 6, 2026

Warning

Rate limit exceeded

@marcusquinn has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 29 minutes and 36 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 86bdd29d-943d-4b9c-a0c5-af4a35564782

📥 Commits

Reviewing files that changed from the base of the PR and between 21d1499 and 3493cea.

📒 Files selected for processing (1)
  • setup.sh
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix/t2947-setup-quality-debt

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.

@github-actions
Copy link

github-actions bot commented Mar 6, 2026

🔍 Code Quality Report

�[0;35m[MONITOR]�[0m Code Review Monitoring Report

�[0;34m[INFO]�[0m Latest Quality Status:
SonarCloud: 0 bugs, 0 vulnerabilities, 108 code smells

�[0;34m[INFO]�[0m Recent monitoring activity:
Fri Mar 6 15:50:52 UTC 2026: Code review monitoring started
Fri Mar 6 15:50:52 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 108

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 108
  • VULNERABILITIES: 0

Generated on: Fri Mar 6 15:50:54 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

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 hardens the setup.sh script by introducing XML escaping for launchd plists and quoting variables in cron entries, aiming to prevent injection attacks. It also enhances debuggability by removing error suppression (2>/dev/null) from launchctl and crontab commands. While the launchd plist hardening effectively prevents XML injection through the _xml_escape function, the hardening of cron entries is incomplete. Variables used in crontab entries are quoted but not escaped for shell metacharacters, which introduces a potential command injection vulnerability if paths contain characters like $(...) or backticks. To address this, it is recommended to implement a shell-escaping helper function for variables used in cron entries and ensure consistent application of hardening and debuggability improvements across the script.

setup.sh Outdated
crontab -l 2>/dev/null | grep -v 'aidevops: supervisor-pulse'
echo "*/2 * * * * OPENCODE_BIN=${opencode_bin} PULSE_DIR=${_aidevops_dir} /bin/bash ${wrapper_script} >> $HOME/.aidevops/logs/pulse-wrapper.log 2>&1 # aidevops: supervisor-pulse"
) | crontab - 2>/dev/null || true
echo "*/2 * * * * PATH=\"/usr/local/bin:/usr/bin:/bin\" OPENCODE_BIN=\"${opencode_bin}\" PULSE_DIR=\"${_aidevops_dir}\" /bin/bash \"${wrapper_script}\" >> \"\$HOME/.aidevops/logs/pulse-wrapper.log\" 2>&1 # aidevops: supervisor-pulse"

Choose a reason for hiding this comment

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

security-high high

The script generates a crontab entry by interpolating variables ${opencode_bin}, ${_aidevops_dir}, and ${wrapper_script} into a string. While these variables are now enclosed in double quotes, they are not escaped for shell metacharacters. If any of these variables (which depend on environment variables like HOME or the current directory path) contain shell metacharacters such as $(...), backticks, or double quotes, it can lead to arbitrary command execution when the cron job is run by the system's cron daemon (which typically uses /bin/sh). An attacker could potentially exploit this by tricking a user into running the setup script in a directory with a malicious name.

Copy link
Owner Author

Choose a reason for hiding this comment

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

_cron_escape() wraps values in single quotes (not double quotes), which prevents all shell expansion by cron /bin/sh — including $(...), backticks, and variable expansion. POSIX specifies that single-quoted strings undergo no expansion. The resulting crontab entry has values like OPENCODE_BIN='/usr/local/bin/opencode' — single-quoted, safe. Addressed in commit 708505c.

setup.sh Outdated
crontab -l 2>/dev/null | grep -v 'aidevops: process-guard'
echo "* * * * * SHELLCHECK_RSS_LIMIT_KB=524288 SHELLCHECK_RUNTIME_LIMIT=120 CHILD_RSS_LIMIT_KB=8388608 CHILD_RUNTIME_LIMIT=7200 /bin/bash \"${guard_script}\" kill-runaways >> \"\$HOME/.aidevops/logs/process-guard.log\" 2>&1 # aidevops: process-guard"
) | crontab - 2>/dev/null || true
echo "* * * * * PATH=\"/usr/local/bin:/usr/bin:/bin\" SHELLCHECK_RSS_LIMIT_KB=524288 SHELLCHECK_RUNTIME_LIMIT=120 CHILD_RSS_LIMIT_KB=8388608 CHILD_RUNTIME_LIMIT=7200 /bin/bash \"${guard_script}\" kill-runaways >> \"\$HOME/.aidevops/logs/process-guard.log\" 2>&1 # aidevops: process-guard"

Choose a reason for hiding this comment

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

security-high high

Similar to the supervisor-pulse cron entry, the process-guard cron entry interpolates ${guard_script} without proper shell escaping. If the path to the guard script contains shell metacharacters, it can lead to command injection when the cron job is executed. Quoting the variable is insufficient to prevent expansion of $(...) or backticks within double quotes in the crontab entry.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Same as above — _cron_escape() wraps the guard script path in single quotes, preventing all shell expansion. Addressed in commit 708505c.

setup.sh Outdated
Comment on lines 912 to 913
<key>PATH</key>
<string>${PATH}</string>

Choose a reason for hiding this comment

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

medium

For consistency with the hardening changes in this PR, the PATH variable should also be XML-escaped before being embedded in the plist. A user's PATH could potentially contain characters like & which would break the XML structure.

You should first declare and assign the escaped variable, for example around lines 885-889:

local _xml_wrapper_script _xml_home _xml_opencode_bin _xml_aidevops_dir _xml_path
_xml_wrapper_script=$(_xml_escape "$wrapper_script")
_xml_home=$(_xml_escape "$HOME")
_xml_opencode_bin=$(_xml_escape "$opencode_bin")
_xml_aidevops_dir=$(_xml_escape "$_aidevops_dir")
_xml_path=$(_xml_escape "$PATH")

Then apply the change here.

Suggested change
<key>PATH</key>
<string>${PATH}</string>
<key>PATH</key>
<string>${_xml_path}</string>
References
  1. When declaring and assigning local variables in shell scripts, separate the local declaration from the assignment if command substitution is involved, to ensure exit code safety. For consistency, this pattern should be maintained even for simple assignments.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Already addressed — _xml_path=$(_xml_escape "$PATH") is declared at line 901 and used at line 925. Fixed in commit e1a35ab.

setup.sh Outdated
print_info "Supervisor pulse disabled (launchd agent removed per config)"
fi
else
if crontab -l 2>/dev/null | grep -qF "pulse-wrapper" 2>/dev/null; then

Choose a reason for hiding this comment

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

medium

In line with the goal of this PR to improve debuggability by removing unnecessary error suppression, the 2>/dev/null on the grep command should be removed. The preceding crontab -l already suppresses the 'no crontab' message, so this second suppression only serves to hide other potential grep errors.

Suggested change
if crontab -l 2>/dev/null | grep -qF "pulse-wrapper" 2>/dev/null; then
if crontab -l 2>/dev/null | grep -qF "pulse-wrapper"; then
References
  1. Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Already addressed — 2>/dev/null removed from grep. Only crontab -l 2>/dev/null remains (correct — suppresses "no crontab for user" stderr). Fixed in commit e1a35ab.

setup.sh Outdated
Comment on lines 1045 to 1046
<key>PATH</key>
<string>${PATH}</string>

Choose a reason for hiding this comment

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

medium

Similar to the pulse plist, the PATH variable here should be XML-escaped to prevent potential plist injection if the path contains special XML characters.

You can add the escaped variable declaration around lines 1020-1022:

local _xml_guard_script _xml_guard_home _xml_path
_xml_guard_script=$(_xml_escape "$guard_script")
_xml_guard_home=$(_xml_escape "$HOME")
_xml_path=$(_xml_escape "$PATH")

Then use it here.

Suggested change
<key>PATH</key>
<string>${PATH}</string>
<key>PATH</key>
<string>${_xml_path}</string>
References
  1. When declaring and assigning local variables in shell scripts, separate the local declaration from the assignment if command substitution is involved, to ensure exit code safety. For consistency, this pattern should be maintained even for simple assignments.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Already addressed — _xml_guard_path=$(_xml_escape "$PATH") is declared at line 1041 and used at line 1065. Fixed in commit 708505c.

setup.sh Outdated
) | crontab - 2>/dev/null || true
echo "* * * * * PATH=\"/usr/local/bin:/usr/bin:/bin\" SHELLCHECK_RSS_LIMIT_KB=524288 SHELLCHECK_RUNTIME_LIMIT=120 CHILD_RSS_LIMIT_KB=8388608 CHILD_RUNTIME_LIMIT=7200 /bin/bash \"${guard_script}\" kill-runaways >> \"\$HOME/.aidevops/logs/process-guard.log\" 2>&1 # aidevops: process-guard"
) | crontab - || true
if crontab -l 2>/dev/null | grep -qF "aidevops: process-guard" 2>/dev/null; then

Choose a reason for hiding this comment

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

medium

For consistency with the other changes in this PR that remove unnecessary error suppression, the 2>/dev/null on this grep command should be removed. This will improve debuggability by revealing potential grep errors, while the crontab -l part already handles the case of a non-existent crontab.

Suggested change
if crontab -l 2>/dev/null | grep -qF "aidevops: process-guard" 2>/dev/null; then
if crontab -l 2>/dev/null | grep -qF "aidevops: process-guard"; then
References
  1. Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Already addressed — 2>/dev/null removed from grep. Only crontab -l 2>/dev/null remains (correct). Fixed in commit 708505c.

marcusquinn added a commit that referenced this pull request Mar 6, 2026
…aping

Address Gemini review feedback on PR #2996:

- Add _cron_escape() to wrap cron entry paths in single quotes, preventing
  command injection via $(…) or backticks in paths (HIGH severity)
- XML-escape $PATH in both pulse and guard launchd plists — PATH can
  contain & which breaks XML structure (MEDIUM severity)
- Remove unnecessary 2>/dev/null from grep after crontab -l pipes —
  crontab -l already handles the no-crontab case, and suppressing grep
  stderr hides diagnostic errors (MEDIUM severity)
@marcusquinn
Copy link
Owner Author

Worker PID 82180 killed after 6h12m with 0 commits (struggle_ratio: 19640). This PR appears stuck — re-dispatching Issue #2947 for a fresh worker.

@github-actions
Copy link

github-actions bot commented Mar 6, 2026

🔍 Code Quality Report

�[0;35m[MONITOR]�[0m Code Review Monitoring Report

�[0;34m[INFO]�[0m Latest Quality Status:
SonarCloud: 0 bugs, 0 vulnerabilities, 108 code smells

�[0;34m[INFO]�[0m Recent monitoring activity:
Fri Mar 6 16:14:04 UTC 2026: Code review monitoring started
Fri Mar 6 16:14:04 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 108

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 108
  • VULNERABILITIES: 0

Generated on: Fri Mar 6 16:14:06 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

…ove debuggability

Address all HIGH and MEDIUM severity findings from PR #2940 review:

- Add _xml_escape() to sanitize paths for XML/plist embedding, preventing
  plist injection if paths contain &, <, >, or quote characters
- Apply XML escaping to all variable interpolations in pulse and guard plists
- Remove blanket 2>/dev/null from launchctl load/unload calls so diagnostic
  errors remain visible (|| true still prevents script abort)
- Quote all variables in cron entries and add explicit PATH to prevent
  command-not-found errors in minimal cron environments
- Remove 2>/dev/null from crontab pipe writes for debuggability
- Add /bin/bash wrapper to guard plist ProgramArguments for consistency
  with pulse plist pattern

Closes #2947
…aping

Address Gemini review feedback on PR #2996:

- Add _cron_escape() to wrap cron entry paths in single quotes, preventing
  command injection via $(…) or backticks in paths (HIGH severity)
- XML-escape $PATH in both pulse and guard launchd plists — PATH can
  contain & which breaks XML structure (MEDIUM severity)
- Remove unnecessary 2>/dev/null from grep after crontab -l pipes —
  crontab -l already handles the no-crontab case, and suppressing grep
  stderr hides diagnostic errors (MEDIUM severity)
@marcusquinn marcusquinn force-pushed the bugfix/t2947-setup-quality-debt branch from 708505c to 3493cea Compare March 6, 2026 16:18
@github-actions
Copy link

github-actions bot commented Mar 6, 2026

🔍 Code Quality Report

�[0;35m[MONITOR]�[0m Code Review Monitoring Report

�[0;34m[INFO]�[0m Latest Quality Status:
SonarCloud: 0 bugs, 0 vulnerabilities, 108 code smells

�[0;34m[INFO]�[0m Recent monitoring activity:
Fri Mar 6 16:18:52 UTC 2026: Code review monitoring started
Fri Mar 6 16:18:53 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 108

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 108
  • VULNERABILITIES: 0

Generated on: Fri Mar 6 16:18:55 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 6, 2026

@marcusquinn
Copy link
Owner Author

Worker killed after 6h21m with 0 commits (struggle_ratio: 19764). Re-dispatching with more context. The issue is setup.sh quality debt from PR #2940 review. New worker will read the PR diff and CodeRabbit review comments first.

@marcusquinn marcusquinn merged commit 276b308 into main Mar 6, 2026
12 checks passed
@marcusquinn marcusquinn deleted the bugfix/t2947-setup-quality-debt branch March 6, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

quality-debt: setup.sh — PR #2940 review feedback (high)

1 participant