




















@@ -152,6 +152,7 @@ export async function applyPatch(
152152153153if (hunk.kind === "add") {
154154const target = await resolvePatchPath(hunk.path, options);
155+await assertPatchParentPath(hunk.path, options);
155156await ensureDir(target.resolved, fileOps);
156157await fileOps.writeFile(target.resolved, hunk.contents);
157158recordSummary(summary, seen, "added", target.display);
@@ -172,6 +173,7 @@ export async function applyPatch(
172173173174if (hunk.movePath) {
174175const moveTarget = await resolvePatchPath(hunk.movePath, options);
176+await assertPatchParentPath(hunk.movePath, options);
175177await ensureDir(moveTarget.resolved, fileOps);
176178await fileOps.writeFile(moveTarget.resolved, applied);
177179await fileOps.remove(target.resolved);
@@ -301,6 +303,54 @@ async function ensureDir(filePath: string, ops: PatchFileOps) {
301303await ops.mkdirp(parent);
302304}
303305306+async function assertPatchParentPath(filePath: string, options: ApplyPatchOptions) {
307+if (options.workspaceOnly === false || options.sandbox) {
308+return;
309+}
310+const parent = path.dirname(filePath);
311+if (!parent || parent === ".") {
312+return;
313+}
314+await assertSandboxPath({
315+filePath: parent,
316+cwd: options.cwd,
317+root: options.cwd,
318+});
319+await assertNoExistingParentAliases({
320+parentPath: resolvePathFromInput(parent, options.cwd),
321+rootPath: options.cwd,
322+});
323+}
324+325+async function assertNoExistingParentAliases(params: { parentPath: string; rootPath: string }) {
326+const rootPath = path.resolve(params.rootPath);
327+const parentPath = path.resolve(params.parentPath);
328+const relative = path.relative(rootPath, parentPath);
329+if (!relative || relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) {
330+return;
331+}
332+333+let current = rootPath;
334+for (const segment of relative.split(path.sep)) {
335+if (!segment) {
336+continue;
337+}
338+current = path.join(current, segment);
339+const stat = await fs.lstat(current).catch((error: unknown) => {
340+if ((error as NodeJS.ErrnoException).code === "ENOENT") {
341+return null;
342+}
343+throw error;
344+});
345+if (!stat) {
346+return;
347+}
348+if (stat.isSymbolicLink()) {
349+throw new Error(`Path alias under sandbox root: ${path.relative(rootPath, current)}`);
350+}
351+}
352+}
353+304354async function resolvePatchPath(
305355filePath: string,
306356options: ApplyPatchOptions,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。