github.com/quay/claircore@v1.5.28/suse/distributionscanner.go (about) 1 package suse 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 // Suse Enterprise Server has service pack releases however their security database files are bundled together 16 // by major version. for example `SUSE Linux Enterprise Server 15 (all Service Packs) - suse.linux.enterprise.server.15.xml` 17 // we choose to normalize detected distributions into major releases and parse vulnerabilities by major release versions. 18 // 19 // Suse Leap has well defined sub releases and their sec db's match up fine. 20 21 const ( 22 scannerName = "suse" 23 scannerVersion = "v0.0.1" 24 scannerKind = "distribution" 25 ) 26 27 const ( 28 osReleasePath = `etc/os-release` 29 suseReleasePath = `etc/SuSE-release` 30 ) 31 32 type suseRegex struct { 33 release Release 34 regexp *regexp.Regexp 35 } 36 37 var suseRegexes = []suseRegex{ 38 { 39 release: EnterpriseServer15, 40 // regex for /etc/issue 41 regexp: regexp.MustCompile(`(?i)SUSE Linux Enterprise Server 15`), 42 }, 43 { 44 release: EnterpriseServer12, 45 regexp: regexp.MustCompile(`(?i)SUSE Linux Enterprise Server 12`), 46 }, 47 { 48 release: EnterpriseServer11, 49 regexp: regexp.MustCompile(`(?i)SUSE Linux Enterprise Server 11`), 50 }, 51 { 52 release: Leap151, 53 regexp: regexp.MustCompile(`(?i)openSUSE Leap 15.1`), 54 }, 55 { 56 release: Leap150, 57 regexp: regexp.MustCompile(`(?i)openSUSE Leap 15.0`), 58 }, 59 { 60 release: Leap423, 61 regexp: regexp.MustCompile(`(?i)openSUSE Leap 42.3`), 62 }, 63 } 64 65 var ( 66 _ indexer.DistributionScanner = (*DistributionScanner)(nil) 67 _ indexer.VersionedScanner = (*DistributionScanner)(nil) 68 ) 69 70 // DistributionScanner attempts to discover if a layer 71 // displays characteristics of a Suse distribution 72 type DistributionScanner struct{} 73 74 // Name implements scanner.VersionedScanner. 75 func (*DistributionScanner) Name() string { return scannerName } 76 77 // Version implements scanner.VersionedScanner. 78 func (*DistributionScanner) Version() string { return scannerVersion } 79 80 // Kind implements scanner.VersionedScanner. 81 func (*DistributionScanner) Kind() string { return scannerKind } 82 83 // Scan will inspect the layer for an os-release or lsb-release file 84 // and perform a regex match for keywords indicating the associated Suse release 85 // 86 // If neither file is found a (nil,nil) is returned. 87 // If the files are found but all regexp fail to match an empty slice is returned. 88 func (ds *DistributionScanner) Scan(ctx context.Context, l *claircore.Layer) ([]*claircore.Distribution, error) { 89 defer trace.StartRegion(ctx, "Scanner.Scan").End() 90 ctx = zlog.ContextWithValues(ctx, 91 "component", "suse/DistributionScanner.Scan", 92 "version", ds.Version(), 93 "layer", l.Hash.String()) 94 zlog.Debug(ctx).Msg("start") 95 defer zlog.Debug(ctx).Msg("done") 96 files, err := l.Files(osReleasePath, suseReleasePath) 97 if err != nil { 98 zlog.Debug(ctx).Msg("didn't find an os-release or SuSE-release") 99 return nil, nil 100 } 101 for _, buff := range files { 102 dist := ds.parse(buff) 103 if dist != nil { 104 return []*claircore.Distribution{dist}, nil 105 } 106 } 107 return []*claircore.Distribution{}, nil 108 } 109 110 // parse attempts to match all SUSE release regexp and returns the associated 111 // distribution if it exists. 112 // 113 // separated into its own method to aid testing. 114 func (ds *DistributionScanner) parse(buff *bytes.Buffer) *claircore.Distribution { 115 for _, ur := range suseRegexes { 116 if ur.regexp.Match(buff.Bytes()) { 117 return releaseToDist(ur.release) 118 } 119 } 120 return nil 121 }