fix: keep agent sandbox sockets on short paths

This commit is contained in:
2026-07-11 02:22:19 +08:00
parent 38d9a9c6cb
commit 035c264179
7 changed files with 72 additions and 44 deletions
+16 -10
View File
@@ -46,7 +46,11 @@ describe("agent subprocess security policy", () => {
expect(policy.env).not.toHaveProperty("HUB_SESSION_SECRET");
expect(policy.env.HOME).toMatch(new RegExp(`^${escapeRegExp(canonicalWorkspace)}/`));
expect(policy.env.CLAUDE_CONFIG_DIR).toMatch(new RegExp(`^${escapeRegExp(canonicalWorkspace)}/`));
expect(policy.env.CLAUDE_CODE_TMPDIR).toBe(join(".cph", "t"));
expect(policy.env.CLAUDE_CODE_TMPDIR).toBe(policy.env.TMPDIR);
expect(policy.env.TMP).toBe(policy.env.TMPDIR);
expect(policy.env.TEMP).toBe(policy.env.TMPDIR);
expect(policy.env.TMPDIR).not.toMatch(new RegExp(`^${escapeRegExp(canonicalWorkspace)}/`));
expect(Buffer.byteLength(policy.env.TMPDIR!)).toBeLessThanOrEqual(64);
expect(policy.sandbox).toMatchObject({
enabled: true,
@@ -54,7 +58,7 @@ describe("agent subprocess security policy", () => {
autoAllowBashIfSandboxed: true,
allowUnsandboxedCommands: false,
filesystem: {
allowWrite: [canonicalWorkspace],
allowWrite: expect.arrayContaining([canonicalWorkspace, policy.env.TMPDIR]),
denyRead: ["/"],
allowRead: expect.arrayContaining([canonicalWorkspace, "/usr/bin"]),
},
@@ -81,7 +85,7 @@ describe("agent subprocess security policy", () => {
})).rejects.toThrow("unsupported provider environment variable: DATABASE_URL");
});
it("keeps the short SDK socket directory inside the project workspace", async () => {
it("keeps every SDK temp variable on a short isolated path outside a long project workspace", async () => {
const { workspaceRoot, workspace } = await makeWorkspace();
const policy = await createAgentSecurityPolicy({
workspaceRoot,
@@ -89,14 +93,16 @@ describe("agent subprocess security policy", () => {
hostEnv: { PATH: "/usr/bin:/bin" },
});
expect(policy.env.CLAUDE_CODE_TMPDIR).toBe(join(".cph", "t"));
const absoluteTemp = join(await realpath(workspace), ".cph", "t");
expect(policy.env.TMPDIR).toBe(absoluteTemp);
expect(policy.env.TMP).toBe(absoluteTemp);
expect(policy.env.TEMP).toBe(absoluteTemp);
expect(policy.sandbox.filesystem.allowWrite).toEqual([await realpath(workspace)]);
const canonicalWorkspace = await realpath(workspace);
const temp = policy.env.TMPDIR!;
expect(policy.env.CLAUDE_CODE_TMPDIR).toBe(temp);
expect(policy.env.TMP).toBe(temp);
expect(policy.env.TEMP).toBe(temp);
expect(temp).not.toMatch(new RegExp(`^${escapeRegExp(canonicalWorkspace)}/`));
expect(Buffer.byteLength(temp)).toBeLessThanOrEqual(64);
expect(policy.sandbox.filesystem.allowWrite).toEqual([canonicalWorkspace, temp]);
expect(policy.sandbox.filesystem.denyWrite).toEqual(["/"]);
expect(policy.sandbox.filesystem.allowRead).not.toContain(expect.stringMatching(/^\/run\//));
expect(policy.sandbox.filesystem.allowRead).toContain(temp);
});
it("rejects a project workspace whose real path escapes the configured workspace root", async () => {
+1 -1
View File
@@ -108,7 +108,7 @@ describe("runAgent", () => {
failIfUnavailable: true,
allowUnsandboxedCommands: false,
filesystem: expect.objectContaining({
allowWrite: [workspace],
allowWrite: expect.arrayContaining([workspace]),
denyRead: ["/"],
allowRead: expect.arrayContaining([workspace]),
}),