summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAiden Cline <[email protected]>2026-01-08 11:07:23 -0600
committerAiden Cline <[email protected]>2026-01-08 11:07:33 -0600
commit3c5043497c159585654169aab3c7b791d861090f (patch)
tree7b4bdf2e20aacdd003480c1f6fb6c08436218951
parent4d09c5618e094dff521444e218632ea964936ba7 (diff)
downloadopencode-3c5043497c159585654169aab3c7b791d861090f.tar.gz
opencode-3c5043497c159585654169aab3c7b791d861090f.zip
ignore: ensure new file truncation stuff still works even if external_directoy is set to deny
-rw-r--r--packages/opencode/src/agent/agent.ts15
-rw-r--r--packages/opencode/test/agent/agent.test.ts63
2 files changed, 78 insertions, 0 deletions
diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts
index ab17dd223..176955838 100644
--- a/packages/opencode/src/agent/agent.ts
+++ b/packages/opencode/src/agent/agent.ts
@@ -209,6 +209,21 @@ export namespace Agent {
item.options = mergeDeep(item.options, value.options ?? {})
item.permission = PermissionNext.merge(item.permission, PermissionNext.fromConfig(value.permission ?? {}))
}
+
+ // Ensure Truncate.DIR is allowed unless explicitly configured
+ for (const name in result) {
+ const agent = result[name]
+ const explicit = agent.permission.some(
+ (r) => r.permission === "external_directory" && r.pattern === Truncate.DIR && r.action === "deny",
+ )
+ if (explicit) continue
+
+ result[name].permission = PermissionNext.merge(
+ result[name].permission,
+ PermissionNext.fromConfig({ external_directory: { [Truncate.DIR]: "allow" } }),
+ )
+ }
+
return result
})
diff --git a/packages/opencode/test/agent/agent.test.ts b/packages/opencode/test/agent/agent.test.ts
index 140ef49d4..68833c794 100644
--- a/packages/opencode/test/agent/agent.test.ts
+++ b/packages/opencode/test/agent/agent.test.ts
@@ -446,3 +446,66 @@ test("legacy tools config maps write/edit/patch/multiedit to edit permission", a
},
})
})
+
+test("Truncate.DIR is allowed even when user denies external_directory globally", async () => {
+ const { Truncate } = await import("../../src/tool/truncation")
+ await using tmp = await tmpdir({
+ config: {
+ permission: {
+ external_directory: "deny",
+ },
+ },
+ })
+ await Instance.provide({
+ directory: tmp.path,
+ fn: async () => {
+ const build = await Agent.get("build")
+ expect(PermissionNext.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("allow")
+ expect(PermissionNext.evaluate("external_directory", "/some/other/path", build!.permission).action).toBe("deny")
+ },
+ })
+})
+
+test("Truncate.DIR is allowed even when user denies external_directory per-agent", async () => {
+ const { Truncate } = await import("../../src/tool/truncation")
+ await using tmp = await tmpdir({
+ config: {
+ agent: {
+ build: {
+ permission: {
+ external_directory: "deny",
+ },
+ },
+ },
+ },
+ })
+ await Instance.provide({
+ directory: tmp.path,
+ fn: async () => {
+ const build = await Agent.get("build")
+ expect(PermissionNext.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("allow")
+ expect(PermissionNext.evaluate("external_directory", "/some/other/path", build!.permission).action).toBe("deny")
+ },
+ })
+})
+
+test("explicit Truncate.DIR deny is respected", async () => {
+ const { Truncate } = await import("../../src/tool/truncation")
+ await using tmp = await tmpdir({
+ config: {
+ permission: {
+ external_directory: {
+ "*": "deny",
+ [Truncate.DIR]: "deny",
+ },
+ },
+ },
+ })
+ await Instance.provide({
+ directory: tmp.path,
+ fn: async () => {
+ const build = await Agent.get("build")
+ expect(PermissionNext.evaluate("external_directory", Truncate.DIR, build!.permission).action).toBe("deny")
+ },
+ })
+})