Skip to content

Commit cdacdfd

Browse files
Add a command denylist (#5614)
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
1 parent 84bfd76 commit cdacdfd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1663
-95
lines changed

packages/types/src/global-settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export const globalSettingsSchema = z.object({
4949
followupAutoApproveTimeoutMs: z.number().optional(),
5050
alwaysAllowUpdateTodoList: z.boolean().optional(),
5151
allowedCommands: z.array(z.string()).optional(),
52+
deniedCommands: z.array(z.string()).optional(),
5253
allowedMaxRequests: z.number().nullish(),
5354
autoCondenseContext: z.boolean().optional(),
5455
autoCondenseContextPercent: z.number().optional(),

src/core/webview/ClineProvider.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,15 +1304,39 @@ export class ClineProvider
13041304
* with proper validation and deduplication
13051305
*/
13061306
private mergeAllowedCommands(globalStateCommands?: string[]): string[] {
1307+
return this.mergeCommandLists("allowedCommands", "allowed", globalStateCommands)
1308+
}
1309+
1310+
/**
1311+
* Merges denied commands from global state and workspace configuration
1312+
* with proper validation and deduplication
1313+
*/
1314+
private mergeDeniedCommands(globalStateCommands?: string[]): string[] {
1315+
return this.mergeCommandLists("deniedCommands", "denied", globalStateCommands)
1316+
}
1317+
1318+
/**
1319+
* Common utility for merging command lists from global state and workspace configuration.
1320+
* Implements the Command Denylist feature's merging strategy with proper validation.
1321+
*
1322+
* @param configKey - VSCode workspace configuration key
1323+
* @param commandType - Type of commands for error logging
1324+
* @param globalStateCommands - Commands from global state
1325+
* @returns Merged and deduplicated command list
1326+
*/
1327+
private mergeCommandLists(
1328+
configKey: "allowedCommands" | "deniedCommands",
1329+
commandType: "allowed" | "denied",
1330+
globalStateCommands?: string[],
1331+
): string[] {
13071332
try {
13081333
// Validate and sanitize global state commands
13091334
const validGlobalCommands = Array.isArray(globalStateCommands)
13101335
? globalStateCommands.filter((cmd) => typeof cmd === "string" && cmd.trim().length > 0)
13111336
: []
13121337

13131338
// Get workspace configuration commands
1314-
const workspaceCommands =
1315-
vscode.workspace.getConfiguration(Package.name).get<string[]>("allowedCommands") || []
1339+
const workspaceCommands = vscode.workspace.getConfiguration(Package.name).get<string[]>(configKey) || []
13161340

13171341
// Validate and sanitize workspace commands
13181342
const validWorkspaceCommands = Array.isArray(workspaceCommands)
@@ -1325,7 +1349,7 @@ export class ClineProvider
13251349

13261350
return mergedCommands
13271351
} catch (error) {
1328-
console.error("Error merging allowed commands:", error)
1352+
console.error(`Error merging ${commandType} commands:`, error)
13291353
// Return empty array as fallback to prevent crashes
13301354
return []
13311355
}
@@ -1343,6 +1367,7 @@ export class ClineProvider
13431367
alwaysAllowWriteProtected,
13441368
alwaysAllowExecute,
13451369
allowedCommands,
1370+
deniedCommands,
13461371
alwaysAllowBrowser,
13471372
alwaysAllowMcp,
13481373
alwaysAllowModeSwitch,
@@ -1414,6 +1439,7 @@ export class ClineProvider
14141439
const telemetryKey = process.env.POSTHOG_API_KEY
14151440
const machineId = vscode.env.machineId
14161441
const mergedAllowedCommands = this.mergeAllowedCommands(allowedCommands)
1442+
const mergedDeniedCommands = this.mergeDeniedCommands(deniedCommands)
14171443
const cwd = this.cwd
14181444

14191445
// Check if there's a system prompt override for the current mode
@@ -1454,6 +1480,7 @@ export class ClineProvider
14541480
shouldShowAnnouncement:
14551481
telemetrySetting !== "unset" && lastShownAnnouncementId !== this.latestAnnouncementId,
14561482
allowedCommands: mergedAllowedCommands,
1483+
deniedCommands: mergedDeniedCommands,
14571484
soundVolume: soundVolume ?? 0.5,
14581485
browserViewportSize: browserViewportSize ?? "900x600",
14591486
screenshotQuality: screenshotQuality ?? 75,
@@ -1610,6 +1637,7 @@ export class ClineProvider
16101637
autoCondenseContextPercent: stateValues.autoCondenseContextPercent ?? 100,
16111638
taskHistory: stateValues.taskHistory,
16121639
allowedCommands: stateValues.allowedCommands,
1640+
deniedCommands: stateValues.deniedCommands,
16131641
soundEnabled: stateValues.soundEnabled ?? false,
16141642
ttsEnabled: stateValues.ttsEnabled ?? false,
16151643
ttsSpeed: stateValues.ttsSpeed ?? 1.0,

src/core/webview/webviewMessageHandler.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,22 @@ export const webviewMessageHandler = async (
776776

777777
break
778778
}
779+
case "deniedCommands": {
780+
// Validate and sanitize the commands array
781+
const commands = message.commands ?? []
782+
const validCommands = Array.isArray(commands)
783+
? commands.filter((cmd) => typeof cmd === "string" && cmd.trim().length > 0)
784+
: []
785+
786+
await updateGlobalState("deniedCommands", validCommands)
787+
788+
// Also update workspace settings.
789+
await vscode.workspace
790+
.getConfiguration(Package.name)
791+
.update("deniedCommands", validCommands, vscode.ConfigurationTarget.Global)
792+
793+
break
794+
}
779795
case "openCustomModesSettings": {
780796
const customModesFilePath = await provider.customModesManager.getCustomModesFilePath()
781797

src/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,14 @@
330330
],
331331
"description": "%commands.allowedCommands.description%"
332332
},
333+
"roo-cline.deniedCommands": {
334+
"type": "array",
335+
"items": {
336+
"type": "string"
337+
},
338+
"default": [],
339+
"description": "%commands.deniedCommands.description%"
340+
},
333341
"roo-cline.vsCodeLmModelSelector": {
334342
"type": "object",
335343
"properties": {

src/package.nls.ca.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"command.documentation.title": "Documentació",
2828
"configuration.title": "Roo Code",
2929
"commands.allowedCommands.description": "Ordres que es poden executar automàticament quan 'Aprova sempre les operacions d'execució' està activat",
30+
"commands.deniedCommands.description": "Prefixos d'ordres que seran automàticament denegats sense demanar aprovació. En cas de conflictes amb ordres permeses, la coincidència de prefix més llarga té prioritat. Afegeix * per denegar totes les ordres.",
3031
"settings.vsCodeLmModelSelector.description": "Configuració per a l'API del model de llenguatge VSCode",
3132
"settings.vsCodeLmModelSelector.vendor.description": "El proveïdor del model de llenguatge (p. ex. copilot)",
3233
"settings.vsCodeLmModelSelector.family.description": "La família del model de llenguatge (p. ex. gpt-4)",

src/package.nls.de.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"command.documentation.title": "Dokumentation",
2828
"configuration.title": "Roo Code",
2929
"commands.allowedCommands.description": "Befehle, die automatisch ausgeführt werden können, wenn 'Ausführungsoperationen immer genehmigen' aktiviert ist",
30+
"commands.deniedCommands.description": "Befehlspräfixe, die automatisch abgelehnt werden, ohne nach Genehmigung zu fragen. Bei Konflikten mit erlaubten Befehlen hat die längste Präfix-Übereinstimmung Vorrang. Füge * hinzu, um alle Befehle abzulehnen.",
3031
"settings.vsCodeLmModelSelector.description": "Einstellungen für die VSCode-Sprachmodell-API",
3132
"settings.vsCodeLmModelSelector.vendor.description": "Der Anbieter des Sprachmodells (z.B. copilot)",
3233
"settings.vsCodeLmModelSelector.family.description": "Die Familie des Sprachmodells (z.B. gpt-4)",

src/package.nls.es.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"command.documentation.title": "Documentación",
2828
"configuration.title": "Roo Code",
2929
"commands.allowedCommands.description": "Comandos que pueden ejecutarse automáticamente cuando 'Aprobar siempre operaciones de ejecución' está activado",
30+
"commands.deniedCommands.description": "Prefijos de comandos que serán automáticamente denegados sin solicitar aprobación. En caso de conflictos con comandos permitidos, la coincidencia de prefijo más larga tiene prioridad. Añade * para denegar todos los comandos.",
3031
"settings.vsCodeLmModelSelector.description": "Configuración para la API del modelo de lenguaje VSCode",
3132
"settings.vsCodeLmModelSelector.vendor.description": "El proveedor del modelo de lenguaje (ej. copilot)",
3233
"settings.vsCodeLmModelSelector.family.description": "La familia del modelo de lenguaje (ej. gpt-4)",

src/package.nls.fr.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"command.documentation.title": "Documentation",
2828
"configuration.title": "Roo Code",
2929
"commands.allowedCommands.description": "Commandes pouvant être exécutées automatiquement lorsque 'Toujours approuver les opérations d'exécution' est activé",
30+
"commands.deniedCommands.description": "Préfixes de commandes qui seront automatiquement refusés sans demander d'approbation. En cas de conflit avec les commandes autorisées, la correspondance de préfixe la plus longue a la priorité. Ajouter * pour refuser toutes les commandes.",
3031
"settings.vsCodeLmModelSelector.description": "Paramètres pour l'API du modèle de langage VSCode",
3132
"settings.vsCodeLmModelSelector.vendor.description": "Le fournisseur du modèle de langage (ex: copilot)",
3233
"settings.vsCodeLmModelSelector.family.description": "La famille du modèle de langage (ex: gpt-4)",

src/package.nls.hi.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"command.documentation.title": "दस्तावेज़ीकरण",
2828
"configuration.title": "Roo Code",
2929
"commands.allowedCommands.description": "वे कमांड जो स्वचालित रूप से निष्पादित की जा सकती हैं जब 'हमेशा निष्पादन संचालन को स्वीकृत करें' सक्रिय हो",
30+
"commands.deniedCommands.description": "कमांड प्रीफिक्स जो स्वचालित रूप से अस्वीकार कर दिए जाएंगे बिना अनुमोदन मांगे। अनुमतित कमांड के साथ संघर्ष की स्थिति में, सबसे लंबा प्रीफिक्स मैच प्राथमिकता लेता है। सभी कमांड को अस्वीकार करने के लिए * जोड़ें।",
3031
"settings.vsCodeLmModelSelector.description": "VSCode भाषा मॉडल API के लिए सेटिंग्स",
3132
"settings.vsCodeLmModelSelector.vendor.description": "भाषा मॉडल का विक्रेता (उदा. copilot)",
3233
"settings.vsCodeLmModelSelector.family.description": "भाषा मॉडल का परिवार (उदा. gpt-4)",

src/package.nls.id.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"command.acceptInput.title": "Terima Input/Saran",
2828
"configuration.title": "Roo Code",
2929
"commands.allowedCommands.description": "Perintah yang dapat dijalankan secara otomatis ketika 'Selalu setujui operasi eksekusi' diaktifkan",
30+
"commands.deniedCommands.description": "Awalan perintah yang akan otomatis ditolak tanpa meminta persetujuan. Jika terjadi konflik dengan perintah yang diizinkan, pencocokan awalan terpanjang akan diprioritaskan. Tambahkan * untuk menolak semua perintah.",
3031
"settings.vsCodeLmModelSelector.description": "Pengaturan untuk API Model Bahasa VSCode",
3132
"settings.vsCodeLmModelSelector.vendor.description": "Vendor dari model bahasa (misalnya copilot)",
3233
"settings.vsCodeLmModelSelector.family.description": "Keluarga dari model bahasa (misalnya gpt-4)",

0 commit comments

Comments
 (0)