Skip to content

Commit 664e6bf

Browse files
committed
test: add more tests to make sure that cwd is locked for read tool
1 parent 160c8ab commit 664e6bf

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

packages/opencode/test/tool/read.test.ts

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,137 @@ const ctx = {
1313
metadata: () => {},
1414
}
1515

16+
describe("tool.read external_directory permission", () => {
17+
test("allows reading absolute path inside project directory", async () => {
18+
await using tmp = await tmpdir({
19+
init: async (dir) => {
20+
await Bun.write(path.join(dir, "test.txt"), "hello world")
21+
await Bun.write(
22+
path.join(dir, "opencode.json"),
23+
JSON.stringify({
24+
permission: {
25+
external_directory: "deny",
26+
},
27+
}),
28+
)
29+
},
30+
})
31+
await Instance.provide({
32+
directory: tmp.path,
33+
fn: async () => {
34+
const read = await ReadTool.init()
35+
const result = await read.execute({ filePath: path.join(tmp.path, "test.txt") }, ctx)
36+
expect(result.output).toContain("hello world")
37+
},
38+
})
39+
})
40+
41+
test("allows reading file in subdirectory inside project directory", async () => {
42+
await using tmp = await tmpdir({
43+
init: async (dir) => {
44+
await Bun.write(path.join(dir, "subdir", "test.txt"), "nested content")
45+
await Bun.write(
46+
path.join(dir, "opencode.json"),
47+
JSON.stringify({
48+
permission: {
49+
external_directory: "deny",
50+
},
51+
}),
52+
)
53+
},
54+
})
55+
await Instance.provide({
56+
directory: tmp.path,
57+
fn: async () => {
58+
const read = await ReadTool.init()
59+
const result = await read.execute({ filePath: path.join(tmp.path, "subdir", "test.txt") }, ctx)
60+
expect(result.output).toContain("nested content")
61+
},
62+
})
63+
})
64+
65+
test("denies reading absolute path outside project directory", async () => {
66+
await using outerTmp = await tmpdir({
67+
init: async (dir) => {
68+
await Bun.write(path.join(dir, "secret.txt"), "secret data")
69+
},
70+
})
71+
await using tmp = await tmpdir({
72+
init: async (dir) => {
73+
await Bun.write(
74+
path.join(dir, "opencode.json"),
75+
JSON.stringify({
76+
permission: {
77+
external_directory: "deny",
78+
},
79+
}),
80+
)
81+
},
82+
})
83+
await Instance.provide({
84+
directory: tmp.path,
85+
fn: async () => {
86+
const read = await ReadTool.init()
87+
await expect(read.execute({ filePath: path.join(outerTmp.path, "secret.txt") }, ctx)).rejects.toThrow(
88+
"not in the current working directory",
89+
)
90+
},
91+
})
92+
})
93+
94+
test("denies reading relative path that traverses outside project directory", async () => {
95+
await using tmp = await tmpdir({
96+
init: async (dir) => {
97+
await Bun.write(
98+
path.join(dir, "opencode.json"),
99+
JSON.stringify({
100+
permission: {
101+
external_directory: "deny",
102+
},
103+
}),
104+
)
105+
},
106+
})
107+
await Instance.provide({
108+
directory: tmp.path,
109+
fn: async () => {
110+
const read = await ReadTool.init()
111+
await expect(read.execute({ filePath: "../../../etc/passwd" }, ctx)).rejects.toThrow(
112+
"not in the current working directory",
113+
)
114+
},
115+
})
116+
})
117+
118+
test("allows reading outside project directory when external_directory is allow", async () => {
119+
await using outerTmp = await tmpdir({
120+
init: async (dir) => {
121+
await Bun.write(path.join(dir, "external.txt"), "external content")
122+
},
123+
})
124+
await using tmp = await tmpdir({
125+
init: async (dir) => {
126+
await Bun.write(
127+
path.join(dir, "opencode.json"),
128+
JSON.stringify({
129+
permission: {
130+
external_directory: "allow",
131+
},
132+
}),
133+
)
134+
},
135+
})
136+
await Instance.provide({
137+
directory: tmp.path,
138+
fn: async () => {
139+
const read = await ReadTool.init()
140+
const result = await read.execute({ filePath: path.join(outerTmp.path, "external.txt") }, ctx)
141+
expect(result.output).toContain("external content")
142+
},
143+
})
144+
})
145+
})
146+
16147
describe("tool.read env file blocking", () => {
17148
test.each([
18149
[".env", true],

0 commit comments

Comments
 (0)