Skip to content

Commit 5f9fff3

Browse files
authored
✨ Separate check from policies for the Vulnerabilities check (#1532)
* raw vulnerabilities seperation * update year * missing files * tests
1 parent 7a6eb28 commit 5f9fff3

File tree

7 files changed

+173
-44
lines changed

7 files changed

+173
-44
lines changed

checker/raw_result.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,19 @@ package checker
1717
// RawResults contains results before a policy
1818
// is applied.
1919
type RawResults struct {
20+
VulnerabilitiesResults VulnerabilitiesData
2021
BinaryArtifactResults BinaryArtifactData
2122
SecurityPolicyResults SecurityPolicyData
2223
DependencyUpdateToolResults DependencyUpdateToolData
2324
BranchProtectionResults BranchProtectionsData
2425
}
2526

27+
// VulnerabilitiesData contains the raw results
28+
// for the Vulnerabilities check.
29+
type VulnerabilitiesData struct {
30+
Vulnerabilities []Vulnerability
31+
}
32+
2633
// SecurityPolicyData contains the raw results
2734
// for the Security-Policy check.
2835
type SecurityPolicyData struct {
@@ -111,3 +118,12 @@ type File struct {
111118
Type FileType // Type of file.
112119
// TODO: add hash.
113120
}
121+
122+
// Vulnerability defines a vulnerability
123+
// from a database.
124+
type Vulnerability struct {
125+
// For OSV: OSV-2020-484
126+
// For CVE: CVE-2022-23945
127+
ID string
128+
// TODO(vuln): Add additional fields, if needed.
129+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2022 Security Scorecard Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package evaluation
16+
17+
import (
18+
"fmt"
19+
"strings"
20+
21+
"github.com/ossf/scorecard/v4/checker"
22+
sce "github.com/ossf/scorecard/v4/errors"
23+
)
24+
25+
// Vulnerabilities applies the score policy for the Vulnerabilities check.
26+
func Vulnerabilities(name string, dl checker.DetailLogger,
27+
r *checker.VulnerabilitiesData) checker.CheckResult {
28+
if r == nil {
29+
e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data")
30+
return checker.CreateRuntimeErrorResult(name, e)
31+
}
32+
33+
score := checker.MaxResultScore
34+
IDs := []string{}
35+
for _, vuln := range r.Vulnerabilities {
36+
IDs = append(IDs, vuln.ID)
37+
score--
38+
}
39+
40+
if score < 0 {
41+
score = 0
42+
}
43+
44+
if len(IDs) > 0 {
45+
dl.Warn3(&checker.LogMessage{
46+
Text: fmt.Sprintf("HEAD is vulnerable to %s", strings.Join(IDs, ", ")),
47+
})
48+
return checker.CreateResultWithScore(name,
49+
fmt.Sprintf("%v existing vulnerabilities detected", len(IDs)), score)
50+
}
51+
52+
return checker.CreateMaxScoreResult(name, "no vulnerabilities detected")
53+
}

checks/raw/vulnerabilities.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2022 Security Scorecard Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package raw
16+
17+
import (
18+
"github.com/ossf/scorecard/v4/checker"
19+
"github.com/ossf/scorecard/v4/clients"
20+
sce "github.com/ossf/scorecard/v4/errors"
21+
)
22+
23+
// Vulnerabilities retrieves the raw data for the Vulnerabilities check.
24+
func Vulnerabilities(c *checker.CheckRequest) (checker.VulnerabilitiesData, error) {
25+
commits, err := c.RepoClient.ListCommits()
26+
if err != nil {
27+
return checker.VulnerabilitiesData{},
28+
sce.WithMessage(sce.ErrScorecardInternal, "Client.Repositories.ListCommits")
29+
}
30+
31+
if len(commits) < 1 || commits[0].SHA == "" {
32+
return checker.VulnerabilitiesData{},
33+
sce.WithMessage(sce.ErrScorecardInternal, "no commits found")
34+
}
35+
36+
resp, err := c.VulnerabilitiesClient.HasUnfixedVulnerabilities(c.Ctx, commits[0].SHA)
37+
if err != nil {
38+
return checker.VulnerabilitiesData{},
39+
sce.WithMessage(sce.ErrScorecardInternal, "VulnerabilitiesClient.HasUnfixedVulnerabilities")
40+
}
41+
42+
vulnIDs := getVulnerabilities(&resp)
43+
vulns := []checker.Vulnerability{}
44+
for _, id := range vulnIDs {
45+
v := checker.Vulnerability{
46+
ID: id,
47+
// Note: add fields if needed.
48+
}
49+
vulns = append(vulns, v)
50+
}
51+
return checker.VulnerabilitiesData{Vulnerabilities: vulns}, nil
52+
}
53+
54+
func getVulnerabilities(resp *clients.VulnerabilitiesResponse) []string {
55+
ids := make([]string, 0, len(resp.Vulns))
56+
for _, vuln := range resp.Vulns {
57+
ids = append(ids, vuln.ID)
58+
}
59+
return ids
60+
}

checks/vulnerabilities.go

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2021 Security Scorecard Authors
1+
// Copyright 2022 Security Scorecard Authors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -15,61 +15,36 @@
1515
package checks
1616

1717
import (
18-
"fmt"
19-
"strings"
20-
2118
"github.com/ossf/scorecard/v4/checker"
22-
"github.com/ossf/scorecard/v4/clients"
19+
"github.com/ossf/scorecard/v4/checks/evaluation"
20+
"github.com/ossf/scorecard/v4/checks/raw"
2321
sce "github.com/ossf/scorecard/v4/errors"
2422
)
2523

26-
const (
27-
// CheckVulnerabilities is the registered name for the OSV check.
28-
CheckVulnerabilities = "Vulnerabilities"
29-
)
24+
// CheckVulnerabilities is the registered name for the OSV check.
25+
const CheckVulnerabilities = "Vulnerabilities"
3026

3127
//nolint:gochecknoinits
3228
func init() {
33-
if err := registerCheck(CheckVulnerabilities, HasUnfixedVulnerabilities); err != nil {
29+
if err := registerCheck(CheckVulnerabilities, Vulnerabilities); err != nil {
3430
// this should never happen
3531
panic(err)
3632
}
3733
}
3834

39-
func getVulnerabilities(resp *clients.VulnerabilitiesResponse) []string {
40-
ids := make([]string, 0, len(resp.Vulns))
41-
for _, vuln := range resp.Vulns {
42-
ids = append(ids, vuln.ID)
43-
}
44-
return ids
45-
}
46-
47-
// HasUnfixedVulnerabilities runs Vulnerabilities check.
48-
func HasUnfixedVulnerabilities(c *checker.CheckRequest) checker.CheckResult {
49-
commits, err := c.RepoClient.ListCommits()
50-
if err != nil {
51-
e := sce.WithMessage(sce.ErrScorecardInternal, "Client.Repositories.ListCommits")
52-
return checker.CreateRuntimeErrorResult(CheckVulnerabilities, e)
53-
}
54-
55-
if len(commits) < 1 || commits[0].SHA == "" {
56-
return checker.CreateInconclusiveResult(CheckVulnerabilities, "no commits found")
57-
}
58-
59-
resp, err := c.VulnerabilitiesClient.HasUnfixedVulnerabilities(c.Ctx, commits[0].SHA)
35+
// Vulnerabilities runs Vulnerabilities check.
36+
func Vulnerabilities(c *checker.CheckRequest) checker.CheckResult {
37+
rawData, err := raw.Vulnerabilities(c)
6038
if err != nil {
61-
e := sce.WithMessage(sce.ErrScorecardInternal, "VulnerabilitiesClient.HasUnfixedVulnerabilities")
39+
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
6240
return checker.CreateRuntimeErrorResult(CheckVulnerabilities, e)
6341
}
6442

65-
// TODO: take severity into account.
66-
vulnIDs := getVulnerabilities(&resp)
67-
if len(vulnIDs) > 0 {
68-
c.Dlogger.Warn3(&checker.LogMessage{
69-
Text: fmt.Sprintf("HEAD is vulnerable to %s", strings.Join(vulnIDs, ", ")),
70-
})
71-
return checker.CreateMinScoreResult(CheckVulnerabilities, "existing vulnerabilities detected")
43+
// Set the raw results.
44+
if c.RawResults != nil {
45+
c.RawResults.VulnerabilitiesResults = rawData
46+
return checker.CheckResult{}
7247
}
7348

74-
return checker.CreateMaxScoreResult(CheckVulnerabilities, "no vulnerabilities detected")
49+
return evaluation.Vulnerabilities(CheckVulnerabilities, c.Dlogger, &rawData)
7550
}

checks/vulnerabilities_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func TestVulnerabilities(t *testing.T) {
6666
Ctx: context.TODO(),
6767
VulnerabilitiesClient: mockVulnClient,
6868
}
69-
res := HasUnfixedVulnerabilities(&req)
69+
res := Vulnerabilities(&req)
7070
if !tt.isError && res.Error != nil {
7171
t.Fail()
7272
} else if tt.isError && res.Error == nil {

e2e/vulnerabilities_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ var _ = Describe("E2E TEST:Vulnerabilities", func() {
5252
NumberOfDebug: 0,
5353
}
5454

55-
result := checks.HasUnfixedVulnerabilities(&req)
55+
result := checks.Vulnerabilities(&req)
5656
// UPGRADEv2: to remove.
5757
// Old version.
5858
Expect(result.Error).Should(BeNil())
@@ -79,12 +79,12 @@ var _ = Describe("E2E TEST:Vulnerabilities", func() {
7979
}
8080
expected := scut.TestReturn{
8181
Error: nil,
82-
Score: checker.MinResultScore,
82+
Score: checker.MaxResultScore - 3, // 3 vulnerabilities remove 3 points.
8383
NumberOfWarn: 1,
8484
NumberOfInfo: 0,
8585
NumberOfDebug: 0,
8686
}
87-
result := checks.HasUnfixedVulnerabilities(&checkRequest)
87+
result := checks.Vulnerabilities(&checkRequest)
8888
// UPGRADEv2: to remove.
8989
// Old version.
9090
Expect(result.Error).Should(BeNil())

pkg/json_raw_results.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ type jsonBranchProtection struct {
6565
}
6666

6767
type jsonRawResults struct {
68+
DatabaseVulnerabilities []jsonDatabaseVulnerability `json:"database-vulnerabilities"`
6869
// List of binaries found in the repo.
6970
Binaries []jsonFile `json:"binaries"`
7071
// List of security policy files found in the repo.
@@ -77,6 +78,25 @@ type jsonRawResults struct {
7778
BranchProtections []jsonBranchProtection `json:"branch-protections"`
7879
}
7980

81+
type jsonDatabaseVulnerability struct {
82+
// For OSV: OSV-2020-484
83+
// For CVE: CVE-2022-23945
84+
ID string
85+
// TODO: additional information
86+
}
87+
88+
//nolint:unparam
89+
func (r *jsonScorecardRawResult) addVulnerbilitiesRawResults(vd *checker.VulnerabilitiesData) error {
90+
r.Results.DatabaseVulnerabilities = []jsonDatabaseVulnerability{}
91+
for _, v := range vd.Vulnerabilities {
92+
r.Results.DatabaseVulnerabilities = append(r.Results.DatabaseVulnerabilities,
93+
jsonDatabaseVulnerability{
94+
ID: v.ID,
95+
})
96+
}
97+
return nil
98+
}
99+
80100
//nolint:unparam
81101
func (r *jsonScorecardRawResult) addBinaryArtifactRawResults(ba *checker.BinaryArtifactData) error {
82102
r.Results.Binaries = []jsonFile{}
@@ -148,6 +168,11 @@ func (r *jsonScorecardRawResult) addBranchProtectionRawResults(bp *checker.Branc
148168
}
149169

150170
func (r *jsonScorecardRawResult) fillJSONRawResults(raw *checker.RawResults) error {
171+
// Vulnerabiliries.
172+
if err := r.addVulnerbilitiesRawResults(&raw.VulnerabilitiesResults); err != nil {
173+
return sce.WithMessage(sce.ErrScorecardInternal, err.Error())
174+
}
175+
151176
// Binary-Artifacts.
152177
if err := r.addBinaryArtifactRawResults(&raw.BinaryArtifactResults); err != nil {
153178
return sce.WithMessage(sce.ErrScorecardInternal, err.Error())

0 commit comments

Comments
 (0)