{"version":3,"file":"fs_node-Cg__jYMW.mjs","names":[],"sources":["../src/batteries/sandbox/node/fs_node.ts"],"sourcesContent":["import { resolve } from 'node:path'\nimport { realpathSync } from 'node:fs'\nimport type { DerivedRules } from '../types'\n\n/**\n * Load upstream's own glob matcher.\n *\n * @remarks\n * Deep-imported rather than ported, so this evaluator CANNOT drift from the profile SRT actually\n * generates — a hand-copied `globToRegex` would make parity a maintenance promise instead of a\n * property. The specifier is deliberately PACKAGE-RELATIVE and resolved through the optional peer,\n * matching `escape.ts`'s deep import of `quote()`: an absolute path would resolve only on the\n * machine that wrote it and would fail at runtime for every consumer of the published package.\n *\n * The module is safe to reach into — `sandbox-utils.js` imports only `os`/`path`/`fs`, so this\n * cannot pull upstream's bundled zod into a repo that has never depended on it.\n *\n * @returns Upstream's `globToRegex`.\n */\nexport const loadGlobToRegex = async (): Promise<(glob: string) => string> => {\n  const moduleName = '@anthropic-ai/sandbox-runtime/dist/sandbox/sandbox-utils.js'\n  const mod = (await import(moduleName)) as {\n    globToRegex: (glob: string) => string\n  }\n  return mod.globToRegex\n}\n\n/**\n * The in-process policy decision procedure.\n *\n * @remarks\n * BESPOKE POLICY CODE, not a thin wrapper: SRT exports rule LISTS\n * (`getFsReadConfig()`/`getFsWriteConfig()`) but **no authorization predicate**, so the decision is\n * ours to make and ours to get wrong. It backs the tools that run OUR code — `open_file*`,\n * `stage_file`, `save_media`, `list_directory` — where there is no untrusted binary between the check\n * and the `open()`, so applying the same derived rules in-process is the same path without a\n * subprocess rather than a weaker one.\n *\n * The residuals are real and unmitigated: a TOCTOU race between check and open, and any bug in this\n * evaluator. There is no OS backstop on this path — SRT restricts spawned children only. The\n * compensating controls are the mandatory gate and a narrow `writeRoot`.\n */\nexport type FsNode = {\n  /** Whether a read of `path` is permitted. Reads default to ALLOW; `allowRead` wins inside `denyRead`. */\n  canRead(path: string): boolean\n  /** Whether a write to `path` is permitted. Writes default to DENY; `denyWrite` wins inside `allowWrite`, and the mandatory-deny set applies on top. */\n  canWrite(path: string): boolean\n}\n\nconst under = (path: string, rule: string): boolean =>\n  rule === '/' ? path.startsWith('/') : path === rule || path.startsWith(`${rule}/`)\n/**\n * Compiled-glob cache, keyed by the raw rule.\n *\n * @remarks\n * `canRead`/`canWrite` are synchronous and run per path, so upstream's matcher is compiled once per\n * rule by {@link primeGlobMatcher} and read from here. A rule whose regex does not COMPILE is stored\n * as `null` and fails closed — that is `undecidableGlobs`' real producer (`[z-a]` → *\"Range out of\n * order in character class\"*).\n */\nconst globCache = new Map<string, RegExp | null>()\n\n/**\n * Compile every glob-bearing rule through upstream's own `globToRegex`.\n *\n * @remarks\n * MUST be awaited before the evaluator is consulted, because the deep import is async while the\n * evaluator is not. {@link srtEnforcer} does this for every rule in the derived lists immediately\n * after capturing them — NOT {@link createFsNode}, which is synchronous and therefore cannot. An\n * earlier comment here named `createFsNode`, which was simply false: nothing primed, so the\n * synchronous fallback was the only path production ever took.\n *\n * @param rules - Raw rule strings from the derived lists.\n */\nexport const primeGlobMatcher = async (rules: Iterable<string>): Promise<void> => {\n  const globToRegex = await loadGlobToRegex()\n  for (const rule of rules) {\n    if (!containsGlobChars(rule) || globCache.has(rule)) continue\n    try {\n      globCache.set(rule, new RegExp(globToRegex(rule)))\n    } catch {\n      globCache.set(rule, null)\n    }\n  }\n}\n\n/**\n * Synchronous fallback translation, used only when a rule was never primed.\n *\n * @remarks\n * REPLICATES UPSTREAM'S REPLACEMENT ORDER, WHICH IS THE WHOLE DIFFICULTY. The order is\n * load-bearing: escape the regex specials, then substitute the `**` + separator form via a\n * PLACEHOLDER, then bare `**`, then `*`, then `?`, and only then restore the placeholders. Expanding\n * bare `**` first is what broke the previous implementation — the subtree form then requires a\n * separator and stops matching zero directories, silently disabling every subtree deny.\n *\n * This exists so an unprimed rule is evaluated CORRECTLY rather than failing closed on a legitimate\n * path: `createFsNode` is synchronous by contract (it is consulted per path) while the upstream\n * import is async, so a caller that has not primed would otherwise get a boundary that refuses\n * everything glob-shaped. {@link primeGlobMatcher} remains preferred — it uses upstream's own\n * function, so it cannot drift at all — and the parity test pins the two against each other.\n *\n * @param rule - A glob-bearing rule.\n * @returns The compiled pattern, or `null` when the pattern does not compile.\n */\nconst compileGlobFallback = (rule: string): RegExp | null => {\n  // Placeholders are chosen to be un-forgeable rather than merely unlikely. NUL cannot appear in a\n  // POSIX path, and a NUL-bearing rule is refused outright below rather than trusted. Built via\n  // fromCharCode so this source file holds no raw control characters.\n  //\n  // ONE DELIBERATE DIVERGENCE FROM UPSTREAM, and it is upstream's bug rather than a parity gap we\n  // can close: `globToRegex` uses PRINTABLE sentinels (`__GLOBSTAR__`), so a rule whose literal text\n  // contains one collides — verified, `globToRegex('__GLOBSTAR__')` returns `^.*$`, a rule that\n  // matches EVERY path. Reproducing that would mean turning a narrow rule into an allow-everything\n  // (or deny-everything) pattern, so this fallback matches such a rule literally instead. The\n  // divergence is unreachable in practice: these sentinels do not appear in SRT's own derived lists\n  // or in the mandatory-deny set, so it can only surface for a hand-written policy entry containing\n  // that exact text. Stated rather than hidden, because the agreement test's whole premise is that\n  // the two evaluators agree.\n  const nul = String.fromCharCode(0)\n  if (rule.includes(nul)) return null\n  const DOUBLE_SEP = `${nul}S${nul}`\n  const DOUBLE = `${nul}D${nul}`\n  try {\n    const source = rule\n      // Upstream's exact escape set — NOT a superset. It deliberately leaves `* ? [ ]` alone (they\n      // are glob syntax) and does NOT escape `-`; escaping more here would make a literal `-` in a\n      // character class behave differently from the profile.\n      .replace(/[.^$+{}()|\\\\]/g, '\\\\$&')\n      // Escape an UNCLOSED `[` so it matches literally, exactly as upstream does. Without this a\n      // rule like `/x/[` compiles upstream (to a literal match) but throws here, and the polarity\n      // fail-closed would then deny a path the real profile permits — stricter than the sandbox,\n      // which the agreement test correctly rejects.\n      .replace(/\\[([^\\]]*?)$/g, '\\\\[$1')\n      .split('**/')\n      .join(DOUBLE_SEP)\n      .split('**')\n      .join(DOUBLE)\n      .split('*')\n      .join('[^/]*')\n      .split('?')\n      .join('[^/]')\n      .split(DOUBLE_SEP)\n      .join('(?:.*/)?')\n      .split(DOUBLE)\n      .join('.*')\n    return new RegExp(`^${source}$`)\n  } catch {\n    return null\n  }\n}\n\nconst containsGlobChars = (rule: string): boolean =>\n  rule.includes('*') || rule.includes('?') || rule.includes('[') || rule.includes(']')\n\n/**\n * Match one path against one rule.\n *\n * @remarks\n * A literal rule is a prefix match. A glob rule is matched by UPSTREAM'S OWN compiled pattern,\n * never by a local translation. A hand-rolled port was wrong in a way that silently disabled the\n * subtree denies entirely: it expanded the double-star before the double-star-slash form, which\n * produced a pattern requiring exactly one intermediate segment and therefore matched NOTHING,\n * where upstream's equivalent makes the directory prefix optional and matches at any depth. That is\n * the replacement-ORDER trap the plan documents, and it is why the rule is to deep-import the\n * matcher rather than reimplement it: a port makes parity a promise, an import makes it a property.\n * An uncompilable rule fails CLOSED - a rule we cannot evaluate is one we must refuse to permit\n * around.\n *\n * FAIL-CLOSED IS NOT ONE VALUE — IT DEPENDS ON THE AXIS, and a blanket answer is wrong half the\n * time. On a RESTRICTIVE list (`denyOnly`, `denyWithinAllow`, `mandatoryDeny`) an unusable rule must\n * count as MATCHING, so the path is refused. On a PERMISSIVE list (`allowWithinDeny`, `allowOnly`)\n * the same `true` would GRANT access on a rule we cannot evaluate — fail-open, the inverse of the\n * intent — so it must count as NOT matching. Hence the explicit `polarity`.\n *\n * @param path - Canonicalised absolute path.\n * @param rule - A literal prefix or a glob from the derived lists.\n * @param polarity - Which direction an unusable rule must fail in.\n * @returns `true` when the rule covers the path.\n */\nconst matches = (path: string, rule: string, polarity: RuleListPolarity): boolean => {\n  if (!containsGlobChars(rule)) return under(path, rule)\n  let compiled = globCache.get(rule)\n  if (compiled === undefined) {\n    // Never primed: translate synchronously, preserving upstream's replacement ORDER, and memoise.\n    compiled = compileGlobFallback(rule)\n    globCache.set(rule, compiled)\n  }\n  // Uncompilable (e.g. the out-of-order class `[z-a]`): refuse on a deny list, do not grant on an\n  // allow list. A rule we cannot evaluate is one we must refuse to permit around.\n  if (compiled === null) return polarity === 'restrictive'\n  return compiled.test(path)\n}\n\n/** Which way an unevaluable rule must fail. See {@link matches}. */\ntype RuleListPolarity = 'restrictive' | 'permissive'\nconst listMatch = (path: string, rules: readonly string[], polarity: RuleListPolarity): boolean =>\n  rules.some((rule) => matches(path, rule, polarity))\n\n/** In-process counterpart of SRT's two derived restriction lists. */\nexport const createFsNode = (rules: DerivedRules): FsNode => {\n  const canonical = (value: string): string => {\n    try {\n      return realpathSync(resolve(value)).replaceAll('\\\\', '/')\n    } catch {\n      return resolve(value).replaceAll('\\\\', '/')\n    }\n  }\n  const mandatory = (path: string): boolean => {\n    if (rules.filesystemDisabled) return false\n    if (rules.mandatoryDeny.form === 'glob')\n      return listMatch(path, rules.mandatoryDeny.entries, 'restrictive')\n    return rules.mandatoryDeny.entries.some((entry) => {\n      const lowerEntry = entry.toLowerCase()\n      if (DANGEROUS_FILES.some((file) => file === lowerEntry))\n        return path.toLowerCase().endsWith(`/${lowerEntry}`) || path.toLowerCase() === lowerEntry\n      if (lowerEntry === '.git/hooks' || lowerEntry === '.git/config') {\n        const suffix = entry\n        return path.includes(`/${suffix}/`) || path.endsWith(`/${suffix}`)\n      }\n      const foldedPath = path.toLowerCase()\n      return under(foldedPath, lowerEntry)\n    })\n  }\n  return {\n    canRead: (raw) => {\n      if (rules.filesystemDisabled) return true\n      const path = canonical(raw)\n      return (\n        !listMatch(path, rules.read.denyOnly, 'restrictive') ||\n        listMatch(path, rules.read.allowWithinDeny, 'permissive')\n      )\n    },\n    canWrite: (raw) => {\n      if (rules.filesystemDisabled) return true\n      const path = canonical(raw)\n      if (\n        !listMatch(path, rules.write.allowOnly, 'permissive') ||\n        listMatch(path, rules.write.denyWithinAllow, 'restrictive')\n      )\n        return false\n      return !mandatory(path)\n    },\n  }\n}\n\n/** Construct a derived snapshot from the shapes returned by SRT. */\nexport const derivedRulesFromSrt = (input: {\n  platform: 'darwin' | 'linux'\n  read: { denyOnly: readonly string[]; allowWithinDeny?: readonly string[] }\n  write: { allowOnly: readonly string[]; denyWithinAllow: readonly string[] }\n  filesystemDisabled?: boolean\n  network?: {\n    /** OURS, not upstream's: `true` only when WE constructed the session in disabled mode. */\n    disabled?: boolean\n    allowedDomains?: readonly string[]\n    deniedDomains?: readonly string[]\n  }\n  mandatoryDeny?: {\n    form: 'glob' | 'expanded-paths'\n    entries: readonly string[]\n    allowGitConfig: boolean\n    searchDepth: number\n    dotGitWasDirectory?: boolean\n  }\n}): DerivedRules => ({\n  matcher: {\n    platform: input.platform,\n    caseInsensitive: input.platform === 'linux',\n    readGlobs: input.platform === 'linux' ? 'expanded' : 'native',\n    writeGlobs: input.platform === 'linux' ? 'dropped' : 'native',\n  },\n  read: {\n    denyOnly: [...input.read.denyOnly],\n    allowWithinDeny: [...(input.read.allowWithinDeny ?? [])],\n  },\n  write: {\n    allowOnly: [...input.write.allowOnly],\n    denyWithinAllow: [...input.write.denyWithinAllow],\n  },\n  mandatoryDeny: input.mandatoryDeny ?? {\n    form: input.platform === 'linux' ? 'expanded-paths' : 'glob',\n    entries: [],\n    allowGitConfig: false,\n    searchDepth: 3,\n  },\n  filesystemDisabled: input.filesystemDisabled ?? false,\n  network: {\n    // PROVENANCE IS PER MODE, and this field must NOT be hardcoded. It is OURS — upstream has no such\n    // flag — and it records *\"we were constructed in disabled mode\"*:\n    //   · WE INITIALIZED ⇒ the constructing ADK policy's value. Pinning it to `false` here silently\n    //     disables the drift SKIP branch, so a handle built in disabled mode would have its domain\n    //     axes compared against `['*']` instead of being skipped-and-logged.\n    //   · WE ADOPTED ⇒ always `false`, because we were not constructed at all. The caller passes\n    //     `false` explicitly in that mode; a foreign `['*']` is an ordinary allow-everything list.\n    disabled: input.network?.disabled ?? false,\n    allowedDomains: [...(input.network?.allowedDomains ?? [])],\n    deniedDomains: [...(input.network?.deniedDomains ?? [])],\n    strictAllowlist: true,\n  },\n  unknownKeys: [],\n  undecidableGlobs: [],\n})\n\n/** The exact upstream dangerous file names, retained for parity tests. */\nexport const DANGEROUS_FILES = [\n  '.gitconfig',\n  '.gitmodules',\n  '.bashrc',\n  '.bash_profile',\n  '.zshrc',\n  '.zprofile',\n  '.profile',\n  '.ripgreprc',\n  '.mcp.json',\n] as const\n/**\n * Directories SRT mandatory-denies, reproduced from upstream.\n *\n * @remarks\n * `.git` is deliberately ABSENT: upstream filters it out of its own list and handles it separately,\n * because the rules differ per platform and per `.git` being a directory rather than a worktree file.\n * Reproducing it here would deny what the profile permits.\n */\nexport const DANGEROUS_DIRECTORIES = [\n  '.vscode',\n  '.idea',\n  '.claude/commands',\n  '.claude/agents',\n] as const\n\n/**\n * Reproduce SRT's profile-injected mandatory-deny set for the CURRENT platform.\n *\n * @remarks\n * THIS IS OUR REPRODUCTION, NOT SRT'S OUTPUT, and the distinction bounds what any check built on it\n * can prove. SRT exposes no function for this set: it is injected at PROFILE GENERATION,\n * `linuxGetMandatoryDenyPaths` is a non-exported local, and `macGetMandatoryDenyPatterns` is not\n * re-exported from the package index. So the entries are re-derived here with the same lists upstream\n * uses — which is why the constant-parity test diffs those lists directly, and why a drift check over\n * this axis proves only \"our inputs did not change\", never \"our reproduction still matches SRT\".\n *\n * Without it the in-process evaluator has NO mandatory denies at all, and `save_media` writes\n * `.bashrc` or `.mcp.json` where the spawned shell is refused — the \"one boundary, two answers\"\n * failure this reproduction exists to prevent.\n *\n * FORM DIFFERS BY PLATFORM and the two are not comparable:\n *  · macOS emits GLOBS the seatbelt profile matches natively — each name resolved against the cwd\n *    plus a the subtree form subtree pattern, so it matches at any depth.\n *  · Linux emits CONCRETE PATHS from a bounded `rg` scan, so it is point-in-time and depth-limited;\n *    a file created afterwards, or nested deeper than `mandatoryDenySearchDepth`, is NOT covered\n *    there. We reproduce the cwd-rooted entries; the scan's discoveries are the profile's own.\n *\n * `.git/hooks` and `.git/config` are PLATFORM-CONDITIONAL: macOS pushes `hooks` unconditionally and\n * `config` unless `allowGitConfig`, while Linux pushes neither for the workspace root unless `.git`\n * is a real DIRECTORY (in a worktree it is a file, and denying it would break bwrap).\n *\n * @param options - The cwd the profile was built against, and the inputs that change the set.\n * @returns The reproduced entries, in the platform's own form.\n */\nexport const reproduceMandatoryDeny = (options: {\n  cwd: string\n  allowGitConfig: boolean\n  platform?: 'darwin' | 'linux'\n  dotGitIsDirectory?: boolean\n}): string[] => {\n  const platform = options.platform ?? (process.platform === 'linux' ? 'linux' : 'darwin')\n  const entries: string[] = []\n  // FILES: the cwd-resolved path, plus a bare a subtree subtree glob on macOS.\n  for (const name of DANGEROUS_FILES) {\n    entries.push(resolve(options.cwd, name))\n    if (platform === 'darwin') entries.push(`**/${name}`)\n  }\n  // DIRECTORIES: upstream's subtree glob ends in `/**` — the directory's CONTENTS, not the directory\n  // name. Emitting a bare `**/.vscode` (as an earlier revision did) fails to cover anything inside it\n  // while adding an entry upstream never had, so the reproduction was both over- and under-inclusive.\n  for (const name of DANGEROUS_DIRECTORIES) {\n    entries.push(resolve(options.cwd, name))\n    if (platform === 'darwin') entries.push(`**/${name}/**`)\n  }\n  // `.git/hooks` is denied unconditionally; `.git/config` only when `allowGitConfig` is false. Their\n  // subtree forms DIFFER, verified against upstream: hooks takes `/**` (a directory of scripts),\n  // config does not (a single file).\n  const gitEntries: Array<[string, boolean]> = [\n    ['.git/hooks', true],\n    ['.git/config', false],\n  ]\n  for (const [suffix, isDirectory] of gitEntries) {\n    if (suffix === '.git/config' && options.allowGitConfig) continue\n    // On Linux the workspace-ROOT entry exists only when `.git` is a real directory: in a worktree it\n    // is a FILE, and denying it would make bubblewrap fail.\n    if (platform === 'darwin' || options.dotGitIsDirectory === true)\n      entries.push(resolve(options.cwd, suffix))\n    if (platform === 'darwin') entries.push(isDirectory ? `**/${suffix}/**` : `**/${suffix}`)\n  }\n  return entries\n}\n"],"mappings":"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"}