mirror of
https://github.com/anchore/syft.git
synced 2026-10-30 14:02:26 +01:00
209 lines
5.4 KiB
Go
209 lines
5.4 KiB
Go
package javascript
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/anchore/packageurl-go"
|
|
"github.com/anchore/syft/internal/log"
|
|
"github.com/anchore/syft/syft/pkg"
|
|
"github.com/anchore/syft/syft/source"
|
|
)
|
|
|
|
func newPackageJSONPackage(u packageJSON, locations ...source.Location) pkg.Package {
|
|
licenses, err := u.licensesFromJSON()
|
|
if err != nil {
|
|
log.Warnf("unable to extract licenses from javascript package.json: %+v", err)
|
|
}
|
|
|
|
p := pkg.Package{
|
|
Name: u.Name,
|
|
Version: u.Version,
|
|
Licenses: licenses,
|
|
PURL: packageURL(u.Name, u.Version),
|
|
Locations: source.NewLocationSet(locations...),
|
|
Language: pkg.JavaScript,
|
|
Type: pkg.NpmPkg,
|
|
MetadataType: pkg.NpmPackageJSONMetadataType,
|
|
Metadata: pkg.NpmPackageJSONMetadata{
|
|
Name: u.Name,
|
|
Version: u.Version,
|
|
Author: u.Author.AuthorString(),
|
|
Homepage: u.Homepage,
|
|
URL: u.Repository.URL,
|
|
Licenses: licenses,
|
|
Private: u.Private,
|
|
},
|
|
}
|
|
|
|
p.SetID()
|
|
|
|
return p
|
|
}
|
|
|
|
func newPackageLockV1Package(resolver source.FileResolver, location source.Location, name string, u lockDependency) pkg.Package {
|
|
version := u.Version
|
|
|
|
const aliasPrefixPackageLockV1 = "npm:"
|
|
|
|
// Handles type aliases https://github.com/npm/rfcs/blob/main/implemented/0001-package-aliases.md
|
|
if strings.HasPrefix(version, aliasPrefixPackageLockV1) {
|
|
// this is an alias.
|
|
// `"version": "npm:canonical-name@X.Y.Z"`
|
|
canonicalPackageAndVersion := version[len(aliasPrefixPackageLockV1):]
|
|
versionSeparator := strings.LastIndex(canonicalPackageAndVersion, "@")
|
|
|
|
name = canonicalPackageAndVersion[:versionSeparator]
|
|
version = canonicalPackageAndVersion[versionSeparator+1:]
|
|
}
|
|
|
|
return finalizeLockPkg(
|
|
resolver,
|
|
location,
|
|
pkg.Package{
|
|
Name: name,
|
|
Version: version,
|
|
Locations: source.NewLocationSet(location),
|
|
PURL: packageURL(name, version),
|
|
Language: pkg.JavaScript,
|
|
Type: pkg.NpmPkg,
|
|
MetadataType: pkg.NpmPackageLockJSONMetadataType,
|
|
Metadata: pkg.NpmPackageLockJSONMetadata{Resolved: u.Resolved, Integrity: u.Integrity},
|
|
},
|
|
)
|
|
}
|
|
|
|
func newPackageLockV2Package(resolver source.FileResolver, location source.Location, name string, u lockPackage) pkg.Package {
|
|
var licenses []string
|
|
|
|
if u.License != nil {
|
|
licenses = u.License
|
|
}
|
|
|
|
return finalizeLockPkg(
|
|
resolver,
|
|
location,
|
|
pkg.Package{
|
|
Name: name,
|
|
Version: u.Version,
|
|
Locations: source.NewLocationSet(location),
|
|
PURL: packageURL(name, u.Version),
|
|
Language: pkg.JavaScript,
|
|
Type: pkg.NpmPkg,
|
|
Licenses: licenses,
|
|
MetadataType: pkg.NpmPackageLockJSONMetadataType,
|
|
Metadata: pkg.NpmPackageLockJSONMetadata{Resolved: u.Resolved, Integrity: u.Integrity},
|
|
},
|
|
)
|
|
}
|
|
|
|
func newPnpmPackage(resolver source.FileResolver, location source.Location, name, version string) pkg.Package {
|
|
return finalizeLockPkg(
|
|
resolver,
|
|
location,
|
|
pkg.Package{
|
|
Name: name,
|
|
Version: version,
|
|
Locations: source.NewLocationSet(location),
|
|
PURL: packageURL(name, version),
|
|
Language: pkg.JavaScript,
|
|
Type: pkg.NpmPkg,
|
|
},
|
|
)
|
|
}
|
|
|
|
func newYarnLockPackage(resolver source.FileResolver, location source.Location, name, version string) pkg.Package {
|
|
return finalizeLockPkg(
|
|
resolver,
|
|
location,
|
|
pkg.Package{
|
|
Name: name,
|
|
Version: version,
|
|
Locations: source.NewLocationSet(location),
|
|
PURL: packageURL(name, version),
|
|
Language: pkg.JavaScript,
|
|
Type: pkg.NpmPkg,
|
|
},
|
|
)
|
|
}
|
|
|
|
func finalizeLockPkg(resolver source.FileResolver, location source.Location, p pkg.Package) pkg.Package {
|
|
p.Licenses = append(p.Licenses, addLicenses(p.Name, resolver, location)...)
|
|
p.SetID()
|
|
return p
|
|
}
|
|
|
|
func addLicenses(name string, resolver source.FileResolver, location source.Location) (allLicenses []string) {
|
|
if resolver == nil {
|
|
return allLicenses
|
|
}
|
|
dir := path.Dir(location.RealPath)
|
|
pkgPath := []string{dir, "node_modules"}
|
|
pkgPath = append(pkgPath, strings.Split(name, "/")...)
|
|
pkgPath = append(pkgPath, "package.json")
|
|
pkgFile := path.Join(pkgPath...)
|
|
locations, err := resolver.FilesByPath(pkgFile)
|
|
|
|
if err != nil {
|
|
log.Debugf("an error occurred attempting to read: %s - %+v", pkgFile, err)
|
|
return allLicenses
|
|
}
|
|
|
|
if len(locations) == 0 {
|
|
return allLicenses
|
|
}
|
|
|
|
for _, l := range locations {
|
|
contentReader, err := resolver.FileContentsByLocation(l)
|
|
if err != nil {
|
|
log.Debugf("error getting file content reader for %s: %v", pkgFile, err)
|
|
return allLicenses
|
|
}
|
|
|
|
contents, err := io.ReadAll(contentReader)
|
|
if err != nil {
|
|
log.Debugf("error reading file contents for %s: %v", pkgFile, err)
|
|
return allLicenses
|
|
}
|
|
|
|
var pkgJSON packageJSON
|
|
err = json.Unmarshal(contents, &pkgJSON)
|
|
if err != nil {
|
|
log.Debugf("error parsing %s: %v", pkgFile, err)
|
|
return allLicenses
|
|
}
|
|
|
|
licenses, err := pkgJSON.licensesFromJSON()
|
|
if err != nil {
|
|
log.Debugf("error getting licenses from %s: %v", pkgFile, err)
|
|
return allLicenses
|
|
}
|
|
|
|
allLicenses = append(allLicenses, licenses...)
|
|
}
|
|
|
|
return allLicenses
|
|
}
|
|
|
|
// packageURL returns the PURL for the specific NPM package (see https://github.com/package-url/purl-spec)
|
|
func packageURL(name, version string) string {
|
|
var namespace string
|
|
|
|
fields := strings.SplitN(name, "/", 2)
|
|
if len(fields) > 1 {
|
|
namespace = fields[0]
|
|
name = fields[1]
|
|
}
|
|
|
|
return packageurl.NewPackageURL(
|
|
packageurl.TypeNPM,
|
|
namespace,
|
|
name,
|
|
version,
|
|
nil,
|
|
"",
|
|
).ToString()
|
|
}
|