Skip to content

GH#2926: fix supervisor pulse consent model — default OFF, persist consent, never silently re-enable#2936

Merged
marcusquinn merged 1 commit intomainfrom
bugfix/t2926-supervisor-pulse-consent
Mar 5, 2026
Merged

GH#2926: fix supervisor pulse consent model — default OFF, persist consent, never silently re-enable#2936
marcusquinn merged 1 commit intomainfrom
bugfix/t2926-supervisor-pulse-consent

Conversation

@marcusquinn
Copy link
Owner

Summary

Fixes the broken consent model for supervisor pulse installation that led to users unknowingly running autonomous AI workers under their GitHub identity.

  • Default OFF: supervisor_pulse defaults to false in all config layers (JSONC defaults, legacy .conf defaults)
  • Default-no prompt: Changed [Y/n] to [y/N] — user must explicitly type "y" to enable
  • Consent persisted: Writes true/false to config.jsonc via cmd_set so the choice survives updates without re-prompting
  • Never silently re-enables: If config says false, setup skips entirely and cleans up any existing launchd/cron entries
  • Non-interactive safe: Only installs if config explicitly says true (was: silently installed with no consent)
  • Env var override: AIDEVOPS_SUPERVISOR_PULSE=true|false overrides all config layers (power user escape hatch)

Files Changed

File Change
.agents/configs/aidevops.defaults.jsonc supervisor_pulse: truefalse
.agents/configs/feature-toggles.conf.defaults supervisor_pulse=truefalse
setup.sh Complete rewrite of pulse consent logic (prompt, config read/write, cleanup)

Upgrade Path

  • Existing users who consented: If they have orchestration.supervisor_pulse=true in their config.jsonc (or env var), pulse continues working — no change in behavior.
  • Existing users who never configured: On next setup.sh run, they'll be prompted with [y/N]. Their choice is persisted.
  • Existing users who manually removed cron: Will NOT be re-prompted (the old bug). If they want it back, they set the config explicitly.
  • New installs: Pulse is OFF by default. Interactive setup prompts with [y/N]. Non-interactive skips entirely.

Testing

  • bash -n setup.sh — syntax valid
  • shellcheck setup.sh — zero violations
  • Logic verified against all 6 scenarios from the issue

Closes #2926

…926)

The supervisor pulse (autonomous AI worker dispatch) had a broken consent
model that led to users unknowingly running automated workers under their
GitHub identity. Four compounding failures:

1. Feature flag defaulted to ON (true) in all config layers
2. Setup prompt defaulted to YES ([Y/n] — Enter enables)
3. Updates silently re-enabled pulse if cron was manually removed
4. No consent record written — no way to distinguish 'consented' from
   'never configured and default kicked in'

Fix all four:

- Default OFF: supervisor_pulse=false in aidevops.defaults.jsonc and
  feature-toggles.conf.defaults
- Default-no prompt: [y/N] — user must explicitly type 'y' to enable
- Consent persisted: writes true/false to config.jsonc via cmd_set,
  survives updates without re-prompting
- Never silently re-enables: if config says false, skip entirely and
  clean up any existing launchd/cron entries
- Non-interactive mode: only installs if config explicitly says true
  (was: silently installed with no consent)
- Env var AIDEVOPS_SUPERVISOR_PULSE overrides all (power user escape)

Closes #2926
@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 user consent model for the autonomous supervisor pulse feature. The changes ensure that the pulse is off by default, requires explicit user permission to enable, and persists that choice across system updates. This prevents unintended activation of autonomous AI workers and provides users with clear control over their system's behavior, addressing a critical privacy and operational concern.

Highlights

  • Default OFF: The supervisor_pulse setting now defaults to false in both JSONC and legacy .conf configuration layers, ensuring autonomous AI workers are not enabled by default.
  • Explicit Consent Required: The interactive prompt for enabling the supervisor pulse has been changed from [Y/n] to [y/N], requiring users to explicitly type 'y' to opt-in.
  • Consent Persisted: User consent (or denial) for the supervisor pulse is now written to config.jsonc via cmd_set, ensuring the choice is remembered across updates and setup runs.
  • Never Silently Re-enables: If the configuration explicitly sets supervisor_pulse to false, the setup process will now skip installation entirely and clean up any existing launchd or cron entries.
  • Non-interactive Safe: In non-interactive environments, the supervisor pulse will only be installed if the configuration explicitly states true, preventing silent installations without user consent.
  • Environment Variable Override: An environment variable AIDEVOPS_SUPERVISOR_PULSE=true|false has been introduced to provide a high-priority override for all other configuration layers.
Changelog
  • .agents/configs/aidevops.defaults.jsonc
    • Changed the default value of orchestration.supervisor_pulse from true to false.
    • Added a comment clarifying that explicit user consent is required and it defaults to OFF.
  • .agents/configs/feature-toggles.conf.defaults
    • Changed the default value of supervisor_pulse from true to false.
    • Updated comments to reflect that explicit user consent is now required and it defaults to OFF.
  • setup.sh
    • Rewrote the supervisor pulse installation logic to implement a robust consent model.
    • Introduced logic to read explicit user consent from config.jsonc and legacy .conf files.
    • Added support for AIDEVOPS_SUPERVISOR_PULSE environment variable to override config.
    • Modified the interactive prompt for supervisor pulse to default to 'No' ([y/N]).
    • Implemented persistence of user consent/decline using cmd_set to config.jsonc.
    • Ensured non-interactive setups default to OFF unless explicitly configured true.
    • Added cleanup logic to remove launchd agents or cron entries if the user explicitly disables the pulse.
    • Updated the post-setup message to guide users on how to enable the supervisor pulse if skipped.
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 5, 2026

Warning

Rate limit exceeded

@marcusquinn has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 7 minutes and 17 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: d5b63fd6-a47b-4975-adf7-1920c53e8c6f

📥 Commits

Reviewing files that changed from the base of the PR and between 682383d and 3429d3d.

📒 Files selected for processing (3)
  • .agents/configs/aidevops.defaults.jsonc
  • .agents/configs/feature-toggles.conf.defaults
  • 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/t2926-supervisor-pulse-consent

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.

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 addresses the supervisor pulse consent issue by defaulting it to off, requiring explicit user consent, and persisting that choice, which is a significant security improvement. However, a command injection vulnerability was identified in the crontab installation logic where variables are used without proper quoting, potentially allowing arbitrary command execution if the repository is installed in a maliciously named directory. Additionally, minor issues were found in setup.sh where error suppression (2>/dev/null) could hide problems, particularly around persisting user consent, and should be addressed to improve script robustness and debuggability.

_do_install=true
# Record explicit consent
if type cmd_set &>/dev/null; then
cmd_set "orchestration.supervisor_pulse" "true" 2>/dev/null || true

Choose a reason for hiding this comment

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

high

The 2>/dev/null here should be removed. If cmd_set fails, the error should be visible to the user so they understand why their consent wasn't persisted. Silently failing means they will be re-prompted on the next run, which undermines a key goal of this change. The || true correctly prevents the script from exiting.

Suggested change
cmd_set "orchestration.supervisor_pulse" "true" 2>/dev/null || true
cmd_set "orchestration.supervisor_pulse" "true" || true
References
  1. In shell scripts with 'set -e' enabled, use '|| true' to prevent the script from exiting on a command's failure, but do not suppress stderr with '2>/dev/null'. This allows important error messages to be visible for debugging, which is crucial for a command that is persisting user consent.

_do_install=false
# Record explicit decline so we never re-prompt on updates
if type cmd_set &>/dev/null; then
cmd_set "orchestration.supervisor_pulse" "false" 2>/dev/null || true

Choose a reason for hiding this comment

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

high

The 2>/dev/null here should be removed. If cmd_set fails, the error should be visible to the user so they understand why their choice to decline wasn't persisted. Silently failing means they will be re-prompted on the next run, which undermines a key goal of this change. The || true correctly prevents the script from exiting.

Suggested change
cmd_set "orchestration.supervisor_pulse" "false" 2>/dev/null || true
cmd_set "orchestration.supervisor_pulse" "false" || true
References
  1. In shell scripts with 'set -e' enabled, use '|| true' to prevent the script from exiting on a command's failure, but do not suppress stderr with '2>/dev/null'. This allows important error messages to be visible for debugging, which is crucial for a command that is persisting user consent.

# Remove old-style cron entries (direct opencode invocation)
(
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"

Choose a reason for hiding this comment

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

security-medium medium

The setup.sh script constructs a crontab entry by concatenating variables opencode_bin and _aidevops_dir without proper quoting or sanitization. If the repository is cloned into a directory with a malicious name (e.g., containing shell metacharacters like ; or $()), or if the opencode binary path contains such characters, an attacker could achieve arbitrary command execution when the cron job runs. This is a classic command injection vulnerability where untrusted input (the directory name) is used to build a command that is later executed by a shell.

Suggested change
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"
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"

# Also check legacy .conf user override
if [[ -z "$_pulse_user_config" && -f "${FEATURE_TOGGLES_USER:-$HOME/.config/aidevops/feature-toggles.conf}" ]]; then
local _legacy_val
_legacy_val=$(grep -E '^supervisor_pulse=' "${FEATURE_TOGGLES_USER:-$HOME/.config/aidevops/feature-toggles.conf}" 2>/dev/null | tail -1 | cut -d= -f2)

Choose a reason for hiding this comment

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

medium

The 2>/dev/null here should be removed. Since the existence of the file is checked on line 771, this grep should not fail with "file not found". Suppressing stderr here could mask other issues, like file permission errors, preventing the user from understanding why their legacy configuration is not being read.

Suggested change
_legacy_val=$(grep -E '^supervisor_pulse=' "${FEATURE_TOGGLES_USER:-$HOME/.config/aidevops/feature-toggles.conf}" 2>/dev/null | tail -1 | cut -d= -f2)
_legacy_val=$(grep -E '^supervisor_pulse=' "${FEATURE_TOGGLES_USER:-$HOME/.config/aidevops/feature-toggles.conf}" | tail -1 | cut -d= -f2)
References
  1. Avoid using 2>/dev/null to suppress errors on file operations if the file's existence has already been verified by a preceding check. This is redundant for 'file not found' errors and can mask other important issues like permissions problems.

@github-actions
Copy link

github-actions bot commented Mar 5, 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:
Thu Mar 5 17:31:28 UTC 2026: Code review monitoring started
Thu Mar 5 17:31:28 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 108

📈 Current Quality Metrics

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

Generated on: Thu Mar 5 17:31:31 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 5, 2026

@marcusquinn marcusquinn merged commit 3116f8b into main Mar 5, 2026
23 of 24 checks passed
@marcusquinn marcusquinn deleted the bugfix/t2926-supervisor-pulse-consent branch March 5, 2026 18:10
marcusquinn added a commit that referenced this pull request Mar 6, 2026
…etup.sh

Address 4 findings from PR #2936 review (GH#2950):

- HIGH: Remove 2>/dev/null from cmd_set calls (lines 815, 821) so users
  see errors when consent persistence fails instead of being silently
  re-prompted on next run. The || true still prevents set -e exits.

- MEDIUM: Remove 2>/dev/null from grep on legacy config (line 773) since
  file existence is already checked on line 771 — suppressing stderr
  masks permission errors, not missing-file errors.

- MEDIUM: Single-quote variable expansions in crontab entry (line 924)
  to prevent command injection via directory names containing shell
  metacharacters.
marcusquinn added a commit that referenced this pull request Mar 6, 2026
)

* fix: t2950 remove error suppression from consent persistence and quote crontab variables

Remove 2>/dev/null from cmd_set calls that persist supervisor pulse
consent — errors should be visible so users understand why consent
wasn't saved. Remove redundant 2>/dev/null from grep where file
existence is already checked. Single-quote variables in crontab entry
to prevent command injection via directory names with metacharacters.

* fix: address CodeRabbit CHANGES_REQUESTED review feedback on PR #2994

1. Replace grep|tail|cut pipeline with awk for legacy config read —
   grep exits 1 on no match, which aborts the script under set -euo
   pipefail. awk always exits 0 and handles the missing-key case safely.

2. Add shell_single_quote() utility and use it for crontab path
   interpolation — prevents syntax errors and command injection when
   paths contain apostrophes (e.g. /home/O'Connor/...).

Both findings verified with functional tests. ShellCheck clean.
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.

bug: supervisor pulse installs with default-to-yes consent, silently re-enables on update

1 participant