Repository navigation
Accept vendored packages and subpackages under their host's identity, recording those reached - #70
ChristopherTuring wants to merge 4 commits into
Conversation
…ched as `vendored` Next.js compiles ~140 dependencies into `dist/compiled/<dir>`, each beside a trimmed package.json naming it (`ua-parser-js`, mostly with no version), so bundling any of them failed #locateModule's nested package.json check: Inconsistent data between node_modules/next/dist/compiled/ua-parser-js/package.json and node_modules/next/package.json A maintained list of vendor dirs, keyed by the host package's name (so pnpm store paths and aliases match), now marks `next`'s `dist/compiled` as holding copies of other packages. A file there stays next's, and the consistency check is skipped only where a package.json below the vendor dir covers it; a nested package.json anywhere else in next is still held to next's identity. For transparency, a dependency's bundle record lists the vendored packages its files are in: `vendored`, by the directory of each one's package.json, with that package.json's `name` and (where given) `version`. Only those actually reached are listed: State records one when it captures a file in it, and serialization keeps the entries holding a file the artifact carries, so each half of a split bundle lists its own and parse refuses an entry holding none. Like `repo`, it is metadata: bundle-only, never in a lockfile, never attested, and merged by union. The --mainFields resolver and `stasis add`, which bucket through findPackageMetadata, follow the same rule; there a vendored package.json with a version used to become a bucket of its own inside next. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NJvPNoXzbzBGVBNknz3hdE
A bundle's `vendored` list becomes part of the SBOM: in CycloneDX, nested in the host's `components`, each bom-ref the host's with the directory as a purl subpath and the directory as its `evidence.occurrences` location; in SPDX, packages after the rest that the host CONTAINS, the directory as `packageFileName`. A purl is minted only beside a version: Next.js's copies mostly record none, and a bare name may not be a registry package at all (its React copy is `react-builtin`). The summary line counts them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NJvPNoXzbzBGVBNknz3hdE
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
…ng, listing those reached as `subpackages` @hookform/resolvers lays its subpath entry points out as microbundle does: zod/package.json, named `@hookform/resolvers/zod`, with a placeholder version of its own (1.0.0; arktype's 2.0.0). The name was already allowed (the package owns its namespace), but the version was held to the package's: Inconsistent data between node_modules/@hookform/resolvers/zod/package.json and node_modules/@hookform/resolvers/package.json The check is there to ask where a package.json nothing expects came from, so the answer accepted instead is narrow and recorded. A nested package.json is a subpackage only where its name is the package's for the very directory it is in (isSubpackage), compared by real path since findPackageJSON resolves a symlinked install; one named in the namespace for another directory is still held to the package's version. Its files stay under the package's identity, and a bundle lists each subpackage it carries a file of in `subpackages` (directory -> its package.json's name and version), metadata like `vendored`: bundle-only, never in a lockfile, merged by union, refused on parse where an entry is misnamed or holds none of the record's files. `stasis sbom` lists none: they are the package's own code. The --mainFields resolver and `stasis add` walk past a subpackage's package.json the same way; before, it took zod/ for a package of its own, `@hookform/resolvers/zod@1.0.0`. The per-directory metadata of `vendored` and `subpackages` now shares one implementation in artifact-util. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NJvPNoXzbzBGVBNknz3hdE
|
@codex review @codex security review The last review covered Generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f76c4e7d28
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…json
A subpackage with a type-only marker below its own package.json (say
zod/dist/package.json, `{"type":"module"}`) went unlisted for the files under
the marker: State looked at the closest package.json alone, and
findPackageMetadata stopped at the first one of any kind. Both now take the
nearest package.json with a name (namedManifestOf), as vendoredPackageOf
already does. State walks it by the file's own path, which also replaces the
real-path comparison of the subpackage's directory.
The version is the subpackage's own only where the closest package.json is
the subpackage's itself: a marker below it that gives a version is still held
to the package's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NJvPNoXzbzBGVBNknz3hdE
|
@codex security review Generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 567c3c8493
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (below) { | ||
| const repo = packageRepo(pkg) | ||
| const { dir: sub, ...identity } = vendored ?? {} | ||
| return { pkgDir: nm.dir, name: pkg.name, version: pkg.version, ecosystem: 'npm', ...(repo === undefined ? {} : { repo }), ...(vendored === undefined ? {} : { vendored: { [sub]: identity } }) } |
There was a problem hiding this comment.
Keep versioned vendored dependencies visible to audit
When a reached Next.js copy has a version (for example the recorded react-is fixture), folding it into the host bucket here removes the dependency bucket that stasis audit can inspect. collectPackagesFromFile in stasis/src/audit.js still considers only each module's top-level name/version, while companion lockfiles explicitly discard vendored, so known advisories for versioned compiled dependencies are now silently missed for both bundle and lockfile audit inputs. Please either teach audit/reason collection to emit code-bearing versioned vendored entries and retain enough lockfile metadata, or preserve an auditable dependency representation.
Useful? React with 👍 / 👎.
Summary
Two common layouts failed
#locateModule's nestedpackage.jsoncheck, which exists to ask where apackage.jsonnothing expects came from:Both now bundle. In both cases the files keep their host's identity, the accepted exception is kept narrow, and every manifest let through is recorded in the bundle, so nothing passes silently.
Vendored packages (Next.js
dist/compiled)Next.js compiles about 140 dependencies into
dist/compiled/<dir>, each beside a trimmedpackage.jsonthat names the dependency (ua-parser-js, usually with no version).VENDOR_DIRSinbundle-util.js, keyed by the host package's name) marksnext'sdist/compiled. Elsewhere in next, a nestedpackage.jsonis still held to next's identity.vendoredfield. It maps each vendored copy's directory to thenameandversionfrom that copy'spackage.json, and lists only the copies the bundle carries a file of.stasis sbomlists each reached copy as a package contained in its host. In CycloneDX it is a nested component; in SPDX the hostCONTAINSit. A purl is emitted only when a version is recorded.Subpackages (
@hookform/resolvers/zod)Microbundle-style subpath entry points have their own
package.json, named in the package's namespace and carrying a placeholder version (1.0.0).@hookform/resolvers/zodatzod/). The directory is compared by real path, becausefindPackageJSONresolves pnpm symlinks. A namespaced name at another directory still fails.subpackagesfield (directory → name and version) listing the reached subpackages. They are the package's own code, so the SBOM doesn't list them.Shared behavior
vendoredandsubpackagesare metadata, likerepo. They are written to bundles only, never to lockfiles, are not attested, and merge by union.--mainFieldsresolver andstasis addfollow the same rules. Before this change they bucketednext/dist/compiled/react-isand@hookform/resolvers/zodas packages of their own.Testing
node --run test: 2645 tests, 0 failures.node --run lintis clean.State, bundle parse and serialize, merges,bundle=add, bothstasis bundlepaths, a pnpm symlinked install, and the SBOM output. Without the fix, the new tests reproduce both errors.stasis bundleandstasis run: only the 3 reached copies out of about 140 are listed.@hookform/resolvers5.9.1: one record at 5.9.1, listing only the reached subpackages.🤖 Generated with Claude Code
https://claude.ai/code/session_01NJvPNoXzbzBGVBNknz3hdE