Repository navigation
fix(cli): preserve approved shell commands across confirmation retries - #29201
chelsealong wants to merge 1 commit into
Conversation
When a TOML custom command needs confirmation for multiple shell commands, each retry re-runs the command action from scratch and only carries forward the commands approved in that single round via a one-time allowlist. Commands approved in an earlier round of the same retry chain were dropped instead of persisted, since the freshly memoized `commandContext.session.sessionShellAllowlist` used for the next round may not yet reflect a prior `setSessionShellAllowlist` update. This caused the confirmation prompts to cycle between commands forever, matching the "toml command interpolation stuck in infinite loop when multiple commands need permission" report, including the "not even allowing the command for the rest of the session breaks the loop" symptom. Fix by accumulating the newly approved commands with whatever was already granted earlier in the same confirmation chain when recursing, so every retry keeps every command approved so far regardless of render timing. Fixes google-gemini#29197
|
📊 PR Size: size/M
|
Summary of ChangesHello, 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 an issue where the CLI would enter an infinite loop when executing custom commands that require multiple shell command confirmations. By modifying 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 the 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 counterproductive. 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. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request updates the slash command processor to accumulate approved shell commands across multiple confirmation rounds. Specifically, in slashCommandProcessor.ts, the handleSlashCommand retry call now merges any previously granted commands in oneTimeShellAllowlist with the newly approved commands, preventing infinite loops when a command action re-runs and re-checks permissions before the session allowlist has updated. Additionally, a comprehensive unit test has been added to slashCommandProcessor.test.tsx to verify this multi-step confirmation behavior. There are no review comments, so I have no feedback to provide.
|
Hi there! Thank you for your interest in contributing to Gemini CLI. To ensure we maintain high code quality and focus on our prioritized roadmap, we only guarantee review and consideration of pull requests for issues that are explicitly labeled as 'help wanted'. This PR will be closed in 7 days if it remains without that designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding. |
|
This pull request is being closed as it has been open for 14 days without a 'help wanted' designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding. |
Fixes #29197
What happened
When a TOML custom command contains multiple
!{...}shell injections that each need confirmation, the CLI could get stuck asking for permission forever — cycling between commands, and never converging even if the user chose "always allow" for every prompt.Root cause
FileCommandLoader's command action re-runs the entire prompt-processing pipeline from scratch on every retry. WhenShellProcessorthrowsConfirmationRequiredError,slashCommandProcessor.ts'sconfirm_shell_commandshandler recurses intohandleSlashCommandwith a fresh one-time allowlist containing only the commands approved in that round:If a second, distinct command still needs confirmation on the retry (e.g. discovered in a later part of the prompt), a second round begins. That round's one-time allowlist only contains the newly approved command — the one approved in the first round is dropped, because:
approvedCommands, andsessionShellAllowlistReact state update from the first round (setSessionShellAllowlist) may not have been reflected into thecommandContextthis in-flight recursive call closure is using yet, even when the user picked "Always".So the command originally approved gets asked again, and this can cycle indefinitely.
Fix
Accumulate approvals across the whole confirmation chain instead of replacing them each round:
Now every retry keeps every command approved so far in that chain, regardless of whether the backing React state has re-rendered yet, so the loop always converges once every distinct command has been confirmed at least once.
Testing
Added a regression test in
packages/cli/src/ui/hooks/slashCommandProcessor.test.tsx("Shell command confirmation > accumulates approvals across multiple confirmation rounds instead of looping forever") that simulates a command action which re-checkscontext.session.sessionShellAllowlistfrom scratch on each invocation and asks forcmd1thencmd2in turn.cmd1again (reproducing the infinite loop).Also ran:
npx eslint src/ui/hooks/slashCommandProcessor.ts src/ui/hooks/slashCommandProcessor.test.tsx— cleannpx tsc --noEmit(packages/cli) — cleannpx vitest run src/services/prompt-processors/shellProcessor.test.ts— 34 tests passed (unaffected)AI assistance disclosure
This PR was prepared with the assistance of an AI coding agent (Claude), including root-cause analysis, the fix, and the regression test. All changes were verified by running the project's real lint/typecheck/test commands as shown above.