forked from quay/claircore
/
reposcanner.go
99 lines (86 loc) · 2.46 KB
/
reposcanner.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
// Package python contains components for interrogating python packages in
// container layers.
package python
import (
"archive/tar"
"context"
"errors"
"io"
"path/filepath"
"runtime/trace"
"strings"
"github.com/quay/zlog"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/label"
"github.com/Panzer1119/claircore"
"github.com/Panzer1119/claircore/internal/indexer"
)
var (
_ indexer.VersionedScanner = (*Scanner)(nil)
_ indexer.PackageScanner = (*Scanner)(nil)
Repository = claircore.Repository{
Name: "pypi",
URI: "https://pypi.org/simple",
}
)
type RepoScanner struct{}
// Name implements scanner.VersionedScanner.
func (*RepoScanner) Name() string { return "pip" }
// Version implements scanner.VersionedScanner.
func (*RepoScanner) Version() string { return "0.0.1" }
// Kind implements scanner.VersionedScanner.
func (*RepoScanner) Kind() string { return "repository" }
// Scan attempts to find wheel or egg info directories and record the package
// information there.
//
// A return of (nil, nil) is expected if there's nothing found.
func (rs *RepoScanner) Scan(ctx context.Context, layer *claircore.Layer) ([]*claircore.Repository, error) {
defer trace.StartRegion(ctx, "RepoScanner.Scan").End()
trace.Log(ctx, "layer", layer.Hash.String())
ctx = baggage.ContextWithValues(ctx,
label.String("component", "python/RepoScanner.Scan"),
label.String("version", rs.Version()),
label.String("layer", layer.Hash.String()))
zlog.Debug(ctx).Msg("start")
defer zlog.Debug(ctx).Msg("done")
if err := ctx.Err(); err != nil {
return nil, err
}
r, err := layer.Reader()
if err != nil {
return nil, err
}
defer r.Close()
rd, ok := r.(interface {
io.ReadCloser
io.Seeker
})
if !ok {
return nil, errors.New("python: cannot seek on returned layer Reader")
}
tr := tar.NewReader(rd)
var h *tar.Header
for h, err = tr.Next(); err == nil; h, err = tr.Next() {
n, err := filepath.Rel("/", filepath.Join("/", h.Name))
if err != nil {
return nil, err
}
switch {
case h.Typeflag != tar.TypeReg:
// Should we chase symlinks with the correct name?
continue
case strings.HasSuffix(n, `.egg-info/PKG-INFO`):
zlog.Debug(ctx).Str("file", n).Msg("found egg")
case strings.HasSuffix(n, `.dist-info/METADATA`):
zlog.Debug(ctx).Str("file", n).Msg("found wheel")
default:
continue
}
// Just claim these came from pypi.
return []*claircore.Repository{&Repository}, nil
}
if err != io.EOF {
return nil, err
}
return nil, nil
}