diff --git a/src/agents/sandbox/shared.test.ts b/src/agents/sandbox/shared.test.ts new file mode 100644 index 00000000000..a6d88336f4c --- /dev/null +++ b/src/agents/sandbox/shared.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from "vitest"; +import { slugifySessionKey } from "./shared.js"; + +describe("slugifySessionKey", () => { + it("produces stable SHA-1 based slugs for existing workspace directories", () => { + // Hash stability is critical: changing the hash algorithm orphans existing + // sandbox workspace directories on upgrade (see #18503). + const slug = slugifySessionKey("agent:clawfront-dev:direct:23057054725"); + expect(slug).toBe("agent-clawfront-dev-direct-23057-906dfaef"); + }); + + it("uses fallback for empty input", () => { + const slug = slugifySessionKey(""); + expect(slug).toContain("session-"); + }); + + it("uses fallback for whitespace-only input", () => { + const slug = slugifySessionKey(" "); + expect(slug).toContain("session-"); + }); + + it("truncates base to 32 chars", () => { + const long = "a".repeat(100); + const slug = slugifySessionKey(long); + // 32 char base + "-" + 8 char hash = 41 chars + expect(slug.length).toBe(41); + }); +}); diff --git a/src/agents/sandbox/shared.ts b/src/agents/sandbox/shared.ts index cb3585aad77..a131031c42a 100644 --- a/src/agents/sandbox/shared.ts +++ b/src/agents/sandbox/shared.ts @@ -1,12 +1,14 @@ +import crypto from "node:crypto"; import path from "node:path"; import { normalizeAgentId } from "../../routing/session-key.js"; import { resolveUserPath } from "../../utils.js"; import { resolveAgentIdFromSessionKey } from "../agent-scope.js"; -import { hashTextSha256 } from "./hash.js"; export function slugifySessionKey(value: string) { const trimmed = value.trim() || "session"; - const hash = hashTextSha256(trimmed).slice(0, 8); + // SHA-1 is intentional: this is a non-security slug differentiator and changing + // the algorithm orphans existing workspace directories on upgrade (#18503). + const hash = crypto.createHash("sha1").update(trimmed).digest("hex").slice(0, 8); const safe = trimmed .toLowerCase() .replace(/[^a-z0-9._-]+/g, "-")