












@@ -1,6 +1,23 @@
1-import { describe, expect, it } from "vitest";
1+import fs from "node:fs";
2+import os from "node:os";
3+import path from "node:path";
4+import { afterEach, describe, expect, it } from "vitest";
25import { appendWorkspaceMountArgs } from "./workspace-mounts.js";
367+const tmpDirs: string[] = [];
8+9+function makeTempWorkspace(): string {
10+const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-sandbox-mounts-"));
11+tmpDirs.push(dir);
12+return dir;
13+}
14+15+afterEach(() => {
16+for (const dir of tmpDirs.splice(0)) {
17+fs.rmSync(dir, { recursive: true, force: true });
18+}
19+});
20+421describe("appendWorkspaceMountArgs", () => {
522it.each([
623{ access: "rw" as const, expected: "/tmp/workspace:/workspace:z" },
@@ -60,4 +77,102 @@ describe("appendWorkspaceMountArgs", () => {
6077const mounts = args.filter((arg) => arg.startsWith("/tmp/"));
6178expect(mounts).toEqual(["/tmp/workspace:/workspace:ro,z", "/tmp/agent-workspace:/agent:ro,z"]);
6279});
80+81+it("overlays workspace skills read-only when workspaceAccess is rw", () => {
82+const agentWorkspaceDir = makeTempWorkspace();
83+fs.mkdirSync(path.join(agentWorkspaceDir, "skills", "demo"), { recursive: true });
84+fs.writeFileSync(path.join(agentWorkspaceDir, "skills", "demo", "SKILL.md"), "# Demo\n");
85+86+const args: string[] = [];
87+appendWorkspaceMountArgs({
88+ args,
89+workspaceDir: agentWorkspaceDir,
90+ agentWorkspaceDir,
91+workdir: "/workspace",
92+workspaceAccess: "rw",
93+});
94+95+const mounts = args.filter((arg) => arg.startsWith(agentWorkspaceDir));
96+expect(mounts).toEqual([
97+`${agentWorkspaceDir}:/workspace:z`,
98+`${path.join(agentWorkspaceDir, "skills")}:/workspace/skills:ro,z`,
99+]);
100+});
101+102+it("overlays project .agents skills read-only when workspaceAccess is rw", () => {
103+const agentWorkspaceDir = makeTempWorkspace();
104+fs.mkdirSync(path.join(agentWorkspaceDir, ".agents", "skills", "demo"), {
105+recursive: true,
106+});
107+fs.writeFileSync(
108+path.join(agentWorkspaceDir, ".agents", "skills", "demo", "SKILL.md"),
109+"# Demo\n",
110+);
111+112+const args: string[] = [];
113+appendWorkspaceMountArgs({
114+ args,
115+workspaceDir: agentWorkspaceDir,
116+ agentWorkspaceDir,
117+workdir: "/workspace",
118+workspaceAccess: "rw",
119+});
120+121+const mounts = args.filter((arg) => arg.startsWith(agentWorkspaceDir));
122+expect(mounts).toEqual([
123+`${agentWorkspaceDir}:/workspace:z`,
124+`${path.join(agentWorkspaceDir, ".agents", "skills")}:/workspace/.agents/skills:ro,z`,
125+]);
126+});
127+128+it("does not add a separate synced skill overlay when workspaceAccess is ro", () => {
129+const agentWorkspaceDir = makeTempWorkspace();
130+const sandboxWorkspaceDir = makeTempWorkspace();
131+fs.mkdirSync(path.join(sandboxWorkspaceDir, "skills", "demo"), { recursive: true });
132+133+const args: string[] = [];
134+appendWorkspaceMountArgs({
135+ args,
136+workspaceDir: sandboxWorkspaceDir,
137+ agentWorkspaceDir,
138+workdir: "/workspace",
139+workspaceAccess: "ro",
140+});
141+142+const mounts = args.filter(
143+(arg) => arg.startsWith(agentWorkspaceDir) || arg.startsWith(sandboxWorkspaceDir),
144+);
145+146+expect(mounts).toEqual([
147+`${sandboxWorkspaceDir}:/workspace:ro,z`,
148+`${agentWorkspaceDir}:/agent:ro,z`,
149+]);
150+expect(mounts).not.toContain(
151+`${path.join(sandboxWorkspaceDir, "skills")}:/workspace/skills:ro,z`,
152+);
153+});
154+155+it("does not add a separate synced skill overlay when workspaceAccess is none", () => {
156+const agentWorkspaceDir = makeTempWorkspace();
157+const sandboxWorkspaceDir = makeTempWorkspace();
158+fs.mkdirSync(path.join(sandboxWorkspaceDir, "skills", "demo"), { recursive: true });
159+160+const args: string[] = [];
161+appendWorkspaceMountArgs({
162+ args,
163+workspaceDir: sandboxWorkspaceDir,
164+ agentWorkspaceDir,
165+workdir: "/workspace",
166+workspaceAccess: "none",
167+});
168+169+const mounts = args.filter(
170+(arg) => arg.startsWith(agentWorkspaceDir) || arg.startsWith(sandboxWorkspaceDir),
171+);
172+173+expect(mounts).toEqual([`${sandboxWorkspaceDir}:/workspace:ro,z`]);
174+expect(mounts).not.toContain(
175+`${path.join(sandboxWorkspaceDir, "skills")}:/workspace/skills:ro,z`,
176+);
177+});
63178});
此內容由慣性聚合(RSS閱讀器)自動聚合整理,僅供閱讀參考。 原文來自 — 版權歸原作者所有。