diff --git a/loopx/control_plane/work_items/task_lease_workspace.ts b/loopx/control_plane/work_items/task_lease_workspace.ts index bf7114f257..3c6778dafe 100644 --- a/loopx/control_plane/work_items/task_lease_workspace.ts +++ b/loopx/control_plane/work_items/task_lease_workspace.ts @@ -5,6 +5,7 @@ import {realpath, stat, readFile, lstat, opendir} from "node:fs/promises"; import {platform} from "node:os"; import {createHash} from "node:crypto"; import {isAbsolute, resolve} from "node:path"; +import {BARE_SHA256_PATTERN} from "../content_digest.ts"; import type {JsonObject} from "../effect_program.ts"; import {EffectRuntimeRequestError} from "../effect_runtime_errors.ts"; import {requireJsonObject} from "../runtime_decode.ts"; @@ -23,7 +24,7 @@ export function leaseWorkspace(value: unknown): LeaseWorkspace | null { if (value == null) return null; const row = requireJsonObject(value, "lease worktree identity"); if (Object.keys(row).sort().join(",") !== "common_directory,host,repository,worktree" || - [row.host, row.common_directory, row.worktree].some(v => typeof v !== "string" || !/^[a-f0-9]{64}$/u.test(v))) { + [row.host, row.common_directory, row.worktree].some(v => typeof v !== "string" || !BARE_SHA256_PATTERN.test(v))) { throw new EffectRuntimeRequestError("invalid lease worktree identity"); } const repository = leaseWriteRepository(row.repository); diff --git a/tests/control_plane_ts/content_digest_single_owner.test.ts b/tests/control_plane_ts/content_digest_single_owner.test.ts index 47b3c0d4c0..e46d52ab2b 100644 --- a/tests/control_plane_ts/content_digest_single_owner.test.ts +++ b/tests/control_plane_ts/content_digest_single_owner.test.ts @@ -126,6 +126,7 @@ const CANONICAL_CONSUMERS = [ "control_plane/work_items/task_lease_acquire.ts", "control_plane/work_items/task_lease_lifecycle.ts", "control_plane/work_items/task_lease_lifecycle_request.ts", + "control_plane/work_items/task_lease_workspace.ts", ]; function packageFiles(dir: string, base = ""): string[] {