Skip to content

Commit

Permalink
add struct to keep snyk projects response; change log.Println to fmt.…
Browse files Browse the repository at this point in the history
…Println to print everything in azure log stream as information; update tests to skip cache
  • Loading branch information
betorvs committed Dec 30, 2021
1 parent 0b1fb4b commit 3ea2047
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 43 deletions.
95 changes: 54 additions & 41 deletions snyk.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ import (
"net/url"
"os"
"strings"
"time"
)

type Data struct {
Data map[string]interface{}
ExpireOn int64
}

var (
// UnknownURL string
UnknownURL = "https://img.shields.io/badge/vulnerabilities-unknown-inactive?logo=snyk"
Expand All @@ -31,6 +37,8 @@ var (
Client *http.Client
// APIURL string
APIURL string
// SnykData Data
SnykData Data
)

// Handle the API request for badge creation.
Expand All @@ -40,46 +48,50 @@ func badgeHandler(w http.ResponseWriter, r *http.Request, apiURL, username, repo
// Default shields.io badge URL
badgeURL := UnknownURL

// Setup the GET request
req, _ := http.NewRequest("GET", apiURL, nil)
fmt.Println("request expiration: ", SnykData.ExpireOn)
if SnykData.ExpireOn == 0 || SnykData.ExpireOn < time.Now().Unix() {
// 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"))
// 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
}
// Perform the request
resp, err := Client.Do(req)

defer resp.Body.Close()
// 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
}

respBody, _ := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
SnykData.ExpireOn = time.Now().Add(time.Second * 15).Unix()
fmt.Println("request expire on: ", SnykData.ExpireOn)

// 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
}
respBody, _ := ioutil.ReadAll(resp.Body)

// Perform JSON loading of the response
var data map[string]interface{}
err = json.Unmarshal([]byte(string(respBody)), &data)
// 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)), &SnykData.Data)

if err != nil {
writeBadge(w, badgeURL)
return
if err != nil {
writeBadge(w, badgeURL)
return
}
}

projects := data["projects"].([]interface{})
projects := SnykData.Data["projects"].([]interface{})

// Check number of vulnerabilities based on search critiria
// org + name without projectID
Expand Down Expand Up @@ -156,26 +168,26 @@ func vulnerabilitiesFound(projects []interface{}, name string, projectID string)
func countVulnerabilities(project map[string]interface{}) (int, bool) {
var criticalCount, highCount, mediumCount, lowCount, totalIssues int
var critical bool
// log.Println("project: ", project)
// fmt.Println("project: ", project)
// Count the number of issues
issues := project["issueCountsBySeverity"].(map[string]interface{})
// fmt.Println("full issues list: ",issues)
log.Println("repository: ", project["name"], ", issues: ", issues["critical"], issues["high"], issues["medium"], issues["low"])
fmt.Println("repository: ", project["name"], ", issues: ", issues["critical"], issues["high"], issues["medium"], issues["low"])
criticalCount = int(issues["critical"].(float64))
highCount = int(issues["high"].(float64))
mediumCount = int(issues["medium"].(float64))
lowCount = int(issues["low"].(float64))
if criticalCount != 0 || highCount != 0 {
critical = true
log.Println("critical found ")
fmt.Println("critical found ")
}
totalIssues = criticalCount + highCount + mediumCount + lowCount
return totalIssues, critical
}

// Return the badge image from the shields.io URL
func writeBadge(w http.ResponseWriter, badgeURL string) {
log.Println("badge url: ", badgeURL)
fmt.Println("badge url: ", badgeURL)
// Set the response header
w.Header().Set("Content-Type", "image/svg+xml;charset=utf-8")

Expand Down Expand Up @@ -207,13 +219,13 @@ func writeBadge(w http.ResponseWriter, badgeURL string) {
}

func Handler(w http.ResponseWriter, r *http.Request) {
log.Println("url path: ", r.URL.Path, r.URL.RawQuery)
fmt.Println("url path: ", r.URL.Path, r.URL.RawQuery)
parameters := r.URL.RawQuery
if strings.Contains(r.URL.RawQuery, ",") {
// adjust because azure functions redirect
// from: org=Org&id=a1&id=b1
// to: org=Org&id=a1,b1
log.Println("found comma in parameters :", r.URL.RawQuery)
fmt.Println("found comma in parameters :", r.URL.RawQuery)
parameters = strings.ReplaceAll(r.URL.RawQuery, ",", "&id=")
}
values, err := url.ParseQuery(parameters)
Expand All @@ -224,14 +236,14 @@ func Handler(w http.ResponseWriter, r *http.Request) {
}

if len(values) == 0 {
log.Println("parameters are empty: ", values)
fmt.Println("parameters are empty: ", values)
}
// Parse URL parameters
org := values.Get("org")
name := values.Get("name")
projectID := values["id"]
if len(projectID) > 1 {
log.Println("found more than one id: ", projectID)
fmt.Println("found more than one id: ", projectID)
}
// Required values:
// org is always required
Expand All @@ -250,7 +262,7 @@ func Handler(w http.ResponseWriter, r *http.Request) {
}

func versionHandler(w http.ResponseWriter, r *http.Request) {
log.Println("url path: ", r.URL.Path)
fmt.Println("url path: ", r.URL.Path)
w.Header().Set("Content-Type", "application/json")
message := fmt.Sprintf("{\"version\": \"%s\", \"commit\":\"%s\"}", Version, Commit)
fmt.Fprint(w, message)
Expand All @@ -260,6 +272,7 @@ func init() {
Client = &http.Client{}
// Generate the Snyk API URL
APIURL = fmt.Sprintf("https://snyk.io/api/v1/org/%s/projects", os.Getenv("SNYK_ORG_ID"))
SnykData = Data{}
}

func main() {
Expand All @@ -270,6 +283,6 @@ func main() {

http.HandleFunc("/api/badges", Handler)
http.HandleFunc("/api/version", versionHandler)
log.Printf("Listen on %s. Go to https://127.0.0.1%s/", listenAddr, listenAddr)
fmt.Printf("Listen on %s. Go to https://127.0.0.1%s/", listenAddr, listenAddr)
log.Fatal(http.ListenAndServe(listenAddr, nil))
}
25 changes: 23 additions & 2 deletions snyk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ func TestHandler(t *testing.T) {
assert.Empty(t, res)

// repository: TestOrg/repositoryOne:helm/templates/deployment.yaml
SnykData.ExpireOn = 0
req2, err2 := http.NewRequest("GET", "/api/badges?org=TestOrg&name=repositoryOne", nil)
assert.NoError(t, err2)
rr2 := httptest.NewRecorder()
Expand All @@ -315,6 +316,7 @@ func TestHandler(t *testing.T) {
assert.Equal(t, res.Header["Content-Type"], []string{"application/json"})

// repository: TestOrg/repositoryOne:helm/templates/deployment.yaml
SnykData.ExpireOn = 0
req3, err3 := http.NewRequest("GET", "/api/badges?org=TestOrg&name=repositoryOne&id=01a88ebb-ee9d-0650-ba1d-c5a93668b36f", nil)
assert.NoError(t, err3)
rr3 := httptest.NewRecorder()
Expand All @@ -323,8 +325,8 @@ func TestHandler(t *testing.T) {
handler3.ServeHTTP(rr3, req3)
assert.Equal(t, http.StatusOK, rr3.Code)

// ??
fmt.Println("/api/badges?org=TestOrg&name=repositoryThree")
//
SnykData.ExpireOn = 0
req4, err4 := http.NewRequest("GET", "/api/badges?org=TestOrg&name=repositoryThree", nil)
assert.NoError(t, err4)
rr4 := httptest.NewRecorder()
Expand All @@ -335,6 +337,7 @@ func TestHandler(t *testing.T) {

//repository: TestOrg/repositoryOne , issues: 0 0 3 0
// repository: TestOrg/repositoryOne:helm/templates/deployment.yaml
SnykData.ExpireOn = 0
req5, err5 := http.NewRequest("GET", "/api/badges?org=TestOrg&name=repositoryOne&id=e48bd952-7a33-0ad8-fec5-e5d644cb9051&id=01a88ebb-ee9d-0650-ba1d-c5a93668b36f", nil)
assert.NoError(t, err5)
rr5 := httptest.NewRecorder()
Expand All @@ -343,6 +346,8 @@ func TestHandler(t *testing.T) {
handler5.ServeHTTP(rr5, req5)
assert.Equal(t, http.StatusOK, rr5.Code)

// id with comma
SnykData.ExpireOn = 0
req6, err6 := http.NewRequest("GET", "/api/badges?org=TestOrg&name=repositoryOne&id=e48bd952-7a33-0ad8-fec5-e5d644cb9051,01a88ebb-ee9d-0650-ba1d-c5a93668b36f", nil)
assert.NoError(t, err6)
rr6 := httptest.NewRecorder()
Expand All @@ -352,13 +357,25 @@ func TestHandler(t *testing.T) {
assert.Equal(t, http.StatusOK, rr6.Code)

// repositoryOne:helm/templates/deployment.yaml
SnykData.ExpireOn = 0
req7, err7 := http.NewRequest("GET", "/api/badges?org=TestOrg&name=repositoryOne:helm/templates/deployment.yaml", nil)
assert.NoError(t, err7)
rr7 := httptest.NewRecorder()
handler7 := http.HandlerFunc(Handler)

handler7.ServeHTTP(rr7, req7)
assert.Equal(t, http.StatusOK, rr7.Code)

// id with comma and name with wrong order
fmt.Println("test multiple names")
SnykData.ExpireOn = 0
req8, err8 := http.NewRequest("GET", "/api/badges?org=TestOrg&id=e48bd952-7a33-0ad8-fec5-e5d644cb9051,01a88ebb-ee9d-0650-ba1d-c5a93668b36f&name=repositoryOne,repositoryTwo", nil)
assert.NoError(t, err8)
rr8 := httptest.NewRecorder()
handler8 := http.HandlerFunc(Handler)

handler8.ServeHTTP(rr8, req8)
assert.Equal(t, http.StatusOK, rr8.Code)
}

func TestHandlerErrors(t *testing.T) {
Expand All @@ -380,6 +397,7 @@ func TestHandlerErrors(t *testing.T) {
FoundURL = fmt.Sprintf("%s/", tss.URL)

// simple error repository not found
SnykData.ExpireOn = 0
req1, err1 := http.NewRequest("GET", "/api/badges?org=TestOrg&name=repositoryFour", nil)
assert.NoError(t, err1)
rr1 := httptest.NewRecorder()
Expand All @@ -395,6 +413,7 @@ func TestHandlerErrors(t *testing.T) {
UnknownURL = tss2.URL

// force fail with required name or id as parameters
SnykData.ExpireOn = 0
req2, err2 := http.NewRequest("GET", "/api/badges?org=TestOrg", nil)
assert.NoError(t, err2)
rr2 := httptest.NewRecorder()
Expand All @@ -404,6 +423,7 @@ func TestHandlerErrors(t *testing.T) {
assert.Equal(t, http.StatusOK, rr2.Code)

// force url.ParseQuery to fail
SnykData.ExpireOn = 0
req3, err3 := http.NewRequest("GET", "/api/badges?org=TestOrg%%", nil)
assert.NoError(t, err3)
rr3 := httptest.NewRecorder()
Expand All @@ -420,6 +440,7 @@ func TestHandlerErrors(t *testing.T) {
defer tss3.Close()
APIURL = tss3.URL
// forcing json.Unmarshal error
SnykData.ExpireOn = 0
req4, err4 := http.NewRequest("GET", "/api/badges?org=TestOrg&name=repositoryTwo", nil)
assert.NoError(t, err4)
rr4 := httptest.NewRecorder()
Expand Down

0 comments on commit 3ea2047

Please sign in to comment.