Skip to content

Commit

Permalink
fix(nodejs): fix infinity loops for pnpm with cyclic imports (#6857)
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriyLewen authored Jun 5, 2024
1 parent 042d6b0 commit 7d083bc
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 4 deletions.
13 changes: 9 additions & 4 deletions pkg/dependency/parser/nodejs/pnpm/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func (p *Parser) parseV9(lockFile LockFile) ([]ftypes.Package, []ftypes.Dependen
if dep, ok := lockFile.Importers.Root.DevDependencies[name]; ok && dep.Version == ver {
relationship = ftypes.RelationshipDirect
}
if dep, ok := lockFile.Importers.Root.Dependencies[name]; ok && dep.Version == ver {
if dep, ok := lockFile.Importers.Root.Dependencies[name]; ok && p.trimPeerDeps(dep.Version, lockVer) == ver {
relationship = ftypes.RelationshipDirect
dev = false // mark root direct deps to update `dev` field of their child deps.
}
Expand All @@ -208,29 +208,34 @@ func (p *Parser) parseV9(lockFile LockFile) ([]ftypes.Package, []ftypes.Dependen
}
}

visited := make(map[string]struct{})
// Overwrite the `Dev` field for dev deps and their child dependencies.
for _, pkg := range resolvedPkgs {
if !pkg.Dev {
p.markRootPkgs(pkg.ID, resolvedPkgs, resolvedDeps)
p.markRootPkgs(pkg.ID, resolvedPkgs, resolvedDeps, visited)
}
}

return maps.Values(resolvedPkgs), maps.Values(resolvedDeps)
}

// markRootPkgs sets `Dev` to false for non dev dependency.
func (p *Parser) markRootPkgs(id string, pkgs map[string]ftypes.Package, deps map[string]ftypes.Dependency) {
func (p *Parser) markRootPkgs(id string, pkgs map[string]ftypes.Package, deps map[string]ftypes.Dependency, visited map[string]struct{}) {
if _, ok := visited[id]; ok {
return
}
pkg, ok := pkgs[id]
if !ok {
return
}

pkg.Dev = false
pkgs[id] = pkg
visited[id] = struct{}{}

// Update child deps
for _, depID := range deps[id].DependsOn {
p.markRootPkgs(depID, pkgs, deps)
p.markRootPkgs(depID, pkgs, deps, visited)
}
return
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/dependency/parser/nodejs/pnpm/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ func TestParse(t *testing.T) {
want: pnpmV9,
wantDeps: pnpmV9Deps,
},
{
name: "v9",
file: "testdata/pnpm-lock_v9.yaml",
want: pnpmV9,
wantDeps: pnpmV9Deps,
},
{
name: "v9 with cyclic dependencies import",
file: "testdata/pnpm-lock_v9_cyclic_import.yaml",
want: pnpmV9CyclicImport,
wantDeps: pnpmV9CyclicImportDeps,
},
}

for _, tt := range tests {
Expand Down
64 changes: 64 additions & 0 deletions pkg/dependency/parser/nodejs/pnpm/parse_testcase.go
Original file line number Diff line number Diff line change
Expand Up @@ -900,4 +900,68 @@ var (
},
},
}

pnpmV9CyclicImport = []ftypes.Package{
{
ID: "[email protected]",
Name: "update-browserslist-db",
Version: "1.0.16",
Relationship: ftypes.RelationshipDirect,
},
{
ID: "[email protected]",
Name: "browserslist",
Version: "4.23.0",
Relationship: ftypes.RelationshipIndirect,
},
{
ID: "[email protected]",
Name: "caniuse-lite",
Version: "1.0.30001627",
Relationship: ftypes.RelationshipIndirect,
},
{
ID: "[email protected]",
Name: "electron-to-chromium",
Version: "1.4.789",
Relationship: ftypes.RelationshipIndirect,
},
{
ID: "[email protected]",
Name: "escalade",
Version: "3.1.2",
Relationship: ftypes.RelationshipIndirect,
},
{
ID: "[email protected]",
Name: "node-releases",
Version: "2.0.14",
Relationship: ftypes.RelationshipIndirect,
},
{
ID: "[email protected]",
Name: "picocolors",
Version: "1.0.1",
Relationship: ftypes.RelationshipIndirect,
},
}
pnpmV9CyclicImportDeps = []ftypes.Dependency{
{
ID: "[email protected]",
DependsOn: []string{
"[email protected]",
"[email protected]",
"[email protected]",
"[email protected]",
},
},
{
ID: "[email protected]",
DependsOn: []string{
"[email protected]",
"[email protected]",
"[email protected]",
},
},
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
lockfileVersion: '9.0'

settings:
autoInstallPeers: true
excludeLinksFromLockfile: false

importers:

.:
dependencies:
update-browserslist-db:
specifier: 1.0.16
version: 1.0.16([email protected])

packages:

[email protected]:
resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true

[email protected]:
resolution: {integrity: sha512-4zgNiB8nTyV/tHhwZrFs88ryjls/lHiqFhrxCW4qSTeuRByBVnPYpDInchOIySWknznucaf31Z4KYqjfbrecVw==}

[email protected]:
resolution: {integrity: sha512-0VbyiaXoT++Fi2vHGo2ThOeS6X3vgRCWrjPeO2FeIAWL6ItiSJ9BqlH8LfCXe3X1IdcG+S0iLoNaxQWhfZoGzQ==}

[email protected]:
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}

[email protected]:
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}

[email protected]:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}

[email protected]:
resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'

snapshots:

[email protected]:
dependencies:
caniuse-lite: 1.0.30001627
electron-to-chromium: 1.4.789
node-releases: 2.0.14
update-browserslist-db: 1.0.16([email protected])

[email protected]: {}

[email protected]: {}

[email protected]: {}

[email protected]: {}

[email protected]: {}

[email protected]([email protected]):
dependencies:
browserslist: 4.23.0
escalade: 3.1.2
picocolors: 1.0.1

0 comments on commit 7d083bc

Please sign in to comment.