Completed
Pull Request — master (#775)
by kota
11:29
created

github.FillGitHubSecurityAlerts   C

Complexity

Conditions 10

Size

Total Lines 77
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 44
dl 0
loc 77
rs 5.9999
c 0
b 0
f 0
nop 4

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like github.FillGitHubSecurityAlerts often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* Vuls - Vulnerability Scanner
2
Copyright (C) 2016  Future Corporation , Japan.
3
4
This program is free software: you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation, either version 3 of the License, or
7
(at your option) any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
package github
19
20
import (
21
	"bytes"
22
	"context"
23
	"encoding/json"
24
	"fmt"
25
	"io/ioutil"
26
	"net/http"
27
28
	"github.com/future-architect/vuls/models"
29
	"github.com/future-architect/vuls/util"
30
	"github.com/k0kubun/pp"
31
	"golang.org/x/oauth2"
32
)
33
34
// FillGitHubSecurityAlerts access to owner/repo on GitHub and fetch scurity alerts of the repository via GitHub API v4 GraphQL and then set to the given ScanResult.
35
// https://help.github.com/articles/about-security-alerts-for-vulnerable-dependencies/
36
func FillGitHubSecurityAlerts(r *models.ScanResult, owner, repo, token string) (nCVEs int, err error) {
37
	src := oauth2.StaticTokenSource(
38
		&oauth2.Token{AccessToken: token},
39
	)
40
	httpClient := oauth2.NewClient(context.Background(), src)
41
	const jsonfmt = `{"query":
42
	"query { repository(owner:\"%s\", name:\"%s\") { name, vulnerabilityAlerts(first: %d, %s) { pageInfo{ endCursor, hasNextPage, startCursor}, edges { node { id, externalIdentifier, externalReference, fixedIn, packageName } } } } }"}`
43
44
	after := ""
45
	for {
46
		jsonStr := fmt.Sprintf(jsonfmt, owner, repo, 100, after)
47
		req, err := http.NewRequest("POST",
48
			"https://api.github.com/graphql",
49
			bytes.NewBuffer([]byte(jsonStr)),
50
		)
51
		if err != nil {
52
			return 0, err
53
		}
54
		req.Header.Set("Content-Type", "application/json")
55
56
		// https://developer.github.com/v4/previews/#repository-vulnerability-alerts
57
		// To toggle this preview and access data, need to provide a custom media type in the Accept header:
58
		// TODO remove this header if it is no longer preview status in the future.
59
		req.Header.Set("Accept", "application/vnd.github.vixen-preview+json")
60
61
		resp, err := httpClient.Do(req)
62
		if err != nil {
63
			return 0, err
64
		}
65
		defer resp.Body.Close()
66
		bodyBytes, err := ioutil.ReadAll(resp.Body)
67
		if err != nil {
68
			return 0, err
69
		}
70
71
		alerts := SecurityAlerts{}
72
		if err = json.Unmarshal(bodyBytes, &alerts); err != nil {
73
			return 0, err
74
		}
75
76
		// TODO remove
77
		util.Log.Debugf("%s", pp.Sprintf("%s", alerts))
0 ignored issues
show
introduced by
arg alerts for printf verb %s of wrong type: github.SecurityAlerts
Loading history...
78
79
		// TODO add type field to models.Pakcage.
80
		// OS Packages ... osPkg
81
		// CPE ... CPE
82
		// GitHub ... GitHub
83
		// WordPress theme ... wpTheme
84
		// WordPress plugin ... wpPlugin
85
		// WordPress core ... wpCore
86
		for _, v := range alerts.Data.Repository.VulnerabilityAlerts.Edges {
87
			cveID := v.Node.ExternalIdentifier
88
			affectedPkg := models.PackageStatus{Name: v.Node.PackageName}
89
			if val, ok := r.ScannedCves[cveID]; ok {
90
				val.AffectedPackages = append(val.AffectedPackages, affectedPkg)
91
				r.ScannedCves[cveID] = val
92
				// TODO add package information to r.Packages
93
				// TODO get current version via github API if possible
94
				nCVEs++
95
			} else {
96
				v := models.VulnInfo{
97
					CveID:            cveID,
98
					Confidences:      models.Confidences{models.GitHubMatch},
99
					AffectedPackages: models.PackageStatuses{affectedPkg},
100
				}
101
				r.ScannedCves[cveID] = v
102
				// TODO add package information to r.Packages
103
				// TODO get current version via github API if possible
104
				nCVEs++
105
			}
106
		}
107
		if !alerts.Data.Repository.VulnerabilityAlerts.PageInfo.HasNextPage {
108
			break
109
		}
110
		after = fmt.Sprintf(`after: \"%s\"`, alerts.Data.Repository.VulnerabilityAlerts.PageInfo.EndCursor)
111
	}
112
	return nCVEs, err
113
}
114
115
//SecurityAlerts has detected CVE-IDs, PackageNames, Refs
116
type SecurityAlerts struct {
117
	Data struct {
118
		Repository struct {
119
			VulnerabilityAlerts struct {
120
				PageInfo struct {
121
					EndCursor   string `json:"endCursor"`
122
					HasNextPage bool   `json:"hasNextPage"`
123
					StartCursor string `json:"startCursor"`
124
				} `json:"pageInfo"`
125
				Edges []struct {
126
					Node struct {
127
						ID                 string `json:"id"`
128
						ExternalIdentifier string `json:"externalIdentifier"`
129
						ExternalReference  string `json:"externalReference"`
130
						FixedIn            string `json:"fixedIn"`
131
						PackageName        string `json:"packageName"`
132
					} `json:"node"`
133
				} `json:"edges"`
134
			} `json:"vulnerabilityAlerts"`
135
		} `json:"repository"`
136
	} `json:"data"`
137
}
138