mirror of
https://github.com/anchore/syft.git
synced 2026-10-23 03:22:21 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4e985b9b0 | ||
|
|
14355aac21 | ||
|
|
e38825a0a2 | ||
|
|
5a37b4a996 | ||
|
|
56dbb342ef | ||
|
|
3267545097 | ||
|
|
7adbdfe624 | ||
|
|
f2646d0156 | ||
|
|
5b9601d9c6 | ||
|
|
80c8bc1afb | ||
|
|
d7194bb00f |
+1
-1
@@ -111,7 +111,7 @@ tools:
|
||||
# used for triggering a release
|
||||
- name: gh
|
||||
version:
|
||||
want: v2.58.0
|
||||
want: v2.59.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: cli/cli
|
||||
|
||||
@@ -148,7 +148,7 @@ jobs:
|
||||
# for updating brew formula in anchore/homebrew-syft
|
||||
GITHUB_BREW_TOKEN: ${{ secrets.ANCHOREOPS_GITHUB_OSS_WRITE_TOKEN }}
|
||||
|
||||
- uses: anchore/sbom-action@f5e124a5e5e1d497a692818ae907d3c45829d033 #v0.17.3
|
||||
- uses: anchore/sbom-action@8d0a6505bf28ced3e85154d13dc6af83299e13f1 #v0.17.4
|
||||
continue-on-error: true
|
||||
with:
|
||||
artifact-name: sbom.spdx.json
|
||||
|
||||
@@ -18,8 +18,8 @@ require (
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240507183024-848e011fc24f
|
||||
github.com/anchore/stereoscope v0.0.4
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f
|
||||
github.com/anchore/stereoscope v0.0.5-0.20241018131503-a38c93517fc7
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
||||
// we are hinting brotli to latest due to warning when installing archiver v3:
|
||||
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
|
||||
@@ -48,7 +48,7 @@ require (
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/iancoleman/strcase v0.3.0
|
||||
github.com/invopop/jsonschema v0.7.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.6.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.6.1
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
|
||||
github.com/knqyf263/go-rpmdb v0.1.1
|
||||
@@ -91,7 +91,7 @@ require google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirec
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0
|
||||
github.com/OneOfOne/xxhash v1.2.8
|
||||
github.com/adrg/xdg v0.5.0
|
||||
github.com/adrg/xdg v0.5.1
|
||||
github.com/magiconair/properties v1.8.7
|
||||
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678
|
||||
)
|
||||
|
||||
@@ -87,8 +87,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||
github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
|
||||
github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY=
|
||||
github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY=
|
||||
github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4=
|
||||
github.com/adrg/xdg v0.5.1 h1:Im8iDbEFARltY09yOJlSGu4Asjk2vF85+3Dyru8uJ0U=
|
||||
github.com/adrg/xdg v0.5.1/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
@@ -113,10 +113,10 @@ github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0v
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZVsCYMrIZBpFxwV26CbsuoEh5muXD5I1Ods=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240507183024-848e011fc24f h1:B/E9ixKNCasntpoch61NDaQyGPDXLEJlL+B9B/PbdbA=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240507183024-848e011fc24f/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
|
||||
github.com/anchore/stereoscope v0.0.4 h1:la/3dA55fX1gU8bcykgYoS0aiqZKulTgmV1CDnDTVtU=
|
||||
github.com/anchore/stereoscope v0.0.4/go.mod h1:pTHFcI/hFgBQ1R1fljEG1WMQavBRjuzgi+sZ4jotwko=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f h1:dAQPIrQ3a5PBqZeZ+B9NGZsGmodk4NO9OjDIsQmQyQM=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI=
|
||||
github.com/anchore/stereoscope v0.0.5-0.20241018131503-a38c93517fc7 h1:CBKDfuMWKRt12EnKtgT/an9FQSQI83mOU1KT57z81IU=
|
||||
github.com/anchore/stereoscope v0.0.5-0.20241018131503-a38c93517fc7/go.mod h1:wH79ZauZcd3erKPocg9+qhDC6Q/z125sD+Isi4d61a4=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
@@ -483,8 +483,8 @@ github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy77
|
||||
github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jedib0t/go-pretty/v6 v6.6.0 h1:wmZVuAcEkZRT+Aq1xXpE8IGat4vE5WXOMmBpbQqERXw=
|
||||
github.com/jedib0t/go-pretty/v6 v6.6.0/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
|
||||
github.com/jedib0t/go-pretty/v6 v6.6.1 h1:iJ65Xjb680rHcikRj6DSIbzCex2huitmc7bDtxYVWyc=
|
||||
github.com/jedib0t/go-pretty/v6 v6.6.1/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
|
||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package licenses
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type licenseScannerKey struct{}
|
||||
|
||||
func SetContextLicenseScanner(ctx context.Context, s Scanner) context.Context {
|
||||
return context.WithValue(ctx, licenseScannerKey{}, s)
|
||||
}
|
||||
|
||||
func ContextLicenseScanner(ctx context.Context) Scanner {
|
||||
if s, ok := ctx.Value(licenseScannerKey{}).(Scanner); ok {
|
||||
return s
|
||||
}
|
||||
return NewDefaultScanner()
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package licenses
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/google/licensecheck"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/license"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
const (
|
||||
coverageThreshold = 75
|
||||
unknownLicenseType = "UNKNOWN"
|
||||
)
|
||||
|
||||
// Parse scans the contents of a license file to attempt to determine the type of license it is
|
||||
func Parse(reader io.Reader, l file.Location) (licenses []pkg.License, err error) {
|
||||
licenses = make([]pkg.License, 0)
|
||||
contents, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scanner, err := licensecheck.NewScanner(licensecheck.BuiltinLicenses())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cov := scanner.Scan(contents)
|
||||
if cov.Percent < coverageThreshold {
|
||||
// unknown or no licenses here?
|
||||
return licenses, nil
|
||||
}
|
||||
|
||||
for _, m := range cov.Match {
|
||||
lic := pkg.NewLicenseFromLocations(m.ID, l)
|
||||
lic.Type = license.Concluded
|
||||
|
||||
licenses = append(licenses, lic)
|
||||
}
|
||||
|
||||
return licenses, nil
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package licenses
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/google/licensecheck"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
)
|
||||
|
||||
const coverageThreshold = 75 // determined by experimentation
|
||||
|
||||
type Scanner interface {
|
||||
IdentifyLicenseIDs(context.Context, io.Reader) ([]string, error)
|
||||
}
|
||||
|
||||
var _ Scanner = (*scanner)(nil)
|
||||
|
||||
type scanner struct {
|
||||
coverageThreshold float64 // between 0 and 100
|
||||
scanner func([]byte) licensecheck.Coverage
|
||||
}
|
||||
|
||||
// NewDefaultScanner returns a scanner that uses a new instance of the default licensecheck package scanner.
|
||||
func NewDefaultScanner() Scanner {
|
||||
s, err := licensecheck.NewScanner(licensecheck.BuiltinLicenses())
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Trace("unable to create default license scanner")
|
||||
s = nil
|
||||
}
|
||||
return &scanner{
|
||||
coverageThreshold: coverageThreshold,
|
||||
scanner: s.Scan,
|
||||
}
|
||||
}
|
||||
|
||||
// TestingOnlyScanner returns a scanner that uses the built-in license scanner from the licensecheck package.
|
||||
// THIS IS ONLY MEANT FOR TEST CODE, NOT PRODUCTION CODE.
|
||||
func TestingOnlyScanner() Scanner {
|
||||
return &scanner{
|
||||
coverageThreshold: coverageThreshold,
|
||||
scanner: licensecheck.Scan,
|
||||
}
|
||||
}
|
||||
|
||||
func (s scanner) IdentifyLicenseIDs(_ context.Context, reader io.Reader) ([]string, error) {
|
||||
if s.scanner == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
content, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cov := s.scanner(content)
|
||||
if cov.Percent < s.coverageThreshold {
|
||||
// unknown or no licenses here?
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var ids []string
|
||||
for _, m := range cov.Match {
|
||||
ids = append(ids, m.ID)
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package licenses
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/license"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
// Search scans the contents of a license file to attempt to determine the type of license it is
|
||||
func Search(ctx context.Context, scanner Scanner, reader file.LocationReadCloser) (licenses []pkg.License, err error) {
|
||||
licenses = make([]pkg.License, 0)
|
||||
|
||||
ids, err := scanner.IdentifyLicenseIDs(ctx, reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
lic := pkg.NewLicenseFromLocations(id, reader.Location)
|
||||
lic.Type = license.Concluded
|
||||
|
||||
licenses = append(licenses, lic)
|
||||
}
|
||||
|
||||
return licenses, nil
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/internal/sbomsync"
|
||||
"github.com/anchore/syft/internal/task"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
@@ -60,6 +61,9 @@ func CreateSBOM(ctx context.Context, src source.Source, cfg *CreateSBOMConfig) (
|
||||
},
|
||||
}
|
||||
|
||||
// inject a single license scanner for all package cataloging tasks into context
|
||||
ctx = licenses.SetContextLicenseScanner(ctx, licenses.NewDefaultScanner())
|
||||
|
||||
catalogingProgress := monitorCatalogingTask(src.ID(), taskGroups)
|
||||
packageCatalogingProgress := monitorPackageCatalogingTask()
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ func Test_PackageURL(t *testing.T) {
|
||||
ID: "alpine",
|
||||
VersionID: "3.4.6",
|
||||
},
|
||||
expected: "pkg:apk/alpine/p@v?arch=a&upstream=origin&distro=alpine-3.4.6",
|
||||
expected: "pkg:apk/alpine/p@v?arch=a&distro=alpine-3.4.6&upstream=origin",
|
||||
},
|
||||
{
|
||||
name: "wolfi distro",
|
||||
|
||||
@@ -108,7 +108,7 @@ func Test_PackageURL(t *testing.T) {
|
||||
ID: "arch",
|
||||
BuildID: "rolling",
|
||||
},
|
||||
expected: "pkg:alpm/arch/p@v?arch=a&upstream=origin&distro=arch-rolling",
|
||||
expected: "pkg:alpm/arch/p@v?arch=a&distro=arch-rolling&upstream=origin",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ func DefaultClassifiers() []Classifier {
|
||||
},
|
||||
{
|
||||
Class: "mariadb-binary",
|
||||
FileGlob: "**/mariadb",
|
||||
FileGlob: "**/{mariadb,mysql}",
|
||||
EvidenceMatcher: FileContentsVersionMatcher(
|
||||
// 10.6.15-MariaDB
|
||||
`(?m)(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)-MariaDB`),
|
||||
|
||||
@@ -81,7 +81,7 @@ func Test_packageURL(t *testing.T) {
|
||||
Source: "s",
|
||||
Version: "v",
|
||||
},
|
||||
expected: "pkg:deb/debian/p@v?upstream=s&distro=debian-11",
|
||||
expected: "pkg:deb/debian/p@v?distro=debian-11&upstream=s",
|
||||
},
|
||||
{
|
||||
name: "with upstream qualifier with source pkg name and version info",
|
||||
@@ -98,7 +98,7 @@ func Test_packageURL(t *testing.T) {
|
||||
Version: "v",
|
||||
SourceVersion: "2.3",
|
||||
},
|
||||
expected: "pkg:deb/debian/p@v?upstream=s%402.3&distro=debian-11",
|
||||
expected: "pkg:deb/debian/p@v?distro=debian-11&upstream=s%402.3",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ func (c *Cataloger) Catalog(ctx context.Context, resolver file.Resolver) ([]pkg.
|
||||
var relationships []artifact.Relationship
|
||||
var errs error
|
||||
|
||||
logger := log.Nested("cataloger", c.upstreamCataloger)
|
||||
lgr := log.Nested("cataloger", c.upstreamCataloger)
|
||||
|
||||
env := Environment{
|
||||
// TODO: consider passing into the cataloger, this would affect the cataloger interface (and all implementations). This can be deferred until later.
|
||||
@@ -166,7 +166,7 @@ func (c *Cataloger) Catalog(ctx context.Context, resolver file.Resolver) ([]pkg.
|
||||
|
||||
log.WithFields("path", location.RealPath).Trace("parsing file contents")
|
||||
|
||||
discoveredPackages, discoveredRelationships, err := invokeParser(ctx, resolver, location, logger, parser, &env)
|
||||
discoveredPackages, discoveredRelationships, err := invokeParser(ctx, resolver, location, lgr, parser, &env)
|
||||
if err != nil {
|
||||
// parsers may return errors and valid packages / relationships
|
||||
errs = unknown.Append(errs, location, err)
|
||||
|
||||
@@ -3,6 +3,7 @@ package golang
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
@@ -79,9 +80,9 @@ func remotesForModule(proxies []string, noProxy []string, module string) []strin
|
||||
return proxies
|
||||
}
|
||||
|
||||
func (c *goLicenseResolver) getLicenses(resolver file.Resolver, moduleName, moduleVersion string) ([]pkg.License, error) {
|
||||
func (c *goLicenseResolver) getLicenses(ctx context.Context, scanner licenses.Scanner, resolver file.Resolver, moduleName, moduleVersion string) ([]pkg.License, error) {
|
||||
// search the scan target first, ignoring local and remote sources
|
||||
goLicenses, err := c.findLicensesInSource(resolver,
|
||||
goLicenses, err := c.findLicensesInSource(ctx, scanner, resolver,
|
||||
fmt.Sprintf(`**/go/pkg/mod/%s@%s/*`, processCaps(moduleName), moduleVersion),
|
||||
)
|
||||
if err != nil || len(goLicenses) > 0 {
|
||||
@@ -90,7 +91,7 @@ func (c *goLicenseResolver) getLicenses(resolver file.Resolver, moduleName, modu
|
||||
|
||||
// look in the local host mod directory...
|
||||
if c.opts.SearchLocalModCacheLicenses {
|
||||
goLicenses, err = c.getLicensesFromLocal(moduleName, moduleVersion)
|
||||
goLicenses, err = c.getLicensesFromLocal(ctx, scanner, moduleName, moduleVersion)
|
||||
if err != nil || len(goLicenses) > 0 {
|
||||
return toPkgLicenses(goLicenses), err
|
||||
}
|
||||
@@ -98,13 +99,13 @@ func (c *goLicenseResolver) getLicenses(resolver file.Resolver, moduleName, modu
|
||||
|
||||
// download from remote sources
|
||||
if c.opts.SearchRemoteLicenses {
|
||||
goLicenses, err = c.getLicensesFromRemote(moduleName, moduleVersion)
|
||||
goLicenses, err = c.getLicensesFromRemote(ctx, scanner, moduleName, moduleVersion)
|
||||
}
|
||||
|
||||
return toPkgLicenses(goLicenses), err
|
||||
}
|
||||
|
||||
func (c *goLicenseResolver) getLicensesFromLocal(moduleName, moduleVersion string) ([]goLicense, error) {
|
||||
func (c *goLicenseResolver) getLicensesFromLocal(ctx context.Context, scanner licenses.Scanner, moduleName, moduleVersion string) ([]goLicense, error) {
|
||||
if c.localModCacheDir == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -120,10 +121,10 @@ func (c *goLicenseResolver) getLicensesFromLocal(moduleName, moduleVersion strin
|
||||
// if we're running against a directory on the filesystem, it may not include the
|
||||
// user's homedir / GOPATH, so we defer to using the localModCacheResolver
|
||||
// we use $GOPATH/pkg/mod to avoid leaking information about the user's system
|
||||
return c.findLicensesInFS("file://$GOPATH/pkg/mod/"+subdir+"/", dir)
|
||||
return c.findLicensesInFS(ctx, scanner, "file://$GOPATH/pkg/mod/"+subdir+"/", dir)
|
||||
}
|
||||
|
||||
func (c *goLicenseResolver) getLicensesFromRemote(moduleName, moduleVersion string) ([]goLicense, error) {
|
||||
func (c *goLicenseResolver) getLicensesFromRemote(ctx context.Context, scanner licenses.Scanner, moduleName, moduleVersion string) ([]goLicense, error) {
|
||||
return c.licenseCache.Resolve(fmt.Sprintf("%s/%s", moduleName, moduleVersion), func() ([]goLicense, error) {
|
||||
proxies := remotesForModule(c.opts.Proxies, c.opts.NoProxy, moduleName)
|
||||
|
||||
@@ -132,11 +133,11 @@ func (c *goLicenseResolver) getLicensesFromRemote(moduleName, moduleVersion stri
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.findLicensesInFS(urlPrefix, fsys)
|
||||
return c.findLicensesInFS(ctx, scanner, urlPrefix, fsys)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *goLicenseResolver) findLicensesInFS(urlPrefix string, fsys fs.FS) ([]goLicense, error) {
|
||||
func (c *goLicenseResolver) findLicensesInFS(ctx context.Context, scanner licenses.Scanner, urlPrefix string, fsys fs.FS) ([]goLicense, error) {
|
||||
var out []goLicense
|
||||
err := fs.WalkDir(fsys, ".", func(filePath string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
@@ -156,7 +157,8 @@ func (c *goLicenseResolver) findLicensesInFS(urlPrefix string, fsys fs.FS) ([]go
|
||||
return nil
|
||||
}
|
||||
defer internal.CloseAndLogError(rdr, filePath)
|
||||
parsed, err := licenses.Parse(rdr, file.NewLocation(filePath))
|
||||
|
||||
parsed, err := licenses.Search(ctx, scanner, file.NewLocationReadCloser(file.NewLocation(filePath), rdr))
|
||||
if err != nil {
|
||||
log.Debugf("error parsing license file %s: %v", filePath, err)
|
||||
return nil
|
||||
@@ -174,7 +176,7 @@ func (c *goLicenseResolver) findLicensesInFS(urlPrefix string, fsys fs.FS) ([]go
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *goLicenseResolver) findLicensesInSource(resolver file.Resolver, globMatch string) ([]goLicense, error) {
|
||||
func (c *goLicenseResolver) findLicensesInSource(ctx context.Context, scanner licenses.Scanner, resolver file.Resolver, globMatch string) ([]goLicense, error) {
|
||||
var out []goLicense
|
||||
locations, err := resolver.FilesByGlob(globMatch)
|
||||
if err != nil {
|
||||
@@ -182,7 +184,7 @@ func (c *goLicenseResolver) findLicensesInSource(resolver file.Resolver, globMat
|
||||
}
|
||||
|
||||
for _, l := range locations {
|
||||
parsed, err := c.parseLicenseFromLocation(l, resolver)
|
||||
parsed, err := c.parseLicenseFromLocation(ctx, scanner, l, resolver)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -200,7 +202,7 @@ func (c *goLicenseResolver) findLicensesInSource(resolver file.Resolver, globMat
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *goLicenseResolver) parseLicenseFromLocation(l file.Location, resolver file.Resolver) ([]goLicense, error) {
|
||||
func (c *goLicenseResolver) parseLicenseFromLocation(ctx context.Context, scanner licenses.Scanner, l file.Location, resolver file.Resolver) ([]goLicense, error) {
|
||||
var out []goLicense
|
||||
fileName := path.Base(l.RealPath)
|
||||
if c.lowerLicenseFileNames.Has(strings.ToLower(fileName)) {
|
||||
@@ -209,7 +211,7 @@ func (c *goLicenseResolver) parseLicenseFromLocation(l file.Location, resolver f
|
||||
return nil, err
|
||||
}
|
||||
defer internal.CloseAndLogError(contents, l.RealPath)
|
||||
parsed, err := licenses.Parse(contents, l)
|
||||
parsed, err := licenses.Search(ctx, scanner, file.NewLocationReadCloser(l, contents))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package golang
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/internal/fileresolver"
|
||||
"github.com/anchore/syft/syft/license"
|
||||
@@ -26,6 +28,8 @@ func Test_LocalLicenseSearch(t *testing.T) {
|
||||
loc2 := file.NewLocation("github.com/!cap!o!r!g/!cap!project@v4.111.5/LICENSE.txt")
|
||||
loc3 := file.NewLocation("github.com/someorg/strangelicense@v1.2.3/LiCeNsE.tXt")
|
||||
|
||||
licenseScanner := licenses.TestingOnlyScanner()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
version string
|
||||
@@ -78,12 +82,12 @@ func Test_LocalLicenseSearch(t *testing.T) {
|
||||
LocalModCacheDir: filepath.Join(wd, "test-fixtures", "licenses", "pkg", "mod"),
|
||||
},
|
||||
)
|
||||
licenses, err := l.getLicenses(fileresolver.Empty{}, test.name, test.version)
|
||||
lics, err := l.getLicenses(context.Background(), licenseScanner, fileresolver.Empty{}, test.name, test.version)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, licenses, 1)
|
||||
require.Len(t, lics, 1)
|
||||
|
||||
require.Equal(t, test.expected, licenses[0])
|
||||
require.Equal(t, test.expected, lics[0])
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -92,6 +96,8 @@ func Test_RemoteProxyLicenseSearch(t *testing.T) {
|
||||
loc1 := file.NewLocation("github.com/someorg/somename@v0.3.2/LICENSE")
|
||||
loc2 := file.NewLocation("github.com/!cap!o!r!g/!cap!project@v4.111.5/LICENSE.txt")
|
||||
|
||||
licenseScanner := licenses.TestingOnlyScanner()
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
buf := &bytes.Buffer{}
|
||||
uri := strings.TrimPrefix(strings.TrimSuffix(r.RequestURI, ".zip"), "/")
|
||||
@@ -169,12 +175,12 @@ func Test_RemoteProxyLicenseSearch(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
licenses, err := l.getLicenses(fileresolver.Empty{}, test.name, test.version)
|
||||
lics, err := l.getLicenses(context.Background(), licenseScanner, fileresolver.Empty{}, test.name, test.version)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, licenses, 1)
|
||||
require.Len(t, lics, 1)
|
||||
|
||||
require.Equal(t, test.expected, licenses[0])
|
||||
require.Equal(t, test.expected, lics[0])
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -248,7 +254,7 @@ func Test_findVersionPath(t *testing.T) {
|
||||
|
||||
func Test_walkDirErrors(t *testing.T) {
|
||||
resolver := newGoLicenseResolver("", CatalogerConfig{})
|
||||
_, err := resolver.findLicensesInFS("somewhere", badFS{})
|
||||
_, err := resolver.findLicensesInFS(context.Background(), licenses.TestingOnlyScanner(), "somewhere", badFS{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -266,6 +272,8 @@ func Test_noLocalGoModDir(t *testing.T) {
|
||||
validTmp := t.TempDir()
|
||||
require.NoError(t, os.MkdirAll(filepath.Join(validTmp, "mod@ver"), 0700|os.ModeDir))
|
||||
|
||||
licenseScanner := licenses.TestingOnlyScanner()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
dir string
|
||||
@@ -299,7 +307,7 @@ func Test_noLocalGoModDir(t *testing.T) {
|
||||
SearchLocalModCacheLicenses: true,
|
||||
LocalModCacheDir: test.dir,
|
||||
})
|
||||
_, err := resolver.getLicensesFromLocal("mod", "ver")
|
||||
_, err := resolver.getLicensesFromLocal(context.Background(), licenseScanner, "mod", "ver")
|
||||
test.wantErr(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,21 +5,15 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func (c *goBinaryCataloger) newGoBinaryPackage(resolver file.Resolver, dep *debug.Module, mainModule, goVersion, architecture string, buildSettings pkg.KeyValues, cryptoSettings, experiments []string, locations ...file.Location) pkg.Package {
|
||||
func (c *goBinaryCataloger) newGoBinaryPackage(dep *debug.Module, mainModule, goVersion, architecture string, buildSettings pkg.KeyValues, cryptoSettings, experiments []string, licenses []pkg.License, locations ...file.Location) pkg.Package {
|
||||
if dep.Replace != nil {
|
||||
dep = dep.Replace
|
||||
}
|
||||
|
||||
licenses, err := c.licenseResolver.getLicenses(resolver, dep.Path, dep.Version)
|
||||
if err != nil {
|
||||
log.Tracef("error getting licenses for golang package: %s %v", dep.Path, err)
|
||||
}
|
||||
|
||||
p := pkg.Package{
|
||||
Name: dep.Path,
|
||||
Version: dep.Version,
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"golang.org/x/mod/module"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
@@ -59,9 +60,11 @@ func newGoBinaryCataloger(opts CatalogerConfig) *goBinaryCataloger {
|
||||
}
|
||||
|
||||
// parseGoBinary catalogs packages found in the "buildinfo" section of a binary built by the go compiler.
|
||||
func (c *goBinaryCataloger) parseGoBinary(_ context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
func (c *goBinaryCataloger) parseGoBinary(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
var pkgs []pkg.Package
|
||||
|
||||
licenseScanner := licenses.ContextLicenseScanner(ctx)
|
||||
|
||||
unionReader, err := unionreader.GetUnionReader(reader.ReadCloser)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -73,7 +76,7 @@ func (c *goBinaryCataloger) parseGoBinary(_ context.Context, resolver file.Resol
|
||||
var rels []artifact.Relationship
|
||||
for _, mod := range mods {
|
||||
var depPkgs []pkg.Package
|
||||
mainPkg, depPkgs := c.buildGoPkgInfo(resolver, reader.Location, mod, mod.arch, unionReader)
|
||||
mainPkg, depPkgs := c.buildGoPkgInfo(ctx, licenseScanner, resolver, reader.Location, mod, mod.arch, unionReader)
|
||||
if mainPkg != nil {
|
||||
rels = createModuleRelationships(*mainPkg, depPkgs)
|
||||
pkgs = append(pkgs, *mainPkg)
|
||||
@@ -101,7 +104,7 @@ func createModuleRelationships(main pkg.Package, deps []pkg.Package) []artifact.
|
||||
var emptyModule debug.Module
|
||||
var moduleFromPartialPackageBuild = debug.Module{Path: "command-line-arguments"}
|
||||
|
||||
func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file.Location, mod *extendedBuildInfo, arch string, reader io.ReadSeekCloser) (*pkg.Package, []pkg.Package) {
|
||||
func (c *goBinaryCataloger) buildGoPkgInfo(ctx context.Context, licenseScanner licenses.Scanner, resolver file.Resolver, location file.Location, mod *extendedBuildInfo, arch string, reader io.ReadSeekCloser) (*pkg.Package, []pkg.Package) {
|
||||
if mod == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -116,9 +119,13 @@ func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file
|
||||
continue
|
||||
}
|
||||
|
||||
lics, err := c.licenseResolver.getLicenses(ctx, licenseScanner, resolver, dep.Path, dep.Version)
|
||||
if err != nil {
|
||||
log.Tracef("error getting licenses for golang package: %s %v", dep.Path, err)
|
||||
}
|
||||
|
||||
gover, experiments := getExperimentsFromVersion(mod.GoVersion)
|
||||
p := c.newGoBinaryPackage(
|
||||
resolver,
|
||||
dep,
|
||||
mod.Main.Path,
|
||||
gover,
|
||||
@@ -126,6 +133,7 @@ func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file
|
||||
nil,
|
||||
mod.cryptoSettings,
|
||||
experiments,
|
||||
lics,
|
||||
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
if pkg.IsValid(&p) {
|
||||
@@ -137,7 +145,7 @@ func (c *goBinaryCataloger) buildGoPkgInfo(resolver file.Resolver, location file
|
||||
return nil, pkgs
|
||||
}
|
||||
|
||||
main := c.makeGoMainPackage(resolver, mod, arch, location, reader)
|
||||
main := c.makeGoMainPackage(ctx, licenseScanner, resolver, mod, arch, location, reader)
|
||||
|
||||
return &main, pkgs
|
||||
}
|
||||
@@ -152,11 +160,16 @@ func missingMainModule(mod *extendedBuildInfo) bool {
|
||||
return mod.Main == moduleFromPartialPackageBuild
|
||||
}
|
||||
|
||||
func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *extendedBuildInfo, arch string, location file.Location, reader io.ReadSeekCloser) pkg.Package {
|
||||
func (c *goBinaryCataloger) makeGoMainPackage(ctx context.Context, licenseScanner licenses.Scanner, resolver file.Resolver, mod *extendedBuildInfo, arch string, location file.Location, reader io.ReadSeekCloser) pkg.Package {
|
||||
gbs := getBuildSettings(mod.Settings)
|
||||
|
||||
lics, err := c.licenseResolver.getLicenses(ctx, licenseScanner, resolver, mod.Main.Path, mod.Main.Version)
|
||||
if err != nil {
|
||||
log.Tracef("error getting licenses for golang package: %s %v", mod.Main.Path, err)
|
||||
}
|
||||
|
||||
gover, experiments := getExperimentsFromVersion(mod.GoVersion)
|
||||
main := c.newGoBinaryPackage(
|
||||
resolver,
|
||||
&mod.Main,
|
||||
mod.Main.Path,
|
||||
gover,
|
||||
@@ -164,6 +177,7 @@ func (c *goBinaryCataloger) makeGoMainPackage(resolver file.Resolver, mod *exten
|
||||
gbs,
|
||||
mod.cryptoSettings,
|
||||
experiments,
|
||||
lics,
|
||||
location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package golang
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
@@ -17,6 +18,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/internal/fileresolver"
|
||||
"github.com/anchore/syft/syft/internal/unionreader"
|
||||
@@ -167,6 +169,8 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
licenseScanner := licenses.TestingOnlyScanner()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
mod *extendedBuildInfo
|
||||
@@ -1053,7 +1057,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
c := newGoBinaryCataloger(DefaultCatalogerConfig())
|
||||
reader, err := unionreader.GetUnionReader(io.NopCloser(strings.NewReader(test.binaryContent)))
|
||||
require.NoError(t, err)
|
||||
mainPkg, pkgs := c.buildGoPkgInfo(fileresolver.Empty{}, location, test.mod, test.mod.arch, reader)
|
||||
mainPkg, pkgs := c.buildGoPkgInfo(context.Background(), licenseScanner, fileresolver.Empty{}, location, test.mod, test.mod.arch, reader)
|
||||
if mainPkg != nil {
|
||||
pkgs = append(pkgs, *mainPkg)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"golang.org/x/mod/modfile"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
@@ -31,9 +32,11 @@ func newGoModCataloger(opts CatalogerConfig) *goModCataloger {
|
||||
// parseGoModFile takes a go.mod and lists all packages discovered.
|
||||
//
|
||||
//nolint:funlen
|
||||
func (c *goModCataloger) parseGoModFile(_ context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
func (c *goModCataloger) parseGoModFile(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
packages := make(map[string]pkg.Package)
|
||||
|
||||
licenseScanner := licenses.ContextLicenseScanner(ctx)
|
||||
|
||||
contents, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to read go module: %w", err)
|
||||
@@ -50,7 +53,7 @@ func (c *goModCataloger) parseGoModFile(_ context.Context, resolver file.Resolve
|
||||
}
|
||||
|
||||
for _, m := range f.Require {
|
||||
licenses, err := c.licenseResolver.getLicenses(resolver, m.Mod.Path, m.Mod.Version)
|
||||
lics, err := c.licenseResolver.getLicenses(ctx, licenseScanner, resolver, m.Mod.Path, m.Mod.Version)
|
||||
if err != nil {
|
||||
log.Tracef("error getting licenses for package: %s %v", m.Mod.Path, err)
|
||||
}
|
||||
@@ -58,7 +61,7 @@ func (c *goModCataloger) parseGoModFile(_ context.Context, resolver file.Resolve
|
||||
packages[m.Mod.Path] = pkg.Package{
|
||||
Name: m.Mod.Path,
|
||||
Version: m.Mod.Version,
|
||||
Licenses: pkg.NewLicenseSet(licenses...),
|
||||
Licenses: pkg.NewLicenseSet(lics...),
|
||||
Locations: file.NewLocationSet(reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(m.Mod.Path, m.Mod.Version),
|
||||
Language: pkg.Go,
|
||||
@@ -71,7 +74,7 @@ func (c *goModCataloger) parseGoModFile(_ context.Context, resolver file.Resolve
|
||||
|
||||
// remove any old packages and replace with new ones...
|
||||
for _, m := range f.Replace {
|
||||
licenses, err := c.licenseResolver.getLicenses(resolver, m.New.Path, m.New.Version)
|
||||
lics, err := c.licenseResolver.getLicenses(ctx, licenseScanner, resolver, m.New.Path, m.New.Version)
|
||||
if err != nil {
|
||||
log.Tracef("error getting licenses for package: %s %v", m.New.Path, err)
|
||||
}
|
||||
@@ -83,7 +86,7 @@ func (c *goModCataloger) parseGoModFile(_ context.Context, resolver file.Resolve
|
||||
packages[m.New.Path] = pkg.Package{
|
||||
Name: m.New.Path,
|
||||
Version: m.New.Version,
|
||||
Licenses: pkg.NewLicenseSet(licenses...),
|
||||
Licenses: pkg.NewLicenseSet(lics...),
|
||||
Locations: file.NewLocationSet(reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(m.New.Path, m.New.Version),
|
||||
Language: pkg.Go,
|
||||
|
||||
@@ -100,6 +100,9 @@
|
||||
"github.com/sap/cloud-security-client-go": [
|
||||
"cpe:2.3:a:sap:cloud-security-client-go:*:*:*:*:*:go:*:*"
|
||||
],
|
||||
"github.com/satori/go.uuid": [
|
||||
"cpe:2.3:a:satori:uuid:*:*:*:*:*:go:*:*"
|
||||
],
|
||||
"github.com/sigstore/gitsign": [
|
||||
"cpe:2.3:a:sigstore:gitsign:*:*:*:*:*:go:*:*"
|
||||
],
|
||||
@@ -2934,7 +2937,7 @@
|
||||
"cpe:2.3:a:electron-packager_project:electron-packager:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"elliptic": [
|
||||
"cpe:2.3:a:elliptic_project:elliptic:*:*:*:*:*:node.js:*:*"
|
||||
"cpe:2.3:a:indutny:elliptic:*:*:*:*:*:node.js:*:*"
|
||||
],
|
||||
"embedza": [
|
||||
"cpe:2.3:a:embedza_project:embedza:*:*:*:*:*:node.js:*:*"
|
||||
@@ -5691,6 +5694,9 @@
|
||||
"jw.util": [
|
||||
"cpe:2.3:a:python:jw.util:*:*:*:*:*:python:*:*"
|
||||
],
|
||||
"jwcrypto": [
|
||||
"cpe:2.3:a:latchset:jwcrypto:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
"keep": [
|
||||
"cpe:2.3:a:keep_project:keep:*:*:*:*:*:*:*:*"
|
||||
],
|
||||
@@ -8185,6 +8191,9 @@
|
||||
"blogger-importer": [
|
||||
"cpe:2.3:a:wordpress:blogger_importer:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"blogintroduction-wordpress-plugin": [
|
||||
"cpe:2.3:a:kimhuebel:blog_introduction:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"blogmentor": [
|
||||
"cpe:2.3:a:auburnforest:blogmentor:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -9352,6 +9361,9 @@
|
||||
"cssable-countdown": [
|
||||
"cpe:2.3:a:dmonnier:cssable_countdown:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"cssjockey-add-ons": [
|
||||
"cpe:2.3:a:cssjockey:wp_builder:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"csv-import-export": [
|
||||
"cpe:2.3:a:csv-import-export_project:csv-import-export:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -9374,6 +9386,9 @@
|
||||
"cube-slider": [
|
||||
"cpe:2.3:a:webpsilon:cube_slider:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"curatorio": [
|
||||
"cpe:2.3:a:curator:curator.io:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"currency-converter-calculator": [
|
||||
"cpe:2.3:a:currencyratetoday:currency_converter_calculator:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -10122,11 +10137,14 @@
|
||||
"cpe:2.3:a:elementor:elementor_page_builder:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:elementor:elementor_page_builder:*:*:*:*:pro:wordpress:*:*",
|
||||
"cpe:2.3:a:elementor:page_builder:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:elementor:website_builder:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:elementor:website_builder:*:*:*:*:free:wordpress:*:*"
|
||||
],
|
||||
"elementor-pro": [
|
||||
"cpe:2.3:a:elementor:elementor_pro:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"elementskit": [
|
||||
"cpe:2.3:a:wpmet:elementskit:*:*:*:*:pro:wordpress:*:*"
|
||||
],
|
||||
"elementskit-lite": [
|
||||
"cpe:2.3:a:wpmet:elements_kit_elementor_addons:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:wpmet:elementskit_elementor_addons:*:*:*:*:*:wordpress:*:*"
|
||||
@@ -10338,7 +10356,8 @@
|
||||
"cpe:2.3:a:eventify_project:eventify:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"eventon-lite": [
|
||||
"cpe:2.3:a:myeventon:eventon-lite:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:myeventon:eventon-lite:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:myeventon:eventon:*:*:*:*:lite:wordpress:*:*"
|
||||
],
|
||||
"eventprime-event-calendar-management": [
|
||||
"cpe:2.3:a:metagauss:eventprime:*:*:*:*:*:wordpress:*:*"
|
||||
@@ -10692,6 +10711,9 @@
|
||||
"cpe:2.3:a:floating_social_bar_project:floating_social_bar:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:wpbeginner:floating_social_bar:*:*:*:*:wordpress:*:*:*"
|
||||
],
|
||||
"floating-social-buttons": [
|
||||
"cpe:2.3:a:click2check:floating_social_buttons:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"floating-social-media-icon": [
|
||||
"cpe:2.3:a:acurax:floating_social_media_icon:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -10756,10 +10778,11 @@
|
||||
"cpe:2.3:a:fivestarplugins:five_star_restaurant_menu:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"foogallery": [
|
||||
"cpe:2.3:a:fooplugins:foogallery:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:fooplugins:foogallery:*:*:*:*:-:wordpress:*:*",
|
||||
"cpe:2.3:a:fooplugins:foogallery:*:*:*:*:premium:wordpress:*:*"
|
||||
],
|
||||
"foogallery-premium": [
|
||||
"cpe:2.3:a:fooplugins:foogallery:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:fooplugins:foogallery:*:*:*:*:-:wordpress:*:*"
|
||||
],
|
||||
"football-leagues-by-anwppro": [
|
||||
"cpe:2.3:a:anwp:football_leagues:*:*:*:*:free:wordpress:*:*",
|
||||
@@ -11754,6 +11777,9 @@
|
||||
"inline-google-spreadsheet-viewer": [
|
||||
"cpe:2.3:a:inline_google_spreadsheet_viewer_project:inline_google_spreadsheet_viewer:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"inline-svg-elementor": [
|
||||
"cpe:2.3:a:namogo:elementor_inline_svg:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"inline-tweet-sharer": [
|
||||
"cpe:2.3:a:winwar:inline_tweet_sharer:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -12481,6 +12507,7 @@
|
||||
"cpe:2.3:a:mailcwp_project:mailcwp:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"mailin": [
|
||||
"cpe:2.3:a:brevo:newsletter\\,_smtp\\,_email_marketing_and_subscribe:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:sendinblue:newsletter\\,_smtp\\,_email_marketing_and_subscribe:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"mailmunch": [
|
||||
@@ -12611,6 +12638,9 @@
|
||||
"maxbuttons": [
|
||||
"cpe:2.3:a:maxfoundry:maxbuttons:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"maximum-products-per-user-for-woocommerce": [
|
||||
"cpe:2.3:a:wpfactory:maximum_products_per_user_for_woocommerce:*:*:*:*:free:wordpress:*:*"
|
||||
],
|
||||
"maz-loader": [
|
||||
"cpe:2.3:a:feataholic:maz_loader:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -13116,6 +13146,9 @@
|
||||
"new-image-gallery": [
|
||||
"cpe:2.3:a:awplife:image_gallery:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"new-order-notification-for-woocommerce": [
|
||||
"cpe:2.3:a:mrebabi:new_order_notification_for_woocommerce:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"new-user-approve": [
|
||||
"cpe:2.3:a:wpexperts:new_user_approve:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -13232,6 +13265,9 @@
|
||||
"notification": [
|
||||
"cpe:2.3:a:bracketspace:notification:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"notification-for-telegram": [
|
||||
"cpe:2.3:a:andreamarinucci:notification_for_telegram:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"notificationx": [
|
||||
"cpe:2.3:a:wpdeveloper:notificationx:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -13794,7 +13830,8 @@
|
||||
"cpe:2.3:a:ays-pro:poll_maker:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"poll-wp": [
|
||||
"cpe:2.3:a:total-soft:responsive_poll:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:total-soft:responsive_poll:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:total-soft:ts_poll:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"polldaddy": [
|
||||
"cpe:2.3:a:automattic:crowdsignal_dashboard:*:*:*:*:*:wordpress:*:*"
|
||||
@@ -14081,6 +14118,9 @@
|
||||
"process-steps-template-designer": [
|
||||
"cpe:2.3:a:coolplugins:process_steps_template_designer:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"product-blocks": [
|
||||
"cpe:2.3:a:wpxpo:wowstore:*:*:*:*:free:wordpress:*:*"
|
||||
],
|
||||
"product-carousel-slider-for-woocommerce": [
|
||||
"cpe:2.3:a:aazztech:woocommerce_product_carousel_slider:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -14191,6 +14231,9 @@
|
||||
"q2w3-post-order": [
|
||||
"cpe:2.3:a:q2w3:q2w3_post_order:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"qa-heatmap-analytics": [
|
||||
"cpe:2.3:a:quarka:qa_analytics:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"qi-addons-for-elementor": [
|
||||
"cpe:2.3:a:qodeinteractive:qi_addons_for_elementor:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -15535,6 +15578,9 @@
|
||||
"social-buttons-pack": [
|
||||
"cpe:2.3:a:bestwebsoft:social_buttons_pack:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"social-icons-widget-by-wpzoom": [
|
||||
"cpe:2.3:a:wpzoom:social_icons_widget:*:*:*:*:free:wordpress:*:*"
|
||||
],
|
||||
"social-locker": [
|
||||
"cpe:2.3:a:byonepress:social_locker:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -16136,6 +16182,9 @@
|
||||
"thumbs-rating": [
|
||||
"cpe:2.3:a:quicoto:thumbs_rating:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"ti-woocommerce-wishlist": [
|
||||
"cpe:2.3:a:templateinvaders:ti_woocommerce_wishlist:*:*:*:*:free:wordpress:*:*"
|
||||
],
|
||||
"tickera-event-ticketing-system": [
|
||||
"cpe:2.3:a:tickera:tickera:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -16314,6 +16363,9 @@
|
||||
"two-factor-authentication": [
|
||||
"cpe:2.3:a:simbahosting:two-factor-authentication:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"two-factor-login-telegram": [
|
||||
"cpe:2.3:a:dueclic:wp_2fa_with_telegram:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"typebot": [
|
||||
"cpe:2.3:a:typebot:typebot:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -16481,7 +16533,7 @@
|
||||
"cpe:2.3:a:unitecms:unlimited_addons_for_wpbakery_page_builder:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"unlimited-elements-for-elementor": [
|
||||
"cpe:2.3:a:unlimited-elements:unlimited_elements_for_elementor_\\(free_widgets\\,_addons\\,_templates\\):*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:unlimited-elements:unlimited_elements_for_elementor:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"unlimited-popups": [
|
||||
"cpe:2.3:a:unlimited_popups_project:unlimited_popups:*:*:*:*:*:wordpress:*:*"
|
||||
@@ -16972,6 +17024,9 @@
|
||||
"whizz": [
|
||||
"cpe:2.3:a:browserweb:whizz:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wholesale-pricing-woocommerce": [
|
||||
"cpe:2.3:a:wpfactory:quantity_dynamic_pricing_\\\u0026_bulk_discounts_for_woocommerce:*:*:*:*:free:wordpress:*:*"
|
||||
],
|
||||
"whydowork-adsense": [
|
||||
"cpe:2.3:a:whydowork_adsense_project:whydowork_adsense:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -17193,6 +17248,7 @@
|
||||
],
|
||||
"woocommerce": [
|
||||
"cpe:2.3:a:woocommerce:woocommerce:*:*:*:*:*:wordpress:*:*",
|
||||
"cpe:2.3:a:woocommerce:woocommerce:*:*:*:*:free:wordpress:*:*",
|
||||
"cpe:2.3:a:woothemes:woocommerce:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"woocommerce-abandoned-cart": [
|
||||
@@ -17408,7 +17464,7 @@
|
||||
"cpe:2.3:a:wp_admin_logo_changer_project:wp_admin_logo_changer:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wp-advanced-search": [
|
||||
"cpe:2.3:a:wp-advanced-search_project:wp-advanced-search:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:internet-formation:wp-advanced-search:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wp-airbnb-review-slider": [
|
||||
"cpe:2.3:a:ljapps:wp_airbnb_review_slider:*:*:*:*:*:wordpress:*:*"
|
||||
@@ -17793,10 +17849,11 @@
|
||||
"cpe:2.3:a:surniaulula:jsm_file_get_contents\\(\\)_shortcode:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wp-file-manager": [
|
||||
"cpe:2.3:a:filemanagerpro:file_manager:*:*:*:*:free:wordpress:*:*",
|
||||
"cpe:2.3:a:webdesi9:file_manager:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wp-file-manager-pro": [
|
||||
"cpe:2.3:a:filemanagerpro:file_manager_pro:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:filemanagerpro:file_manager:*:*:*:*:pro:wordpress:*:*"
|
||||
],
|
||||
"wp-file-upload": [
|
||||
"cpe:2.3:a:iptanus:wordpress_file_upload:*:*:*:*:*:wordpress:*:*"
|
||||
@@ -18509,6 +18566,9 @@
|
||||
"wp-terms-popup": [
|
||||
"cpe:2.3:a:linksoftwarellc:wp_terms_popup:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wp-testimonial-widget": [
|
||||
"cpe:2.3:a:starkdigital:wp_testimonial_widget:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"wp-testing": [
|
||||
"cpe:2.3:a:psychological_tests_\\\u0026_quizzes_project:psychological_tests_\\\u0026_quizzes:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
@@ -19020,7 +19080,7 @@
|
||||
"cpe:2.3:a:stefanoai:widget_responsive_for_youtube:*:*:*:*:*:wordpress:*:*"
|
||||
],
|
||||
"youzify": [
|
||||
"cpe:2.3:a:kainelabs:youzify:*:*:*:*:*:wordpress:*:*"
|
||||
"cpe:2.3:a:kainelabs:youzify:*:*:*:*:free:wordpress:*:*"
|
||||
],
|
||||
"yt-player": [
|
||||
"cpe:2.3:a:video_player_for_youtube_project:video_player_for_youtube:*:*:*:*:*:wordpress:*:*"
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"crypto"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
@@ -49,14 +50,15 @@ var javaArchiveHashes = []crypto.Hash{
|
||||
}
|
||||
|
||||
type archiveParser struct {
|
||||
fileManifest intFile.ZipFileManifest
|
||||
location file.Location
|
||||
archivePath string
|
||||
contentPath string
|
||||
fileInfo archiveFilename
|
||||
detectNested bool
|
||||
cfg ArchiveCatalogerConfig
|
||||
maven *mavenResolver
|
||||
fileManifest intFile.ZipFileManifest
|
||||
location file.Location
|
||||
archivePath string
|
||||
contentPath string
|
||||
fileInfo archiveFilename
|
||||
detectNested bool
|
||||
cfg ArchiveCatalogerConfig
|
||||
maven *mavenResolver
|
||||
licenseScanner licenses.Scanner
|
||||
}
|
||||
|
||||
type genericArchiveParserAdapter struct {
|
||||
@@ -69,7 +71,7 @@ func newGenericArchiveParserAdapter(cfg ArchiveCatalogerConfig) genericArchivePa
|
||||
|
||||
// parseJavaArchive is a parser function for java archive contents, returning all Java libraries and nested archives.
|
||||
func (gap genericArchiveParserAdapter) parseJavaArchive(ctx context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
parser, cleanupFn, err := newJavaArchiveParser(reader, true, gap.cfg)
|
||||
parser, cleanupFn, err := newJavaArchiveParser(ctx, reader, true, gap.cfg)
|
||||
// note: even on error, we should always run cleanup functions
|
||||
defer cleanupFn()
|
||||
if err != nil {
|
||||
@@ -88,7 +90,9 @@ func uniquePkgKey(groupID string, p *pkg.Package) string {
|
||||
|
||||
// newJavaArchiveParser returns a new java archive parser object for the given archive. Can be configured to discover
|
||||
// and parse nested archives or ignore them.
|
||||
func newJavaArchiveParser(reader file.LocationReadCloser, detectNested bool, cfg ArchiveCatalogerConfig) (*archiveParser, func(), error) {
|
||||
func newJavaArchiveParser(ctx context.Context, reader file.LocationReadCloser, detectNested bool, cfg ArchiveCatalogerConfig) (*archiveParser, func(), error) {
|
||||
licenseScanner := licenses.ContextLicenseScanner(ctx)
|
||||
|
||||
// fetch the last element of the virtual path
|
||||
virtualElements := strings.Split(reader.Path(), ":")
|
||||
currentFilepath := virtualElements[len(virtualElements)-1]
|
||||
@@ -104,14 +108,15 @@ func newJavaArchiveParser(reader file.LocationReadCloser, detectNested bool, cfg
|
||||
}
|
||||
|
||||
return &archiveParser{
|
||||
fileManifest: fileManifest,
|
||||
location: reader.Location,
|
||||
archivePath: archivePath,
|
||||
contentPath: contentPath,
|
||||
fileInfo: newJavaArchiveFilename(currentFilepath),
|
||||
detectNested: detectNested,
|
||||
cfg: cfg,
|
||||
maven: newMavenResolver(nil, cfg),
|
||||
fileManifest: fileManifest,
|
||||
location: reader.Location,
|
||||
archivePath: archivePath,
|
||||
contentPath: contentPath,
|
||||
fileInfo: newJavaArchiveFilename(currentFilepath),
|
||||
detectNested: detectNested,
|
||||
cfg: cfg,
|
||||
maven: newMavenResolver(nil, cfg),
|
||||
licenseScanner: licenseScanner,
|
||||
}, cleanupFn, nil
|
||||
}
|
||||
|
||||
@@ -220,7 +225,7 @@ func (j *archiveParser) discoverMainPackage(ctx context.Context) (*pkg.Package,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name, version, licenses, err := j.discoverNameVersionLicense(ctx, manifest)
|
||||
name, version, lics, err := j.discoverNameVersionLicense(ctx, manifest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -230,7 +235,7 @@ func (j *archiveParser) discoverMainPackage(ctx context.Context) (*pkg.Package,
|
||||
Name: name,
|
||||
Version: version,
|
||||
Language: pkg.Java,
|
||||
Licenses: pkg.NewLicenseSet(licenses...),
|
||||
Licenses: pkg.NewLicenseSet(lics...),
|
||||
Locations: file.NewLocationSet(
|
||||
j.location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
),
|
||||
@@ -246,7 +251,7 @@ func (j *archiveParser) discoverMainPackage(ctx context.Context) (*pkg.Package,
|
||||
func (j *archiveParser) discoverNameVersionLicense(ctx context.Context, manifest *pkg.JavaManifest) (string, string, []pkg.License, error) {
|
||||
// we use j.location because we want to associate the license declaration with where we discovered the contents in the manifest
|
||||
// TODO: when we support locations of paths within archives we should start passing the specific manifest location object instead of the top jar
|
||||
licenses := pkg.NewLicensesFromLocation(j.location, selectLicenses(manifest)...)
|
||||
lics := pkg.NewLicensesFromLocation(j.location, selectLicenses(manifest)...)
|
||||
/*
|
||||
We should name and version from, in this order:
|
||||
1. pom.properties if we find exactly 1
|
||||
@@ -262,25 +267,25 @@ func (j *archiveParser) discoverNameVersionLicense(ctx context.Context, manifest
|
||||
version = selectVersion(manifest, j.fileInfo)
|
||||
}
|
||||
|
||||
if len(licenses) == 0 {
|
||||
fileLicenses, err := j.getLicenseFromFileInArchive()
|
||||
if len(lics) == 0 {
|
||||
fileLicenses, err := j.getLicenseFromFileInArchive(ctx)
|
||||
if err != nil {
|
||||
return "", "", nil, err
|
||||
}
|
||||
if fileLicenses != nil {
|
||||
licenses = append(licenses, fileLicenses...)
|
||||
lics = append(lics, fileLicenses...)
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find any licenses in the archive so far, we'll try again in Maven Central using groupIDFromJavaMetadata
|
||||
if len(licenses) == 0 {
|
||||
if len(lics) == 0 {
|
||||
// Today we don't have a way to distinguish between licenses from the manifest and licenses from the pom.xml
|
||||
// until the file.Location object can support sub-paths (i.e. paths within archives, recursively; issue https://github.com/anchore/syft/issues/2211).
|
||||
// Until then it's less confusing to use the licenses from the pom.xml only if the manifest did not list any.
|
||||
licenses = j.findLicenseFromJavaMetadata(ctx, groupID, artifactID, version, parsedPom, manifest)
|
||||
lics = j.findLicenseFromJavaMetadata(ctx, groupID, artifactID, version, parsedPom, manifest)
|
||||
}
|
||||
|
||||
return artifactID, version, licenses, nil
|
||||
return artifactID, version, lics, nil
|
||||
}
|
||||
|
||||
// findLicenseFromJavaMetadata attempts to find license information from all available maven metadata properties and pom info
|
||||
@@ -446,7 +451,7 @@ func getDigestsFromArchive(archivePath string) ([]file.Digest, error) {
|
||||
return digests, nil
|
||||
}
|
||||
|
||||
func (j *archiveParser) getLicenseFromFileInArchive() ([]pkg.License, error) {
|
||||
func (j *archiveParser) getLicenseFromFileInArchive(ctx context.Context) ([]pkg.License, error) {
|
||||
var fileLicenses []pkg.License
|
||||
for _, filename := range licenses.FileNames() {
|
||||
licenseMatches := j.fileManifest.GlobMatch(true, "/META-INF/"+filename)
|
||||
@@ -463,7 +468,8 @@ func (j *archiveParser) getLicenseFromFileInArchive() ([]pkg.License, error) {
|
||||
|
||||
for _, licenseMatch := range licenseMatches {
|
||||
licenseContents := contents[licenseMatch]
|
||||
parsed, err := licenses.Parse(strings.NewReader(licenseContents), j.location)
|
||||
r := strings.NewReader(licenseContents)
|
||||
parsed, err := licenses.Search(ctx, j.licenseScanner, file.NewLocationReadCloser(j.location, io.NopCloser(r)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/vifraa/gopom"
|
||||
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/license"
|
||||
@@ -30,6 +31,8 @@ import (
|
||||
func TestSearchMavenForLicenses(t *testing.T) {
|
||||
url := mockMavenRepo(t)
|
||||
|
||||
ctx := licenses.SetContextLicenseScanner(context.Background(), licenses.TestingOnlyScanner())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
@@ -71,6 +74,7 @@ func TestSearchMavenForLicenses(t *testing.T) {
|
||||
|
||||
// setup parser
|
||||
ap, cleanupFn, err := newJavaArchiveParser(
|
||||
ctx,
|
||||
file.LocationReadCloser{
|
||||
Location: file.NewLocation(fixture.Name()),
|
||||
ReadCloser: fixture,
|
||||
@@ -86,6 +90,8 @@ func TestSearchMavenForLicenses(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseJar(t *testing.T) {
|
||||
ctx := licenses.SetContextLicenseScanner(context.Background(), licenses.TestingOnlyScanner())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
@@ -347,10 +353,12 @@ func TestParseJar(t *testing.T) {
|
||||
UseNetwork: false,
|
||||
UseMavenLocalRepository: false,
|
||||
}
|
||||
parser, cleanupFn, err := newJavaArchiveParser(file.LocationReadCloser{
|
||||
Location: file.NewLocation(fixture.Name()),
|
||||
ReadCloser: fixture,
|
||||
}, false, cfg)
|
||||
parser, cleanupFn, err := newJavaArchiveParser(
|
||||
ctx,
|
||||
file.LocationReadCloser{
|
||||
Location: file.NewLocation(fixture.Name()),
|
||||
ReadCloser: fixture,
|
||||
}, false, cfg)
|
||||
defer cleanupFn()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1352,6 +1360,8 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_deterministicMatchingPomProperties(t *testing.T) {
|
||||
ctx := licenses.SetContextLicenseScanner(context.Background(), licenses.TestingOnlyScanner())
|
||||
|
||||
tests := []struct {
|
||||
fixture string
|
||||
expected mavenID
|
||||
@@ -1371,10 +1381,12 @@ func Test_deterministicMatchingPomProperties(t *testing.T) {
|
||||
fixture, err := os.Open(fixturePath)
|
||||
require.NoError(t, err)
|
||||
|
||||
parser, cleanupFn, err := newJavaArchiveParser(file.LocationReadCloser{
|
||||
Location: file.NewLocation(fixture.Name()),
|
||||
ReadCloser: fixture,
|
||||
}, false, ArchiveCatalogerConfig{UseNetwork: false})
|
||||
parser, cleanupFn, err := newJavaArchiveParser(
|
||||
ctx,
|
||||
file.LocationReadCloser{
|
||||
Location: file.NewLocation(fixture.Name()),
|
||||
ReadCloser: fixture,
|
||||
}, false, ArchiveCatalogerConfig{UseNetwork: false})
|
||||
defer cleanupFn()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
@@ -22,6 +23,7 @@ func Test_KernelCataloger(t *testing.T) {
|
||||
),
|
||||
Type: pkg.LinuxKernelPkg,
|
||||
PURL: "pkg:generic/linux-kernel@6.0.7-301.fc37.x86_64",
|
||||
CPEs: []cpe.CPE{cpe.Must("cpe:2.3:o:linux:linux_kernel:6.0.7-301.fc37.x86_64:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource)},
|
||||
Metadata: pkg.LinuxKernel{
|
||||
Name: "",
|
||||
Architecture: "x86",
|
||||
|
||||
@@ -4,12 +4,26 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/syft/cpe"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
const linuxKernelPackageName = "linux-kernel"
|
||||
|
||||
func createLinuxKernelCPEs(version string) []cpe.CPE {
|
||||
c := cpe.NewWithAny()
|
||||
c.Part = "o"
|
||||
c.Product = "linux_kernel"
|
||||
c.Vendor = "linux"
|
||||
c.Version = version
|
||||
if cpe.ValidateString(c.String()) != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return []cpe.CPE{{Attributes: c, Source: cpe.NVDDictionaryLookupSource}}
|
||||
}
|
||||
|
||||
func newLinuxKernelPackage(metadata pkg.LinuxKernel, archiveLocation file.Location) pkg.Package {
|
||||
p := pkg.Package{
|
||||
Name: linuxKernelPackageName,
|
||||
@@ -18,6 +32,7 @@ func newLinuxKernelPackage(metadata pkg.LinuxKernel, archiveLocation file.Locati
|
||||
PURL: packageURL(linuxKernelPackageName, metadata.Version),
|
||||
Type: pkg.LinuxKernelPkg,
|
||||
Metadata: metadata,
|
||||
CPEs: createLinuxKernelCPEs(metadata.Version),
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package python
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -72,7 +73,26 @@ func newPackageForRequirementsWithMetadata(name, version string, metadata pkg.Py
|
||||
return p
|
||||
}
|
||||
|
||||
func newPackageForPackage(resolver file.Resolver, m parsedData, sources ...file.Location) pkg.Package {
|
||||
func newPackageForPackage(m parsedData, licenses pkg.LicenseSet, sources ...file.Location) pkg.Package {
|
||||
name := normalize(m.Name)
|
||||
|
||||
p := pkg.Package{
|
||||
Name: name,
|
||||
Version: m.Version,
|
||||
PURL: packageURL(name, m.Version, &m.PythonPackage),
|
||||
Locations: file.NewLocationSet(sources...),
|
||||
Licenses: licenses,
|
||||
Language: pkg.Python,
|
||||
Type: pkg.PythonPkg,
|
||||
Metadata: m.PythonPackage,
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func findLicenses(ctx context.Context, scanner licenses.Scanner, resolver file.Resolver, m parsedData) pkg.LicenseSet {
|
||||
var licenseSet pkg.LicenseSet
|
||||
|
||||
switch {
|
||||
@@ -89,7 +109,7 @@ func newPackageForPackage(resolver file.Resolver, m parsedData, sources ...file.
|
||||
if len(found) > 0 {
|
||||
metadataContents, err := resolver.FileContentsByLocation(found[0])
|
||||
if err == nil {
|
||||
parsed, err := licenses.Parse(metadataContents, m.LicenseLocation)
|
||||
parsed, err := licenses.Search(ctx, scanner, file.NewLocationReadCloser(m.LicenseLocation, metadataContents))
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Tracef("unable to parse a license from the file in %s", m.LicenseLocation.Path())
|
||||
}
|
||||
@@ -101,23 +121,7 @@ func newPackageForPackage(resolver file.Resolver, m parsedData, sources ...file.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
name := normalize(m.Name)
|
||||
|
||||
p := pkg.Package{
|
||||
Name: name,
|
||||
Version: m.Version,
|
||||
PURL: packageURL(name, m.Version, &m.PythonPackage),
|
||||
Locations: file.NewLocationSet(sources...),
|
||||
Licenses: licenseSet,
|
||||
Language: pkg.Python,
|
||||
Type: pkg.PythonPkg,
|
||||
Metadata: m.PythonPackage,
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
|
||||
return p
|
||||
return licenseSet
|
||||
}
|
||||
|
||||
func packageURL(name, version string, m *pkg.PythonPackage) string {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
@@ -18,7 +19,9 @@ import (
|
||||
|
||||
// parseWheelOrEgg takes the primary metadata file reference and returns the python package it represents. Contained
|
||||
// fields are governed by the PyPA core metadata specification (https://packaging.python.org/en/latest/specifications/core-metadata/).
|
||||
func parseWheelOrEgg(_ context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
func parseWheelOrEgg(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
licenseScanner := licenses.ContextLicenseScanner(ctx)
|
||||
|
||||
pd, sources, err := assembleEggOrWheelMetadata(resolver, reader.Location)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -33,7 +36,13 @@ func parseWheelOrEgg(_ context.Context, resolver file.Resolver, _ *generic.Envir
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
pkgs := []pkg.Package{newPackageForPackage(resolver, *pd, sources...)}
|
||||
pkgs := []pkg.Package{
|
||||
newPackageForPackage(
|
||||
*pd,
|
||||
findLicenses(ctx, licenseScanner, resolver, *pd),
|
||||
sources...,
|
||||
),
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
@@ -60,7 +69,7 @@ func fetchInstalledFiles(resolver file.Resolver, metadataLocation file.Location,
|
||||
// parse the installed-files contents
|
||||
installedFiles, err := parseInstalledFiles(installedFilesContents, metadataLocation.RealPath, sitePackagesRootPath)
|
||||
if err != nil {
|
||||
log.Warnf("unable to parse installed-files.txt for python package=%+v: %w", metadataLocation.RealPath, err)
|
||||
log.WithFields("error", err, "path", metadataLocation.RealPath).Trace("unable to parse installed-files.txt for python package")
|
||||
return files, sources, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ func Test_packageURL(t *testing.T) {
|
||||
Release: "r",
|
||||
Epoch: intRef(1),
|
||||
},
|
||||
expected: "pkg:rpm/centos/p@v-r?arch=a&epoch=1&distro=centos-7",
|
||||
expected: "pkg:rpm/centos/p@v-r?arch=a&distro=centos-7&epoch=1",
|
||||
},
|
||||
{
|
||||
name: "missing distro",
|
||||
@@ -67,7 +67,7 @@ func Test_packageURL(t *testing.T) {
|
||||
Release: "r",
|
||||
SourceRpm: "sourcerpm",
|
||||
},
|
||||
expected: "pkg:rpm/redhat/p@v-r?upstream=sourcerpm&distro=rhel-8.4",
|
||||
expected: "pkg:rpm/redhat/p@v-r?distro=rhel-8.4&upstream=sourcerpm",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ func TestLanguageFromPURL(t *testing.T) {
|
||||
want: Lua,
|
||||
},
|
||||
{
|
||||
purl: "pkg:opam/ocaml-base-compiler@ 5.2.0",
|
||||
purl: "pkg:opam/ocaml-base-compiler@5.2.0",
|
||||
want: OCaml,
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user