)]}'
{
  "commit": "07442c1f7576ee25be75526cb89bd4bb2f719ab8",
  "tree": "d343f6acb471afb4d8d2bc4d8cbf9daeec6655c1",
  "parents": [
    "2f927566d2d7c167383bf36fff61211f23d9e7e4"
  ],
  "author": {
    "name": "mloeppky-zoox",
    "email": "mloeppky@zoox.com",
    "time": "Fri Jul 17 18:42:49 2026 -0700"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Fri Jul 17 18:42:49 2026 -0700"
  },
  "message": "fix(node-patches): resolve readlink target against the real parent dir (#2916)\n\nFixes #2914\n\n## Problem\n\n`fs.readlink` / `fs.readlinkSync` in the node-patches compute the\ntarget\u0027s absolute path by joining the raw kernel link target onto the\n**lexical** parent of the *queried* path:\n\n```js\nconst targetAbs \u003d path.resolve(path.dirname(resolved), linkTarget)\n```\n\n`path.dirname(resolved)` is the parent of the path *as the caller wrote\nit*, which may itself traverse symlinks. When the caller reaches the\nlink through symlinks whose resolution changes directory depth (e.g. an\naliased `node_modules` path that is a different number of segments deep\nthan the link\u0027s real location), a relative (`../…`) target is counted\nfrom the wrong base. The resulting absolute path lands one or more\nlevels off — but still *inside* the guard root, so `isEscape` doesn\u0027t\nflag it and the bogus path is handed to the caller.\n\nAny tool that resolves modules via `readlink` then stats a nonexistent\npath and fails with `ENOENT`. We hit this with ESLint\u0027s\n`import/namespace` rule (via `eslint-import-resolver-typescript` →\n`enhanced-resolve`) resolving a first-party package reached through a\npackage-store alias one segment shallower than its real `bazel-out` dir.\n\n## Fix\n\nResolve the link\u0027s parent to its **real** path before joining the target\n(`origRealpathSyncNative`, with a try/catch fallback to the previous\nbehavior). This is an identity transform whenever the queried path is\nalready fully resolved, so it only changes results that were previously\nwrong. Applied to both the async `readlink` callback and `readlinkSync`;\nregenerated the checked-in `fs.cjs` from `src/fs.cts` via the\n`write_source_files` target.\n\n## Testing\n\n- Existing `//js/private/test/node-patches:readlink_*` targets pass on\nnode 20/22/24 (cjs + esm) — no regression.\n- Verified end-to-end in a downstream monorepo: the fix resolves an\n`ENOENT` in an `eslint_test` that was resolving `@scope/base` through\n`@scope/web`\u0027s store copy.\n\nIsolated repro (no Bazel): load `js/private/node-patches/register.cjs`\nwith `JS_BINARY__FS_PATCH_ROOTS` set, then `fs.readlinkSync()` a symlink\nreached through a parent symlink of a different depth — the returned\nabsolute path is wrong before this change, correct after.\n\nHappy to add a dedicated regression test to `readlink.mjs` if you\u0027d like\nto guide the fixture shape (the observable difference is in the\nescape/`nextHop` mapping, so it needs a sandbox-style fixture with a\ndepth-mismatched alias).\n\nCo-Authored-By: Claude Code\n\n---------\n\nSigned-off-by: mloeppky-zoox \u003cmloeppky@zoox.com\u003e\nCo-authored-by: Cursor \u003ccursoragent@cursor.com\u003e",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "9435bbe581c6384907ca4eca693314a259baf562",
      "old_mode": 33188,
      "old_path": "js/private/node-patches/fs.cjs",
      "new_id": "b9693f3d70c005e211e8a00fc117b8c160e7e825",
      "new_mode": 33188,
      "new_path": "js/private/node-patches/fs.cjs"
    },
    {
      "type": "modify",
      "old_id": "277f2748b9e761687f147570a54e824446503fcf",
      "old_mode": 33188,
      "old_path": "js/private/node-patches/src/fs.cts",
      "new_id": "416b7e7dabd15506870423c7fb65ed43a4a6246d",
      "new_mode": 33188,
      "new_path": "js/private/node-patches/src/fs.cts"
    },
    {
      "type": "modify",
      "old_id": "63157c3c332522608998c98d5d32098cbd078c77",
      "old_mode": 33188,
      "old_path": "js/private/test/image/checksum_test.expected",
      "new_id": "c462696e5d18a180036c680a4406f11500bc3ab0",
      "new_mode": 33188,
      "new_path": "js/private/test/image/checksum_test.expected"
    },
    {
      "type": "modify",
      "old_id": "c1a00ca1626301403d53ad5e856c0cd7c92e7011",
      "old_mode": 33188,
      "old_path": "js/private/test/image/custom_layers_nomatch_test_node.listing",
      "new_id": "f00fda100ae745de4f51ad6637c06a89bc979808",
      "new_mode": 33188,
      "new_path": "js/private/test/image/custom_layers_nomatch_test_node.listing"
    },
    {
      "type": "modify",
      "old_id": "f17d0404f03ed4130754dd3ffaa0c9b1f59e1dc0",
      "old_mode": 33188,
      "old_path": "js/private/test/image/custom_owner_test_node.listing",
      "new_id": "ee38282979d0de848307949103eb74fed2731886",
      "new_mode": 33188,
      "new_path": "js/private/test/image/custom_owner_test_node.listing"
    },
    {
      "type": "modify",
      "old_id": "d4671d836a5050741b0d928f0ac65e4eb26216dc",
      "old_mode": 33188,
      "old_path": "js/private/test/image/default_test_node.listing",
      "new_id": "b15ac420292e71ff39c599961e87dfb07660acd7",
      "new_mode": 33188,
      "new_path": "js/private/test/image/default_test_node.listing"
    },
    {
      "type": "modify",
      "old_id": "943512df2ff34794fc075034af34b87e836a4976",
      "old_mode": 33188,
      "old_path": "js/private/test/image/non_ascii/custom_layer_groups_test_just_the_fs_patch.listing",
      "new_id": "a94a99ba7ffd9807903271015a1d19a21c11c448",
      "new_mode": 33188,
      "new_path": "js/private/test/image/non_ascii/custom_layer_groups_test_just_the_fs_patch.listing"
    },
    {
      "type": "modify",
      "old_id": "b1bbf9c113fc26e7059e16360e44c4b8c66776f4",
      "old_mode": 33188,
      "old_path": "js/private/test/image/platform_deps/rspack_linux_arm64_test_node.listing",
      "new_id": "d9d8a53590ee1965f779835c56714acdd11a7434",
      "new_mode": 33188,
      "new_path": "js/private/test/image/platform_deps/rspack_linux_arm64_test_node.listing"
    },
    {
      "type": "modify",
      "old_id": "c1a00ca1626301403d53ad5e856c0cd7c92e7011",
      "old_mode": 33188,
      "old_path": "js/private/test/image/regex_edge_cases_test_node.listing",
      "new_id": "f00fda100ae745de4f51ad6637c06a89bc979808",
      "new_mode": 33188,
      "new_path": "js/private/test/image/regex_edge_cases_test_node.listing"
    },
    {
      "type": "modify",
      "old_id": "da8c6f0560aec5886ce59a5aa1900b562eda5e4e",
      "old_mode": 33188,
      "old_path": "js/private/test/node-patches/readlink.mjs",
      "new_id": "366c9c6ef0efdbc5698cb269f79d404bd191580c",
      "new_mode": 33188,
      "new_path": "js/private/test/node-patches/readlink.mjs"
    }
  ]
}
