diff --git a/src/agents/sandbox/fs-paths.test.ts b/src/agents/sandbox/fs-paths.test.ts index a796df22a74..40d59395f01 100644 --- a/src/agents/sandbox/fs-paths.test.ts +++ b/src/agents/sandbox/fs-paths.test.ts @@ -1,12 +1,12 @@ import path from "node:path"; import { describe, expect, it } from "vitest"; +import type { SandboxContext } from "./types.js"; import { buildSandboxFsMounts, parseSandboxBindMount, resolveSandboxFsPathWithMounts, } from "./fs-paths.js"; import { createSandboxTestContext } from "./test-fixtures.js"; -import type { SandboxContext } from "./types.js"; function createSandbox(overrides?: Partial): SandboxContext { return createSandboxTestContext({ overrides }); @@ -38,6 +38,14 @@ describe("parseSandboxBindMount", () => { writable: true, }); }); + + it("parses UNC-style host paths", () => { + expect(parseSandboxBindMount("//server/share:/workspace:ro")).toEqual({ + hostRoot: path.resolve("//server/share"), + containerRoot: "/workspace", + writable: false, + }); + }); }); describe("resolveSandboxFsPathWithMounts", () => { diff --git a/src/agents/sandbox/fs-paths.ts b/src/agents/sandbox/fs-paths.ts index ce0f0932079..446d5266843 100644 --- a/src/agents/sandbox/fs-paths.ts +++ b/src/agents/sandbox/fs-paths.ts @@ -1,7 +1,7 @@ import path from "node:path"; +import type { SandboxContext } from "./types.js"; import { resolveSandboxInputPath, resolveSandboxPath } from "../sandbox-paths.js"; import { SANDBOX_AGENT_WORKSPACE_MOUNT } from "./constants.js"; -import type { SandboxContext } from "./types.js"; export type SandboxFsMount = { hostRoot: string; @@ -61,36 +61,34 @@ export function parseSandboxBindMount(spec: string): ParsedBindMount | null { } function splitBindSpec(spec: string): SplitBindSpec | null { - // Windows drive-letter host path: C:\\path:/container[:opts] or C:/path:/container[:opts] - if (/^[A-Za-z]:[\\/]/.test(spec)) { - const hostEnd = spec.indexOf(":", 2); - if (hostEnd === -1) { - return null; - } - const host = spec.slice(0, hostEnd); - const rest = spec.slice(hostEnd + 1); - const optionsStart = rest.indexOf(":"); - if (optionsStart === -1) { - return { host, container: rest, options: "" }; - } - return { - host, - container: rest.slice(0, optionsStart), - options: rest.slice(optionsStart + 1), - }; - } - - const parts = spec.split(":"); - if (parts.length < 2) { + const separator = getHostContainerSeparatorIndex(spec); + if (separator === -1) { return null; } + + const host = spec.slice(0, separator); + const rest = spec.slice(separator + 1); + const optionsStart = rest.indexOf(":"); + if (optionsStart === -1) { + return { host, container: rest, options: "" }; + } return { - host: parts[0] ?? "", - container: parts[1] ?? "", - options: parts.slice(2).join(":"), + host, + container: rest.slice(0, optionsStart), + options: rest.slice(optionsStart + 1), }; } +function getHostContainerSeparatorIndex(spec: string): number { + const hasDriveLetterPrefix = /^[A-Za-z]:[\\/]/.test(spec); + for (let i = hasDriveLetterPrefix ? 2 : 0; i < spec.length; i += 1) { + if (spec[i] === ":") { + return i; + } + } + return -1; +} + export function buildSandboxFsMounts(sandbox: SandboxContext): SandboxFsMount[] { const mounts: SandboxFsMount[] = [ {