121 lines
3.3 KiB
TypeScript
121 lines
3.3 KiB
TypeScript
import { PATH_ALIAS_POLICIES } from "../../infra/path-alias-guards.js";
|
|
import type { AnchoredSandboxEntry, PathSafetyCheck } from "./fs-bridge-path-safety.js";
|
|
import type { SandboxResolvedFsPath } from "./fs-paths.js";
|
|
|
|
export type SandboxFsCommandPlan = {
|
|
checks: PathSafetyCheck[];
|
|
script: string;
|
|
args?: string[];
|
|
recheckBeforeCommand?: boolean;
|
|
allowFailure?: boolean;
|
|
};
|
|
|
|
export function buildReadFilePlan(target: SandboxResolvedFsPath): SandboxFsCommandPlan {
|
|
return {
|
|
checks: [{ target, options: { action: "read files" } }],
|
|
script: 'set -eu; cat -- "$1"',
|
|
args: [target.containerPath],
|
|
};
|
|
}
|
|
|
|
export function buildWriteCommitPlan(
|
|
target: SandboxResolvedFsPath,
|
|
tempPath: string,
|
|
): SandboxFsCommandPlan {
|
|
return {
|
|
checks: [{ target, options: { action: "write files", requireWritable: true } }],
|
|
recheckBeforeCommand: true,
|
|
script: 'set -eu; mv -f -- "$1" "$2"',
|
|
args: [tempPath, target.containerPath],
|
|
};
|
|
}
|
|
|
|
export function buildMkdirpPlan(
|
|
target: SandboxResolvedFsPath,
|
|
anchoredTarget: AnchoredSandboxEntry,
|
|
): SandboxFsCommandPlan {
|
|
return {
|
|
checks: [
|
|
{
|
|
target,
|
|
options: {
|
|
action: "create directories",
|
|
requireWritable: true,
|
|
allowedType: "directory",
|
|
},
|
|
},
|
|
],
|
|
script: 'set -eu\ncd -- "$1"\nmkdir -p -- "$2"',
|
|
args: [anchoredTarget.canonicalParentPath, anchoredTarget.basename],
|
|
};
|
|
}
|
|
|
|
export function buildRemovePlan(params: {
|
|
target: SandboxResolvedFsPath;
|
|
anchoredTarget: AnchoredSandboxEntry;
|
|
recursive?: boolean;
|
|
force?: boolean;
|
|
}): SandboxFsCommandPlan {
|
|
const flags = [params.force === false ? "" : "-f", params.recursive ? "-r" : ""].filter(Boolean);
|
|
const rmCommand = flags.length > 0 ? `rm ${flags.join(" ")}` : "rm";
|
|
return {
|
|
checks: [
|
|
{
|
|
target: params.target,
|
|
options: {
|
|
action: "remove files",
|
|
requireWritable: true,
|
|
aliasPolicy: PATH_ALIAS_POLICIES.unlinkTarget,
|
|
},
|
|
},
|
|
],
|
|
recheckBeforeCommand: true,
|
|
script: `set -eu\ncd -- "$1"\n${rmCommand} -- "$2"`,
|
|
args: [params.anchoredTarget.canonicalParentPath, params.anchoredTarget.basename],
|
|
};
|
|
}
|
|
|
|
export function buildRenamePlan(params: {
|
|
from: SandboxResolvedFsPath;
|
|
to: SandboxResolvedFsPath;
|
|
anchoredFrom: AnchoredSandboxEntry;
|
|
anchoredTo: AnchoredSandboxEntry;
|
|
}): SandboxFsCommandPlan {
|
|
return {
|
|
checks: [
|
|
{
|
|
target: params.from,
|
|
options: {
|
|
action: "rename files",
|
|
requireWritable: true,
|
|
aliasPolicy: PATH_ALIAS_POLICIES.unlinkTarget,
|
|
},
|
|
},
|
|
{
|
|
target: params.to,
|
|
options: {
|
|
action: "rename files",
|
|
requireWritable: true,
|
|
},
|
|
},
|
|
],
|
|
recheckBeforeCommand: true,
|
|
script: ["set -eu", 'mkdir -p -- "$2"', 'cd -- "$1"', 'mv -- "$3" "$2/$4"'].join("\n"),
|
|
args: [
|
|
params.anchoredFrom.canonicalParentPath,
|
|
params.anchoredTo.canonicalParentPath,
|
|
params.anchoredFrom.basename,
|
|
params.anchoredTo.basename,
|
|
],
|
|
};
|
|
}
|
|
|
|
export function buildStatPlan(target: SandboxResolvedFsPath): SandboxFsCommandPlan {
|
|
return {
|
|
checks: [{ target, options: { action: "stat files" } }],
|
|
script: 'set -eu; stat -c "%F|%s|%Y" -- "$1"',
|
|
args: [target.containerPath],
|
|
allowFailure: true,
|
|
};
|
|
}
|