feat(nodejs): parse licenses from package-lock.json file (#9983)

This commit is contained in:
DmitriyLewen
2025-12-29 11:57:06 +06:00
committed by GitHub
parent 43d4e5597b
commit b64d5adc6b
4 changed files with 33 additions and 6 deletions

View File

@@ -37,8 +37,9 @@ Trivy parses your files generated by package managers in filesystem/repository s
### npm
Trivy parses `package-lock.json`.
To identify licenses, you need to download dependencies to `node_modules` beforehand.
Trivy analyzes `node_modules` for licenses.
Trivy retrieves dependency license information from the lock file (starting with v2).
If license information is missing, Trivy checks the `package.json` files from the `node_modules` folder.
By default, Trivy doesn't report development dependencies. Use the `--include-dev-deps` flag to include them.

View File

@@ -41,6 +41,7 @@ type Dependency struct {
type Package struct {
Name string `json:"name"`
Version string `json:"version"`
License string `json:"license"`
Dependencies map[string]string `json:"dependencies"`
OptionalDependencies map[string]string `json:"optionalDependencies"`
DevDependencies map[string]string `json:"devDependencies"`
@@ -139,14 +140,25 @@ func (p *Parser) parseV2(packages map[string]Package) ([]ftypes.Package, []ftype
savedPkg.Locations = append(savedPkg.Locations, ftypes.Location(pkg.Location))
sort.Sort(savedPkg.Locations)
// If for some reason license is missing in savedPkg, but exists in the current pkg, add it.
if len(savedPkg.Licenses) == 0 && pkg.License != "" {
savedPkg.Licenses = []string{pkg.License}
}
pkgs[pkgID] = savedPkg
continue
}
var licenses []string
if pkg.License != "" {
licenses = []string{pkg.License}
}
newPkg := ftypes.Package{
ID: pkgID,
Name: pkgName,
Version: pkg.Version,
Licenses: licenses,
Relationship: lo.Ternary(pkgIndirect, ftypes.RelationshipIndirect, ftypes.RelationshipDirect),
Dev: pkg.Dev,
ExternalReferences: lo.Ternary(ref.URL != "", []ftypes.ExternalRef{ref}, nil),

View File

@@ -1336,6 +1336,7 @@ var (
ID: "function1",
Name: "function1",
Version: "",
Licenses: []string{"ISC"},
Relationship: ftypes.RelationshipDirect,
ExternalReferences: []ftypes.ExternalRef{
{
@@ -1354,6 +1355,7 @@ var (
ID: "nested_func@1.0.0",
Name: "nested_func",
Version: "1.0.0",
Licenses: []string{"ISC"},
Relationship: ftypes.RelationshipDirect,
ExternalReferences: []ftypes.ExternalRef{
{
@@ -1466,6 +1468,7 @@ var (
ID: "lodash@4.17.21",
Name: "lodash",
Version: "4.17.21",
Licenses: []string{"MIT"},
Relationship: ftypes.RelationshipIndirect,
ExternalReferences: []ftypes.ExternalRef{
{
@@ -1495,6 +1498,7 @@ var (
ID: "lodash@4.17.21",
Name: "lodash",
Version: "4.17.21",
Licenses: []string{"MIT"},
Relationship: ftypes.RelationshipDirect,
ExternalReferences: []ftypes.ExternalRef{
{
@@ -1513,6 +1517,7 @@ var (
ID: "winston-mail@2.0.0",
Name: "winston-mail",
Version: "2.0.0",
Licenses: []string{"MIT"},
Relationship: ftypes.RelationshipDirect,
ExternalReferences: []ftypes.ExternalRef{
{
@@ -1531,6 +1536,7 @@ var (
ID: "mustache@2.3.2",
Name: "mustache",
Version: "2.3.2",
Licenses: []string{"MIT"},
Relationship: ftypes.RelationshipIndirect,
ExternalReferences: []ftypes.ExternalRef{
{
@@ -1549,6 +1555,7 @@ var (
ID: "triple-beam@1.4.1",
Name: "triple-beam",
Version: "1.4.1",
Licenses: []string{"MIT"},
Relationship: ftypes.RelationshipIndirect,
ExternalReferences: []ftypes.ExternalRef{
{
@@ -1567,6 +1574,7 @@ var (
ID: "winston@3.17.0",
Name: "winston",
Version: "3.17.0",
Licenses: []string{"MIT"},
Relationship: ftypes.RelationshipIndirect,
ExternalReferences: []ftypes.ExternalRef{
{
@@ -1607,6 +1615,7 @@ var (
ID: "func1@1.0.0",
Name: "func1",
Version: "1.0.0",
Licenses: []string{"ISC"},
Relationship: ftypes.RelationshipDirect,
ExternalReferences: []ftypes.ExternalRef{
{
@@ -1702,6 +1711,7 @@ var (
URL: "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
},
},
Licenses: []string{"MIT"},
Locations: []ftypes.Location{
{
StartLine: 38,
@@ -1717,6 +1727,7 @@ var (
ID: "mkdirp@0.5.1",
Name: "mkdirp",
Version: "0.5.1",
Licenses: []string{"MIT"},
Relationship: ftypes.RelationshipIndirect,
Dev: true,
Locations: []ftypes.Location{
@@ -1730,6 +1741,7 @@ var (
ID: "node-pre-gyp@0.12.0",
Name: "node-pre-gyp",
Version: "0.12.0",
Licenses: []string{"BSD-3-Clause"},
Relationship: ftypes.RelationshipIndirect,
Dev: true,
Locations: []ftypes.Location{

View File

@@ -66,10 +66,12 @@ func (a npmLibraryAnalyzer) PostAnalyze(ctx context.Context, input analyzer.Post
return nil
}
// Fill licenses
for i, lib := range app.Packages {
if ll, ok := licenses[lib.ID]; ok {
app.Packages[i].Licenses = ll
// Fill licenses from package.json only if not present in lock file
for i, pkg := range app.Packages {
if len(pkg.Licenses) == 0 {
if ll, ok := licenses[pkg.ID]; ok {
app.Packages[i].Licenses = ll
}
}
}