fix(agent): isolate conversation workspaces
This commit is contained in:
@@ -129,4 +129,42 @@ describe("permission approval policy", () => {
|
||||
title: "已按始终允许模式放行",
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
"rm -rf ./target",
|
||||
"rm -rf ./target",
|
||||
"rm -Rf ./target",
|
||||
"/bin/rm -rf ./target",
|
||||
"command rm --force --recursive ./target",
|
||||
"env LANG=C rm -r -f ./target",
|
||||
"SAFE=1 rm -rf ./target",
|
||||
"env -u HOME rm -rf ./target",
|
||||
"r\"\"m -rf ./target",
|
||||
"(rm -rf ./target)",
|
||||
"! rm -rf ./target",
|
||||
"npm test && rm --recursive --force ./target",
|
||||
])("rejects direct recursive force removal in always mode: %s", (command) => {
|
||||
expect(
|
||||
resolvePermissionApproval("always", "bash", {
|
||||
metadata: { command },
|
||||
patterns: [command],
|
||||
}),
|
||||
).toMatchObject({
|
||||
autoApprove: false,
|
||||
autoReject: true,
|
||||
title: "已拒绝递归强制删除",
|
||||
});
|
||||
});
|
||||
|
||||
it.each(["rm tmp.txt", "rm -f tmp.txt", "rm -r tmp-dir", "echo 'rm -rf tmp'"])(
|
||||
"keeps non-recursive or non-executed removal text available for confirmation: %s",
|
||||
(command) => {
|
||||
expect(
|
||||
resolvePermissionApproval("always", "bash", {
|
||||
metadata: { command },
|
||||
patterns: [command],
|
||||
}),
|
||||
).toMatchObject({ autoApprove: false, autoReject: false });
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -435,6 +435,54 @@ describe("streamPromptResponse", () => {
|
||||
expect(events.some((item) => item.event === "permission_request")).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects recursive force removal even in always mode", async () => {
|
||||
const replies: Array<Record<string, unknown>> = [];
|
||||
const runtime = {
|
||||
subscribeEvents: async () =>
|
||||
createEventStream([
|
||||
{
|
||||
type: "permission.asked",
|
||||
properties: {
|
||||
id: "perm-always-rm-rf",
|
||||
sessionID: "runtime-session-1",
|
||||
permission: "bash",
|
||||
patterns: ["/bin/rm -rf ./target"],
|
||||
metadata: { command: "/bin/rm -rf ./target" },
|
||||
always: ["/bin/rm -rf ./target"],
|
||||
},
|
||||
},
|
||||
{ type: "session.idle", properties: { sessionID: "runtime-session-1" } },
|
||||
]),
|
||||
prompt: async () => undefined,
|
||||
messages: async () => [],
|
||||
replyPermission: async (options: Record<string, unknown>) => replies.push(options),
|
||||
} as unknown as OpencodeRuntimeAdapter;
|
||||
const events: Array<{ event: string; data: Record<string, unknown> }> = [];
|
||||
|
||||
await streamPromptResponse({
|
||||
runtime,
|
||||
sessionId: "runtime-session-1",
|
||||
clientSessionId: "client-session-1",
|
||||
message: "delete recursively",
|
||||
approvalMode: "always",
|
||||
write: (event, data) => events.push({ event, data }),
|
||||
});
|
||||
|
||||
expect(replies).toEqual([
|
||||
{
|
||||
requestId: "perm-always-rm-rf",
|
||||
sessionId: "runtime-session-1",
|
||||
reply: "reject",
|
||||
},
|
||||
]);
|
||||
expect(events.some((item) => item.event === "permission_request")).toBe(false);
|
||||
expect(events.find((item) => item.event === "permission_response")?.data).toEqual({
|
||||
session_id: "client-session-1",
|
||||
request_id: "perm-always-rm-rf",
|
||||
reply: "reject",
|
||||
});
|
||||
});
|
||||
|
||||
it("forwards opencode v2 permission requests as SSE payloads", async () => {
|
||||
const runtime = {
|
||||
subscribeEvents: async () =>
|
||||
|
||||
Reference in New Issue
Block a user