Skip to content

Give the native import probe an owned package copy again - #2949

Merged
trissim merged 2 commits into
mainfrom
fix/native-import-rpc-owned-copy
Oct 23, 2026
Merged

trissim merged 2 commits into
mainfrom
fix/native-import-rpc-owned-copy

Conversation

@trissim

@trissim trissim commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

native-scripts has failed on every merge to main since #2873 (15:42 on 10-23; #2883 at 15:40 passed). The failure is stack/test-native-import-rpc.py:124, seen == [].

Cause. 7a51a47 (merged in #2873) replaced the probe's private package copy with a symlink into the shared native store (stack/test-native-import-rpc.py:344). Node resolves modules by their realpath. So the parentURL of the probed ws/lib/buffer-util.js became the store path, while the probe compares it with the lexical link path (requiringModule from argv[4], line 85). The fence still refused bufferutil, but the comparison filtered the refusal out.

The symlink also broke ownership. ancestor.mkdir at line 56 planted bufferutil inside the shared store's node_modules for the length of the run. The is_relative_to(root) guard at line 54 checks only the lexical path, so it passed anyway.

Fix. Copy the prepared package into the temporary root again, so every ancestor of the probed entry is owned. TemporaryDirectory reaps the sealed copy. Before 7a51a47, the copy was removed by remove_native_tree. That commit deleted the function from native_package.py, so it no longer exists on main, and this PR does not bring it back. qualify checks only layout and seal, so it accepts the copy.

The ownership guard at line 54 now compares real paths (package.resolve().is_relative_to(root.resolve())). A package symlinked under root therefore fails the guard before the probe can plant or remove bufferutil in a shared tree (IDEN-7: the guard checked the spelled path, but the fact it needs is where the package really lives).

The test is a native build input (native_build_inputs.py:35 inventories every stack/*.py), so the manifest's inputs pin is regenerated with stack/bin/prepare-pi-native --update-pins.

Proof (local, Node 26.4.0, the workflow's command under the Core runtime):

  • before, on main 7eefe39: AssertionError: {'factory': 'function', ..., 'seen': []}, rc 1. This is the same assertion as hosted run 40032749628, so the failure does not depend on the environment.
  • after: rc 0, "seen": [{"code": "ERR_NATIVE_IMPORT_BOUNDARY", "parent": "file:///tmp/native-import-rpc-.../ws/lib/buffer-util.js"}]. No /tmp/native-import-rpc-* dir is left behind.

Assumed:

  • Copying 192M into the temporary root per run is acceptable, as it was before 7a51a47. Hardlinks cannot cross into a tmpfs /tmp.

🤖 Generated with Claude Code

7a51a47 replaced the probe's private package copy with a symlink to the
shared native store. Node resolves modules by realpath, so the probed ws
entry's parentURL became the store path while the probe compared it with
the lexical link path: the fence still refused bufferutil, the comparison
filtered the refusal out, and native-scripts failed with seen == [] on
every merge since #2873. The planted bufferutil also landed inside the
shared store's node_modules for the length of the run.

Copy the prepared package into the temporary root again so every ancestor
of the probed entry is owned. TemporaryDirectory reaps the sealed copy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 23, 2026 22:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

The ownership guard compared spelled paths, so a package symlinked under
the temporary root passed it while the probe planted and removed
bufferutil inside the shared store. Compare resolved paths instead.

Every stack/*.py is a native build input (native_build_inputs.py:35), so
the probe edit moves the inputs pin; regenerate it with
prepare-pi-native --update-pins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trissim
trissim merged commit b0b889a into main Oct 23, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants