github.com/quay/claircore@v1.5.28/oracle/distributionscanner.go (about)

     1  package oracle
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"regexp"
     7  	"runtime/trace"
     8  
     9  	"github.com/quay/zlog"
    10  
    11  	"github.com/quay/claircore"
    12  	"github.com/quay/claircore/indexer"
    13  )
    14  
    15  // Oracle Linux has minor releases such as 7.7 and 6.10
    16  // however their elsa OVAL xml sec db always references the major release
    17  // for example: <platform>Oracle Linux 5</platform>
    18  // for this reason the oracle distribution scanner will detect and normalize
    19  // minor releases to major releases to match vulnerabilities correctly
    20  
    21  const (
    22  	scannerName    = "oracle"
    23  	scannerVersion = "1"
    24  	scannerKind    = "distribution"
    25  )
    26  
    27  const osReleasePath = `etc/os-release`
    28  
    29  // Oracle Linux 5 will not have os-release and only has etc/issue
    30  const issuePath = `etc/issue`
    31  
    32  type oracleRegex struct {
    33  	release Release
    34  	regexp  *regexp.Regexp
    35  }
    36  
    37  var oracleRegexes = []oracleRegex{
    38  	{
    39  		release: Five,
    40  		// regex for /etc/issue
    41  		regexp: regexp.MustCompile(`(?is)Oracle Linux Server release ?5(\.\d*)?`),
    42  	},
    43  	{
    44  		release: Six,
    45  		regexp:  regexp.MustCompile(`(?is)Oracle Linux Server 6(\.\d*)?`),
    46  	},
    47  	{
    48  		release: Seven,
    49  		regexp:  regexp.MustCompile(`(?is)Oracle Linux Server 7(\.\d*)?`),
    50  	},
    51  	{
    52  		release: Eight,
    53  		regexp:  regexp.MustCompile(`(?is)Oracle Linux Server 8(\.\d*)?`),
    54  	},
    55  	{
    56  		release: Nine,
    57  		regexp:  regexp.MustCompile(`(?is)Oracle Linux Server 9(\.\d*)?`),
    58  	},
    59  }
    60  
    61  var (
    62  	_ indexer.DistributionScanner = (*DistributionScanner)(nil)
    63  	_ indexer.VersionedScanner    = (*DistributionScanner)(nil)
    64  )
    65  
    66  // DistributionScanner attempts to discover if a layer
    67  // displays characteristics of a Oracle distribution
    68  type DistributionScanner struct{}
    69  
    70  // Name implements scanner.VersionedScanner.
    71  func (*DistributionScanner) Name() string { return scannerName }
    72  
    73  // Version implements scanner.VersionedScanner.
    74  func (*DistributionScanner) Version() string { return scannerVersion }
    75  
    76  // Kind implements scanner.VersionedScanner.
    77  func (*DistributionScanner) Kind() string { return scannerKind }
    78  
    79  // Scan will inspect the layer for an os-release or lsb-release file
    80  // and perform a regex match for keywords indicating the associated Oracle release
    81  //
    82  // If neither file is found a (nil,nil) is returned.
    83  // If the files are found but all regexp fail to match an empty slice is returned.
    84  func (ds *DistributionScanner) Scan(ctx context.Context, l *claircore.Layer) ([]*claircore.Distribution, error) {
    85  	defer trace.StartRegion(ctx, "Scanner.Scan").End()
    86  	ctx = zlog.ContextWithValues(ctx,
    87  		"component", "oracle/DistributionScanner.Scan",
    88  		"version", ds.Version(),
    89  		"layer", l.Hash.String())
    90  	zlog.Debug(ctx).Msg("start")
    91  	defer zlog.Debug(ctx).Msg("done")
    92  	files, err := l.Files(osReleasePath, issuePath)
    93  	if err != nil {
    94  		zlog.Debug(ctx).Msg("didn't find an os-release or issues file")
    95  		return nil, nil
    96  	}
    97  	for _, buff := range files {
    98  		dist := ds.parse(buff)
    99  		if dist != nil {
   100  			return []*claircore.Distribution{dist}, nil
   101  		}
   102  	}
   103  	return []*claircore.Distribution{}, nil
   104  }
   105  
   106  // parse attempts to match all Oracle release regexp and returns the associated
   107  // distribution if it exists.
   108  //
   109  // separated into its own method to aid testing.
   110  func (ds *DistributionScanner) parse(buff *bytes.Buffer) *claircore.Distribution {
   111  	for _, ur := range oracleRegexes {
   112  		if ur.regexp.Match(buff.Bytes()) {
   113  			return releaseToDist(ur.release)
   114  		}
   115  	}
   116  	return nil
   117  }