-
Notifications
You must be signed in to change notification settings - Fork 0
/
scan.go
116 lines (98 loc) · 2.85 KB
/
scan.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
106
107
108
109
110
111
112
113
114
115
116
package main
import (
"bytes"
"fmt"
"log"
"path"
"path/filepath"
"regexp"
"strings"
"github.com/chartmuseum/storage"
"k8s.io/helm/pkg/chartutil"
)
func check(backend storage.Backend) error {
_, err := backend.ListObjects("")
return err
}
func scan(backend storage.Backend, prefix string, debug bool) {
objects, _ := backend.ListObjects(prefix)
for _, object := range objects {
fullPath := path.Join(prefix, object.Path)
isChartPackage := strings.HasSuffix(fullPath, ".tgz")
isProvenanceFile := strings.HasSuffix(fullPath, ".prov")
if isChartPackage {
validateChartPackage(backend, fullPath, debug)
} else if isProvenanceFile {
validateProvenanceFile(backend, fullPath, debug)
} else {
scan(backend, fullPath, debug)
}
}
}
func validateChartPackage(backend storage.Backend, filePath string, debug bool) {
object, err := backend.GetObject(filePath)
if err != nil {
log.Printf("ERROR %s could not be retrieved\n", filePath)
exitCode = 1
return
}
chart, err := chartutil.LoadArchive(bytes.NewBuffer(object.Content))
if err != nil {
log.Printf("ERROR %s could not be loaded as a chart\n", filePath)
exitCode = 1
return
}
fileBaseName := filepath.Base(filePath)
name := chart.Metadata.Name
version := chart.Metadata.Version
// the actual validation occurs here
if strings.ContainsAny(name, "/\\") ||
strings.ContainsAny(version, "/\\") ||
fileBaseName != fmt.Sprintf("%s-%s.tgz", name, version) {
log.Printf("ERROR %s has bad chart name \"%s\"\n", filePath, name)
exitCode = 1
return
}
if debug {
log.Printf("DEBUG %s is valid\n", filePath)
}
}
func validateProvenanceFile(backend storage.Backend, filePath string, debug bool) {
object, err := backend.GetObject(filePath)
if err != nil {
log.Printf("ERROR %s could not be retrieved\n", filePath)
exitCode = 1
return
}
contentStr := string(object.Content[:])
hasPGPBegin := strings.HasPrefix(contentStr, "-----BEGIN PGP SIGNED MESSAGE-----")
nameMatch := regexp.MustCompile("\nname:[ *](.+)").FindStringSubmatch(contentStr)
versionMatch := regexp.MustCompile("\nversion:[ *](.+)").FindStringSubmatch(contentStr)
if !hasPGPBegin || len(nameMatch) != 2 || len(versionMatch) != 2 {
log.Printf("ERROR %s is not a valid provenance file\n", filePath)
exitCode = 1
return
}
fileBaseName := filepath.Base(filePath)
name := trimQuotes(nameMatch[1])
version := trimQuotes(versionMatch[1])
// the actual validation occurs here
if strings.ContainsAny(name, "/\\") ||
strings.ContainsAny(version, "/\\") ||
fileBaseName != fmt.Sprintf("%s-%s.tgz.prov", name, version) {
log.Printf("ERROR %s has bad chart name \"%s\"\n", filePath, name)
exitCode = 1
return
}
if debug {
log.Printf("DEBUG %s is valid\n", filePath)
}
}
func trimQuotes(s string) string {
if len(s) >= 2 {
if s[0] == '"' && s[len(s)-1] == '"' {
return s[1 : len(s)-1]
}
}
return s
}