github.com/anchore/syft@v1.38.2/internal/licenses/scanner.go (about) 1 package licenses 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 8 "github.com/google/licensecheck" 9 10 "github.com/anchore/syft/internal/log" 11 ) 12 13 const ( 14 UnknownLicensePrefix = unknownLicenseType + "_" 15 DefaultCoverageThreshold = 75 // determined by experimentation 16 17 unknownLicenseType = "UNKNOWN" 18 ) 19 20 type Evidence struct { 21 ID string // License identifier. (See licenses/README.md.) 22 Type licensecheck.Type // The type of the license: BSD, MIT, etc. 23 Start int // Start offset of match in text; match is at text[Start:End]. 24 End int // End offset of match in text. 25 IsURL bool // Whether match is a URL. 26 } 27 28 type Scanner interface { 29 FindEvidence(context.Context, io.Reader) ([]Evidence, []byte, error) 30 } 31 32 var _ Scanner = (*scanner)(nil) 33 34 type scanner struct { 35 coverageThreshold float64 // between 0 and 100 36 scanner func([]byte) licensecheck.Coverage 37 } 38 39 type ScannerConfig struct { 40 CoverageThreshold float64 41 Scanner func([]byte) licensecheck.Coverage 42 } 43 44 type Option func(*scanner) 45 46 func WithCoverage(coverage float64) Option { 47 return func(s *scanner) { 48 s.coverageThreshold = coverage 49 } 50 } 51 52 // NewDefaultScanner returns a scanner that uses a new instance of the default licensecheck package scanner. 53 func NewDefaultScanner(o ...Option) (Scanner, error) { 54 s, err := licensecheck.NewScanner(licensecheck.BuiltinLicenses()) 55 if err != nil { 56 log.WithFields("error", err).Trace("unable to create default license scanner") 57 return nil, fmt.Errorf("unable to create default license scanner: %w", err) 58 } 59 60 newScanner := &scanner{ 61 coverageThreshold: DefaultCoverageThreshold, 62 scanner: s.Scan, 63 } 64 65 for _, opt := range o { 66 opt(newScanner) 67 } 68 return newScanner, nil 69 } 70 71 // NewScanner generates a license Scanner with the given ScannerConfig 72 // if config is nil NewDefaultScanner is used 73 func NewScanner(c *ScannerConfig) (Scanner, error) { 74 if c == nil { 75 return NewDefaultScanner() 76 } 77 78 return &scanner{ 79 coverageThreshold: c.CoverageThreshold, 80 scanner: c.Scanner, 81 }, nil 82 }