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  }