fix: check worktree for external_directory permission in subdirs (#7811)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { test, expect, describe } from "bun:test"
|
||||
import path from "path"
|
||||
import fs from "fs/promises"
|
||||
import { Filesystem } from "../../src/util/filesystem"
|
||||
import { File } from "../../src/file"
|
||||
import { Instance } from "../../src/project/instance"
|
||||
@@ -113,3 +114,85 @@ describe("File.list path traversal protection", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("Instance.containsPath", () => {
|
||||
test("returns true for path inside directory", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: () => {
|
||||
expect(Instance.containsPath(path.join(tmp.path, "foo.txt"))).toBe(true)
|
||||
expect(Instance.containsPath(path.join(tmp.path, "src", "file.ts"))).toBe(true)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("returns true for path inside worktree but outside directory (monorepo subdirectory scenario)", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
const subdir = path.join(tmp.path, "packages", "lib")
|
||||
await fs.mkdir(subdir, { recursive: true })
|
||||
|
||||
await Instance.provide({
|
||||
directory: subdir,
|
||||
fn: () => {
|
||||
// .opencode at worktree root, but we're running from packages/lib
|
||||
expect(Instance.containsPath(path.join(tmp.path, ".opencode", "state"))).toBe(true)
|
||||
// sibling package should also be accessible
|
||||
expect(Instance.containsPath(path.join(tmp.path, "packages", "other", "file.ts"))).toBe(true)
|
||||
// worktree root itself
|
||||
expect(Instance.containsPath(tmp.path)).toBe(true)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("returns false for path outside both directory and worktree", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: () => {
|
||||
expect(Instance.containsPath("/etc/passwd")).toBe(false)
|
||||
expect(Instance.containsPath("/tmp/other-project")).toBe(false)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("returns false for path with .. escaping worktree", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: () => {
|
||||
expect(Instance.containsPath(path.join(tmp.path, "..", "escape.txt"))).toBe(false)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("handles directory === worktree (running from repo root)", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: () => {
|
||||
expect(Instance.directory).toBe(Instance.worktree)
|
||||
expect(Instance.containsPath(path.join(tmp.path, "file.txt"))).toBe(true)
|
||||
expect(Instance.containsPath("/etc/passwd")).toBe(false)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("non-git project does not allow arbitrary paths via worktree='/'", async () => {
|
||||
await using tmp = await tmpdir() // no git: true
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: () => {
|
||||
// worktree is "/" for non-git projects, but containsPath should NOT allow all paths
|
||||
expect(Instance.containsPath(path.join(tmp.path, "file.txt"))).toBe(true)
|
||||
expect(Instance.containsPath("/etc/passwd")).toBe(false)
|
||||
expect(Instance.containsPath("/tmp/other")).toBe(false)
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user