pi-better-background-tasks 0.2.17 → 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/shared-sandbox-core.ts +30 -7
package/package.json
CHANGED
|
@@ -79,6 +79,8 @@ export type SandboxCommandArgs = SandboxTarget & {
|
|
|
79
79
|
/** Where the macOS backend writes its generated SBPL profile. */
|
|
80
80
|
profilePath: string;
|
|
81
81
|
policy: SandboxWritePolicy;
|
|
82
|
+
/** Fixed internal helper only: expose its executable in a hidden Linux root. */
|
|
83
|
+
internalHelperExecutable?: boolean;
|
|
82
84
|
};
|
|
83
85
|
|
|
84
86
|
/** The wrapper command to spawn: the backend executable and its full argv. */
|
|
@@ -410,7 +412,21 @@ const macOSSandboxBackend: SandboxBackend = {
|
|
|
410
412
|
buildCommand: buildMacOSSandboxCommand,
|
|
411
413
|
};
|
|
412
414
|
|
|
413
|
-
/** Resolve
|
|
415
|
+
/** Resolve only a root-owned system executable; never inspect task PATH. */
|
|
416
|
+
function systemSandboxExecutable(name: string): string | undefined {
|
|
417
|
+
// Never resolve the host-side confinement launcher through task-influenced PATH.
|
|
418
|
+
for (const directory of ["/usr/bin", "/bin"]) {
|
|
419
|
+
const candidate = join(directory, name);
|
|
420
|
+
try {
|
|
421
|
+
const info = statSync(candidate);
|
|
422
|
+
if (!info.isFile() || info.uid !== 0 || (info.mode & 0o022) !== 0) continue;
|
|
423
|
+
accessSync(candidate, constants.X_OK);
|
|
424
|
+
return candidate;
|
|
425
|
+
} catch { /* Try the next system location. */ }
|
|
426
|
+
}
|
|
427
|
+
return undefined;
|
|
428
|
+
}
|
|
429
|
+
|
|
414
430
|
export function executableFromPath(name: string): string | undefined {
|
|
415
431
|
const path = process.env.PATH;
|
|
416
432
|
if (!path) return undefined;
|
|
@@ -592,6 +608,12 @@ function buildLinuxPermissionCommand(
|
|
|
592
608
|
if (existsSync(root)) mounts.push("--ro-bind", root, root);
|
|
593
609
|
}
|
|
594
610
|
mounts.push("--tmpfs", "/tmp");
|
|
611
|
+
if (args.internalHelperExecutable) {
|
|
612
|
+
const executable = canonicalizePath(args.execPath, seams);
|
|
613
|
+
if (!RUNTIME_ROOTS.some((root) => contains(canonicalizePath(root, seams), executable))) {
|
|
614
|
+
mounts.push("--ro-bind", executable, executable);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
595
617
|
} else {
|
|
596
618
|
mounts.push(permissions.outsideProject === "read" ? "--ro-bind" : "--bind", "/tmp", "/tmp");
|
|
597
619
|
}
|
|
@@ -605,17 +627,18 @@ function buildLinuxPermissionCommand(
|
|
|
605
627
|
}
|
|
606
628
|
}
|
|
607
629
|
for (const path of policy.runtimeWrite ?? []) {
|
|
608
|
-
if (
|
|
630
|
+
if (credentials.some((protectedPath) => contains(path, protectedPath) || contains(protectedPath, path)) ||
|
|
631
|
+
policy.denyWrite.some((protectedPath) => contains(protectedPath, path))) {
|
|
609
632
|
throw new Error("Runtime directory overlaps protected credentials or control paths.");
|
|
610
633
|
}
|
|
611
634
|
mounts.push("--bind", path, path);
|
|
612
635
|
}
|
|
613
636
|
const protectedPaths = [...policy.denyWrite,
|
|
614
637
|
...(permissions.storedCredentials !== "read-write" ? overlappingCredentials : [])];
|
|
615
|
-
|
|
638
|
+
for (const writableRoot of [...(writableProject ? [project] : []), ...(policy.runtimeWrite ?? [])]) {
|
|
616
639
|
const materialize = seams.materializeDenyPath ?? materializeDenyPath;
|
|
617
|
-
const leaves = protectedPaths.filter((path) => contains(
|
|
618
|
-
for (const parent of protectedAncestors(leaves).filter((path) => contains(
|
|
640
|
+
const leaves = protectedPaths.filter((path) => contains(writableRoot, path) && materialize(path));
|
|
641
|
+
for (const parent of protectedAncestors(leaves).filter((path) => contains(writableRoot, path) && path !== writableRoot)) {
|
|
619
642
|
mounts.push("--bind", parent, parent);
|
|
620
643
|
}
|
|
621
644
|
for (const path of leaves) mounts.push("--ro-bind", path, path);
|
|
@@ -628,7 +651,7 @@ function buildLinuxPermissionCommand(
|
|
|
628
651
|
}
|
|
629
652
|
|
|
630
653
|
function linuxSandboxBackend(seams: SandboxSeams): SandboxBackend | undefined {
|
|
631
|
-
const bwrap = (seams.lookupExecutable ??
|
|
654
|
+
const bwrap = (seams.lookupExecutable ?? systemSandboxExecutable)("bwrap");
|
|
632
655
|
if (!bwrap) return undefined;
|
|
633
656
|
return {
|
|
634
657
|
id: "linux-bubblewrap",
|
|
@@ -651,7 +674,7 @@ function selectedSandboxBackend(seams: SandboxSeams): SandboxBackend | undefined
|
|
|
651
674
|
*/
|
|
652
675
|
function unavailableMessage(platform: string): string {
|
|
653
676
|
if (platform === "linux") {
|
|
654
|
-
return "Linux sandbox requires executable bubblewrap (bwrap)
|
|
677
|
+
return "Linux sandbox requires executable bubblewrap (bwrap) in /usr/bin or /bin. Install bubblewrap to enable it.";
|
|
655
678
|
}
|
|
656
679
|
if (platform === "darwin") {
|
|
657
680
|
return "macOS sandbox requires /usr/bin/sandbox-exec, which is missing here.";
|