()
| 170 | } |
| 171 | |
| 172 | function getSimpleSandboxSection(): string { |
| 173 | if (!SandboxManager.isSandboxingEnabled()) { |
| 174 | return '' |
| 175 | } |
| 176 | |
| 177 | const fsReadConfig = SandboxManager.getFsReadConfig() |
| 178 | const fsWriteConfig = SandboxManager.getFsWriteConfig() |
| 179 | const networkRestrictionConfig = SandboxManager.getNetworkRestrictionConfig() |
| 180 | const allowUnixSockets = SandboxManager.getAllowUnixSockets() |
| 181 | const ignoreViolations = SandboxManager.getIgnoreViolations() |
| 182 | const allowUnsandboxedCommands = |
| 183 | SandboxManager.areUnsandboxedCommandsAllowed() |
| 184 | |
| 185 | // Replace the per-UID temp dir literal (e.g. /private/tmp/claude-1001/) with |
| 186 | // "$TMPDIR" so the prompt is identical across users — avoids busting the |
| 187 | // cross-user global prompt cache. The sandbox already sets $TMPDIR at runtime. |
| 188 | const claudeTempDir = getClaudeTempDir() |
| 189 | const normalizeAllowOnly = (paths: string[]): string[] => |
| 190 | [...new Set(paths)].map(p => (p === claudeTempDir ? '$TMPDIR' : p)) |
| 191 | |
| 192 | const filesystemConfig = { |
| 193 | read: { |
| 194 | denyOnly: dedup(fsReadConfig.denyOnly), |
| 195 | ...(fsReadConfig.allowWithinDeny && { |
| 196 | allowWithinDeny: dedup(fsReadConfig.allowWithinDeny), |
| 197 | }), |
| 198 | }, |
| 199 | write: { |
| 200 | allowOnly: normalizeAllowOnly(fsWriteConfig.allowOnly), |
| 201 | denyWithinAllow: dedup(fsWriteConfig.denyWithinAllow), |
| 202 | }, |
| 203 | } |
| 204 | |
| 205 | const networkConfig = { |
| 206 | ...(networkRestrictionConfig?.allowedHosts && { |
| 207 | allowedHosts: dedup(networkRestrictionConfig.allowedHosts), |
| 208 | }), |
| 209 | ...(networkRestrictionConfig?.deniedHosts && { |
| 210 | deniedHosts: dedup(networkRestrictionConfig.deniedHosts), |
| 211 | }), |
| 212 | ...(allowUnixSockets && { allowUnixSockets: dedup(allowUnixSockets) }), |
| 213 | } |
| 214 | |
| 215 | const restrictionsLines = [] |
| 216 | if (Object.keys(filesystemConfig).length > 0) { |
| 217 | restrictionsLines.push(`Filesystem: ${jsonStringify(filesystemConfig)}`) |
| 218 | } |
| 219 | if (Object.keys(networkConfig).length > 0) { |
| 220 | restrictionsLines.push(`Network: ${jsonStringify(networkConfig)}`) |
| 221 | } |
| 222 | if (ignoreViolations) { |
| 223 | restrictionsLines.push( |
| 224 | `Ignored violations: ${jsonStringify(ignoreViolations)}`, |
| 225 | ) |
| 226 | } |
| 227 | |
| 228 | const sandboxOverrideItems: Array<string | string[]> = |
| 229 | allowUnsandboxedCommands |
no test coverage detected