fix(websearch): close review gaps in managed runtime

This commit is contained in:
Tam Nhu Tran committed 2026-03-30 23:02:20 -04:00
1 parent de7171d810
commit cae5b710b8
15 files changed
+299 -60

No files matched your search

+4 -2
View File
@@ -7,6 +7,7 @@
*/
import { getWebSearchConfig } from '../../config/unified-config-loader';
import { resolveAllowedWebSearchTraceFile } from './trace';
/**
* Get environment variables for WebSearch hook configuration.
@@ -22,8 +23,9 @@ export function getWebSearchHookEnv(): Record<string, string> {
if (process.env.CCS_WEBSEARCH_TRACE === '1' || process.env.CCS_DEBUG === '1') {
env.CCS_WEBSEARCH_TRACE = '1';
}
if (process.env.CCS_WEBSEARCH_TRACE_FILE) {
env.CCS_WEBSEARCH_TRACE_FILE = process.env.CCS_WEBSEARCH_TRACE_FILE;
const traceFileOverride = resolveAllowedWebSearchTraceFile(process.env);
if (traceFileOverride) {
env.CCS_WEBSEARCH_TRACE_FILE = traceFileOverride;
}
// Skip hook entirely if disabled
+13 -1
View File
@@ -194,7 +194,19 @@ export function installWebSearchMcpServer(): boolean {
try {
fs.copyFileSync(sourcePath, tempPath);
fs.chmodSync(tempPath, 0o755);
fs.renameSync(tempPath, serverPath);
try {
fs.renameSync(tempPath, serverPath);
} catch (renameError) {
const errorCode = (renameError as NodeJS.ErrnoException).code;
if (errorCode !== 'EEXIST' && errorCode !== 'EPERM') {
throw renameError;
}
if (!hasMatchingContents(sourcePath, serverPath)) {
fs.copyFileSync(tempPath, serverPath);
fs.chmodSync(serverPath, 0o755);
}
}
appendWebSearchTrace('websearch_mcp_install_ready', { serverPath });
return true;
} catch (error) {
+26 -15
View File
@@ -7,11 +7,11 @@
*/
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { getCcsDir } from '../config-manager';
const TRACE_FILE_NAME = 'websearch-trace.jsonl';
const SAFE_SYSTEM_TRACE_PREFIXES = ['/tmp/', '/var/log/'];
const NATIVE_WEBSEARCH_TOOL = 'WebSearch';
const DISALLOWED_TOOLS_FLAG = '--disallowedTools';
const APPEND_SYSTEM_PROMPT_FLAG = '--append-system-prompt';
@@ -75,26 +75,36 @@ function hasExactFlagValue(args: string[], flag: string, expectedValue: string):
return false;
}
function getTraceFilePath(env: NodeJS.ProcessEnv): string {
function normalizeSafePrefix(inputPath: string): string {
return `${path.resolve(inputPath)}${path.sep}`;
}
function getSafeTracePrefixes(): string[] {
return [
normalizeSafePrefix(path.join(getCcsDir(), 'logs')),
normalizeSafePrefix(os.tmpdir()),
normalizeSafePrefix('/var/log'),
];
}
export function resolveAllowedWebSearchTraceFile(
env: NodeJS.ProcessEnv = process.env
): string | null {
const configured = env.CCS_WEBSEARCH_TRACE_FILE?.trim();
if (!configured) {
return path.join(getCcsDir(), 'logs', TRACE_FILE_NAME);
return null;
}
const resolved = path.resolve(configured);
const home = env.HOME || env.USERPROFILE || '';
const normalizedHome = home ? `${path.resolve(home)}${path.sep}` : '';
const normalizedCcsDir = `${path.resolve(getCcsDir())}${path.sep}`;
if (
resolved.startsWith(normalizedCcsDir) ||
(normalizedHome && resolved.startsWith(normalizedHome)) ||
SAFE_SYSTEM_TRACE_PREFIXES.some((prefix) => resolved.startsWith(prefix))
) {
if (getSafeTracePrefixes().some((prefix) => resolved.startsWith(prefix))) {
return resolved;
}
return path.join(getCcsDir(), 'logs', TRACE_FILE_NAME);
return null;
}
function getTraceFilePath(env: NodeJS.ProcessEnv): string {
return resolveAllowedWebSearchTraceFile(env) ?? path.join(getCcsDir(), 'logs', TRACE_FILE_NAME);
}
export function isWebSearchTraceEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
@@ -197,8 +207,9 @@ export function createWebSearchTraceContext(params: {
CCS_WEBSEARCH_TRACE_LAUNCHER: params.launcher,
};
if (env.CCS_WEBSEARCH_TRACE_FILE) {
traceEnv.CCS_WEBSEARCH_TRACE_FILE = env.CCS_WEBSEARCH_TRACE_FILE;
const traceFileOverride = resolveAllowedWebSearchTraceFile(env);
if (traceFileOverride) {
traceEnv.CCS_WEBSEARCH_TRACE_FILE = traceFileOverride;
}
appendWebSearchTrace(