Ver código fonte

Preapprove agent tmp directory access (#25226)

Dax 4 meses atrás
pai
commit
2283979199

+ 5 - 0
packages/core/src/global.ts

@@ -11,6 +11,7 @@ const data = path.join(xdgData!, app)
 const cache = path.join(xdgCache!, app)
 const cache = path.join(xdgCache!, app)
 const config = path.join(xdgConfig!, app)
 const config = path.join(xdgConfig!, app)
 const state = path.join(xdgState!, app)
 const state = path.join(xdgState!, app)
+const tmp = path.join(os.tmpdir(), app)
 
 
 const paths = {
 const paths = {
   get home() {
   get home() {
@@ -22,6 +23,7 @@ const paths = {
   cache,
   cache,
   config,
   config,
   state,
   state,
+  tmp,
 }
 }
 
 
 export const Path = paths
 export const Path = paths
@@ -32,6 +34,7 @@ await Promise.all([
   fs.mkdir(Path.data, { recursive: true }),
   fs.mkdir(Path.data, { recursive: true }),
   fs.mkdir(Path.config, { recursive: true }),
   fs.mkdir(Path.config, { recursive: true }),
   fs.mkdir(Path.state, { recursive: true }),
   fs.mkdir(Path.state, { recursive: true }),
+  fs.mkdir(Path.tmp, { recursive: true }),
   fs.mkdir(Path.log, { recursive: true }),
   fs.mkdir(Path.log, { recursive: true }),
   fs.mkdir(Path.bin, { recursive: true }),
   fs.mkdir(Path.bin, { recursive: true }),
 ])
 ])
@@ -44,6 +47,7 @@ export interface Interface {
   readonly cache: string
   readonly cache: string
   readonly config: string
   readonly config: string
   readonly state: string
   readonly state: string
+  readonly tmp: string
   readonly bin: string
   readonly bin: string
   readonly log: string
   readonly log: string
 }
 }
@@ -55,6 +59,7 @@ export function make(input: Partial<Interface> = {}): Interface {
     cache: Path.cache,
     cache: Path.cache,
     config: Flag.OPENCODE_CONFIG_DIR ?? Path.config,
     config: Flag.OPENCODE_CONFIG_DIR ?? Path.config,
     state: Path.state,
     state: Path.state,
+    tmp: Path.tmp,
     bin: Path.bin,
     bin: Path.bin,
     log: Path.log,
     log: Path.log,
     ...input,
     ...input,

+ 5 - 1
packages/opencode/src/agent/agent.ts

@@ -81,7 +81,11 @@ export const layer = Layer.effect(
       Effect.fn("Agent.state")(function* (ctx) {
       Effect.fn("Agent.state")(function* (ctx) {
         const cfg = yield* config.get()
         const cfg = yield* config.get()
         const skillDirs = yield* skill.dirs()
         const skillDirs = yield* skill.dirs()
-        const whitelistedDirs = [Truncate.GLOB, ...skillDirs.map((dir) => path.join(dir, "*"))]
+        const whitelistedDirs = [
+          Truncate.GLOB,
+          path.join(Global.Path.tmp, "*"),
+          ...skillDirs.map((dir) => path.join(dir, "*")),
+        ]
 
 
         const defaults = Permission.fromConfig({
         const defaults = Permission.fromConfig({
           "*": "allow",
           "*": "allow",

+ 2 - 0
packages/opencode/src/tool/bash.ts

@@ -14,6 +14,7 @@ import { AppFileSystem } from "@opencode-ai/core/filesystem"
 import { fileURLToPath } from "url"
 import { fileURLToPath } from "url"
 import { Config } from "@/config/config"
 import { Config } from "@/config/config"
 import { Flag } from "@opencode-ai/core/flag/flag"
 import { Flag } from "@opencode-ai/core/flag/flag"
+import { Global } from "@opencode-ai/core/global"
 import { Shell } from "@/shell/shell"
 import { Shell } from "@/shell/shell"
 
 
 import { BashArity } from "@/permission/arity"
 import { BashArity } from "@/permission/arity"
@@ -587,6 +588,7 @@ export const BashTool = Tool.define(
 
 
         return {
         return {
           description: DESCRIPTION.replaceAll("${directory}", instance.directory)
           description: DESCRIPTION.replaceAll("${directory}", instance.directory)
+            .replaceAll("${tmp}", Global.Path.tmp)
             .replaceAll("${os}", process.platform)
             .replaceAll("${os}", process.platform)
             .replaceAll("${shell}", name)
             .replaceAll("${shell}", name)
             .replaceAll("${chaining}", chain)
             .replaceAll("${chaining}", chain)

+ 2 - 0
packages/opencode/src/tool/bash.txt

@@ -4,6 +4,8 @@ Be aware: OS: ${os}, Shell: ${shell}
 
 
 All commands run in the current working directory by default. Use the `workdir` parameter if you need to run a command in a different directory. AVOID using `cd <directory> && <command>` patterns - use `workdir` instead.
 All commands run in the current working directory by default. Use the `workdir` parameter if you need to run a command in a different directory. AVOID using `cd <directory> && <command>` patterns - use `workdir` instead.
 
 
+Use `${tmp}` for temporary work outside the workspace. This directory is pre-approved for external directory access.
+
 IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.
 IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.
 
 
 Before executing the command, please follow these steps:
 Before executing the command, please follow these steps: