From 242d42a6a6119dd9113bceaa1e173f7b1099ec72 Mon Sep 17 00:00:00 2001 From: laurentsimon Date: Tue, 29 Mar 2022 15:37:32 +0000 Subject: [PATCH 1/5] Raw results for best practices badge --- checker/raw_result.go | 25 +++++++++++ checks/cii_best_practices.go | 50 +++++++--------------- checks/evaluation/cii_best_practices.go | 57 +++++++++++++++++++++++++ checks/raw/cii_best_practices.go | 55 ++++++++++++++++++++++++ pkg/json_raw_results.go | 24 +++++++++++ 5 files changed, 176 insertions(+), 35 deletions(-) create mode 100644 checks/evaluation/cii_best_practices.go create mode 100644 checks/raw/cii_best_practices.go diff --git a/checker/raw_result.go b/checker/raw_result.go index c27b6a18d81..58fd237788a 100644 --- a/checker/raw_result.go +++ b/checker/raw_result.go @@ -20,6 +20,7 @@ import "time" // is applied. //nolint type RawResults struct { + CIIBestPracticesResults CIIBestPracticesData VulnerabilitiesResults VulnerabilitiesData BinaryArtifactResults BinaryArtifactData SecurityPolicyResults SecurityPolicyData @@ -249,3 +250,27 @@ type ReleaseAsset struct { Name string URL string } + +// CIIBadge corresponds to CII-Best-Practices badges. +// https://bestpractices.coreinfrastructure.org/en +type CIIBadge string + +const ( + // CIIBadgeUnknown or non-parsable CII Best Practices badge. + CIIBadgeUnknown CIIBadge = "unknown" + // CIIBadgeNotFound represents when CII Best Practices returns an empty response for a project. + CIIBadgeNotFound CIIBadge = "not_found" + // CIIBadgeInProgress state of CII Best Practices badge. + CIIBadgeInProgress CIIBadge = "in_progress" + // CIIBadgePassing for CII Best Practices badge. + CIIBadgePassing CIIBadge = "passing" + // CIIBadgeSilver for CII Best Practices badge. + CIIBadgeSilver CIIBadge = "silver" + // CIIBadgeGold for CII Best Practices badge. + CIIBadgeGold CIIBadge = "gold" +) + +// CIIBestPracticesData contains data foor CIIBestPractices check. +type CIIBestPracticesData struct { + Badge CIIBadge +} diff --git a/checks/cii_best_practices.go b/checks/cii_best_practices.go index 6e6e5ee6f34..f24ad36afe5 100644 --- a/checks/cii_best_practices.go +++ b/checks/cii_best_practices.go @@ -15,22 +15,14 @@ package checks import ( - "fmt" - "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/clients" + "github.com/ossf/scorecard/v4/checks/evaluation" + "github.com/ossf/scorecard/v4/checks/raw" sce "github.com/ossf/scorecard/v4/errors" ) -const ( - // CheckCIIBestPractices is the registered name for CIIBestPractices. - CheckCIIBestPractices = "CII-Best-Practices" - silverScore = 7 - // Note: if this value is changed, please update the action's threshold score - // https://github.com/ossf/scorecard-action/blob/main/policies/template.yml#L61. - passingScore = 5 - inProgressScore = 2 -) +// CheckCIIBestPractices is the registered name for CIIBestPractices. +const CheckCIIBestPractices = "CII-Best-Practices" //nolint:gochecknoinits func init() { @@ -40,31 +32,19 @@ func init() { } } -// CIIBestPractices runs CII-Best-Practices check. +// CIIBestPractices will check if the maintainers have a best practice badge. func CIIBestPractices(c *checker.CheckRequest) checker.CheckResult { - if c.CIIClient == nil { - return checker.CreateInconclusiveResult(CheckCIIBestPractices, "CII client is nil") + rawData, err := raw.CIIBestPractices(c) + if err != nil { + e := sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e) } - // TODO: not supported for local clients. - badgeLevel, err := c.CIIClient.GetBadgeLevel(c.Ctx, c.Repo.URI()) - if err == nil { - switch badgeLevel { - case clients.NotFound: - return checker.CreateMinScoreResult(CheckCIIBestPractices, "no badge detected") - case clients.InProgress: - return checker.CreateResultWithScore(CheckCIIBestPractices, "badge detected: in_progress", inProgressScore) - case clients.Passing: - return checker.CreateResultWithScore(CheckCIIBestPractices, "badge detected: passing", passingScore) - case clients.Silver: - return checker.CreateResultWithScore(CheckCIIBestPractices, "badge detected: silver", silverScore) - case clients.Gold: - return checker.CreateMaxScoreResult(CheckCIIBestPractices, "badge detected: gold") - case clients.Unknown: - e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("unsupported badge: %v", badgeLevel)) - return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e) - } + // Return raw results. + if c.RawResults != nil { + c.RawResults.CIIBestPracticesResults = rawData } - e := sce.WithMessage(sce.ErrScorecardInternal, err.Error()) - return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e) + + // Return the score evaluation. + return evaluation.CIIBestPractices(CheckCIIBestPractices, c.Dlogger, &rawData) } diff --git a/checks/evaluation/cii_best_practices.go b/checks/evaluation/cii_best_practices.go new file mode 100644 index 00000000000..b04ee58e21a --- /dev/null +++ b/checks/evaluation/cii_best_practices.go @@ -0,0 +1,57 @@ +// Copyright Security Scorecard Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package evaluation + +import ( + "fmt" + + "github.com/ossf/scorecard/v4/checker" + sce "github.com/ossf/scorecard/v4/errors" +) + +const ( + silverScore = 7 + // Note: if this value is changed, please update the action's threshold score + // https://github.com/ossf/scorecard-action/blob/main/policies/template.yml#L61. + passingScore = 5 + inProgressScore = 2 +) + +// CIIBestPractices applies the score policy for the CIIBestPractices check. +func CIIBestPractices(name string, dl checker.DetailLogger, r *checker.CIIBestPracticesData) checker.CheckResult { + if r == nil { + e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data") + return checker.CreateRuntimeErrorResult(name, e) + } + + var results checker.CheckResult + switch r.Badge { + case checker.CIIBadgeNotFound: + results = checker.CreateMinScoreResult(name, "no badge detected") + case checker.CIIBadgeInProgress: + results = checker.CreateResultWithScore(name, "badge detected: in_progress", inProgressScore) + case checker.CIIBadgePassing: + results = checker.CreateResultWithScore(name, "badge detected: passing", passingScore) + case checker.CIIBadgeSilver: + results = checker.CreateResultWithScore(name, "badge detected: silver", silverScore) + case checker.CIIBadgeGold: + results = checker.CreateMaxScoreResult(name, "badge detected: gold") + case checker.CIIBadgeUnknown: + e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("unsupported badge: %v", r.Badge)) + results = checker.CreateRuntimeErrorResult(name, e) + } + + return results +} diff --git a/checks/raw/cii_best_practices.go b/checks/raw/cii_best_practices.go new file mode 100644 index 00000000000..fb2aee36fe3 --- /dev/null +++ b/checks/raw/cii_best_practices.go @@ -0,0 +1,55 @@ +// Copyright 2022 Security Scorecard Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package raw + +import ( + "errors" + "fmt" + + "github.com/ossf/scorecard/v4/checker" + "github.com/ossf/scorecard/v4/clients" +) + +var errEmptyClient = errors.New("CII client is nil") + +// CIIBestPractices retrieves the raw data for the CIIBestPractices check. +func CIIBestPractices(c *checker.CheckRequest) (checker.CIIBestPracticesData, error) { + var results checker.CIIBestPracticesData + if c.CIIClient == nil { + return results, fmt.Errorf("%w", errEmptyClient) + } + + badge, err := c.CIIClient.GetBadgeLevel(c.Ctx, c.Repo.URI()) + if err != nil { + return results, fmt.Errorf("%w", err) + } + + switch badge { + case clients.NotFound: + results.Badge = checker.CIIBadgeNotFound + case clients.InProgress: + results.Badge = checker.CIIBadgeInProgress + case clients.Passing: + results.Badge = checker.CIIBadgePassing + case clients.Silver: + results.Badge = checker.CIIBadgeSilver + case clients.Gold: + results.Badge = checker.CIIBadgeGold + case clients.Unknown: + results.Badge = checker.CIIBadgeUnknown + } + + return results, nil +} diff --git a/pkg/json_raw_results.go b/pkg/json_raw_results.go index c75eeab2172..b523ded2a65 100644 --- a/pkg/json_raw_results.go +++ b/pkg/json_raw_results.go @@ -136,6 +136,16 @@ type jsonRawResults struct { // List of recent issues. RecentIssues []jsonIssue `json:"issues"` // List of vulnerabilities. +} + +type jsonOssfBestPractices struct { + Badge string `json:"badge"` +} + +type jsonRawResults struct { + // OSSF best practices badge. + OssfBestPractices jsonOssfBestPractices `json:"openssf-best-practices-badge"` + // Vulnerabilities. DatabaseVulnerabilities []jsonDatabaseVulnerability `json:"database-vulnerabilities"` // List of binaries found in the repo. Binaries []jsonFile `json:"binaries"` @@ -230,6 +240,15 @@ func (r *jsonScorecardRawResult) setDefaultCommitData(commits []checker.DefaultB return nil } + +//nolint:unparam +func (r *jsonScorecardRawResult) addOssfBestPracticesRawResults(cbp *checker.CIIBestPracticesData) error { + r.Results.OssfBestPractices.Badge = string(cbp.Badge) + return nil +} + +//nolint:unparam +func (r *jsonScorecardRawResult) addCodeReviewRawResults(cr *checker.CodeReviewData) error { r.Results.DefaultBranchCommits = []jsonDefaultBranchCommit{} for _, commit := range commits { com := jsonDefaultBranchCommit{ @@ -403,6 +422,11 @@ func (r *jsonScorecardRawResult) fillJSONRawResults(raw *checker.RawResults) err if err := r.addSignedReleasesRawResults(&raw.SignedReleasesResults); err != nil { return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) } + + // CII-Best-Practices. + if err := r.addOssfBestPracticesRawResults(&raw.CIIBestPracticesResults); err != nil { + return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) + } return nil } From c39ea0010582a36aac103605817d6507f5696a6c Mon Sep 17 00:00:00 2001 From: laurentsimon Date: Tue, 29 Mar 2022 15:39:55 +0000 Subject: [PATCH 2/5] updates --- checks/evaluation/cii_best_practices.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/checks/evaluation/cii_best_practices.go b/checks/evaluation/cii_best_practices.go index b04ee58e21a..f84d375282a 100644 --- a/checks/evaluation/cii_best_practices.go +++ b/checks/evaluation/cii_best_practices.go @@ -41,13 +41,17 @@ func CIIBestPractices(name string, dl checker.DetailLogger, r *checker.CIIBestPr case checker.CIIBadgeNotFound: results = checker.CreateMinScoreResult(name, "no badge detected") case checker.CIIBadgeInProgress: - results = checker.CreateResultWithScore(name, "badge detected: in_progress", inProgressScore) + msg := fmt.Sprintf("badge detected: %v", r.Badge) + results = checker.CreateResultWithScore(name, msg, inProgressScore) case checker.CIIBadgePassing: - results = checker.CreateResultWithScore(name, "badge detected: passing", passingScore) + msg := fmt.Sprintf("badge detected: %v", r.Badge) + results = checker.CreateResultWithScore(name, msg, passingScore) case checker.CIIBadgeSilver: - results = checker.CreateResultWithScore(name, "badge detected: silver", silverScore) + msg := fmt.Sprintf("badge detected: %v", r.Badge) + results = checker.CreateResultWithScore(name, msg, silverScore) case checker.CIIBadgeGold: - results = checker.CreateMaxScoreResult(name, "badge detected: gold") + msg := fmt.Sprintf("badge detected: %v", r.Badge) + results = checker.CreateMaxScoreResult(name, msg) case checker.CIIBadgeUnknown: e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("unsupported badge: %v", r.Badge)) results = checker.CreateRuntimeErrorResult(name, e) From ff7d1d2ed97ce795d3eeea991fbcd39d2b9e6d50 Mon Sep 17 00:00:00 2001 From: laurentsimon Date: Tue, 29 Mar 2022 15:42:07 +0000 Subject: [PATCH 3/5] updates --- checks/evaluation/cii_best_practices.go | 1 - 1 file changed, 1 deletion(-) diff --git a/checks/evaluation/cii_best_practices.go b/checks/evaluation/cii_best_practices.go index f84d375282a..593b6199687 100644 --- a/checks/evaluation/cii_best_practices.go +++ b/checks/evaluation/cii_best_practices.go @@ -56,6 +56,5 @@ func CIIBestPractices(name string, dl checker.DetailLogger, r *checker.CIIBestPr e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("unsupported badge: %v", r.Badge)) results = checker.CreateRuntimeErrorResult(name, e) } - return results } From f15a661a6a67eb321f36f117cded7d11315a1460 Mon Sep 17 00:00:00 2001 From: laurentsimon Date: Tue, 29 Mar 2022 21:26:16 +0000 Subject: [PATCH 4/5] tests --- checks/cii_best_practices_test.go | 6 +++--- checks/evaluation/cii_best_practices.go | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/checks/cii_best_practices_test.go b/checks/cii_best_practices_test.go index faf08d34b28..81fe156a462 100644 --- a/checks/cii_best_practices_test.go +++ b/checks/cii_best_practices_test.go @@ -66,21 +66,21 @@ func TestCIIBestPractices(t *testing.T) { name: "InProgressBadge", badgeLevel: clients.InProgress, expected: scut.TestReturn{ - Score: inProgressScore, + Score: 2, }, }, { name: "PassingBadge", badgeLevel: clients.Passing, expected: scut.TestReturn{ - Score: passingScore, + Score: 5, }, }, { name: "SilverBadge", badgeLevel: clients.Silver, expected: scut.TestReturn{ - Score: silverScore, + Score: 7, }, }, { diff --git a/checks/evaluation/cii_best_practices.go b/checks/evaluation/cii_best_practices.go index 593b6199687..ee711c1ac61 100644 --- a/checks/evaluation/cii_best_practices.go +++ b/checks/evaluation/cii_best_practices.go @@ -21,6 +21,7 @@ import ( sce "github.com/ossf/scorecard/v4/errors" ) +// Note: exported for unit tests. const ( silverScore = 7 // Note: if this value is changed, please update the action's threshold score From 19edc334e71e26071cf24888a4b7fdba60c8d849 Mon Sep 17 00:00:00 2001 From: laurentsimon Date: Fri, 1 Apr 2022 22:30:59 +0000 Subject: [PATCH 5/5] comment --- pkg/json_raw_results.go | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/pkg/json_raw_results.go b/pkg/json_raw_results.go index b523ded2a65..8dce6c58401 100644 --- a/pkg/json_raw_results.go +++ b/pkg/json_raw_results.go @@ -131,18 +131,13 @@ type jsonReleaseAsset struct { URL string `json:"url"` } -//nolint -type jsonRawResults struct { - // List of recent issues. - RecentIssues []jsonIssue `json:"issues"` - // List of vulnerabilities. -} - type jsonOssfBestPractices struct { Badge string `json:"badge"` } type jsonRawResults struct { + // Issues. + RecentIssues []jsonIssue `json:"issues"` // OSSF best practices badge. OssfBestPractices jsonOssfBestPractices `json:"openssf-best-practices-badge"` // Vulnerabilities. @@ -240,15 +235,6 @@ func (r *jsonScorecardRawResult) setDefaultCommitData(commits []checker.DefaultB return nil } - -//nolint:unparam -func (r *jsonScorecardRawResult) addOssfBestPracticesRawResults(cbp *checker.CIIBestPracticesData) error { - r.Results.OssfBestPractices.Badge = string(cbp.Badge) - return nil -} - -//nolint:unparam -func (r *jsonScorecardRawResult) addCodeReviewRawResults(cr *checker.CodeReviewData) error { r.Results.DefaultBranchCommits = []jsonDefaultBranchCommit{} for _, commit := range commits { com := jsonDefaultBranchCommit{ @@ -294,6 +280,12 @@ func (r *jsonScorecardRawResult) addCodeReviewRawResults(cr *checker.CodeReviewD return nil } +//nolint:unparam +func (r *jsonScorecardRawResult) addOssfBestPracticesRawResults(cbp *checker.CIIBestPracticesData) error { + r.Results.OssfBestPractices.Badge = string(cbp.Badge) + return nil +} + func (r *jsonScorecardRawResult) addCodeReviewRawResults(cr *checker.CodeReviewData) error { return r.setDefaultCommitData(cr.DefaultBranchCommits) } @@ -422,7 +414,7 @@ func (r *jsonScorecardRawResult) fillJSONRawResults(raw *checker.RawResults) err if err := r.addSignedReleasesRawResults(&raw.SignedReleasesResults); err != nil { return sce.WithMessage(sce.ErrScorecardInternal, err.Error()) } - + // CII-Best-Practices. if err := r.addOssfBestPracticesRawResults(&raw.CIIBestPracticesResults); err != nil { return sce.WithMessage(sce.ErrScorecardInternal, err.Error())