add single license scanner instance

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman
2024-10-21 17:27:31 +01:00
committed by Weston Steimel
parent 01de99b253
commit 4fd1828ba9
16 changed files with 277 additions and 142 deletions
+18
View File
@@ -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()
}
-39
View File
@@ -1,39 +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
}
cov := licensecheck.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
}
+68
View File
@@ -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,
}
}
// StaticScanner 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 StaticScanner() 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
}
+28
View File
@@ -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
}