source dump of claude code
at main 144 lines 4.0 kB view raw
1import { 2 DANGEROUS_SHELL_SETTINGS, 3 SAFE_ENV_VARS, 4} from '../../utils/managedEnvConstants.js' 5import type { SettingsJson } from '../../utils/settings/types.js' 6import { jsonStringify } from '../../utils/slowOperations.js' 7 8type DangerousShellSetting = (typeof DANGEROUS_SHELL_SETTINGS)[number] 9 10export type DangerousSettings = { 11 shellSettings: Partial<Record<DangerousShellSetting, string>> 12 envVars: Record<string, string> 13 hasHooks: boolean 14 hooks?: unknown 15} 16 17/** 18 * Extract dangerous settings from a settings object. 19 * 20 * Dangerous env vars are determined by checking against SAFE_ENV_VARS - 21 * any env var NOT in SAFE_ENV_VARS is considered dangerous. 22 * See managedEnv.ts for the authoritative list and threat categories. 23 */ 24export function extractDangerousSettings( 25 settings: SettingsJson | null | undefined, 26): DangerousSettings { 27 if (!settings) { 28 return { 29 shellSettings: {}, 30 envVars: {}, 31 hasHooks: false, 32 } 33 } 34 35 // Extract dangerous shell settings 36 const shellSettings: Partial<Record<DangerousShellSetting, string>> = {} 37 for (const key of DANGEROUS_SHELL_SETTINGS) { 38 const value = settings[key] 39 if (typeof value === 'string' && value.length > 0) { 40 shellSettings[key] = value 41 } 42 } 43 44 // Extract dangerous env vars - any var NOT in SAFE_ENV_VARS is dangerous 45 const envVars: Record<string, string> = {} 46 if (settings.env && typeof settings.env === 'object') { 47 for (const [key, value] of Object.entries(settings.env)) { 48 if (typeof value === 'string' && value.length > 0) { 49 // Check if this env var is NOT in the safe list 50 if (!SAFE_ENV_VARS.has(key.toUpperCase())) { 51 envVars[key] = value 52 } 53 } 54 } 55 } 56 57 // Check for hooks 58 const hasHooks = 59 settings.hooks !== undefined && 60 settings.hooks !== null && 61 typeof settings.hooks === 'object' && 62 Object.keys(settings.hooks).length > 0 63 64 return { 65 shellSettings, 66 envVars, 67 hasHooks, 68 hooks: hasHooks ? settings.hooks : undefined, 69 } 70} 71 72/** 73 * Check if settings contain any dangerous settings 74 */ 75export function hasDangerousSettings(dangerous: DangerousSettings): boolean { 76 return ( 77 Object.keys(dangerous.shellSettings).length > 0 || 78 Object.keys(dangerous.envVars).length > 0 || 79 dangerous.hasHooks 80 ) 81} 82 83/** 84 * Compare two sets of dangerous settings to see if the new settings 85 * have changed or added dangerous settings compared to the old settings 86 */ 87export function hasDangerousSettingsChanged( 88 oldSettings: SettingsJson | null | undefined, 89 newSettings: SettingsJson | null | undefined, 90): boolean { 91 const oldDangerous = extractDangerousSettings(oldSettings) 92 const newDangerous = extractDangerousSettings(newSettings) 93 94 // If new settings don't have any dangerous settings, no prompt needed 95 if (!hasDangerousSettings(newDangerous)) { 96 return false 97 } 98 99 // If old settings didn't have dangerous settings but new does, prompt needed 100 if (!hasDangerousSettings(oldDangerous)) { 101 return true 102 } 103 104 // Compare the dangerous settings - any change triggers a prompt 105 const oldJson = jsonStringify({ 106 shellSettings: oldDangerous.shellSettings, 107 envVars: oldDangerous.envVars, 108 hooks: oldDangerous.hooks, 109 }) 110 const newJson = jsonStringify({ 111 shellSettings: newDangerous.shellSettings, 112 envVars: newDangerous.envVars, 113 hooks: newDangerous.hooks, 114 }) 115 116 return oldJson !== newJson 117} 118 119/** 120 * Format dangerous settings as a human-readable list for the UI 121 * Only returns setting names, not values 122 */ 123export function formatDangerousSettingsList( 124 dangerous: DangerousSettings, 125): string[] { 126 const items: string[] = [] 127 128 // Shell settings (names only) 129 for (const key of Object.keys(dangerous.shellSettings)) { 130 items.push(key) 131 } 132 133 // Env vars (names only) 134 for (const key of Object.keys(dangerous.envVars)) { 135 items.push(key) 136 } 137 138 // Hooks 139 if (dangerous.hasHooks) { 140 items.push('hooks') 141 } 142 143 return items 144}