Skip to content

[Feat] Integrate destructive command guard with auto-approval - #1050

Draft
navedmerchant wants to merge 13 commits into
mainfrom
feat/autoapprovecommands
Draft

[Feat] Integrate destructive command guard with auto-approval#1050
navedmerchant wants to merge 13 commits into
mainfrom
feat/autoapprovecommands

Conversation

@navedmerchant

@navedmerchant navedmerchant commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Opened on behalf of Naved Merchant. View the task or mention @zoomote for follow-up asks.

Related GitHub Issue

Closes: #1049

Description

Integrates Destructive Command Guard (DCG) into command execution so modern models can run complex commands and generated scripts without unnecessary pauses while preserving an explicit approval boundary for dangerous operations.

Key implementation details:

  • Adds a persisted destructiveCommandGuardEnabled setting across shared types, extension state, settings submission, and provider state.
  • Adds DCG binary download, version management, checksum verification, and execution services.
  • Evaluates commands with DCG before the auto-approval decision. Commands DCG permits can bypass the legacy command allowlist when command auto-approval is enabled; commands DCG blocks remain protected and require explicit approval.
  • Preserves the existing allowed/denied command workflow when DCG is disabled.
  • Adds localized blocked/denied messaging with the DCG reason and rule identifier when available.
  • Updates Auto-Approve settings with DCG installation and enablement controls.
  • Adds focused extension and webview tests for classification, auto-approval, persistence, command execution, and denial UX.

Reviewers should pay particular attention to the safety boundary between DCG classification and checkAutoApproval, plus binary lifecycle handling in the DCG manager.

Test Procedure

Automated tests run from the package directories that declare Vitest:

cd src
npx vitest run core/auto-approval/__tests__/dcg.spec.ts core/tools/__tests__/executeCommandTool.spec.ts core/webview/__tests__/ClineProvider.spec.ts services/destructive-command-guard/__tests__/manager.spec.ts

Result: 4 test files passed, 141 tests passed.

cd webview-ui
npx vitest run src/components/chat/__tests__/ChatRow.command-denied.spec.tsx src/components/chat/__tests__/CommandExecution.spec.tsx src/components/settings/__tests__/AutoApproveSettings.spec.tsx

Result: 3 test files passed, 47 tests passed.

Full repository suite after the review follow-up commit (pnpm test from the repo root): all tasks successful, 7223 tests passed, 38 skipped.

Manual verification:

  1. Enable command auto-approval and DCG in Auto-Approve settings.
  2. Run a command DCG classifies as safe and verify it proceeds without an allowlist prompt.
  3. Run a command DCG classifies as dangerous and verify the UI asks for explicit approval.
  4. Deny the dangerous command and verify the chat displays the localized DCG explanation.
  5. Disable DCG and verify the existing allowed/denied command controls and behavior return.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes (if applicable).
  • Visual Snapshot (UI changes only): If a user would notice this change at a glance (layout, theme tokens, brand elements, empty/error states), I've added or updated a *.visual.tsx snapshot in webview-ui/. See webview-ui/AGENTS.md → "When a UI change needs a snapshot".
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Visual Snapshots

image

Videos (interaction / animation only)

Not applicable; this change does not introduce animation or a motion-dependent flow.

Documentation Updates

  • No documentation updates are required.
  • Yes, documentation updates are required.

Additional Notes

The DCG integration is opt-in. Existing command allowlist and denylist behavior remains available when DCG is disabled.

Review follow-up (commit 2478d1f): addressed the remaining review findings in the shared managed-binary services — the installer now adopts a valid installation completed by a concurrent VS Code window instead of removing it mid-swap, and the downloader destroys the piped output stream when aborting an oversized archive so the file descriptor is not leaked. Both fixes include regression tests.

Get in Touch

GitHub: @navedmerchant

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added an optional Destructive Command Guard setting for terminal command execution.
    • When enabled, allowed commands auto-run, blocked commands require approval, and blocked executions show a dedicated denied status (including reason/rule details).
    • Added localized UI and chat strings for the new setting and denied/block messaging.
  • Bug Fixes

    • If the guard can’t be enabled, it’s automatically turned off and an error is shown.
  • Tests

    • Added/updated tests for guard decision precedence, installation/message flows, settings persistence, and denied-command rendering.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Destructive Command Guard support for command auto-approval, including persisted settings, secure binary installation, guarded execution, approval-state recording, denied-command rendering, tests, and localized UI text.

Changes

Destructive Command Guard integration

Layer / File(s) Summary
Persisted setting and state wiring
AGENTS.md, packages/types/src/*, src/core/webview/*, src/core/webview/webviewMessageHandler.ts, webview-ui/src/components/settings/*, src/i18n/locales/*/common.json
Adds destructiveCommandGuardEnabled, buffers and persists it through settings, exposes it to the webview, installs DCG when enabled, and reports enablement failures.
DCG installation and runtime
src/services/destructive-command-guard/*
Adds platform metadata, trusted downloads, checksum verification, archive extraction, version validation, installation concurrency control, and bounded process execution.
Approval and denied-command flow
src/core/auto-approval/*, src/core/task/Task.ts, src/core/tools/*, webview-ui/src/components/chat/*
Runs DCG before approval, requires explicit approval for protected commands, records autoApprovalDecision, and renders denied commands with the selector hidden.
Localization and validation
src/i18n/locales/*/tools.json, webview-ui/src/i18n/locales/*, **/__tests__/*
Adds localized DCG messages and tests for installation, approval precedence, persistence, settings behavior, and denied-command rendering.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SettingsView
  participant webviewMessageHandler
  participant DCGManager
  participant ExecuteCommandTool
  participant Task
  participant ChatRow
  SettingsView->>webviewMessageHandler: updateSettings(destructiveCommandGuardEnabled)
  webviewMessageHandler->>DCGManager: ensureDcgInstalled(storageDir)
  ExecuteCommandTool->>DCGManager: runDcg(binaryPath, command, cwd)
  DCGManager-->>ExecuteCommandTool: allow or deny decision
  ExecuteCommandTool->>Task: request approval with protection state
  Task-->>ChatRow: autoApprovalDecision
Loading

Suggested labels: awaiting-review

Suggested reviewers: hannesrudolph

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The code adds DCG classification, approval gating, persisted settings, UI controls, localized messaging, and tests matching #1049.
Out of Scope Changes check ✅ Passed The changes are focused on DCG integration and supporting docs, types, tests, UI, and localization without clear unrelated additions.
Title check ✅ Passed The title clearly matches the main change: integrating destructive command guard with auto-approval.
Description check ✅ Passed The description includes all required sections and sufficient detail on implementation, testing, and issue linkage.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/autoapprovecommands

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (8)
src/core/webview/ClineProvider.ts (1)

2443-2443: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse a shared DCG default constant.

Both state builders hard-code false. Define one shared default alongside the setting schema and use it in getState() and getStateToPostToWebview() to keep default semantics consistent.

Also applies to: 2676-2676

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/webview/ClineProvider.ts` at line 2443, Define a shared default
constant for destructive command guard behavior alongside the setting schema,
then replace the hard-coded false fallbacks in both getState() and
getStateToPostToWebview() with that constant. Preserve the existing
nullish-coalescing behavior.

Source: Coding guidelines

packages/types/src/message.ts (1)

275-275: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add focused schema tests for autoApprovalDecision.

Cover both accepted values ("approve"/"deny") and rejection of invalid values in packages/types/src/__tests__/message.test.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/types/src/message.ts` at line 275, Add focused tests in the message
schema test suite for autoApprovalDecision, asserting that "approve" and "deny"
are accepted while invalid values are rejected. Reuse the existing message
schema test patterns and reference the autoApprovalDecision field directly.

Source: Coding guidelines

webview-ui/src/components/chat/CommandExecution.tsx (1)

39-45: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

New isDenied prop shadows the local isDenied in handleDenyPatternChange (Line 112).

Harmless today, but the inner const isDenied = deniedCommands.includes(pattern) now hides the prop of the same name. Renaming the local (e.g. isPatternDenied) removes the ambiguity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@webview-ui/src/components/chat/CommandExecution.tsx` around lines 39 - 45,
Rename the local isDenied variable inside handleDenyPatternChange to a distinct
name such as isPatternDenied, and update its references there while preserving
the isDenied prop used by CommandExecution.
src/core/auto-approval/__tests__/dcg.spec.ts (1)

40-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider covering alwaysAllowExecute: false with DCG enabled.

The suite never asserts that DCG alone cannot auto-approve when the execute toggle is off — the most important negative boundary of this new branch.

♻️ Suggested additional case
it("does not auto-approve via DCG when execute auto-approval is off", async () => {
	const state = { ...baseState, alwaysAllowExecute: false }

	expect(await checkAutoApproval({ state, ask: "command", text: "echo safe" })).toEqual({ decision: "ask" })
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/auto-approval/__tests__/dcg.spec.ts` around lines 40 - 62, Add a
test alongside the existing checkAutoApproval cases that keeps
destructiveCommandGuardEnabled enabled while setting
baseState.alwaysAllowExecute to false, then verify a safe command returns
decision "ask" rather than being auto-approved via DCG.
src/core/tools/__tests__/executeCommandTool.spec.ts (1)

210-248: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the allow-path and unavailable-binary cases.

Currently only the deny branch is exercised. Two cheap additions with real value: DCG enabled + decision: "allow" should call askApproval("command", "echo test") with no protection flag, and getDcgBinaryPath returning undefined should surface the enablement error via handleError rather than silently executing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/tools/__tests__/executeCommandTool.spec.ts` around lines 210 - 248,
Extend the executeCommandTool tests around the existing DCG deny-case test to
cover an enabled guard returning decision "allow", asserting askApproval is
called with "command", "echo test", and no protection flag. Add an
unavailable-binary case by making getDcgBinaryPath return undefined, and assert
handleError receives the DCG enablement error without executing the command.
src/services/destructive-command-guard/constants.ts (1)

9-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider deep-freezing archive metadata.

Readonly<Record<string, DcgArchiveInfo>> only prevents reassigning top-level keys; nested fields like sha256 on each DcgArchiveInfo remain mutable at runtime. Since these values pin the trusted checksum used for supply-chain verification, marking the literal as const (and typing accordingly) would harden against accidental mutation elsewhere in the codebase.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/destructive-command-guard/constants.ts` around lines 9 - 40,
Update DCG_ARCHIVES to use a deeply immutable literal by applying `as const` and
adjusting its type so each archive entry’s `archive`, `binary`, and `sha256`
fields cannot be reassigned. Preserve the existing platform entries and checksum
values while ensuring nested metadata is read-only at compile time.
src/services/destructive-command-guard/manager.ts (1)

51-160: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Add unit test coverage for the checksum/download/install security path.

manager.spec.ts only exercises the pure platform-mapping helpers (getDcgArchiveInfo, isDcgSupportedPlatform, getDcgBinaryPath). downloadFile's trusted-domain/redirect/size enforcement, verifyChecksum, extractSingleBinary's layout validation, and installDcg's atomic swap are the actual security guarantees of this module and remain untested. These are mockable via https/fs/child_process module mocks.

Based on learnings, "Prefer the narrowest test layer that proves behavior: focused tests first, integration tests for cross-module contracts, and end-to-end tests only for full workflow confidence."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/destructive-command-guard/manager.ts` around lines 51 - 160, Add
focused unit tests in manager.spec.ts for downloadFile’s trusted-host checks,
redirect limits, and download-size enforcement; verifyChecksum’s success and
mismatch behavior; extractSingleBinary’s single-entry layout validation; and
installDcg’s atomic swap behavior. Mock https, fs streams, and
child_process.runProcess dependencies to exercise these paths without real
network, archive, or process operations, while preserving the existing
platform-helper tests.

Source: Learnings

src/services/destructive-command-guard/runner.ts (1)

16-84: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

No test coverage for runDcg's branch logic.

This function gates command auto-approval and has several distinct failure branches (timeout, output-size overflow, invalid JSON, unsupported schema version, decision/exit-code mismatch) that aren't covered by any test in this cohort (manager.spec.ts only tests unrelated helpers). Given this is on the safety-critical approval path, focused unit tests mocking child_process.spawn would materially increase confidence.

Based on learnings, "For regressions, add the test at the lowest layer that would have failed; add an e2e test only when lower-level tests cannot represent the failure mode."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/destructive-command-guard/runner.ts` around lines 16 - 84, Add
focused unit tests for runDcg by mocking child_process.spawn and simulating its
stdout, stderr, close, and error events. Cover successful allow/deny decisions
plus timeout, output-size overflow, invalid JSON, unsupported schema versions,
decision/exit-code mismatches, and nonzero termination failures, asserting the
resulting resolution or rejection messages.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/tools/ExecuteCommandTool.ts`:
- Around line 128-144: Replace the hardcoded missing-binary error in the
destructive-command guard block of ExecuteCommandTool with the localized
common.errors.destructiveCommandGuard.unavailable message. Add the unavailable
key to that error template in common.json for every locale, preserving the
existing destructive_command_guard_enable_failed template and using the
established localization lookup pattern.

In `@src/services/destructive-command-guard/manager.ts`:
- Around line 162-212: Prevent cross-process installation races in installDcg:
before the destructive fs.rm(finalDir) and fs.rename(stagingDir, finalDir)
replacement, re-check whether the verified binaryPath already exists and return
it while cleaning up staging, or implement an equivalent lightweight lock under
installRoot. Preserve checksum, extraction, and version verification, and ensure
concurrent windows never remove an already valid installation.
- Around line 145-160: Update extractSingleBinary to use a Windows-safe native,
PowerShell, or Node-based ZIP extraction path for .zip archives instead of
invoking runProcess("tar", ...). Preserve the existing tar listing and
extraction behavior for non-ZIP archives, and continue validating that the
archive contains only info.binary before extraction.

In `@webview-ui/src/components/chat/ChatRow.tsx`:
- Around line 294-301: Add stable React keys to both JSX elements returned by
the autoApprovalDecision "deny" branch in the surrounding message-rendering
function, resolving the react/jsx-key lint errors without changing the
denied-state content or styling.

In `@webview-ui/src/i18n/locales/de/settings.json`:
- Around line 331-334: Update the description in the destructiveCommandGuard
localization entry to replace “Zoos Befehlslisten” with the clearer German
wording “Die Befehlslisten von Zoo sind währenddessen deaktiviert.”

In `@webview-ui/src/i18n/locales/fr/settings.json`:
- Around line 332-335: Update the description in the destructiveCommandGuard
translation to replace the informal French pronouns “tu” and “ton” with the
formal “vous” and “votre”, preserving the existing meaning and wording
otherwise.

---

Nitpick comments:
In `@packages/types/src/message.ts`:
- Line 275: Add focused tests in the message schema test suite for
autoApprovalDecision, asserting that "approve" and "deny" are accepted while
invalid values are rejected. Reuse the existing message schema test patterns and
reference the autoApprovalDecision field directly.

In `@src/core/auto-approval/__tests__/dcg.spec.ts`:
- Around line 40-62: Add a test alongside the existing checkAutoApproval cases
that keeps destructiveCommandGuardEnabled enabled while setting
baseState.alwaysAllowExecute to false, then verify a safe command returns
decision "ask" rather than being auto-approved via DCG.

In `@src/core/tools/__tests__/executeCommandTool.spec.ts`:
- Around line 210-248: Extend the executeCommandTool tests around the existing
DCG deny-case test to cover an enabled guard returning decision "allow",
asserting askApproval is called with "command", "echo test", and no protection
flag. Add an unavailable-binary case by making getDcgBinaryPath return
undefined, and assert handleError receives the DCG enablement error without
executing the command.

In `@src/core/webview/ClineProvider.ts`:
- Line 2443: Define a shared default constant for destructive command guard
behavior alongside the setting schema, then replace the hard-coded false
fallbacks in both getState() and getStateToPostToWebview() with that constant.
Preserve the existing nullish-coalescing behavior.

In `@src/services/destructive-command-guard/constants.ts`:
- Around line 9-40: Update DCG_ARCHIVES to use a deeply immutable literal by
applying `as const` and adjusting its type so each archive entry’s `archive`,
`binary`, and `sha256` fields cannot be reassigned. Preserve the existing
platform entries and checksum values while ensuring nested metadata is read-only
at compile time.

In `@src/services/destructive-command-guard/manager.ts`:
- Around line 51-160: Add focused unit tests in manager.spec.ts for
downloadFile’s trusted-host checks, redirect limits, and download-size
enforcement; verifyChecksum’s success and mismatch behavior;
extractSingleBinary’s single-entry layout validation; and installDcg’s atomic
swap behavior. Mock https, fs streams, and child_process.runProcess dependencies
to exercise these paths without real network, archive, or process operations,
while preserving the existing platform-helper tests.

In `@src/services/destructive-command-guard/runner.ts`:
- Around line 16-84: Add focused unit tests for runDcg by mocking
child_process.spawn and simulating its stdout, stderr, close, and error events.
Cover successful allow/deny decisions plus timeout, output-size overflow,
invalid JSON, unsupported schema versions, decision/exit-code mismatches, and
nonzero termination failures, asserting the resulting resolution or rejection
messages.

In `@webview-ui/src/components/chat/CommandExecution.tsx`:
- Around line 39-45: Rename the local isDenied variable inside
handleDenyPatternChange to a distinct name such as isPatternDenied, and update
its references there while preserving the isDenied prop used by
CommandExecution.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7668a3bc-553d-4f41-8d64-ff82c2563941

📥 Commits

Reviewing files that changed from the base of the PR and between dcaa3cb and d7b7b5b.

📒 Files selected for processing (96)
  • AGENTS.md
  • packages/types/src/global-settings.ts
  • packages/types/src/message.ts
  • packages/types/src/vscode-extension-host.ts
  • src/core/auto-approval/__tests__/dcg.spec.ts
  • src/core/auto-approval/index.ts
  • src/core/task/Task.ts
  • src/core/tools/ExecuteCommandTool.ts
  • src/core/tools/__tests__/executeCommandTool.spec.ts
  • src/core/webview/ClineProvider.ts
  • src/core/webview/__tests__/ClineProvider.spec.ts
  • src/core/webview/webviewMessageHandler.ts
  • src/i18n/locales/ca/common.json
  • src/i18n/locales/ca/tools.json
  • src/i18n/locales/de/common.json
  • src/i18n/locales/de/tools.json
  • src/i18n/locales/en/common.json
  • src/i18n/locales/en/tools.json
  • src/i18n/locales/es/common.json
  • src/i18n/locales/es/tools.json
  • src/i18n/locales/fr/common.json
  • src/i18n/locales/fr/tools.json
  • src/i18n/locales/hi/common.json
  • src/i18n/locales/hi/tools.json
  • src/i18n/locales/id/common.json
  • src/i18n/locales/id/tools.json
  • src/i18n/locales/it/common.json
  • src/i18n/locales/it/tools.json
  • src/i18n/locales/ja/common.json
  • src/i18n/locales/ja/tools.json
  • src/i18n/locales/ko/common.json
  • src/i18n/locales/ko/tools.json
  • src/i18n/locales/nl/common.json
  • src/i18n/locales/nl/tools.json
  • src/i18n/locales/pl/common.json
  • src/i18n/locales/pl/tools.json
  • src/i18n/locales/pt-BR/common.json
  • src/i18n/locales/pt-BR/tools.json
  • src/i18n/locales/ru/common.json
  • src/i18n/locales/ru/tools.json
  • src/i18n/locales/tr/common.json
  • src/i18n/locales/tr/tools.json
  • src/i18n/locales/vi/common.json
  • src/i18n/locales/vi/tools.json
  • src/i18n/locales/zh-CN/common.json
  • src/i18n/locales/zh-CN/tools.json
  • src/i18n/locales/zh-TW/common.json
  • src/i18n/locales/zh-TW/tools.json
  • src/services/destructive-command-guard/__tests__/manager.spec.ts
  • src/services/destructive-command-guard/constants.ts
  • src/services/destructive-command-guard/index.ts
  • src/services/destructive-command-guard/manager.ts
  • src/services/destructive-command-guard/runner.ts
  • webview-ui/src/components/chat/ChatRow.tsx
  • webview-ui/src/components/chat/CommandExecution.tsx
  • webview-ui/src/components/chat/__tests__/ChatRow.command-denied.spec.tsx
  • webview-ui/src/components/chat/__tests__/CommandExecution.spec.tsx
  • webview-ui/src/components/settings/AutoApproveSettings.tsx
  • webview-ui/src/components/settings/SettingsView.tsx
  • webview-ui/src/components/settings/__tests__/AutoApproveSettings.spec.tsx
  • webview-ui/src/i18n/locales/ca/chat.json
  • webview-ui/src/i18n/locales/ca/settings.json
  • webview-ui/src/i18n/locales/de/chat.json
  • webview-ui/src/i18n/locales/de/settings.json
  • webview-ui/src/i18n/locales/en/chat.json
  • webview-ui/src/i18n/locales/en/settings.json
  • webview-ui/src/i18n/locales/es/chat.json
  • webview-ui/src/i18n/locales/es/settings.json
  • webview-ui/src/i18n/locales/fr/chat.json
  • webview-ui/src/i18n/locales/fr/settings.json
  • webview-ui/src/i18n/locales/hi/chat.json
  • webview-ui/src/i18n/locales/hi/settings.json
  • webview-ui/src/i18n/locales/id/chat.json
  • webview-ui/src/i18n/locales/id/settings.json
  • webview-ui/src/i18n/locales/it/chat.json
  • webview-ui/src/i18n/locales/it/settings.json
  • webview-ui/src/i18n/locales/ja/chat.json
  • webview-ui/src/i18n/locales/ja/settings.json
  • webview-ui/src/i18n/locales/ko/chat.json
  • webview-ui/src/i18n/locales/ko/settings.json
  • webview-ui/src/i18n/locales/nl/chat.json
  • webview-ui/src/i18n/locales/nl/settings.json
  • webview-ui/src/i18n/locales/pl/chat.json
  • webview-ui/src/i18n/locales/pl/settings.json
  • webview-ui/src/i18n/locales/pt-BR/chat.json
  • webview-ui/src/i18n/locales/pt-BR/settings.json
  • webview-ui/src/i18n/locales/ru/chat.json
  • webview-ui/src/i18n/locales/ru/settings.json
  • webview-ui/src/i18n/locales/tr/chat.json
  • webview-ui/src/i18n/locales/tr/settings.json
  • webview-ui/src/i18n/locales/vi/chat.json
  • webview-ui/src/i18n/locales/vi/settings.json
  • webview-ui/src/i18n/locales/zh-CN/chat.json
  • webview-ui/src/i18n/locales/zh-CN/settings.json
  • webview-ui/src/i18n/locales/zh-TW/chat.json
  • webview-ui/src/i18n/locales/zh-TW/settings.json

Comment thread src/core/tools/ExecuteCommandTool.ts
Comment thread src/services/destructive-command-guard/manager.ts Outdated
Comment thread src/services/destructive-command-guard/manager.ts Outdated
Comment thread webview-ui/src/components/chat/ChatRow.tsx
Comment thread webview-ui/src/i18n/locales/de/settings.json
Comment thread webview-ui/src/i18n/locales/fr/settings.json
@navedmerchant
navedmerchant force-pushed the feat/autoapprovecommands branch from d7b7b5b to bce10d6 Compare July 29, 2026 06:34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/core/webview/webviewMessageHandler.ts (1)

577-577: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Wrap case bodies in blocks to fix no-case-declarations.

const mcpHub = ... (577) and const vsCodeLmModels = ... (1383) are let/const declarations directly inside case clauses without a block, which both ESLint and Biome flag — the declaration is otherwise visible to sibling case clauses in the same switch.

🐛 Proposed fix
-		case "webviewDidLaunch":
+		case "webviewDidLaunch": {
 			// Load custom modes first
 			...
-			provider.isViewLaunched = true
-			break
+			provider.isViewLaunched = true
+			break
+		}
-		case "requestVsCodeLmModels":
-			const vsCodeLmModels = await getVsCodeLmModels()
-			// TODO: Cache like we do for OpenRouter, etc?
-			await provider.postMessageToWebview({ type: "vsCodeLmModels", vsCodeLmModels })
-			break
+		case "requestVsCodeLmModels": {
+			const vsCodeLmModels = await getVsCodeLmModels()
+			// TODO: Cache like we do for OpenRouter, etc?
+			await provider.postMessageToWebview({ type: "vsCodeLmModels", vsCodeLmModels })
+			break
+		}

As per coding guidelines, "Fix lint violations in new TypeScript code instead of adding suppressions."

Also applies to: 1382-1386

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/webview/webviewMessageHandler.ts` at line 577, Wrap the affected
switch case bodies in explicit blocks to satisfy no-case-declarations. Update
the case containing provider.getMcpHub() and the case containing the
vsCodeLmModels declaration, keeping each case’s existing logic and control flow
unchanged while scoping its const declarations to that case.

Sources: Coding guidelines, Linters/SAST tools

src/core/webview/__tests__/ClineProvider.spec.ts (1)

847-847: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Replace as any with the typed pattern already used above.

Line 826 in this same file types the identical expression as ReturnType<typeof vi.fn>; line 847 uses as any instead, which ESLint flags (no-explicit-any).

🐛 Proposed fix
-		const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as any).mock.calls[0][0]
+		const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as ReturnType<typeof vi.fn>).mock
+			.calls[0][0]

As per coding guidelines, "Avoid as any; use typed APIs, bracket notation for private members, or precise test doubles and type guards."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/webview/__tests__/ClineProvider.spec.ts` at line 847, Replace the
`as any` cast in the `messageHandler` assignment with the existing
`ReturnType<typeof vi.fn>` typed pattern used for the identical
`onDidReceiveMessage` expression above, preserving the current test behavior and
satisfying the no-explicit-any rule.

Sources: Coding guidelines, Linters/SAST tools

♻️ Duplicate comments (1)
webview-ui/src/components/chat/ChatRow.tsx (1)

294-301: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Missing key props on the denied-command JSX array — previously flagged, still unresolved.

ESLint still reports react/jsx-key on both elements returned from this branch.

🐛 Proposed fix
 				if (message.autoApprovalDecision === "deny") {
 					return [
-						<OctagonX className="size-4 text-vscode-errorForeground" aria-label="Denied command icon" />,
-						<span className="font-bold text-vscode-errorForeground">
+						<OctagonX
+							key="denied-icon"
+							className="size-4 text-vscode-errorForeground"
+							aria-label="Denied command icon"
+						/>,
+						<span key="denied-title" className="font-bold text-vscode-errorForeground">
 							{t("chat:commandExecution.denied")}
 						</span>,
 					]
 				}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@webview-ui/src/components/chat/ChatRow.tsx` around lines 294 - 301, Add
stable key props to both JSX elements returned by the denied branch of the
message rendering logic, specifically the OctagonX icon and the denied-command
span. Keep their existing content and styling unchanged while ensuring each
array element has a unique key.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/destructive-command-guard/manager.ts`:
- Around line 84-95: Update the oversized-download handling in the response data
listener to destroy the piped output write stream when received exceeds
DCG_MAX_ARCHIVE_BYTES, alongside destroying the request. Preserve the existing
size-limit error and ensure the output stream cannot remain open after aborting.

---

Outside diff comments:
In `@src/core/webview/__tests__/ClineProvider.spec.ts`:
- Line 847: Replace the `as any` cast in the `messageHandler` assignment with
the existing `ReturnType<typeof vi.fn>` typed pattern used for the identical
`onDidReceiveMessage` expression above, preserving the current test behavior and
satisfying the no-explicit-any rule.

In `@src/core/webview/webviewMessageHandler.ts`:
- Line 577: Wrap the affected switch case bodies in explicit blocks to satisfy
no-case-declarations. Update the case containing provider.getMcpHub() and the
case containing the vsCodeLmModels declaration, keeping each case’s existing
logic and control flow unchanged while scoping its const declarations to that
case.

---

Duplicate comments:
In `@webview-ui/src/components/chat/ChatRow.tsx`:
- Around line 294-301: Add stable key props to both JSX elements returned by the
denied branch of the message rendering logic, specifically the OctagonX icon and
the denied-command span. Keep their existing content and styling unchanged while
ensuring each array element has a unique key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ae067f4b-724a-4c0d-b9b7-6cd367315dfd

📥 Commits

Reviewing files that changed from the base of the PR and between d7b7b5b and bce10d6.

📒 Files selected for processing (96)
  • AGENTS.md
  • packages/types/src/global-settings.ts
  • packages/types/src/message.ts
  • packages/types/src/vscode-extension-host.ts
  • src/core/auto-approval/__tests__/dcg.spec.ts
  • src/core/auto-approval/index.ts
  • src/core/task/Task.ts
  • src/core/tools/ExecuteCommandTool.ts
  • src/core/tools/__tests__/executeCommandTool.spec.ts
  • src/core/webview/ClineProvider.ts
  • src/core/webview/__tests__/ClineProvider.spec.ts
  • src/core/webview/webviewMessageHandler.ts
  • src/i18n/locales/ca/common.json
  • src/i18n/locales/ca/tools.json
  • src/i18n/locales/de/common.json
  • src/i18n/locales/de/tools.json
  • src/i18n/locales/en/common.json
  • src/i18n/locales/en/tools.json
  • src/i18n/locales/es/common.json
  • src/i18n/locales/es/tools.json
  • src/i18n/locales/fr/common.json
  • src/i18n/locales/fr/tools.json
  • src/i18n/locales/hi/common.json
  • src/i18n/locales/hi/tools.json
  • src/i18n/locales/id/common.json
  • src/i18n/locales/id/tools.json
  • src/i18n/locales/it/common.json
  • src/i18n/locales/it/tools.json
  • src/i18n/locales/ja/common.json
  • src/i18n/locales/ja/tools.json
  • src/i18n/locales/ko/common.json
  • src/i18n/locales/ko/tools.json
  • src/i18n/locales/nl/common.json
  • src/i18n/locales/nl/tools.json
  • src/i18n/locales/pl/common.json
  • src/i18n/locales/pl/tools.json
  • src/i18n/locales/pt-BR/common.json
  • src/i18n/locales/pt-BR/tools.json
  • src/i18n/locales/ru/common.json
  • src/i18n/locales/ru/tools.json
  • src/i18n/locales/tr/common.json
  • src/i18n/locales/tr/tools.json
  • src/i18n/locales/vi/common.json
  • src/i18n/locales/vi/tools.json
  • src/i18n/locales/zh-CN/common.json
  • src/i18n/locales/zh-CN/tools.json
  • src/i18n/locales/zh-TW/common.json
  • src/i18n/locales/zh-TW/tools.json
  • src/services/destructive-command-guard/__tests__/manager.spec.ts
  • src/services/destructive-command-guard/constants.ts
  • src/services/destructive-command-guard/index.ts
  • src/services/destructive-command-guard/manager.ts
  • src/services/destructive-command-guard/runner.ts
  • webview-ui/src/components/chat/ChatRow.tsx
  • webview-ui/src/components/chat/CommandExecution.tsx
  • webview-ui/src/components/chat/__tests__/ChatRow.command-denied.spec.tsx
  • webview-ui/src/components/chat/__tests__/CommandExecution.spec.tsx
  • webview-ui/src/components/settings/AutoApproveSettings.tsx
  • webview-ui/src/components/settings/SettingsView.tsx
  • webview-ui/src/components/settings/__tests__/AutoApproveSettings.spec.tsx
  • webview-ui/src/i18n/locales/ca/chat.json
  • webview-ui/src/i18n/locales/ca/settings.json
  • webview-ui/src/i18n/locales/de/chat.json
  • webview-ui/src/i18n/locales/de/settings.json
  • webview-ui/src/i18n/locales/en/chat.json
  • webview-ui/src/i18n/locales/en/settings.json
  • webview-ui/src/i18n/locales/es/chat.json
  • webview-ui/src/i18n/locales/es/settings.json
  • webview-ui/src/i18n/locales/fr/chat.json
  • webview-ui/src/i18n/locales/fr/settings.json
  • webview-ui/src/i18n/locales/hi/chat.json
  • webview-ui/src/i18n/locales/hi/settings.json
  • webview-ui/src/i18n/locales/id/chat.json
  • webview-ui/src/i18n/locales/id/settings.json
  • webview-ui/src/i18n/locales/it/chat.json
  • webview-ui/src/i18n/locales/it/settings.json
  • webview-ui/src/i18n/locales/ja/chat.json
  • webview-ui/src/i18n/locales/ja/settings.json
  • webview-ui/src/i18n/locales/ko/chat.json
  • webview-ui/src/i18n/locales/ko/settings.json
  • webview-ui/src/i18n/locales/nl/chat.json
  • webview-ui/src/i18n/locales/nl/settings.json
  • webview-ui/src/i18n/locales/pl/chat.json
  • webview-ui/src/i18n/locales/pl/settings.json
  • webview-ui/src/i18n/locales/pt-BR/chat.json
  • webview-ui/src/i18n/locales/pt-BR/settings.json
  • webview-ui/src/i18n/locales/ru/chat.json
  • webview-ui/src/i18n/locales/ru/settings.json
  • webview-ui/src/i18n/locales/tr/chat.json
  • webview-ui/src/i18n/locales/tr/settings.json
  • webview-ui/src/i18n/locales/vi/chat.json
  • webview-ui/src/i18n/locales/vi/settings.json
  • webview-ui/src/i18n/locales/zh-CN/chat.json
  • webview-ui/src/i18n/locales/zh-CN/settings.json
  • webview-ui/src/i18n/locales/zh-TW/chat.json
  • webview-ui/src/i18n/locales/zh-TW/settings.json
🚧 Files skipped from review as they are similar to previous changes (83)
  • src/i18n/locales/hi/common.json
  • src/i18n/locales/ru/common.json
  • webview-ui/src/i18n/locales/tr/chat.json
  • src/i18n/locales/es/common.json
  • src/i18n/locales/en/tools.json
  • packages/types/src/global-settings.ts
  • webview-ui/src/i18n/locales/ja/chat.json
  • src/i18n/locales/pt-BR/tools.json
  • src/i18n/locales/ja/tools.json
  • webview-ui/src/i18n/locales/fr/chat.json
  • src/i18n/locales/pl/tools.json
  • src/i18n/locales/vi/tools.json
  • webview-ui/src/i18n/locales/ru/settings.json
  • webview-ui/src/components/chat/tests/ChatRow.command-denied.spec.tsx
  • src/i18n/locales/ca/tools.json
  • webview-ui/src/i18n/locales/vi/chat.json
  • src/i18n/locales/id/tools.json
  • src/i18n/locales/ko/tools.json
  • webview-ui/src/i18n/locales/id/chat.json
  • webview-ui/src/i18n/locales/fr/settings.json
  • src/services/destructive-command-guard/tests/manager.spec.ts
  • webview-ui/src/i18n/locales/hi/chat.json
  • src/i18n/locales/es/tools.json
  • src/i18n/locales/ru/tools.json
  • src/i18n/locales/nl/tools.json
  • webview-ui/src/components/settings/tests/AutoApproveSettings.spec.tsx
  • src/i18n/locales/zh-TW/tools.json
  • src/i18n/locales/it/common.json
  • src/services/destructive-command-guard/index.ts
  • packages/types/src/message.ts
  • src/i18n/locales/de/tools.json
  • src/i18n/locales/pl/common.json
  • packages/types/src/vscode-extension-host.ts
  • src/i18n/locales/tr/tools.json
  • webview-ui/src/i18n/locales/pt-BR/chat.json
  • src/i18n/locales/zh-CN/tools.json
  • src/i18n/locales/it/tools.json
  • src/i18n/locales/ca/common.json
  • webview-ui/src/i18n/locales/en/chat.json
  • webview-ui/src/i18n/locales/zh-CN/chat.json
  • webview-ui/src/i18n/locales/ja/settings.json
  • webview-ui/src/i18n/locales/ru/chat.json
  • webview-ui/src/i18n/locales/ko/chat.json
  • webview-ui/src/i18n/locales/it/chat.json
  • webview-ui/src/i18n/locales/es/chat.json
  • src/i18n/locales/nl/common.json
  • webview-ui/src/i18n/locales/de/chat.json
  • webview-ui/src/i18n/locales/nl/chat.json
  • webview-ui/src/i18n/locales/ca/chat.json
  • webview-ui/src/i18n/locales/ko/settings.json
  • webview-ui/src/i18n/locales/pl/settings.json
  • src/i18n/locales/pt-BR/common.json
  • webview-ui/src/i18n/locales/es/settings.json
  • src/i18n/locales/zh-TW/common.json
  • webview-ui/src/i18n/locales/tr/settings.json
  • src/i18n/locales/de/common.json
  • src/core/auto-approval/tests/dcg.spec.ts
  • webview-ui/src/i18n/locales/it/settings.json
  • webview-ui/src/i18n/locales/vi/settings.json
  • webview-ui/src/i18n/locales/nl/settings.json
  • src/i18n/locales/zh-CN/common.json
  • webview-ui/src/i18n/locales/pl/chat.json
  • src/core/task/Task.ts
  • webview-ui/src/components/settings/SettingsView.tsx
  • webview-ui/src/components/chat/tests/CommandExecution.spec.tsx
  • webview-ui/src/i18n/locales/zh-TW/settings.json
  • webview-ui/src/i18n/locales/id/settings.json
  • src/i18n/locales/ko/common.json
  • webview-ui/src/components/chat/CommandExecution.tsx
  • webview-ui/src/i18n/locales/pt-BR/settings.json
  • src/i18n/locales/hi/tools.json
  • webview-ui/src/i18n/locales/hi/settings.json
  • src/i18n/locales/tr/common.json
  • src/core/webview/ClineProvider.ts
  • src/core/tools/ExecuteCommandTool.ts
  • webview-ui/src/i18n/locales/de/settings.json
  • src/i18n/locales/fr/tools.json
  • webview-ui/src/components/settings/AutoApproveSettings.tsx
  • src/services/destructive-command-guard/constants.ts
  • src/i18n/locales/ja/common.json
  • src/core/tools/tests/executeCommandTool.spec.ts
  • src/core/auto-approval/index.ts
  • webview-ui/src/i18n/locales/ca/settings.json

Comment thread src/services/destructive-command-guard/manager.ts Outdated
@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 29, 2026
@navedmerchant
navedmerchant marked this pull request as draft July 29, 2026 06:58
@github-actions github-actions Bot removed the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 29, 2026
@zoomote

zoomote Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Done — reviewed all 7 unresolved review threads and pushed 2478d1f.

Fixed in this commit:

  • Cross-process install race in the managed-binary installer: it now re-checks the installed version before the destructive swap and adopts a valid installation completed by a concurrent VS Code window instead of deleting it mid-flight.
  • Oversized-download abort now destroys the piped output write stream, closing the leaked file descriptor.
  • Both fixes have regression tests; one semble-downloader test mock was made path-aware to model the new mid-install re-check.

Already addressed on the branch head (verified, threads resolved):

  • Localized DCG unavailable error in ExecuteCommandTool (key present in all 18 locales)
  • Windows ZIP extraction via PowerShell Expand-Archive instead of tar
  • React key props on the denied-command branch in ChatRow.tsx
  • German settings wording and formal French register

Validation: full pnpm test at repo root passes (7223 tests, 38 skipped), repo-wide lint and type checks pass. All 7 review threads resolved. Browser visual proof not applicable — the changes are extension-host internals with no rendered UI surface.

- Adopt a concurrently completed installation instead of removing it
  when another VS Code window finishes first, preventing transient
  ENOENT for consumers mid-swap.
- Destroy the piped output stream when aborting an oversized download
  so the file descriptor is not leaked until GC.
- Make the semble downloader test mock path-aware so the added
  mid-install re-check is modeled correctly.
@zoomote zoomote Bot changed the title feat: integrate destructive command guard with auto-approval [Feat] Integrate destructive command guard with auto-approval Jul 30, 2026
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.

Add destructive command guard for smooth command auto-approval

1 participant