fix(sandbox): parse Windows bind mounts in fs-path mapping

This commit is contained in:
Rain
2026-02-16 18:21:56 +08:00
committed by Peter Steinberger
parent 3f617e33b7
commit dacffd7ac8
2 changed files with 57 additions and 5 deletions

View File

@@ -25,6 +25,19 @@ describe("parseSandboxBindMount", () => {
writable: true,
});
});
it("parses Windows drive-letter host paths", () => {
expect(parseSandboxBindMount("C:\\Users\\kai\\workspace:/workspace:ro")).toEqual({
hostRoot: path.resolve("C:\\Users\\kai\\workspace"),
containerRoot: "/workspace",
writable: false,
});
expect(parseSandboxBindMount("D:/data:/workspace-data:rw")).toEqual({
hostRoot: path.resolve("D:/data"),
containerRoot: "/workspace-data",
writable: true,
});
});
});
describe("resolveSandboxFsPathWithMounts", () => {

View File

@@ -23,21 +23,29 @@ type ParsedBindMount = {
writable: boolean;
};
type SplitBindSpec = {
host: string;
container: string;
options: string;
};
export function parseSandboxBindMount(spec: string): ParsedBindMount | null {
const trimmed = spec.trim();
if (!trimmed) {
return null;
}
const parts = trimmed.split(":");
if (parts.length < 2) {
const parsed = splitBindSpec(trimmed);
if (!parsed) {
return null;
}
const hostToken = (parts[0] ?? "").trim();
const containerToken = (parts[1] ?? "").trim();
const hostToken = parsed.host.trim();
const containerToken = parsed.container.trim();
if (!hostToken || !containerToken || !path.posix.isAbsolute(containerToken)) {
return null;
}
const optionsToken = parts.slice(2).join(":").trim().toLowerCase();
const optionsToken = parsed.options.trim().toLowerCase();
const optionParts = optionsToken
? optionsToken
.split(",")
@@ -52,6 +60,37 @@ 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) {
return null;
}
return {
host: parts[0] ?? "",
container: parts[1] ?? "",
options: parts.slice(2).join(":"),
};
}
export function buildSandboxFsMounts(sandbox: SandboxContext): SandboxFsMount[] {
const mounts: SandboxFsMount[] = [
{