sea: mount bundled assets as a virtual file system - #65675
Open
mcollina wants to merge 2 commits into
Open
Conversation
Collaborator
|
Review requested:
|
mcollina
force-pushed
the
vfs-sea-integration
branch
2 times, most recently
from
August 31, 2026 09:13
7e3ed4b to
148a0d7
Compare
Add a "useVfs" boolean to the SEA configuration. When enabled, the bundled assets are mounted as a read-only virtual file system before the main script runs, and the main script is placed at the mount point root and executed from there via wrapModuleLoad. __filename, __dirname, relative require() calls, and node_modules lookups then all resolve against the bundled assets, confined to the mount. Since a VFS never shadows the real file system, bundled code reaches the assets through __dirname-relative paths instead of a fixed mount location. The new SEAProvider derives the directory tree from the asset keys and keeps asset content in the executable's SEA blob, copying it into JS memory only when a file is opened. The main script is not duplicated into the assets at build time; its source already lives in the blob and is injected into the provider at runtime. The implicit SEA mount does not emit the VirtualFileSystem experimental warning, which is already covered by the SEA warning. "useVfs" is rejected together with "useSnapshot", "useCodeCache", and "mainFormat": "module"; ESM entry points are left as future work. Signed-off-by: Matteo Collina <hello@matteocollina.com>
mcollina
force-pushed
the
vfs-sea-integration
branch
from
August 31, 2026 09:14
148a0d7 to
4991e64
Compare
Allow "mainFormat": "module" together with "useVfs": true. The ESM main script is placed at the mount point root like the CommonJS one, and loaded through the ESM loader via runEntryPointWithESMLoader, so import.meta.url, import.meta.filename, and import.meta.dirname reflect the location of the main module inside the virtual file system, and static imports, dynamic import(), and bare specifier lookups all resolve against the bundled assets. Signed-off-by: Matteo Collina <hello@matteocollina.com>
mcollina
requested review from
Qard and
joyeecheung
and removed request for
Qard
August 31, 2026 10:46
pipobscure
added a commit
to pipobscure/bundles
that referenced
this pull request
Sep 1, 2026
The tool was one directory of JavaScript that doubled as a library by accident. This makes the library the point: `src/` is TypeScript compiled to ESM in `dist/`, every capability has a declared entry point, and the CLI is a thin wrapper over the same functions an embedder gets. Four things are now separately importable, which is the shape the rest of the design needs: . create / sign / verify / inspect / run, from code (api.ts) ./record the -r preload that writes down what a run reads ./register the -r preload that mounts only what is signed ./sea build and boot a self-validating executable plus ./provider, ./recorder, ./cli, ./manifest, ./archive, ./files, ./skill, ./sigstore and ./oidc for the layers underneath. The package root deliberately does not re-export the two providers: importing either needs node:vfs, and creating or verifying an archive does not, so a plain `import '@pipobscure/bundle'` must not drag `--experimental-vfs` in. There is a test that holds that line. The sources are erasable-syntax-only, so `node src/main.ts` runs them directly under node's type stripping. That is what lets the tests import the sources rather than the build, and a preload be `-r ./src/register.ts`. @types/node carries neither the node:zlib ZIP API nor node:vfs's provider registry, so `src/types/` declares them; the shapes were checked against the running runtime rather than transcribed from documentation. sea.js is replaced by src/sea.ts. The old bootstrap was a copy of manifest.js inlined into a CommonJS file, which had drifted: its signature marker regex was still the two-field form, so it read every sigstore-signed container as unsigned. The replacement mounts this package out of the SEA blob with node:vfs and requires the real library from there — the userland form of nodejs/node#65675, with the difference that the mount running the application is the signed archive appended to the file. Nothing is duplicated, and the verifier a container runs is the one the test suite tests. `bundle sea` builds one. Three bugs the type checker and the new tests turned up, all real: * --identity and BUNDLE_IDENTITY were only consulted on the sigstore path, so an archive signed against an ordinary CA — which carries no identity claim at all — satisfied a policy demanding one. A machine configured to run only releases from a workflow would have mounted anything key-signed. It now reports valid-untrusted. * Arguments beginning with `--` never reached a mounted application; node claimed them as its own flags. mountArgv() now ends with `--`. * Verifying from a Buffer crashed, and sigstore signing was written against @sigstore/bundle v2 while v3 is installed. Both fixed, and the Buffer path now has a test. 131 tests over the format, both providers, the API, the CLI, the SEA and the published package's own shape, replacing three JavaScript suites.
mcollina
marked this pull request as ready for review
September 1, 2026 15:04
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #65675 +/- ##
==========================================
+ Coverage 90.05% 90.07% +0.02%
==========================================
Files 754 756 +2
Lines 256308 256897 +589
Branches 48464 48563 +99
==========================================
+ Hits 230817 231405 +588
- Misses 16593 16615 +22
+ Partials 8898 8877 -21
🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds the SEA integration for the virtual file system landed in #63653: setting
"useVfs": truein the SEA configuration mounts the bundled assets as a read-only VFS and runs the injected main script from inside the mount.Since a VFS never shadows the real file system and its mount point is reserved and chosen at runtime, there is no fixed
/seapath. Instead, the main script is placed at the root of the mount and executed from there, so:__filenameand__dirnamepoint inside the virtual file system;__dirname-relative paths with regularnode:fsAPIs;require()calls andnode_moduleslookups resolve against the bundled assets, confined to the mount by the module loader integration.Implementation notes:
SEAProvideris read-only and lazy: asset content stays in the executable's SEA blob and is copied into JS memory only when a file is opened, with sizes cached forstat.VirtualFileSystemexperimental warning; the SEA warning already covers it."mainFormat": "module") are supported: the ESM main is loaded from inside the mount through the ESM loader, soimport.meta.url/filename/dirnamereflect the mount and static imports, dynamicimport(), and bare specifier lookups resolve against the bundled assets."useVfs"is rejected together with"useSnapshot"and"useCodeCache".This PR was prepared with the help of AI. I've reviewed all changes myself.