UNPKG

buroventures-harald-code

Version:

Harald Code - AI-powered coding assistant CLI

77 lines 3.42 kB
/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { checkCommandPermissions, ShellExecutionService, } from 'buroventures-harald-code-core'; export class ConfirmationRequiredError extends Error { commandsToConfirm; constructor(message, commandsToConfirm) { super(message); this.commandsToConfirm = commandsToConfirm; this.name = 'ConfirmationRequiredError'; } } /** * Finds all instances of shell command injections (`!{...}`) in a prompt, * executes them, and replaces the injection site with the command's output. * * This processor ensures that only allowlisted commands are executed. If a * disallowed command is found, it halts execution and reports an error. */ export class ShellProcessor { commandName; /** * A regular expression to find all instances of `!{...}`. The inner * capture group extracts the command itself. */ static SHELL_INJECTION_REGEX = /!\{([^}]*)\}/g; /** * @param commandName The name of the custom command being executed, used * for logging and error messages. */ constructor(commandName) { this.commandName = commandName; } async process(prompt, context) { const { config, sessionShellAllowlist } = { ...context.services, ...context.session, }; const commandsToExecute = []; const commandsToConfirm = new Set(); const matches = [...prompt.matchAll(ShellProcessor.SHELL_INJECTION_REGEX)]; if (matches.length === 0) { return prompt; // No shell commands, nothing to do. } // Discover all commands and check permissions. for (const match of matches) { const command = match[1].trim(); const { allAllowed, disallowedCommands, blockReason, isHardDenial } = checkCommandPermissions(command, config, sessionShellAllowlist); if (!allAllowed) { // If it's a hard denial, this is a non-recoverable security error. if (isHardDenial) { throw new Error(`${this.commandName} cannot be run. ${blockReason || 'A shell command in this custom command is explicitly blocked in your config settings.'}`); } // Add each soft denial disallowed command to the set for confirmation. disallowedCommands.forEach((uc) => commandsToConfirm.add(uc)); } commandsToExecute.push({ fullMatch: match[0], command }); } // If any commands require confirmation, throw a special error to halt the // pipeline and trigger the UI flow. if (commandsToConfirm.size > 0) { throw new ConfirmationRequiredError('Shell command confirmation required', Array.from(commandsToConfirm)); } // Execute all commands (only runs if no confirmation was needed). let processedPrompt = prompt; for (const { fullMatch, command } of commandsToExecute) { const { result } = ShellExecutionService.execute(command, config.getTargetDir(), () => { }, // No streaming needed. new AbortController().signal); const executionResult = await result; processedPrompt = processedPrompt.replace(fullMatch, executionResult.output); } return processedPrompt; } } //# sourceMappingURL=shellProcessor.js.map