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