Skip to content

Commit

Permalink
feat(nodejs): add yarn alias support (aquasecurity#5818)
Browse files Browse the repository at this point in the history
Signed-off-by: knqyf263 <knqyf263@gmail.com>
Co-authored-by: knqyf263 <knqyf263@gmail.com>
  • Loading branch information
DmitriyLewen and knqyf263 committed Jan 4, 2024
1 parent 013df4c commit 30eff9c
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 11 deletions.
5 changes: 4 additions & 1 deletion docs/docs/coverage/language/nodejs.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ By default, Trivy doesn't report development dependencies. Use the `--include-de

### Yarn
Trivy parses `yarn.lock`, which doesn't contain information about development dependencies.
To exclude devDependencies, `package.json` also needs to be present next to `yarn.lock`.
Trivy also uses `package.json` file to handle [aliases](https://classic.yarnpkg.com/lang/en/docs/cli/add/#toc-yarn-add-alias).

To exclude devDependencies and allow aliases, `package.json` also needs to be present next to `yarn.lock`.

Trivy analyzes `.yarn` (Yarn 2+) or `node_modules` (Yarn Classic) folder next to the yarn.lock file to detect licenses.

By default, Trivy doesn't report development dependencies. Use the `--include-dev-deps` flag to include them.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "test",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"foo-json": "npm:@types/jsonstream@0.8.33",
"foo-uuid": "npm:@types/uuid"
},
"dependencies": {
"foo-debug": "npm:debug@^4.3",
"foo-ms": "npm:ms"
}
}
44 changes: 44 additions & 0 deletions pkg/fanal/analyzer/language/nodejs/yarn/testdata/alias/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@types/node@*":
version "20.10.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2"
integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==
dependencies:
undici-types "~5.26.4"

"foo-debug@npm:debug@^4.3":
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"

"foo-json@npm:@types/jsonstream@0.8.33":
version "0.8.33"
resolved "https://registry.yarnpkg.com/@types/jsonstream/-/jsonstream-0.8.33.tgz#7d37a16a78cf68a67858110dc1767023436fca23"
integrity sha512-yhg1SNOgJ8y2nOkvAQ1zZ1Z2xibxgFs7984+EeBPuWgo/TbuYo79+rj2wUVch3KF4GhhcwAi/AlJcehmLCXb3g==
dependencies:
"@types/node" "*"

"foo-ms@npm:ms":
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==

"foo-uuid@npm:@types/uuid":
version "9.0.7"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.7.tgz#b14cebc75455eeeb160d5fe23c2fcc0c64f724d8"
integrity sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==

ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==

undici-types@~5.26.4:
version "5.26.5"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
38 changes: 28 additions & 10 deletions pkg/fanal/analyzer/language/nodejs/yarn/yarn.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"sort"
"strings"

Expand Down Expand Up @@ -36,6 +37,10 @@ func init() {

const version = 2

// Taken from Yarn
// cf. https://github.com/yarnpkg/yarn/blob/328fd596de935acc6c3e134741748fcc62ec3739/src/resolvers/exotics/registry-resolver.js#L12
var fragmentRegexp = regexp.MustCompile(`(\S+):(@?.*?)(@(.*?)|)$`)

type yarnAnalyzer struct {
packageJsonParser *packagejson.Parser
lockParser godeptypes.Parser
Expand Down Expand Up @@ -193,17 +198,30 @@ func (a yarnAnalyzer) walkDependencies(libs []types.Package, pkgIDs map[string]t
// Identify direct dependencies
pkgs := make(map[string]types.Package)
for _, pkg := range libs {
if constraint, ok := directDeps[pkg.Name]; ok {
// npm has own comparer to compare versions
if match, err := a.comparer.MatchVersion(pkg.Version, constraint); err != nil {
return nil, xerrors.Errorf("unable to match version for %s", pkg.Name)
} else if match {
// Mark as a direct dependency
pkg.Indirect = false
pkg.Dev = dev
pkgs[pkg.ID] = pkg
}
constraint, ok := directDeps[pkg.Name]
if !ok {
continue
}

// Handle aliases
// cf. https://classic.yarnpkg.com/lang/en/docs/cli/add/#toc-yarn-add-alias
if m := fragmentRegexp.FindStringSubmatch(constraint); len(m) == 5 {
pkg.Name = m[2] // original name
constraint = m[4]
}

// npm has own comparer to compare versions
if match, err := a.comparer.MatchVersion(pkg.Version, constraint); err != nil {
return nil, xerrors.Errorf("unable to match version for %s", pkg.Name)
} else if !match {
continue
}

// Mark as a direct dependency
pkg.Indirect = false
pkg.Dev = dev
pkgs[pkg.ID] = pkg

}

// Walk indirect dependencies
Expand Down
111 changes: 111 additions & 0 deletions pkg/fanal/analyzer/language/nodejs/yarn/yarn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,117 @@ func Test_yarnLibraryAnalyzer_Analyze(t *testing.T) {
},
},
},
{
name: "happy path with alias rewrite",
dir: "testdata/alias",
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.Yarn,
FilePath: "yarn.lock",
Libraries: types.Packages{
{
ID: "foo-json@0.8.33",
Name: "@types/jsonstream",
Version: "0.8.33",
Indirect: false,
Dev: true,
Locations: []types.Location{
{
StartLine: 19,
EndLine: 24,
},
},
DependsOn: []string{
"@types/node@20.10.5",
},
},
{
ID: "@types/node@20.10.5",
Name: "@types/node",
Version: "20.10.5",
Indirect: true,
Dev: true,
Locations: []types.Location{
{
StartLine: 5,
EndLine: 10,
},
},
DependsOn: []string{
"undici-types@5.26.5",
},
},
{
ID: "foo-uuid@9.0.7",
Name: "@types/uuid",
Version: "9.0.7",
Indirect: false,
Dev: true,
Locations: []types.Location{
{
StartLine: 31,
EndLine: 34,
},
},
},
{
ID: "foo-debug@4.3.4",
Name: "debug",
Version: "4.3.4",
Indirect: false,
Locations: []types.Location{
{
StartLine: 12,
EndLine: 17,
},
},
DependsOn: []string{
"ms@2.1.2",
},
},
{
ID: "ms@2.1.2",
Name: "ms",
Version: "2.1.2",
Indirect: true,
Locations: []types.Location{
{
StartLine: 36,
EndLine: 39,
},
},
},
{
ID: "foo-ms@2.1.3",
Name: "ms",
Version: "2.1.3",
Indirect: false,
Locations: []types.Location{
{
StartLine: 26,
EndLine: 29,
},
},
},
{
ID: "undici-types@5.26.5",
Name: "undici-types",
Version: "5.26.5",
Indirect: true,
Dev: true,
Locations: []types.Location{
{
StartLine: 41,
EndLine: 44,
},
},
},
},
},
},
},
},
{
name: "monorepo",
dir: "testdata/monorepo",
Expand Down

0 comments on commit 30eff9c

Please sign in to comment.