github.com/quay/claircore@v1.5.28/debian/distributionscanner.go (about) 1 package debian 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "io/fs" 8 "regexp" 9 "runtime/trace" 10 "strconv" 11 "strings" 12 "unicode" 13 14 "github.com/quay/zlog" 15 16 "github.com/quay/claircore" 17 "github.com/quay/claircore/indexer" 18 "github.com/quay/claircore/osrelease" 19 ) 20 21 var ( 22 _ indexer.DistributionScanner = (*DistributionScanner)(nil) 23 _ indexer.VersionedScanner = (*DistributionScanner)(nil) 24 ) 25 26 // DistributionScanner attempts to discover if a layer 27 // displays characteristics of a Debian distribution. 28 type DistributionScanner struct{} 29 30 // Name implements [indexer.VersionedScanner]. 31 func (*DistributionScanner) Name() string { return "debian" } 32 33 // Version implements [indexer.VersionedScanner]. 34 func (*DistributionScanner) Version() string { return "3" } 35 36 // Kind implements [indexer.VersionedScanner]. 37 func (*DistributionScanner) Kind() string { return "distribution" } 38 39 // Scan implements [indexer.DistributionScanner]. 40 func (ds *DistributionScanner) Scan(ctx context.Context, l *claircore.Layer) ([]*claircore.Distribution, error) { 41 defer trace.StartRegion(ctx, "Scanner.Scan").End() 42 ctx = zlog.ContextWithValues(ctx, 43 "component", "debian/DistributionScanner.Scan", 44 "version", ds.Version(), 45 "layer", l.Hash.String()) 46 zlog.Debug(ctx).Msg("start") 47 defer zlog.Debug(ctx).Msg("done") 48 49 sys, err := l.FS() 50 if err != nil { 51 return nil, fmt.Errorf("debian: unable to open layer: %w", err) 52 } 53 d, err := findDist(ctx, sys) 54 if err != nil { 55 return nil, err 56 } 57 if d == nil { 58 return nil, nil 59 } 60 return []*claircore.Distribution{d}, nil 61 } 62 63 func findDist(ctx context.Context, sys fs.FS) (*claircore.Distribution, error) { 64 f, err := sys.Open(osrelease.Path) 65 switch { 66 case errors.Is(err, nil): 67 case errors.Is(err, fs.ErrNotExist): 68 zlog.Debug(ctx).Msg("no os-release file") 69 return nil, nil 70 default: 71 return nil, fmt.Errorf("debian: unexpected error: %w", err) 72 } 73 kv, err := osrelease.Parse(ctx, f) 74 if err != nil { 75 zlog.Info(ctx). 76 Err(err).Msg("malformed os-release file") 77 return nil, nil 78 } 79 if kv[`ID`] != `debian` { 80 return nil, nil 81 } 82 83 // Regex pattern matches item within string that appear as so: (bookworm), (buster), (bullseye) 84 ver := regexp.MustCompile(`\(\w+\)$`) 85 86 name, nameok := kv[`VERSION_CODENAME`] 87 idstr := kv[`VERSION_ID`] 88 if !nameok { 89 name = strings.TrimFunc(ver.FindString(kv[`VERSION`]), func(r rune) bool { return !unicode.IsLetter(r) }) 90 } 91 if name == "" || idstr == "" { 92 zlog.Info(ctx). 93 Err(err).Msg("malformed os-release file") 94 return nil, nil 95 } 96 id, err := strconv.ParseInt(idstr, 10, 32) 97 if err != nil { 98 zlog.Info(ctx). 99 Err(err).Msg("malformed os-release file") 100 return nil, nil 101 } 102 return mkDist(name, int(id)), nil 103 }