mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-13 11:39:41 +03:00
107 lines
3.9 KiB
TypeScript
107 lines
3.9 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|
import path from "node:path"
|
|
import type { Permission } from "@opencode/schema/permission"
|
|
import { makeSession, rpcError, startWire, type Wire } from "./wire-fixture"
|
|
|
|
const key = "opencode.acp.additionalDirectories"
|
|
|
|
const grant = (directory: string): Permission.Rule => ({
|
|
action: "external_directory",
|
|
resource: path.join(directory, "*"),
|
|
effect: "allow",
|
|
})
|
|
|
|
const sharedLib = path.resolve("/shared/lib")
|
|
const productDocs = path.resolve("/product-docs")
|
|
const old = path.resolve("/old")
|
|
|
|
const userGrant: Permission.Rule = { action: "external_directory", resource: "/x/**", effect: "allow" }
|
|
|
|
const other: Permission.Rule[] = [
|
|
{ action: "read", resource: "*.secret", effect: "deny" },
|
|
{ action: "external_directory", resource: "/shared/lib/private/*", effect: "deny" },
|
|
]
|
|
|
|
const updates = (acp: Wire) =>
|
|
acp.server.requests.filter((request) => request.method === "PATCH" && request.path.startsWith("/api/session/"))
|
|
|
|
describe("acp additional directories over the wire", () => {
|
|
test.each(["shared/lib", "", "/shared/*", "/shared/lib?"])(
|
|
"rejects %p before creating a session",
|
|
async (directory) => {
|
|
await using acp = await startWire()
|
|
await acp.initialize()
|
|
|
|
expect(
|
|
await rpcError(
|
|
acp.request("session/new", {
|
|
cwd: "/workspace",
|
|
additionalDirectories: ["/shared/ok", directory],
|
|
mcpServers: [],
|
|
}),
|
|
),
|
|
).toMatchObject({ code: -32602, data: { additionalDirectory: directory } })
|
|
expect(acp.server.sessions.size).toBe(0)
|
|
},
|
|
)
|
|
|
|
test("load and resume replace ACP grants and keep other session rules and metadata", async () => {
|
|
await using acp = await startWire()
|
|
acp.server.sessions.set("ses_saved", {
|
|
...makeSession("ses_saved"),
|
|
metadata: { host: "tui", [key]: [old] },
|
|
permissions: [grant(old), userGrant, ...other],
|
|
})
|
|
await acp.initialize()
|
|
|
|
await acp.request("session/load", {
|
|
cwd: "/workspace",
|
|
sessionId: "ses_saved",
|
|
additionalDirectories: ["/shared/lib", "/product-docs"],
|
|
mcpServers: [],
|
|
})
|
|
expect(acp.server.sessions.get("ses_saved")).toMatchObject({
|
|
metadata: { host: "tui", [key]: [sharedLib, productDocs] },
|
|
permissions: [grant(sharedLib), grant(productDocs), userGrant, ...other],
|
|
})
|
|
|
|
await acp.request("session/resume", {
|
|
cwd: "/workspace",
|
|
sessionId: "ses_saved",
|
|
additionalDirectories: ["/shared/lib", "/product-docs"],
|
|
})
|
|
expect(updates(acp)).toHaveLength(1)
|
|
|
|
await acp.request("session/resume", { cwd: "/workspace", sessionId: "ses_saved" })
|
|
expect(acp.server.sessions.get("ses_saved")?.metadata).toEqual({ host: "tui" })
|
|
expect(acp.server.sessions.get("ses_saved")?.permissions).toEqual([userGrant, ...other])
|
|
expect((await acp.request("session/list", { cwd: "/workspace" })).sessions[0]).not.toHaveProperty(
|
|
"additionalDirectories",
|
|
)
|
|
})
|
|
|
|
test("forks replace inherited grants with the requested list", async () => {
|
|
await using acp = await startWire()
|
|
acp.server.sessions.set("ses_source", {
|
|
...makeSession("ses_source"),
|
|
metadata: { [key]: [old] },
|
|
permissions: [grant(old), ...other],
|
|
})
|
|
await acp.initialize()
|
|
|
|
const plain = await acp.request("session/fork", { cwd: "/workspace", sessionId: "ses_source" })
|
|
const granted = await acp.request("session/fork", {
|
|
cwd: "/workspace",
|
|
sessionId: "ses_source",
|
|
additionalDirectories: ["/shared/lib"],
|
|
})
|
|
|
|
expect(acp.server.sessions.get(plain.sessionId)).toMatchObject({ metadata: {}, permissions: other })
|
|
expect(acp.server.sessions.get(granted.sessionId)).toMatchObject({
|
|
metadata: { [key]: [sharedLib] },
|
|
permissions: [grant(sharedLib), ...other],
|
|
})
|
|
expect(acp.server.sessions.get("ses_source")?.permissions).toEqual([grant(old), ...other])
|
|
})
|
|
})
|