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

     1  package photon
     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  // Photon provides one security database file per major version. So far, there are 3 versions
    16  // Photon 1.0, Photon 2.0 and Photon 3.0
    17  
    18  const (
    19  	scannerName    = "photon"
    20  	scannerVersion = "v0.0.1"
    21  	scannerKind    = "distribution"
    22  )
    23  
    24  const (
    25  	osReleasePath     = `etc/os-release`
    26  	photonReleasePath = `etc/photon-release`
    27  )
    28  
    29  type photonRegex struct {
    30  	release Release
    31  	regexp  *regexp.Regexp
    32  }
    33  
    34  var photonRegexes = []photonRegex{
    35  	{
    36  		release: Photon1,
    37  		// regex for /etc/os-release
    38  		regexp: regexp.MustCompile(`^.*"VMware Photon"\sVERSION="1.0"`),
    39  	},
    40  	{
    41  		release: Photon2,
    42  		// regex for /etc/os-release
    43  		regexp: regexp.MustCompile(`^.*"VMware Photon OS"\sVERSION="2.0"`),
    44  	},
    45  	{
    46  		release: Photon3,
    47  		// regex for /etc/os-release
    48  		regexp: regexp.MustCompile(`^.*"VMware Photon OS"\sVERSION="3.0"`),
    49  	},
    50  }
    51  
    52  var (
    53  	_ indexer.DistributionScanner = (*DistributionScanner)(nil)
    54  	_ indexer.VersionedScanner    = (*DistributionScanner)(nil)
    55  )
    56  
    57  // DistributionScanner attempts to discover if a layer
    58  // displays characteristics of a photon distribution
    59  type DistributionScanner struct{}
    60  
    61  // Name implements scanner.VersionedScanner.
    62  func (*DistributionScanner) Name() string { return scannerName }
    63  
    64  // Version implements scanner.VersionedScanner.
    65  func (*DistributionScanner) Version() string { return scannerVersion }
    66  
    67  // Kind implements scanner.VersionedScanner.
    68  func (*DistributionScanner) Kind() string { return scannerKind }
    69  
    70  // Scan will inspect the layer for an os-release or lsb-release file
    71  // and perform a regex match for keywords indicating the associated photon release
    72  //
    73  // If neither file is found a (nil,nil) is returned.
    74  // If the files are found but all regexp fail to match an empty slice is returned.
    75  func (ds *DistributionScanner) Scan(ctx context.Context, l *claircore.Layer) ([]*claircore.Distribution, error) {
    76  	defer trace.StartRegion(ctx, "Scanner.Scan").End()
    77  	ctx = zlog.ContextWithValues(ctx,
    78  		"component", "photon/DistributionScanner.Scan",
    79  		"version", ds.Version(),
    80  		"layer", l.Hash.String())
    81  	zlog.Debug(ctx).Msg("start")
    82  	defer zlog.Debug(ctx).Msg("done")
    83  	files, err := l.Files(osReleasePath, photonReleasePath)
    84  	if err != nil {
    85  		zlog.Debug(ctx).Msg("didn't find an os-release or photon-release")
    86  		return nil, nil
    87  	}
    88  	for _, buff := range files {
    89  		dist := ds.parse(buff)
    90  		if dist != nil {
    91  			return []*claircore.Distribution{dist}, nil
    92  		}
    93  	}
    94  	return []*claircore.Distribution{}, nil
    95  }
    96  
    97  // parse attempts to match all Photon release regexp and returns the associated
    98  // distribution if it exists.
    99  //
   100  // separated into its own method to aid testing.
   101  func (ds *DistributionScanner) parse(buff *bytes.Buffer) *claircore.Distribution {
   102  	for _, ur := range photonRegexes {
   103  		if ur.regexp.Match(buff.Bytes()) {
   104  			return releaseToDist(ur.release)
   105  		}
   106  	}
   107  	return nil
   108  }