SPB Git

spb/autoscholar

Public

Reproduction sandbox: canonical (/private/var) paths so reproduce.sh can execute

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed (Oct 30, 2026) parent 7be2efb Browse files

1 changed file +16 −1

Unified Split
modified services/research-runner/src/runner.ts +16 −1
@@ -479,7 +479,22 @@ export class ResearchRunner {
479 479 await mkdir(join(reproDir, "results/tables"), { recursive: true });
480 480 await mkdir(join(reproDir, "results/figures"), { recursive: true });
481 481 await mkdir(join(reproDir, "home"), { recursive: true });
482 − const profile = `(version 1)\n(allow default)\n(deny file-write*)\n(allow file-write* (subpath "${reproDir}") (subpath "/private/tmp") (subpath "/tmp") (subpath "/private/var/folders") (literal "/dev/null") (regex #"^/dev/tty") (subpath "${this.host.tectonicCache ?? join(this.ws, ".cache/tectonic")}"))\n(deny file-read* (subpath "/Users") (subpath "/etc/autoscholar") (subpath "/var/autoscholar/runs") (subpath "/private/var/autoscholar/runs"))\n(allow file-read* (subpath "${reproDir}") (subpath "${this.ws}/.cache"))\n`;
482 + // Seatbelt matches canonical paths (/private/var/...): resolve every path and allow both spellings
483 + const real = async (p: string) => realpath(p).catch(() => p);
484 + const reproReal = await real(reproDir);
485 + const wsReal = await real(this.ws);
486 + const cacheDir = this.host.tectonicCache ?? join(this.ws, ".cache/tectonic");
487 + const cacheReal = await real(cacheDir);
488 + const both = (p: string, q: string) => [...new Set([p, q])].map((x) => `(subpath "${x}")`).join(" ");
489 + const profile = [
490 + "(version 1)",
491 + "(allow default)",
492 + "(deny file-write*)",
493 + `(allow file-write* ${both(reproDir, reproReal)} (subpath "/private/tmp") (subpath "/tmp") (subpath "/private/var/folders") (literal "/dev/null") (regex #"^/dev/tty") ${both(cacheDir, cacheReal)} ${both(join(this.ws, ".cache"), join(wsReal, ".cache"))})`,
494 + `(deny file-read* (subpath "/Users") (subpath "/etc/autoscholar") (subpath "/private/etc/autoscholar") (subpath "/var/autoscholar/runs") (subpath "/private/var/autoscholar/runs"))`,
495 + `(allow file-read* ${both(reproDir, reproReal)} ${both(join(this.ws, ".cache"), join(wsReal, ".cache"))} ${both(cacheDir, cacheReal)})`,
496 + "",
497 + ].join("\n");
483 498 const profilePath = join(this.ws, "_repro/repro.sb");
484 499 await writeFile(profilePath, profile);
485 500 const t0 = Date.now();
486 501
Menu

Theme