Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Raw results for best practices badge #1795

Merged
merged 7 commits into from Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions checker/raw_result.go
Expand Up @@ -20,6 +20,7 @@ import "time"
// is applied.
//nolint
type RawResults struct {
CIIBestPracticesResults CIIBestPracticesData
DangerousWorkflowResults DangerousWorkflowData
VulnerabilitiesResults VulnerabilitiesData
BinaryArtifactResults BinaryArtifactData
Expand Down Expand Up @@ -258,6 +259,30 @@ type ReleaseAsset struct {
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
}

// DangerousWorkflowData contains raw results
// for dangerous workflow check.
type DangerousWorkflowData struct {
Expand Down
49 changes: 16 additions & 33 deletions checks/cii_best_practices.go
Expand Up @@ -15,20 +15,15 @@
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
passingScore = 5
inProgressScore = 2
)
// CheckCIIBestPractices is the registered name for CIIBestPractices.
const CheckCIIBestPractices = "CII-Best-Practices"


//nolint:gochecknoinits
func init() {
Expand All @@ -38,31 +33,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)
}
6 changes: 3 additions & 3 deletions checks/cii_best_practices_test.go
Expand Up @@ -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,
},
},
{
Expand Down
61 changes: 61 additions & 0 deletions checks/evaluation/cii_best_practices.go
@@ -0,0 +1,61 @@
// 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"
)

// Note: exported for unit tests.
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:
msg := fmt.Sprintf("badge detected: %v", r.Badge)
results = checker.CreateResultWithScore(name, msg, inProgressScore)
case checker.CIIBadgePassing:
msg := fmt.Sprintf("badge detected: %v", r.Badge)
results = checker.CreateResultWithScore(name, msg, passingScore)
case checker.CIIBadgeSilver:
msg := fmt.Sprintf("badge detected: %v", r.Badge)
results = checker.CreateResultWithScore(name, msg, silverScore)
case checker.CIIBadgeGold:
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)
}
return results
}
55 changes: 55 additions & 0 deletions 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
}
21 changes: 19 additions & 2 deletions pkg/json_raw_results.go
Expand Up @@ -132,6 +132,10 @@ type jsonReleaseAsset struct {
URL string `json:"url"`
}

type jsonOssfBestPractices struct {
Badge string `json:"badge"`
}

//nolint
type jsonLicense struct {
File jsonFile `json:"file"`
Expand Down Expand Up @@ -172,7 +176,9 @@ type jsonRawResults struct {
Licenses []jsonLicense `json:"licenses"`
// List of recent issues.
RecentIssues []jsonIssue `json:"issues"`
// List of vulnerabilities.
// 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"`
Expand Down Expand Up @@ -377,6 +383,12 @@ 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
}

func (r *jsonScorecardRawResult) addCodeReviewRawResults(cr *checker.CodeReviewData) error {
return r.setDefaultCommitData(cr.DefaultBranchCommits)
}
Expand Down Expand Up @@ -526,7 +538,12 @@ func (r *jsonScorecardRawResult) fillJSONRawResults(raw *checker.RawResults) err
return sce.WithMessage(sce.ErrScorecardInternal, err.Error())
}

// Dangerous workflow.
// CII-Best-Practices.
if err := r.addOssfBestPracticesRawResults(&raw.CIIBestPracticesResults); err != nil {
return sce.WithMessage(sce.ErrScorecardInternal, err.Error())
}

// Dangerous workflow.
if err := r.addDangerousWorkflowRawResults(&raw.DangerousWorkflowResults); err != nil {
return sce.WithMessage(sce.ErrScorecardInternal, err.Error())
}
Expand Down