-
Notifications
You must be signed in to change notification settings - Fork 329
/
extractor.go
103 lines (82 loc) · 2.5 KB
/
extractor.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
package image
import (
"fmt"
"io"
"path"
"sort"
"github.com/google/osv-scanner/pkg/lockfile"
)
// artifactExtractors contains only extractors for artifacts that are important in
// the final layer of a container image
var artifactExtractors map[string]lockfile.Extractor = map[string]lockfile.Extractor{
"node_modules": lockfile.NodeModulesExtractor{},
"apk-installed": lockfile.ApkInstalledExtractor{},
"dpkg": lockfile.DpkgStatusExtractor{},
}
func findArtifactExtractor(path string) (lockfile.Extractor, string) {
for name, extractor := range artifactExtractors {
if extractor.ShouldExtract(path) {
return extractor, name
}
}
return nil, ""
}
func extractArtifactDeps(path string, img *Image) (lockfile.Lockfile, error) {
extractor, extractedAs := findArtifactExtractor(path)
if extractor == nil {
return lockfile.Lockfile{}, fmt.Errorf("%w for %s", lockfile.ErrExtractorNotFound, path)
}
f, err := OpenLayerFile(path, img.LastLayer())
if err != nil {
return lockfile.Lockfile{}, fmt.Errorf("attempted to open file but failed: %w", err)
}
defer f.Close()
packages, err := extractor.Extract(f)
if err != nil && extractedAs != "" {
err = fmt.Errorf("(extracting as %s) %w", extractedAs, err)
return lockfile.Lockfile{}, fmt.Errorf("failed to close file: %w", err)
}
// Sort to have deterministic output, and to match behavior of lockfile.extractDeps
sort.Slice(packages, func(i, j int) bool {
if packages[i].Name == packages[j].Name {
return packages[i].Version < packages[j].Version
}
return packages[i].Name < packages[j].Name
})
return lockfile.Lockfile{
FilePath: f.Path(),
ParsedAs: extractedAs,
Packages: packages,
}, err
}
// A ImageFile represents a file that exists in an image
type ImageFile struct {
io.ReadCloser
layer fileMap
path string
}
func (f ImageFile) Open(openPath string) (lockfile.NestedDepFile, error) {
// use path instead of filepath, because container is always in Unix paths (for now)
if path.IsAbs(openPath) {
return OpenLayerFile(openPath, f.layer)
} else {
absPath := path.Join(f.path, openPath)
return OpenLayerFile(absPath, f.layer)
}
}
func (f ImageFile) Path() string {
return f.path
}
func OpenLayerFile(path string, layer fileMap) (ImageFile, error) {
readCloser, err := layer.OpenFile(path)
if err != nil {
return ImageFile{}, err
}
return ImageFile{
ReadCloser: readCloser,
path: path,
layer: layer,
}, nil
}
var _ lockfile.DepFile = ImageFile{}
var _ lockfile.NestedDepFile = ImageFile{}