-
Notifications
You must be signed in to change notification settings - Fork 10
/
snyk.go
149 lines (116 loc) · 3.71 KB
/
snyk.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"regexp"
"strings"
)
// Handle the API request for badge creation.
// Hit Snyk's List Projects API and get a list of projects. Check if the caller has access to the repo referred to by
// username/repo and return a badge if access.
func badgeHandler(w http.ResponseWriter, r *http.Request, username string, repo string) {
// Default shields.io badge URL
badgeURL := "https://img.shields.io/badge/vulnerabilities-unknown-inactive"
client := &http.Client{}
// Generate the Snyk API URL
apiURL := fmt.Sprintf("https://snyk.io/api/v1/org/%s/projects", os.Getenv("SNYK_ORG_ID"))
// Setup the GET request
req, _ := http.NewRequest("GET", apiURL, nil)
// Setup the headers
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", os.Getenv("SNYK_API_KEY"))
// Perform the request
resp, err := client.Do(req)
// Could not perform the request
// Likely network issues
if err != nil {
log.Println("Errored when sending request to the Snyk server")
writeBadge(w, badgeURL)
return
}
defer resp.Body.Close()
respBody, _ := ioutil.ReadAll(resp.Body)
// Non-200 response received
// Likely the creds are wrong
if resp.StatusCode != 200 {
log.Println("Did not receive a 200 OK response from the Snyk server")
writeBadge(w, badgeURL)
return
}
// Perform JSON loading of the response
var data map[string]interface{}
err = json.Unmarshal([]byte(string(respBody)), &data)
if err != nil {
writeBadge(w, badgeURL)
return
}
projects := data["projects"].([]interface{})
// Check if the requested repo is available
for _, project := range projects {
project := project.(map[string]interface{})
if strings.HasPrefix(project["name"].(string), username+"/"+repo+":") {
// Count the number of issues
issues := project["issueCountsBySeverity"].(map[string]interface{})
highCount := int(issues["high"].(float64))
mediumCount := int(issues["medium"].(float64))
lowCount := int(issues["low"].(float64))
totalIssues := highCount + mediumCount + lowCount
if totalIssues == 0 {
// No vulnerabilities
badgeURL = "https://img.shields.io/badge/vulnerabilities-0-brightgreen"
} else {
// Vulnerabilities found
badgeURL = fmt.Sprintf("https://img.shields.io/badge/vulnerabilities-%d-red", totalIssues)
}
break
}
}
writeBadge(w, badgeURL)
return
}
// Return the badge image from the shields.io URL
func writeBadge(w http.ResponseWriter, badgeURL string) {
// Set the response header
w.Header().Set("Content-Type", "image/svg+xml;charset=utf-8")
client := &http.Client{}
req, _ := http.NewRequest("GET", badgeURL, nil)
resp, err := client.Do(req)
// Could not perform the request
// Likely network issues
if err != nil {
log.Println("Errored when sending request to the Shields server")
fmt.Fprintf(w, badgeURL)
return
}
defer resp.Body.Close()
// Non-200 response received
// Likely the service is down
if resp.StatusCode != 200 {
log.Println("Did not receive a 200 OK response from the Shields server")
fmt.Fprintf(w, badgeURL)
return
}
// Write the SVG image to the response object
io.Copy(w, resp.Body)
}
var validPath = regexp.MustCompile("^/badge/([a-zA-Z0-9-]+)/([a-zA-Z0-9-]+)/$")
func makeHandler(fn func(http.ResponseWriter, *http.Request, string, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Path validation
m := validPath.FindStringSubmatch(r.URL.Path)
if m == nil {
writeBadge(w, "https://img.shields.io/badge/vulnerabilities-unknown-inactive")
return
}
fn(w, r, m[1], m[2])
}
}
func main() {
http.HandleFunc("/badge/", makeHandler(badgeHandler))
log.Fatal(http.ListenAndServe(":8080", nil))
}