🌱 : Reduce code duplication for follow-up cron refactoring (#338)

*  Refactor to reduce code duplication

* 

* Move lib/ back to checker/

* Move lib/ back to checker/

* Move lib/ back to checker/

* Address PR comments.

* Addressing PR comments.

* Avoid printing `ShouldRetry` and `Error` in output JSON.

* Fix JSON output.

Co-authored-by: Azeem Shaikh <azeems@google.com>
This commit is contained in:
Azeem Shaikh 2021-04-10 05:26:56 -07:00 committed by GitHub
parent 6aad826067
commit a58818d258
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 438 additions and 383 deletions

View File

@ -1,105 +0,0 @@
// Copyright 2020 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 checker
type CheckResult struct {
Pass bool
Details []string
Confidence int
ShouldRetry bool
Error error
}
var InconclusiveResult = CheckResult{
Pass: false,
Confidence: 0,
}
var retryResult = CheckResult{
Pass: false,
ShouldRetry: true,
}
const pass int = 10
var PassResult = CheckResult{
Pass: true,
Confidence: pass,
}
var maxConfidence int = 10
func RetryResult(err error) CheckResult {
r := retryResult
r.Error = err
return r
}
type CheckFn func(Checker) CheckResult
func Bool2int(b bool) int {
if b {
return 1
}
return 0
}
func MultiCheck(fns ...CheckFn) CheckFn {
return func(c Checker) CheckResult {
var maxResult CheckResult
for _, fn := range fns {
result := fn(c)
if Bool2int(result.Pass) < Bool2int(maxResult.Pass) {
continue
}
if result.Pass && result.Confidence >= maxConfidence {
return result
}
if result.Confidence >= maxResult.Confidence {
maxResult = result
}
}
return maxResult
}
}
func ProportionalResult(numerator int, denominator int, threshold float32) CheckResult {
if numerator == 0 {
return CheckResult{
Pass: false,
Confidence: maxConfidence,
}
}
actual := float32(numerator) / float32(denominator)
const confidence = 10
if actual >= threshold {
return CheckResult{
Pass: true,
Confidence: int(actual * confidence),
}
}
return CheckResult{
Pass: false,
Confidence: maxConfidence - int(actual*confidence),
}
}
type NamedCheck struct {
Name string
Fn CheckFn
}

View File

@ -16,15 +16,13 @@ package checker
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"strings"
"github.com/google/go-github/v32/github" "github.com/google/go-github/v32/github"
"github.com/shurcooL/githubv4" "github.com/shurcooL/githubv4"
) )
type Checker struct { type CheckRequest struct {
Ctx context.Context Ctx context.Context
Client *github.Client Client *github.Client
GraphClient *githubv4.Client GraphClient *githubv4.Client
@ -32,34 +30,3 @@ type Checker struct {
Owner, Repo string Owner, Repo string
Logf func(s string, f ...interface{}) Logf func(s string, f ...interface{})
} }
type logger struct {
messages []string
}
func (l *logger) Logf(s string, f ...interface{}) {
l.messages = append(l.messages, fmt.Sprintf(s, f...))
}
type Runner struct {
Checker Checker
}
func (r *Runner) Run(f CheckFn) CheckResult {
var res CheckResult
var l logger
for retriesRemaining := 3; retriesRemaining > 0; retriesRemaining-- {
checker := r.Checker
l = logger{}
checker.Logf = l.Logf
res = f(checker)
if res.ShouldRetry && !strings.Contains(res.Error.Error(), "invalid header field value") {
checker.Logf("error, retrying: %s", res.Error)
continue
}
break
}
res.Details = l.messages
return res
}

79
checker/check_result.go Normal file
View File

@ -0,0 +1,79 @@
// Copyright 2020 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 checker
const MaxResultConfidence = 10
type CheckResult struct {
Name string
Pass bool
Confidence int
Details []string
ShouldRetry bool `json:"-"`
Error error `json:"-"`
}
func MakeInconclusiveResult(name string) CheckResult {
return CheckResult{
Name: name,
Pass: false,
Confidence: 0,
}
}
func MakePassResult(name string) CheckResult {
return CheckResult{
Name: name,
Pass: true,
Confidence: MaxResultConfidence,
}
}
func MakeRetryResult(name string, err error) CheckResult {
return CheckResult{
Name: name,
Pass: false,
ShouldRetry: true,
Error: err,
}
}
func MakeProportionalResult(name string, numerator int, denominator int,
threshold float32) CheckResult {
if denominator == 0 {
return MakeInconclusiveResult(name)
}
if numerator == 0 {
return CheckResult{
Name: name,
Pass: false,
Confidence: MaxResultConfidence,
}
}
actual := float32(numerator) / float32(denominator)
if actual >= threshold {
return CheckResult{
Name: name,
Pass: true,
Confidence: int(actual * MaxResultConfidence),
}
}
return CheckResult{
Name: name,
Pass: false,
Confidence: MaxResultConfidence - int(actual*MaxResultConfidence),
}
}

84
checker/check_runner.go Normal file
View File

@ -0,0 +1,84 @@
// Copyright 2020 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 checker
import (
"fmt"
"strings"
)
const checkRetries = 3
type Runner struct {
CheckRequest CheckRequest
}
type CheckFn func(CheckRequest) CheckResult
type CheckNameToFnMap map[string]CheckFn
type logger struct {
messages []string
}
func (l *logger) Logf(s string, f ...interface{}) {
l.messages = append(l.messages, fmt.Sprintf(s, f...))
}
func (r *Runner) Run(f CheckFn) CheckResult {
var res CheckResult
var l logger
for retriesRemaining := checkRetries; retriesRemaining > 0; retriesRemaining-- {
checkRequest := r.CheckRequest
l = logger{}
checkRequest.Logf = l.Logf
res = f(checkRequest)
if res.ShouldRetry && !strings.Contains(res.Error.Error(), "invalid header field value") {
checkRequest.Logf("error, retrying: %s", res.Error)
continue
}
break
}
res.Details = l.messages
return res
}
func Bool2int(b bool) int {
if b {
return 1
}
return 0
}
func MultiCheck(fns ...CheckFn) CheckFn {
return func(c CheckRequest) CheckResult {
var maxResult CheckResult
for _, fn := range fns {
result := fn(c)
if Bool2int(result.Pass) < Bool2int(maxResult.Pass) {
continue
}
if result.Pass && result.Confidence >= MaxResultConfidence {
return result
}
if result.Confidence >= maxResult.Confidence {
maxResult = result
}
}
return maxResult
}
}

View File

@ -21,16 +21,19 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
var lookbackDays int = 90 const (
activeStr = "Active"
lookbackDays = 90
)
func init() { func init() {
registerCheck("Active", IsActive) registerCheck(activeStr, IsActive)
} }
func IsActive(c checker.Checker) checker.CheckResult { func IsActive(c checker.CheckRequest) checker.CheckResult {
commits, _, err := c.Client.Repositories.ListCommits(c.Ctx, c.Owner, c.Repo, &github.CommitsListOptions{}) commits, _, err := c.Client.Repositories.ListCommits(c.Ctx, c.Owner, c.Repo, &github.CommitsListOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(activeStr, err)
} }
tz, _ := time.LoadLocation("UTC") tz, _ := time.LoadLocation("UTC")
@ -39,7 +42,7 @@ func IsActive(c checker.Checker) checker.CheckResult {
for _, commit := range commits { for _, commit := range commits {
commitFull, _, err := c.Client.Git.GetCommit(c.Ctx, c.Owner, c.Repo, commit.GetSHA()) commitFull, _, err := c.Client.Git.GetCommit(c.Ctx, c.Owner, c.Repo, commit.GetSHA())
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(activeStr, err)
} }
if commitFull.GetAuthor().GetDate().After(threshold) { if commitFull.GetAuthor().GetDate().After(threshold) {
totalCommits++ totalCommits++
@ -49,6 +52,7 @@ func IsActive(c checker.Checker) checker.CheckResult {
const numCommits = 2 const numCommits = 2
const confidence = 10 const confidence = 10
return checker.CheckResult{ return checker.CheckResult{
Name: activeStr,
Pass: totalCommits >= numCommits, Pass: totalCommits >= numCommits,
Confidence: confidence, Confidence: confidence,
} }

View File

@ -16,11 +16,8 @@ package checks
import "github.com/ossf/scorecard/checker" import "github.com/ossf/scorecard/checker"
var AllChecks = []checker.NamedCheck{} var AllChecks = checker.CheckNameToFnMap{}
func registerCheck(name string, fn checker.CheckFn) { func registerCheck(name string, fn checker.CheckFn) {
AllChecks = append(AllChecks, checker.NamedCheck{ AllChecks[name] = fn
Name: name,
Fn: fn,
})
} }

View File

@ -19,27 +19,30 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const branchProtectionStr = "Branch-Protection"
func init() { func init() {
registerCheck("Branch-Protection", BranchProtection) registerCheck(branchProtectionStr, BranchProtection)
} }
func BranchProtection(c checker.Checker) checker.CheckResult { func BranchProtection(c checker.CheckRequest) checker.CheckResult {
repo, _, err := c.Client.Repositories.Get(c.Ctx, c.Owner, c.Repo) repo, _, err := c.Client.Repositories.Get(c.Ctx, c.Owner, c.Repo)
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(branchProtectionStr, err)
} }
protection, resp, err := c.Client.Repositories. protection, resp, err := c.Client.Repositories.
GetBranchProtection(c.Ctx, c.Owner, c.Repo, *repo.DefaultBranch) GetBranchProtection(c.Ctx, c.Owner, c.Repo, *repo.DefaultBranch)
const fileNotFound = 404 const fileNotFound = 404
if resp.StatusCode == fileNotFound { if resp.StatusCode == fileNotFound {
return checker.RetryResult(err) return checker.MakeRetryResult(branchProtectionStr, err)
} }
if err != nil { if err != nil {
c.Logf("!! branch protection not enabled") c.Logf("!! branch protection not enabled")
const confidence = 10 const confidence = 10
return checker.CheckResult{ return checker.CheckResult{
Name: branchProtectionStr,
Pass: false, Pass: false,
Confidence: confidence, Confidence: confidence,
} }
@ -48,7 +51,7 @@ func BranchProtection(c checker.Checker) checker.CheckResult {
} }
func IsBranchProtected(protection *github.Protection, c checker.Checker) checker.CheckResult { func IsBranchProtected(protection *github.Protection, c checker.CheckRequest) checker.CheckResult {
totalChecks := 6 totalChecks := 6
totalSuccess := 0 totalSuccess := 0
@ -104,5 +107,5 @@ func IsBranchProtected(protection *github.Protection, c checker.Checker) checker
} }
} }
return checker.ProportionalResult(totalSuccess, totalChecks, 1.0) return checker.MakeProportionalResult(branchProtectionStr, totalSuccess, totalChecks, 1.0)
} }

View File

@ -22,6 +22,7 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
// TODO: these logging functions are repeated from lib/check_fn.go. Reuse code.
type log struct { type log struct {
messages []string messages []string
} }
@ -33,7 +34,7 @@ func (l *log) Logf(s string, f ...interface{}) {
func TestIsBranchProtected(t *testing.T) { func TestIsBranchProtected(t *testing.T) {
type args struct { type args struct {
protection *github.Protection protection *github.Protection
c checker.Checker c checker.CheckRequest
} }
l := log{} l := log{}
@ -77,8 +78,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false, Enabled: false,
}, },
}, },
c: checker.Checker{Logf: l.Logf}}, c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{ want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false, Pass: false,
Details: nil, Details: nil,
Confidence: 7, Confidence: 7,
@ -120,8 +122,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false, Enabled: false,
}, },
}, },
c: checker.Checker{Logf: l.Logf}}, c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{ want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false, Pass: false,
Details: nil, Details: nil,
Confidence: 5, Confidence: 5,
@ -163,8 +166,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false, Enabled: false,
}, },
}, },
c: checker.Checker{Logf: l.Logf}}, c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{ want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false, Pass: false,
Details: nil, Details: nil,
Confidence: 7, Confidence: 7,
@ -207,8 +211,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false, Enabled: false,
}, },
}, },
c: checker.Checker{Logf: l.Logf}}, c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{ want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false, Pass: false,
Details: nil, Details: nil,
Confidence: 5, Confidence: 5,
@ -250,8 +255,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false, Enabled: false,
}, },
}, },
c: checker.Checker{Logf: l.Logf}}, c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{ want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false, Pass: false,
Details: nil, Details: nil,
Confidence: 5, Confidence: 5,
@ -293,8 +299,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false, Enabled: false,
}, },
}, },
c: checker.Checker{Logf: l.Logf}}, c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{ want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false, Pass: false,
Details: nil, Details: nil,
Confidence: 5, Confidence: 5,
@ -336,8 +343,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false, Enabled: false,
}, },
}, },
c: checker.Checker{Logf: l.Logf}}, c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{ want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false, Pass: false,
Details: nil, Details: nil,
Confidence: 9, Confidence: 9,
@ -378,8 +386,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: true, Enabled: true,
}, },
}, },
c: checker.Checker{Logf: l.Logf}}, c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{ want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false, Pass: false,
Details: nil, Details: nil,
Confidence: 9, Confidence: 9,
@ -419,8 +428,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false, Enabled: false,
}, },
}, },
c: checker.Checker{Logf: l.Logf}}, c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{ want: checker.CheckResult{
Name: branchProtectionStr,
Pass: true, Pass: true,
Details: nil, Details: nil,
Confidence: 10, Confidence: 10,

View File

@ -26,30 +26,30 @@ import (
// CheckIfFileExists downloads the tar of the repository and calls the predicate to check // CheckIfFileExists downloads the tar of the repository and calls the predicate to check
// for the occurrence. // for the occurrence.
func CheckIfFileExists(c checker.Checker, predicate func(name string, func CheckIfFileExists(checkName string, c checker.CheckRequest, predicate func(name string,
Logf func(s string, f ...interface{})) bool) checker.CheckResult { Logf func(s string, f ...interface{})) bool) checker.CheckResult {
r, _, err := c.Client.Repositories.Get(c.Ctx, c.Owner, c.Repo) r, _, err := c.Client.Repositories.Get(c.Ctx, c.Owner, c.Repo)
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(checkName, err)
} }
url := r.GetArchiveURL() url := r.GetArchiveURL()
url = strings.Replace(url, "{archive_format}", "tarball/", 1) url = strings.Replace(url, "{archive_format}", "tarball/", 1)
url = strings.Replace(url, "{/ref}", r.GetDefaultBranch(), 1) url = strings.Replace(url, "{/ref}", r.GetDefaultBranch(), 1)
// Using the http.get instead of the checker httpClient because // Using the http.get instead of the lib httpClient because
// the default checker.HTTPClient caches everything in the memory and it causes oom. // the default checker.HTTPClient caches everything in the memory and it causes oom.
//https://securego.io/docs/rules/g107.html //https://securego.io/docs/rules/g107.html
//nolint //nolint
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(checkName, err)
} }
defer resp.Body.Close() defer resp.Body.Close()
gz, err := gzip.NewReader(resp.Body) gz, err := gzip.NewReader(resp.Body)
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(checkName, err)
} }
tr := tar.NewReader(gz) tr := tar.NewReader(gz)
@ -58,7 +58,7 @@ func CheckIfFileExists(c checker.Checker, predicate func(name string,
if err == io.EOF { if err == io.EOF {
break break
} else if err != nil { } else if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(checkName, err)
} }
// Strip the repo name // Strip the repo name
@ -70,11 +70,12 @@ func CheckIfFileExists(c checker.Checker, predicate func(name string,
name := names[1] name := names[1]
if predicate(name, c.Logf) { if predicate(name, c.Logf) {
return checker.PassResult return checker.MakePassResult(checkName)
} }
} }
const confidence = 5 const confidence = 5
return checker.CheckResult{ return checker.CheckResult{
Name: checkName,
Pass: false, Pass: false,
Confidence: confidence, Confidence: confidence,
} }

View File

@ -21,16 +21,18 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const ciTestsStr = "CI-Tests"
func init() { func init() {
registerCheck("CI-Tests", CITests) registerCheck(ciTestsStr, CITests)
} }
func CITests(c checker.Checker) checker.CheckResult { func CITests(c checker.CheckRequest) checker.CheckResult {
prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{ prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{
State: "closed", State: "closed",
}) })
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(ciTestsStr, err)
} }
const ( const (
@ -56,7 +58,7 @@ func CITests(c checker.Checker) checker.CheckResult {
if usedSystem <= githubStatuses { if usedSystem <= githubStatuses {
statuses, _, err := c.Client.Repositories.ListStatuses(c.Ctx, c.Owner, c.Repo, pr.GetHead().GetSHA(), &github.ListOptions{}) statuses, _, err := c.Client.Repositories.ListStatuses(c.Ctx, c.Owner, c.Repo, pr.GetHead().GetSHA(), &github.ListOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(ciTestsStr, err)
} }
for _, status := range statuses { for _, status := range statuses {
@ -81,7 +83,7 @@ func CITests(c checker.Checker) checker.CheckResult {
if usedSystem == githubCheckRuns || usedSystem == unknown { if usedSystem == githubCheckRuns || usedSystem == unknown {
crs, _, err := c.Client.Checks.ListCheckRunsForRef(c.Ctx, c.Owner, c.Repo, pr.GetHead().GetSHA(), &github.ListCheckRunsOptions{}) crs, _, err := c.Client.Checks.ListCheckRunsForRef(c.Ctx, c.Owner, c.Repo, pr.GetHead().GetSHA(), &github.ListCheckRunsOptions{})
if err != nil || crs == nil { if err != nil || crs == nil {
return checker.RetryResult(err) return checker.MakeRetryResult(ciTestsStr, err)
} }
for _, cr := range crs.CheckRuns { for _, cr := range crs.CheckRuns {
@ -107,7 +109,7 @@ func CITests(c checker.Checker) checker.CheckResult {
} }
c.Logf("found CI tests for %d of %d merged PRs", totalTested, totalMerged) c.Logf("found CI tests for %d of %d merged PRs", totalTested, totalMerged)
return checker.ProportionalResult(totalTested, totalMerged, .75) return checker.MakeProportionalResult(ciTestsStr, totalTested, totalMerged, .75)
} }
func isTest(s string) bool { func isTest(s string) bool {

View File

@ -22,39 +22,41 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const ciiBestPracticesStr = "CII-Best-Practices"
func init() { func init() {
registerCheck("CII-Best-Practices", CIIBestPractices) registerCheck(ciiBestPracticesStr, CIIBestPractices)
} }
type response struct { type response struct {
BadgeLevel string `json:"badge_level"` BadgeLevel string `json:"badge_level"`
} }
func CIIBestPractices(c checker.Checker) checker.CheckResult { func CIIBestPractices(c checker.CheckRequest) checker.CheckResult {
repoUrl := fmt.Sprintf("https://github.com/%s/%s", c.Owner, c.Repo) repoUrl := fmt.Sprintf("https://github.com/%s/%s", c.Owner, c.Repo)
url := fmt.Sprintf("https://bestpractices.coreinfrastructure.org/projects.json?url=%s", repoUrl) url := fmt.Sprintf("https://bestpractices.coreinfrastructure.org/projects.json?url=%s", repoUrl)
resp, err := c.HttpClient.Get(url) resp, err := c.HttpClient.Get(url)
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(ciiBestPracticesStr, err)
} }
defer resp.Body.Close() defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body) b, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(ciiBestPracticesStr, err)
} }
parsedResponse := []response{} parsedResponse := []response{}
if err := json.Unmarshal(b, &parsedResponse); err != nil { if err := json.Unmarshal(b, &parsedResponse); err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(ciiBestPracticesStr, err)
} }
const confidence = 10
if len(parsedResponse) < 1 { if len(parsedResponse) < 1 {
c.Logf("no badge found") c.Logf("no badge found")
return checker.CheckResult{ return checker.CheckResult{
Name: ciiBestPracticesStr,
Pass: false, Pass: false,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }
@ -63,13 +65,15 @@ func CIIBestPractices(c checker.Checker) checker.CheckResult {
if result.BadgeLevel != "" { if result.BadgeLevel != "" {
return checker.CheckResult{ return checker.CheckResult{
Name: ciiBestPracticesStr,
Pass: true, Pass: true,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }
return checker.CheckResult{ return checker.CheckResult{
Name: ciiBestPracticesStr,
Pass: false, Pass: false,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }

View File

@ -21,8 +21,10 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const codeReviewStr = "Code-Review"
func init() { func init() {
registerCheck("Code-Review", DoesCodeReview) registerCheck(codeReviewStr, DoesCodeReview)
} }
// DoesCodeReview attempts to determine whether a project requires review before code gets merged. // DoesCodeReview attempts to determine whether a project requires review before code gets merged.
@ -30,7 +32,7 @@ func init() {
// - Looking at the repo configuration to see if reviews are required // - Looking at the repo configuration to see if reviews are required
// - Checking if most of the recent merged PRs were "Approved" // - Checking if most of the recent merged PRs were "Approved"
// - Looking for other well-known review labels // - Looking for other well-known review labels
func DoesCodeReview(c checker.Checker) checker.CheckResult { func DoesCodeReview(c checker.CheckRequest) checker.CheckResult {
return checker.MultiCheck( return checker.MultiCheck(
IsPrReviewRequired, IsPrReviewRequired,
GithubCodeReview, GithubCodeReview,
@ -39,13 +41,13 @@ func DoesCodeReview(c checker.Checker) checker.CheckResult {
)(c) )(c)
} }
func GithubCodeReview(c checker.Checker) checker.CheckResult { func GithubCodeReview(c checker.CheckRequest) checker.CheckResult {
// Look at some merged PRs to see if they were reviewed // Look at some merged PRs to see if they were reviewed
prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{ prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{
State: "closed", State: "closed",
}) })
if err != nil { if err != nil {
return checker.InconclusiveResult return checker.MakeInconclusiveResult(codeReviewStr)
} }
totalMerged := 0 totalMerged := 0
@ -91,39 +93,40 @@ func GithubCodeReview(c checker.Checker) checker.CheckResult {
if totalReviewed > 0 { if totalReviewed > 0 {
c.Logf("github code reviews found") c.Logf("github code reviews found")
} }
return checker.ProportionalResult(totalReviewed, totalMerged, .75) return checker.MakeProportionalResult(codeReviewStr, totalReviewed, totalMerged, .75)
} }
func IsPrReviewRequired(c checker.Checker) checker.CheckResult { func IsPrReviewRequired(c checker.CheckRequest) checker.CheckResult {
// Look to see if review is enforced. // Look to see if review is enforced.
r, _, err := c.Client.Repositories.Get(c.Ctx, c.Owner, c.Repo) r, _, err := c.Client.Repositories.Get(c.Ctx, c.Owner, c.Repo)
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(codeReviewStr, err)
} }
// Check the branch protection rules, we may not be able to get these though. // Check the branch protection rules, we may not be able to get these though.
bp, _, err := c.Client.Repositories.GetBranchProtection(c.Ctx, c.Owner, c.Repo, r.GetDefaultBranch()) bp, _, err := c.Client.Repositories.GetBranchProtection(c.Ctx, c.Owner, c.Repo, r.GetDefaultBranch())
if err != nil { if err != nil {
return checker.InconclusiveResult return checker.MakeInconclusiveResult(codeReviewStr)
} }
if bp.GetRequiredPullRequestReviews().RequiredApprovingReviewCount >= 1 { if bp.GetRequiredPullRequestReviews().RequiredApprovingReviewCount >= 1 {
c.Logf("pr review policy enforced") c.Logf("pr review policy enforced")
const confidence = 5 const confidence = 5
return checker.CheckResult{ return checker.CheckResult{
Name: codeReviewStr,
Pass: true, Pass: true,
Confidence: confidence, Confidence: confidence,
} }
} }
return checker.InconclusiveResult return checker.MakeInconclusiveResult(codeReviewStr)
} }
func ProwCodeReview(c checker.Checker) checker.CheckResult { func ProwCodeReview(c checker.CheckRequest) checker.CheckResult {
// Look at some merged PRs to see if they were reviewed // Look at some merged PRs to see if they were reviewed
prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{ prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{
State: "closed", State: "closed",
}) })
if err != nil { if err != nil {
return checker.InconclusiveResult return checker.MakeInconclusiveResult(codeReviewStr)
} }
totalMerged := 0 totalMerged := 0
@ -142,16 +145,16 @@ func ProwCodeReview(c checker.Checker) checker.CheckResult {
} }
if totalReviewed == 0 { if totalReviewed == 0 {
return checker.InconclusiveResult return checker.MakeInconclusiveResult(codeReviewStr)
} }
c.Logf("prow code reviews found") c.Logf("prow code reviews found")
return checker.ProportionalResult(totalReviewed, totalMerged, .75) return checker.MakeProportionalResult(codeReviewStr, totalReviewed, totalMerged, .75)
} }
func CommitMessageHints(c checker.Checker) checker.CheckResult { func CommitMessageHints(c checker.CheckRequest) checker.CheckResult {
commits, _, err := c.Client.Repositories.ListCommits(c.Ctx, c.Owner, c.Repo, &github.CommitsListOptions{}) commits, _, err := c.Client.Repositories.ListCommits(c.Ctx, c.Owner, c.Repo, &github.CommitsListOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(codeReviewStr, err)
} }
total := 0 total := 0
@ -182,8 +185,8 @@ func CommitMessageHints(c checker.Checker) checker.CheckResult {
} }
if totalReviewed == 0 { if totalReviewed == 0 {
return checker.InconclusiveResult return checker.MakeInconclusiveResult(codeReviewStr)
} }
c.Logf("code reviews found") c.Logf("code reviews found")
return checker.ProportionalResult(totalReviewed, total, .75) return checker.MakeProportionalResult(codeReviewStr, totalReviewed, total, .75)
} }

View File

@ -21,24 +21,29 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const (
minContributionsPerUser = 5
minOrganizationCount = 2
contributorsStr = "Contributors"
)
func init() { func init() {
registerCheck("Contributors", Contributors) registerCheck(contributorsStr, Contributors)
} }
func Contributors(c checker.Checker) checker.CheckResult { func Contributors(c checker.CheckRequest) checker.CheckResult {
contribs, _, err := c.Client.Repositories.ListContributors(c.Ctx, c.Owner, c.Repo, &github.ListContributorsOptions{}) contribs, _, err := c.Client.Repositories.ListContributors(c.Ctx, c.Owner, c.Repo, &github.ListContributorsOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(contributorsStr, err)
} }
companies := map[string]struct{}{} companies := map[string]struct{}{}
for _, contrib := range contribs { for _, contrib := range contribs {
const contributorsCount = 5
//nolint:nestif //nolint:nestif
if contrib.GetContributions() >= contributorsCount { if contrib.GetContributions() >= minContributionsPerUser {
u, _, err := c.Client.Users.Get(c.Ctx, contrib.GetLogin()) u, _, err := c.Client.Users.Get(c.Ctx, contrib.GetLogin())
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(contributorsStr, err)
} }
orgs, _, err := c.Client.Organizations.List(c.Ctx, contrib.GetLogin(), nil) orgs, _, err := c.Client.Organizations.List(c.Ctx, contrib.GetLogin(), nil)
if err != nil { if err != nil {
@ -65,16 +70,16 @@ func Contributors(c checker.Checker) checker.CheckResult {
names = append(names, c) names = append(names, c)
} }
c.Logf("companies found: %v", strings.Join(names, ",")) c.Logf("companies found: %v", strings.Join(names, ","))
const numContributors = 2 if len(companies) >= minOrganizationCount {
const confidence = 10
if len(companies) >= numContributors {
return checker.CheckResult{ return checker.CheckResult{
Name: contributorsStr,
Pass: true, Pass: true,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }
return checker.CheckResult{ return checker.CheckResult{
Name: contributorsStr,
Pass: false, Pass: false,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }

View File

@ -20,13 +20,15 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const frozenDepsStr = "Frozen-Deps"
func init() { func init() {
registerCheck("Frozen-Deps", FrozenDeps) registerCheck(frozenDepsStr, FrozenDeps)
} }
// FrozenDeps will check the repository if it contains frozen dependecies. // FrozenDeps will check the repository if it contains frozen dependecies.
func FrozenDeps(c checker.Checker) checker.CheckResult { func FrozenDeps(c checker.CheckRequest) checker.CheckResult {
return CheckIfFileExists(c, filePredicate) return CheckIfFileExists(frozenDepsStr, c, filePredicate)
} }
// filePredicate will validate the if frozen dependecies file name exists. // filePredicate will validate the if frozen dependecies file name exists.

View File

@ -21,29 +21,32 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const fuzzingStr = "Fuzzing"
func init() { func init() {
registerCheck("Fuzzing", Fuzzing) registerCheck(fuzzingStr, Fuzzing)
} }
func Fuzzing(c checker.Checker) checker.CheckResult { func Fuzzing(c checker.CheckRequest) checker.CheckResult {
url := fmt.Sprintf("github.com/%s/%s", c.Owner, c.Repo) url := fmt.Sprintf("github.com/%s/%s", c.Owner, c.Repo)
searchString := url + " repo:google/oss-fuzz in:file filename:project.yaml" searchString := url + " repo:google/oss-fuzz in:file filename:project.yaml"
results, _, err := c.Client.Search.Code(c.Ctx, searchString, &github.SearchOptions{}) results, _, err := c.Client.Search.Code(c.Ctx, searchString, &github.SearchOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(fuzzingStr, err)
} }
const confidence = 10
if *results.Total > 0 { if *results.Total > 0 {
c.Logf("found project in OSS-Fuzz") c.Logf("found project in OSS-Fuzz")
return checker.CheckResult{ return checker.CheckResult{
Name: fuzzingStr,
Pass: true, Pass: true,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }
return checker.CheckResult{ return checker.CheckResult{
Name: fuzzingStr,
Pass: false, Pass: false,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }

View File

@ -23,22 +23,23 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const packagingStr = "Packaging"
func init() { func init() {
registerCheck("Packaging", Packaging) registerCheck(packagingStr, Packaging)
} }
func Packaging(c checker.Checker) checker.CheckResult { func Packaging(c checker.CheckRequest) checker.CheckResult {
_, dc, _, err := c.Client.Repositories.GetContents(c.Ctx, c.Owner, c.Repo, ".github/workflows", &github.RepositoryContentGetOptions{}) _, dc, _, err := c.Client.Repositories.GetContents(c.Ctx, c.Owner, c.Repo, ".github/workflows", &github.RepositoryContentGetOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(packagingStr, err)
} }
const confidence = 10
for _, f := range dc { for _, f := range dc {
fp := f.GetPath() fp := f.GetPath()
fo, _, _, err := c.Client.Repositories.GetContents(c.Ctx, c.Owner, c.Repo, fp, &github.RepositoryContentGetOptions{}) fo, _, _, err := c.Client.Repositories.GetContents(c.Ctx, c.Owner, c.Repo, fp, &github.RepositoryContentGetOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(packagingStr, err)
} }
if fo == nil { if fo == nil {
// path is a directory, not a file. skip. // path is a directory, not a file. skip.
@ -46,7 +47,7 @@ func Packaging(c checker.Checker) checker.CheckResult {
} }
fc, err := fo.GetContent() fc, err := fo.GetContent()
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(packagingStr, err)
} }
if !isPackagingWorkflow(fc, fp, c) { if !isPackagingWorkflow(fc, fp, c) {
@ -57,25 +58,27 @@ func Packaging(c checker.Checker) checker.CheckResult {
Status: "success", Status: "success",
}) })
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(packagingStr, err)
} }
if *runs.TotalCount > 0 { if *runs.TotalCount > 0 {
c.Logf("found a completed run: %s", runs.WorkflowRuns[0].GetHTMLURL()) c.Logf("found a completed run: %s", runs.WorkflowRuns[0].GetHTMLURL())
return checker.CheckResult{ return checker.CheckResult{
Name: packagingStr,
Pass: true, Pass: true,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }
c.Logf("!! no run completed") c.Logf("!! no run completed")
} }
return checker.CheckResult{ return checker.CheckResult{
Name: packagingStr,
Pass: false, Pass: false,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }
func isPackagingWorkflow(s string, fp string, c checker.Checker) bool { func isPackagingWorkflow(s string, fp string, c checker.CheckRequest) bool {
// nodejs packages // nodejs packages
if strings.Contains(s, "uses: actions/setup-node@") { if strings.Contains(s, "uses: actions/setup-node@") {
r1, _ := regexp.Compile(`(?s)registry-url.*https://registry\.npmjs\.org`) r1, _ := regexp.Compile(`(?s)registry-url.*https://registry\.npmjs\.org`)

View File

@ -21,14 +21,16 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const pullRequestsStr = "Pull-Requests"
func init() { func init() {
registerCheck("Pull-Requests", PullRequests) registerCheck(pullRequestsStr, PullRequests)
} }
func PullRequests(c checker.Checker) checker.CheckResult { func PullRequests(c checker.CheckRequest) checker.CheckResult {
commits, _, err := c.Client.Repositories.ListCommits(c.Ctx, c.Owner, c.Repo, &github.CommitsListOptions{}) commits, _, err := c.Client.Repositories.ListCommits(c.Ctx, c.Owner, c.Repo, &github.CommitsListOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(pullRequestsStr, err)
} }
total := 0 total := 0
@ -59,7 +61,7 @@ func PullRequests(c checker.Checker) checker.CheckResult {
prs, _, err := c.Client.PullRequests.ListPullRequestsWithCommit(c.Ctx, c.Owner, c.Repo, commit.GetSHA(), &github.PullRequestListOptions{}) prs, _, err := c.Client.PullRequests.ListPullRequestsWithCommit(c.Ctx, c.Owner, c.Repo, commit.GetSHA(), &github.PullRequestListOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(pullRequestsStr, err)
} }
if len(prs) > 0 { if len(prs) > 0 {
totalWithPrs++ totalWithPrs++
@ -69,5 +71,5 @@ func PullRequests(c checker.Checker) checker.CheckResult {
} }
} }
c.Logf("found PRs for %d out of %d commits", totalWithPrs, total) c.Logf("found PRs for %d out of %d commits", totalWithPrs, total)
return checker.ProportionalResult(totalWithPrs, total, .75) return checker.MakeProportionalResult(pullRequestsStr, totalWithPrs, total, .75)
} }

View File

@ -19,25 +19,27 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const sastStr = "SAST"
var sastTools map[string]bool = map[string]bool{"github-code-scanning": true, "sonarcloud": true} var sastTools map[string]bool = map[string]bool{"github-code-scanning": true, "sonarcloud": true}
func init() { func init() {
registerCheck("SAST", SAST) registerCheck(sastStr, SAST)
} }
func SAST(c checker.Checker) checker.CheckResult { func SAST(c checker.CheckRequest) checker.CheckResult {
return checker.MultiCheck( return checker.MultiCheck(
CodeQLInCheckDefinitions, CodeQLInCheckDefinitions,
SASTToolInCheckRuns, SASTToolInCheckRuns,
)(c) )(c)
} }
func SASTToolInCheckRuns(c checker.Checker) checker.CheckResult { func SASTToolInCheckRuns(c checker.CheckRequest) checker.CheckResult {
prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{ prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{
State: "closed", State: "closed",
}) })
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(sastStr, err)
} }
totalMerged := 0 totalMerged := 0
@ -49,10 +51,10 @@ func SASTToolInCheckRuns(c checker.Checker) checker.CheckResult {
totalMerged++ totalMerged++
crs, _, err := c.Client.Checks.ListCheckRunsForRef(c.Ctx, c.Owner, c.Repo, pr.GetHead().GetSHA(), &github.ListCheckRunsOptions{}) crs, _, err := c.Client.Checks.ListCheckRunsForRef(c.Ctx, c.Owner, c.Repo, pr.GetHead().GetSHA(), &github.ListCheckRunsOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(sastStr, err)
} }
if crs == nil { if crs == nil {
return checker.InconclusiveResult return checker.MakeInconclusiveResult(sastStr)
} }
for _, cr := range crs.CheckRuns { for _, cr := range crs.CheckRuns {
if cr.GetStatus() != "completed" { if cr.GetStatus() != "completed" {
@ -69,25 +71,25 @@ func SASTToolInCheckRuns(c checker.Checker) checker.CheckResult {
} }
} }
if totalTested == 0 { if totalTested == 0 {
return checker.InconclusiveResult return checker.MakeInconclusiveResult(sastStr)
} }
return checker.ProportionalResult(totalTested, totalMerged, .75) return checker.MakeProportionalResult(sastStr, totalTested, totalMerged, .75)
} }
func CodeQLInCheckDefinitions(c checker.Checker) checker.CheckResult { func CodeQLInCheckDefinitions(c checker.CheckRequest) checker.CheckResult {
searchQuery := ("github/codeql-action path:/.github/workflows repo:" + c.Owner + "/" + c.Repo) searchQuery := ("github/codeql-action path:/.github/workflows repo:" + c.Owner + "/" + c.Repo)
results, _, err := c.Client.Search.Code(c.Ctx, searchQuery, &github.SearchOptions{}) results, _, err := c.Client.Search.Code(c.Ctx, searchQuery, &github.SearchOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(sastStr, err)
} }
for _, result := range results.CodeResults { for _, result := range results.CodeResults {
c.Logf("found CodeQL definition: %s", result.GetPath()) c.Logf("found CodeQL definition: %s", result.GetPath())
} }
const confidence = 10
return checker.CheckResult{ return checker.CheckResult{
Name: sastStr,
Pass: *results.Total > 0, Pass: *results.Total > 0,
Confidence: confidence, Confidence: checker.MaxResultConfidence,
} }
} }

View File

@ -20,13 +20,15 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
const securityPolicyStr = "Security-Policy"
func init() { func init() {
registerCheck("Security-Policy", SecurityPolicy) registerCheck(securityPolicyStr, SecurityPolicy)
} }
func SecurityPolicy(c checker.Checker) checker.CheckResult { func SecurityPolicy(c checker.CheckRequest) checker.CheckResult {
// check repository for repository-specific policy // check repository for repository-specific policy
result := CheckIfFileExists(c, func(name string, logf func(s string, f ...interface{})) bool { result := CheckIfFileExists(securityPolicyStr, c, func(name string, logf func(s string, f ...interface{})) bool {
if strings.EqualFold(name, "security.md") { if strings.EqualFold(name, "security.md") {
logf("security policy : %s", name) logf("security policy : %s", name)
return true return true
@ -43,7 +45,7 @@ func SecurityPolicy(c checker.Checker) checker.CheckResult {
dotGitHub := c dotGitHub := c
dotGitHub.Repo = ".github" dotGitHub.Repo = ".github"
return CheckIfFileExists(dotGitHub, func(name string, logf func(s string, f ...interface{})) bool { return CheckIfFileExists(securityPolicyStr, dotGitHub, func(name string, logf func(s string, f ...interface{})) bool {
if strings.EqualFold(name, "security.md") { if strings.EqualFold(name, "security.md") {
logf("security policy within .github folder : %s", name) logf("security policy within .github folder : %s", name)
return true return true

View File

@ -21,16 +21,19 @@ import (
"github.com/ossf/scorecard/checker" "github.com/ossf/scorecard/checker"
) )
var releaseLookBack int = 5 const (
signedReleasesStr = "Signed-Releases"
releaseLookBackDays = 5
)
func init() { func init() {
registerCheck("Signed-Releases", SignedReleases) registerCheck(signedReleasesStr, SignedReleases)
} }
func SignedReleases(c checker.Checker) checker.CheckResult { func SignedReleases(c checker.CheckRequest) checker.CheckResult {
releases, _, err := c.Client.Repositories.ListReleases(c.Ctx, c.Owner, c.Repo, &github.ListOptions{}) releases, _, err := c.Client.Repositories.ListReleases(c.Ctx, c.Owner, c.Repo, &github.ListOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(signedReleasesStr, err)
} }
artifactExtensions := []string{".asc", ".minisig", ".sig"} artifactExtensions := []string{".asc", ".minisig", ".sig"}
@ -40,7 +43,7 @@ func SignedReleases(c checker.Checker) checker.CheckResult {
for _, r := range releases { for _, r := range releases {
assets, _, err := c.Client.Repositories.ListReleaseAssets(c.Ctx, c.Owner, c.Repo, r.GetID(), &github.ListOptions{}) assets, _, err := c.Client.Repositories.ListReleaseAssets(c.Ctx, c.Owner, c.Repo, r.GetID(), &github.ListOptions{})
if err != nil { if err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(signedReleasesStr, err)
} }
if len(assets) == 0 { if len(assets) == 0 {
continue continue
@ -64,16 +67,16 @@ func SignedReleases(c checker.Checker) checker.CheckResult {
if !signed { if !signed {
c.Logf("!! release %s has no signed artifacts", r.GetTagName()) c.Logf("!! release %s has no signed artifacts", r.GetTagName())
} }
if totalReleases > releaseLookBack { if totalReleases > releaseLookBackDays {
break break
} }
} }
if totalReleases == 0 { if totalReleases == 0 {
c.Logf("no releases found") c.Logf("no releases found")
return checker.InconclusiveResult return checker.MakeInconclusiveResult(signedReleasesStr)
} }
c.Logf("found signed artifacts for %d out of %d releases", totalSigned, totalReleases) c.Logf("found signed artifacts for %d out of %d releases", totalSigned, totalReleases)
return checker.ProportionalResult(totalSigned, totalReleases, 0.8) return checker.MakeProportionalResult(signedReleasesStr, totalSigned, totalReleases, 0.8)
} }

View File

@ -19,13 +19,16 @@ import (
"github.com/shurcooL/githubv4" "github.com/shurcooL/githubv4"
) )
var tagLookBack int = 5 const (
signedTagsStr = "Signed-Tags"
tagLookBack = 5
)
func init() { func init() {
registerCheck("Signed-Tags", SignedTags) registerCheck(signedTagsStr, SignedTags)
} }
func SignedTags(c checker.Checker) checker.CheckResult { func SignedTags(c checker.CheckRequest) checker.CheckResult {
type ref struct { type ref struct {
Name githubv4.String Name githubv4.String
Target struct { Target struct {
@ -47,7 +50,7 @@ func SignedTags(c checker.Checker) checker.CheckResult {
} }
if err := c.GraphClient.Query(c.Ctx, &query, variables); err != nil { if err := c.GraphClient.Query(c.Ctx, &query, variables); err != nil {
return checker.RetryResult(err) return checker.MakeRetryResult(signedTagsStr, err)
} }
totalTags := 0 totalTags := 0
totalSigned := 0 totalSigned := 0
@ -69,9 +72,9 @@ func SignedTags(c checker.Checker) checker.CheckResult {
if totalTags == 0 { if totalTags == 0 {
c.Logf("no tags found") c.Logf("no tags found")
return checker.InconclusiveResult return checker.MakeInconclusiveResult(signedTagsStr)
} }
c.Logf("found %d out of %d verified tags", totalSigned, totalTags) c.Logf("found %d out of %d verified tags", totalSigned, totalTags)
return checker.ProportionalResult(totalSigned, totalTags, 0.8) return checker.MakeProportionalResult(signedTagsStr, totalSigned, totalTags, 0.8)
} }

View File

@ -68,7 +68,7 @@ or ./scorecard --{npm,pypi,rubgems}=<package_name> [--checks=check1,...] [--show
defer logger.Sync() // flushes buffer, if any defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar() sugar := logger.Sugar()
var outputFn func([]pkg.Result) var outputFn func([]checker.CheckResult)
switch format { switch format {
case formatCSV: case formatCSV:
outputFn = outputCSV outputFn = outputCSV
@ -110,30 +110,26 @@ or ./scorecard --{npm,pypi,rubgems}=<package_name> [--checks=check1,...] [--show
} }
} }
enabledChecks := []checker.NamedCheck{} enabledChecks := checker.CheckNameToFnMap{}
if len(checksToRun) != 0 { if len(checksToRun) != 0 {
checkNames := map[string]struct{}{} for _, checkToRun := range checksToRun {
for _, s := range checksToRun { if checkFn, ok := checks.AllChecks[checkToRun]; ok {
checkNames[s] = struct{}{} enabledChecks[checkToRun] = checkFn
}
for _, c := range checks.AllChecks {
if _, ok := checkNames[c.Name]; ok {
enabledChecks = append(enabledChecks, c)
} }
} }
} else { } else {
enabledChecks = checks.AllChecks enabledChecks = checks.AllChecks
} }
for _, c := range enabledChecks { for checkName := range enabledChecks {
if format == formatDefault { if format == formatDefault {
fmt.Fprintf(os.Stderr, "Starting [%s]\n", c.Name) fmt.Fprintf(os.Stderr, "Starting [%s]\n", checkName)
} }
} }
ctx := context.Background() ctx := context.Background()
resultsCh := pkg.RunScorecards(ctx, sugar, repo, enabledChecks) resultsCh := pkg.RunScorecards(ctx, sugar, repo, enabledChecks)
// Collect results // Collect results
results := []pkg.Result{} results := []checker.CheckResult{}
for result := range resultsCh { for result := range resultsCh {
if format == formatDefault { if format == formatDefault {
fmt.Fprintf(os.Stderr, "Finished [%s]\n", result.Name) fmt.Fprintf(os.Stderr, "Finished [%s]\n", result.Name)
@ -150,13 +146,6 @@ or ./scorecard --{npm,pypi,rubgems}=<package_name> [--checks=check1,...] [--show
}, },
} }
type checkResult struct {
CheckName string
Pass bool
Confidence int
Details []string
}
type npmSearchResults struct { type npmSearchResults struct {
Objects []struct { Objects []struct {
Package struct { Package struct {
@ -182,11 +171,11 @@ type rubyGemsSearchResults struct {
type record struct { type record struct {
Repo string Repo string
Date string Date string
Checks []checkResult Checks []checker.CheckResult
MetaData []string MetaData []string
} }
func outputJSON(results []pkg.Result) { func outputJSON(results []checker.CheckResult) {
d := time.Now() d := time.Now()
or := record{ or := record{
Repo: repo.String(), Repo: repo.String(),
@ -195,16 +184,15 @@ func outputJSON(results []pkg.Result) {
} }
for _, r := range results { for _, r := range results {
var details []string tmpResult := checker.CheckResult{
if showDetails { Name: r.Name,
details = r.Cr.Details Pass: r.Pass,
Confidence: r.Confidence,
} }
or.Checks = append(or.Checks, checkResult{ if showDetails {
CheckName: r.Name, tmpResult.Details = r.Details
Pass: r.Cr.Pass, }
Confidence: r.Cr.Confidence, or.Checks = append(or.Checks, tmpResult)
Details: details,
})
} }
output, err := json.Marshal(or) output, err := json.Marshal(or)
if err != nil { if err != nil {
@ -213,13 +201,13 @@ func outputJSON(results []pkg.Result) {
fmt.Println(string(output)) fmt.Println(string(output))
} }
func outputCSV(results []pkg.Result) { func outputCSV(results []checker.CheckResult) {
w := csv.NewWriter(os.Stdout) w := csv.NewWriter(os.Stdout)
record := []string{repo.String()} record := []string{repo.String()}
columns := []string{"Repository"} columns := []string{"Repository"}
for _, r := range results { for _, r := range results {
columns = append(columns, r.Name+"-Pass", r.Name+"-Confidence") columns = append(columns, r.Name+"-Pass", r.Name+"-Confidence")
record = append(record, strconv.FormatBool(r.Cr.Pass), strconv.Itoa(r.Cr.Confidence)) record = append(record, strconv.FormatBool(r.Pass), strconv.Itoa(r.Confidence))
} }
fmt.Fprintln(os.Stderr, "CSV COLUMN NAMES") fmt.Fprintln(os.Stderr, "CSV COLUMN NAMES")
fmt.Fprintf(os.Stderr, "%s\n", strings.Join(columns, ",")) fmt.Fprintf(os.Stderr, "%s\n", strings.Join(columns, ","))
@ -229,14 +217,14 @@ func outputCSV(results []pkg.Result) {
w.Flush() w.Flush()
} }
func outputDefault(results []pkg.Result) { func outputDefault(results []checker.CheckResult) {
fmt.Println() fmt.Println()
fmt.Println("RESULTS") fmt.Println("RESULTS")
fmt.Println("-------") fmt.Println("-------")
for _, r := range results { for _, r := range results {
fmt.Println(r.Name+":", displayResult(r.Cr.Pass), r.Cr.Confidence) fmt.Println(r.Name+":", displayResult(r.Pass), r.Confidence)
if showDetails { if showDetails {
for _, d := range r.Cr.Details { for _, d := range r.Details {
fmt.Println(" " + d) fmt.Println(" " + d)
} }
} }
@ -352,8 +340,8 @@ func init() {
rootCmd.Flags().BoolVar(&showDetails, "show-details", false, "show extra details about each check") rootCmd.Flags().BoolVar(&showDetails, "show-details", false, "show extra details about each check")
checkNames := []string{} checkNames := []string{}
for _, c := range checks.AllChecks { for checkName := range checks.AllChecks {
checkNames = append(checkNames, c.Name) checkNames = append(checkNames, checkName)
} }
rootCmd.Flags().StringSliceVar(&checksToRun, "checks", []string{}, rootCmd.Flags().StringSliceVar(&checksToRun, "checks", []string{},
fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ","))) fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ",")))

View File

@ -24,6 +24,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/pkg" "github.com/ossf/scorecard/pkg"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -101,7 +102,7 @@ var serveCmd = &cobra.Command{
} }
// encodeJson encodes the result to json // encodeJson encodes the result to json
func encodeJson(repo string, results []pkg.Result) ([]byte, error) { func encodeJson(repo string, results []checker.CheckResult) ([]byte, error) {
d := time.Now() d := time.Now()
or := record{ or := record{
Repo: repo, Repo: repo,
@ -109,16 +110,15 @@ func encodeJson(repo string, results []pkg.Result) ([]byte, error) {
} }
for _, r := range results { for _, r := range results {
var details []string tmpResult := checker.CheckResult{
if showDetails { Name: r.Name,
details = r.Cr.Details Pass: r.Pass,
Confidence: r.Confidence,
} }
or.Checks = append(or.Checks, checkResult{ if showDetails {
CheckName: r.Name, tmpResult.Details = r.Details
Pass: r.Cr.Pass, }
Confidence: r.Cr.Confidence, or.Checks = append(or.Checks, tmpResult)
Details: details,
})
} }
output, err := json.Marshal(or) output, err := json.Marshal(or)
if err != nil { if err != nil {
@ -129,7 +129,7 @@ func encodeJson(repo string, results []pkg.Result) ([]byte, error) {
type tc struct { type tc struct {
URL string URL string
Results []pkg.Result Results []checker.CheckResult
} }
const tpl = ` const tpl = `
@ -142,7 +142,7 @@ const tpl = `
<body> <body>
{{range .Results}} {{range .Results}}
<div> <div>
<p>{{ .Name }}: {{ .Cr.Pass }}</p> <p>{{ .Name }}: {{ .Pass }}</p>
</div> </div>
{{end}} {{end}}
</body> </body>

BIN
cron/cron Executable file

Binary file not shown.

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:Active", func() { var _ = Describe("E2E TEST:Active", func() {
Context("E2E TEST:Validating active status", func() { Context("E2E TEST:Validating active status", func() {
It("Should return valid active status", func() { It("Should return valid active status", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:Active", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.IsActive(checker) result := checks.IsActive(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:Branch Protection", func() { var _ = Describe("E2E TEST:Branch Protection", func() {
Context("E2E TEST:Validating branch protection", func() { Context("E2E TEST:Validating branch protection", func() {
It("Should fail to return branch protection on other repositories", func() { It("Should fail to return branch protection on other repositories", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:Branch Protection", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.BranchProtection(checker) result := checks.BranchProtection(checkRequest)
Expect(result.Error).ShouldNot(BeNil()) Expect(result.Error).ShouldNot(BeNil())
Expect(result.Pass).Should(BeFalse()) Expect(result.Pass).Should(BeFalse())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:CITests", func() { var _ = Describe("E2E TEST:CITests", func() {
Context("E2E TEST:Validating use of CI tests", func() { Context("E2E TEST:Validating use of CI tests", func() {
It("Should return use of CI tests", func() { It("Should return use of CI tests", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:CITests", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.CITests(checker) result := checks.CITests(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:CIIBestPractices", func() { var _ = Describe("E2E TEST:CIIBestPractices", func() {
Context("E2E TEST:Validating use of CII Best Practices", func() { Context("E2E TEST:Validating use of CII Best Practices", func() {
It("Should return use of CII Best Practices", func() { It("Should return use of CII Best Practices", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:CIIBestPractices", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.CIIBestPractices(checker) result := checks.CIIBestPractices(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:CodeReview", func() { var _ = Describe("E2E TEST:CodeReview", func() {
Context("E2E TEST:Validating use of code reviews", func() { Context("E2E TEST:Validating use of code reviews", func() {
It("Should return use of code reviews", func() { It("Should return use of code reviews", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:CodeReview", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.DoesCodeReview(checker) result := checks.DoesCodeReview(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -27,7 +27,7 @@ var _ = Describe("E2E TEST:CodeReview", func() {
Context("E2E TEST:Validating project contributors", func() { Context("E2E TEST:Validating project contributors", func() {
It("Should return valid project contributors", func() { It("Should return valid project contributors", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,13 +36,13 @@ var _ = Describe("E2E TEST:CodeReview", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.Contributors(checker) result := checks.Contributors(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })
It("Should return valid project contributors", func() { It("Should return valid project contributors", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -51,7 +51,7 @@ var _ = Describe("E2E TEST:CodeReview", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.Contributors(checker) result := checks.Contributors(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:FrozenDeps", func() { var _ = Describe("E2E TEST:FrozenDeps", func() {
Context("E2E TEST:Validating deps are frozen", func() { Context("E2E TEST:Validating deps are frozen", func() {
It("Should return deps are frozen", func() { It("Should return deps are frozen", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:FrozenDeps", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.FrozenDeps(checker) result := checks.FrozenDeps(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:Fuzzing", func() { var _ = Describe("E2E TEST:Fuzzing", func() {
Context("E2E TEST:Validating use of fuzzing tools", func() { Context("E2E TEST:Validating use of fuzzing tools", func() {
It("Should return use of fuzzing tools", func() { It("Should return use of fuzzing tools", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:Fuzzing", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.Fuzzing(checker) result := checks.Fuzzing(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -27,7 +27,7 @@ var _ = Describe("E2E TEST:Packaging", func() {
Context("E2E TEST:Validating use of packaging in CI/CD", func() { Context("E2E TEST:Validating use of packaging in CI/CD", func() {
It("Should return use of packaging in CI/CD", func() { It("Should return use of packaging in CI/CD", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,13 +36,13 @@ var _ = Describe("E2E TEST:Packaging", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.Packaging(checker) result := checks.Packaging(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })
It("Should return use of packaging in CI/CD for scorecard", func() { It("Should return use of packaging in CI/CD for scorecard", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -51,7 +51,7 @@ var _ = Describe("E2E TEST:Packaging", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.Packaging(checker) result := checks.Packaging(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:PullRequests", func() { var _ = Describe("E2E TEST:PullRequests", func() {
Context("E2E TEST:Validating use of pull requests", func() { Context("E2E TEST:Validating use of pull requests", func() {
It("Should return use of pull requests", func() { It("Should return use of pull requests", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:PullRequests", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.PullRequests(checker) result := checks.PullRequests(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:SAST", func() { var _ = Describe("E2E TEST:SAST", func() {
Context("E2E TEST:Validating use of SAST tools", func() { Context("E2E TEST:Validating use of SAST tools", func() {
It("Should return use of SAST tools", func() { It("Should return use of SAST tools", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:SAST", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.SAST(checker) result := checks.SAST(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:SecurityPolicy", func() { var _ = Describe("E2E TEST:SecurityPolicy", func() {
Context("E2E TEST:Validating security policy", func() { Context("E2E TEST:Validating security policy", func() {
It("Should return valid security policy", func() { It("Should return valid security policy", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:SecurityPolicy", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.SecurityPolicy(checker) result := checks.SecurityPolicy(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -19,15 +19,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:Signedreleases", func() { var _ = Describe("E2E TEST:Signedreleases", func() {
Context("E2E TEST:Validating signed releases", func() { Context("E2E TEST:Validating signed releases", func() {
It("Should return valid signed releases", func() { It("Should return valid signed releases", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -36,7 +36,7 @@ var _ = Describe("E2E TEST:Signedreleases", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.SignedReleases(checker) result := checks.SignedReleases(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

View File

@ -20,15 +20,15 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/ossf/scorecard/checker"
"github.com/ossf/scorecard/checks" "github.com/ossf/scorecard/checks"
"github.com/ossf/scorecard/checker"
) )
var _ = Describe("E2E TEST:Signedtags", func() { var _ = Describe("E2E TEST:Signedtags", func() {
Context("E2E TEST:Validating signed tags", func() { Context("E2E TEST:Validating signed tags", func() {
It("Should return valid signed tags", func() { It("Should return valid signed tags", func() {
l := log{} l := log{}
checker := checker.Checker{ checkRequest := checker.CheckRequest{
Ctx: context.Background(), Ctx: context.Background(),
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -37,7 +37,7 @@ var _ = Describe("E2E TEST:Signedtags", func() {
GraphClient: graphClient, GraphClient: graphClient,
Logf: l.Logf, Logf: l.Logf,
} }
result := checks.SignedTags(checker) result := checks.SignedTags(checkRequest)
Expect(result.Error).Should(BeNil()) Expect(result.Error).Should(BeNil())
Expect(result.Pass).Should(BeTrue()) Expect(result.Pass).Should(BeTrue())
}) })

3
go.mod
View File

@ -17,6 +17,7 @@ require (
go.uber.org/zap v1.16.0 go.uber.org/zap v1.16.0
gocloud.dev v0.22.0 gocloud.dev v0.22.0
golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19 golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c // indirect golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
golang.org/x/tools v0.1.0 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
) )

8
go.sum
View File

@ -566,8 +566,10 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -636,8 +638,8 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201202200335-bef1c476418a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201202200335-bef1c476418a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201203202102-a1a1cbeaa516/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201203202102-a1a1cbeaa516/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c h1:dS09fXwOFF9cXBnIzZexIuUBj95U1NyQjkEhkgidDow= golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -30,12 +30,6 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
type Result struct {
Cr checker.CheckResult
Name string
MetaData []string
}
type RepoURL struct { type RepoURL struct {
Host, Owner, Repo string Host, Owner, Repo string
} }
@ -80,11 +74,11 @@ func (r *RepoURL) Set(s string) error {
} }
func RunScorecards(ctx context.Context, logger *zap.SugaredLogger, func RunScorecards(ctx context.Context, logger *zap.SugaredLogger,
repo RepoURL, checksToRun []checker.NamedCheck) <-chan Result { repo RepoURL, checksToRun checker.CheckNameToFnMap) <-chan checker.CheckResult {
resultsCh := make(chan Result) resultsCh := make(chan checker.CheckResult)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
for _, check := range checksToRun { for _, checkFn := range checksToRun {
check := check checkFn := checkFn
wg.Add(1) wg.Add(1)
go func() { go func() {
// Use our custom roundtripper // Use our custom roundtripper
@ -96,7 +90,7 @@ func RunScorecards(ctx context.Context, logger *zap.SugaredLogger,
ghClient := github.NewClient(client) ghClient := github.NewClient(client)
graphClient := githubv4.NewClient(client) graphClient := githubv4.NewClient(client)
c := checker.Checker{ c := checker.CheckRequest{
Ctx: ctx, Ctx: ctx,
Client: ghClient, Client: ghClient,
HttpClient: client, HttpClient: client,
@ -105,12 +99,8 @@ func RunScorecards(ctx context.Context, logger *zap.SugaredLogger,
GraphClient: graphClient, GraphClient: graphClient,
} }
defer wg.Done() defer wg.Done()
runner := checker.Runner{Checker: c} runner := checker.Runner{CheckRequest: c}
r := runner.Run(check.Fn) resultsCh <- runner.Run(checkFn)
resultsCh <- Result{
Name: check.Name,
Cr: r,
}
}() }()
} }
go func() { go func() {