From 4a2ad666b22f514df25a4d1a33c165701f7db4d8 Mon Sep 17 00:00:00 2001 From: Devflex2 Date: Sun, 19 Apr 2026 15:20:10 +0000 Subject: [PATCH 01/10] feat: add Cody agent runtime hardening foundations and shell mutation guard --- app/components/chat/APIKeyManager.tsx | 5 +- app/components/chat/BaseChat.tsx | 24 +- app/components/chat/Chat.client.tsx | 7 +- app/components/chat/ChatAlert.tsx | 6 +- app/components/chat/ChatBox.tsx | 4 +- app/components/chat/UserMessage.tsx | 2 +- app/components/workbench/Workbench.client.tsx | 8 +- app/lib/common/prompts/new-prompt.ts | 6 +- app/lib/common/prompts/optimized.ts | 2 +- app/lib/common/prompts/prompts.ts | 13 +- app/lib/common/prompts/small-model.ts | 28 +- app/lib/runtime/action-runner.spec.ts | 47 ++ app/lib/runtime/action-runner.ts | 66 +++ app/lib/runtime/api-key-storage.ts | 153 ++++++- app/lib/runtime/enhanced-message-parser.ts | 23 +- app/lib/runtime/message-parser.spec.ts | 7 + app/lib/runtime/message-parser.ts | 15 + app/lib/runtime/shell-interceptor.ts | 28 ++ app/lib/webcontainer/index.ts | 119 +----- .../manager/WebContainerManager.ts | 401 ++++++++++++++++++ app/lib/webcontainer/runtime.ts | 23 + 21 files changed, 832 insertions(+), 155 deletions(-) create mode 100644 app/lib/runtime/shell-interceptor.ts create mode 100644 app/lib/webcontainer/manager/WebContainerManager.ts create mode 100644 app/lib/webcontainer/runtime.ts diff --git a/app/components/chat/APIKeyManager.tsx b/app/components/chat/APIKeyManager.tsx index ff689177..49a89dd6 100644 --- a/app/components/chat/APIKeyManager.tsx +++ b/app/components/chat/APIKeyManager.tsx @@ -1,8 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { IconButton } from '~/components/ui/IconButton'; import type { ProviderInfo } from '~/types/model'; -import Cookies from 'js-cookie'; -import { getApiKeysFromCookies } from '~/lib/runtime/api-key-storage'; +import { getApiKeysFromCookies, setApiKeysCookie } from '~/lib/runtime/api-key-storage'; interface APIKeyManagerProps { provider: ProviderInfo; @@ -66,7 +65,7 @@ export const APIKeyManager: React.FC = ({ provider, apiKey, // Save to cookies const currentKeys = getApiKeysFromCookies(); const newKeys = { ...currentKeys, [provider.name]: normalizedKey }; - Cookies.set('apiKeys', JSON.stringify(newKeys), { expires: 365 }); + setApiKeysCookie(newKeys, 365); setIsEditing(false); }; diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index 47ad1f5a..f5c0f50c 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -4,9 +4,14 @@ import { ClientOnly } from 'remix-utils/client-only'; import { Menu } from '~/components/sidebar/Menu.client'; import { classNames } from '~/utils/classNames'; import { PROVIDER_LIST } from '~/utils/constants'; -import { getApiKeysFromCookies } from '~/lib/runtime/api-key-storage'; +import { + getApiKeysFromCookies, + loadApiKeysFromSecureStorage, + removeApiKeysCookie, + setApiKeysCookie, +} from '~/lib/runtime/api-key-storage'; import { ChatBox } from './ChatBox'; -import Cookies from 'js-cookie'; + import * as Tooltip from '@radix-ui/react-tooltip'; import styles from './BaseChat.module.scss'; import { ImportButtons } from '~/components/chat/chatExportAndImport/ImportButtons'; @@ -506,9 +511,20 @@ export const BaseChat = React.forwardRef( try { parsedApiKeys = getApiKeysFromCookies(); setApiKeys(parsedApiKeys); + + if (Object.keys(parsedApiKeys).length === 0) { + void loadApiKeysFromSecureStorage().then((secureApiKeys) => { + if (Object.keys(secureApiKeys).length === 0) { + return; + } + + setApiKeys(secureApiKeys); + setApiKeysCookie(secureApiKeys); + }); + } } catch (error) { console.error('Error loading API keys from cookies:', error); - Cookies.remove('apiKeys'); + removeApiKeysCookie(); } setIsModelLoading('all'); @@ -531,7 +547,7 @@ export const BaseChat = React.forwardRef( const normalizedApiKey = apiKey.trim(); const newApiKeys = { ...apiKeys, [providerName]: normalizedApiKey }; setApiKeys(newApiKeys); - Cookies.set('apiKeys', JSON.stringify(newApiKeys), { expires: 365 }); + setApiKeysCookie(newApiKeys, 365); setIsModelLoading(providerName); diff --git a/app/components/chat/Chat.client.tsx b/app/components/chat/Chat.client.tsx index a971f3fd..8920f029 100644 --- a/app/components/chat/Chat.client.tsx +++ b/app/components/chat/Chat.client.tsx @@ -66,6 +66,7 @@ import type { import { shouldUnlockPromptAfterPreviewReady } from './execution-status'; import { hasFallbackStarterPlaceholder, STARTER_PLACEHOLDER_TEXT } from '~/lib/runtime/starter-placeholder'; import { getHiddenContinuationDelay, shouldDispatchHiddenContinuation } from '~/lib/runtime/continuation-dispatch'; +import { getApiKeysFromCookies, setApiKeysCookie } from '~/lib/runtime/api-key-storage'; const logger = createScopedLogger('Chat'); const ARCHITECT_NAME = 'Architect'; @@ -161,7 +162,7 @@ function loadStoredProjectMemory(): StoredProjectMemory { } function getApiKeysFromCookiesSafe(): Record { - return parseApiKeysCookie(Cookies.get('apiKeys')); + return getApiKeysFromCookies(); } function getProviderSettingsFromCookiesSafe(): Record { @@ -2387,7 +2388,7 @@ Requirements: if (temResp) { const { assistantMessage, usingLocalFallback } = temResp; - const starterActionCount = (assistantMessage.match(/ { setApiKeys(updatedApiKeys); - Cookies.set('apiKeys', JSON.stringify(updatedApiKeys), { expires: CHAT_SELECTION_COOKIE_EXPIRY_DAYS }); + setApiKeysCookie(updatedApiKeys, CHAT_SELECTION_COOKIE_EXPIRY_DAYS); const normalizedKey = apiKey.trim(); diff --git a/app/components/chat/ChatAlert.tsx b/app/components/chat/ChatAlert.tsx index 773c6809..cdb7c0ee 100644 --- a/app/components/chat/ChatAlert.tsx +++ b/app/components/chat/ChatAlert.tsx @@ -24,8 +24,8 @@ export default function ChatAlert({ alert, clearAlert, postMessage, autoFixState ? 'Architect has queued an automatic preview repair and will run it as soon as the current step finishes.' : 'Architect has queued an automatic terminal repair and will run it as soon as the current step finishes.' : isPreview - ? 'We encountered an error while running the preview. Would you like Bolt to analyze and help resolve this issue?' - : 'We encountered an error while running terminal commands. Would you like Bolt to analyze and help resolve this issue?'; + ? 'We encountered an error while running the preview. Would you like Cody agent to analyze and help resolve this issue?' + : 'We encountered an error while running terminal commands. Would you like Cody agent to analyze and help resolve this issue?'; return ( @@ -96,7 +96,7 @@ export default function ChatAlert({ alert, clearAlert, postMessage, autoFixState )} >
- {autoFixState === 'running' ? 'Auto-fixing' : autoFixState === 'queued' ? 'Queued' : 'Ask Bolt'} + {autoFixState === 'running' ? 'Auto-fixing' : autoFixState === 'queued' ? 'Queued' : 'Ask Cody agent'}