🌱 : 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 (
"context"
"fmt"
"net/http"
"strings"
"github.com/google/go-github/v32/github"
"github.com/shurcooL/githubv4"
)
type Checker struct {
type CheckRequest struct {
Ctx context.Context
Client *github.Client
GraphClient *githubv4.Client
@ -32,34 +30,3 @@ type Checker struct {
Owner, Repo string
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"
)
var lookbackDays int = 90
const (
activeStr = "Active"
lookbackDays = 90
)
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{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(activeStr, err)
}
tz, _ := time.LoadLocation("UTC")
@ -39,7 +42,7 @@ func IsActive(c checker.Checker) checker.CheckResult {
for _, commit := range commits {
commitFull, _, err := c.Client.Git.GetCommit(c.Ctx, c.Owner, c.Repo, commit.GetSHA())
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(activeStr, err)
}
if commitFull.GetAuthor().GetDate().After(threshold) {
totalCommits++
@ -49,6 +52,7 @@ func IsActive(c checker.Checker) checker.CheckResult {
const numCommits = 2
const confidence = 10
return checker.CheckResult{
Name: activeStr,
Pass: totalCommits >= numCommits,
Confidence: confidence,
}

View File

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

View File

@ -19,27 +19,30 @@ import (
"github.com/ossf/scorecard/checker"
)
const branchProtectionStr = "Branch-Protection"
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)
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(branchProtectionStr, err)
}
protection, resp, err := c.Client.Repositories.
GetBranchProtection(c.Ctx, c.Owner, c.Repo, *repo.DefaultBranch)
const fileNotFound = 404
if resp.StatusCode == fileNotFound {
return checker.RetryResult(err)
return checker.MakeRetryResult(branchProtectionStr, err)
}
if err != nil {
c.Logf("!! branch protection not enabled")
const confidence = 10
return checker.CheckResult{
Name: branchProtectionStr,
Pass: false,
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
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"
)
// TODO: these logging functions are repeated from lib/check_fn.go. Reuse code.
type log struct {
messages []string
}
@ -33,7 +34,7 @@ func (l *log) Logf(s string, f ...interface{}) {
func TestIsBranchProtected(t *testing.T) {
type args struct {
protection *github.Protection
c checker.Checker
c checker.CheckRequest
}
l := log{}
@ -77,8 +78,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false,
},
},
c: checker.Checker{Logf: l.Logf}},
c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false,
Details: nil,
Confidence: 7,
@ -120,8 +122,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false,
},
},
c: checker.Checker{Logf: l.Logf}},
c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false,
Details: nil,
Confidence: 5,
@ -163,8 +166,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false,
},
},
c: checker.Checker{Logf: l.Logf}},
c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false,
Details: nil,
Confidence: 7,
@ -207,8 +211,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false,
},
},
c: checker.Checker{Logf: l.Logf}},
c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false,
Details: nil,
Confidence: 5,
@ -250,8 +255,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false,
},
},
c: checker.Checker{Logf: l.Logf}},
c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false,
Details: nil,
Confidence: 5,
@ -293,8 +299,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false,
},
},
c: checker.Checker{Logf: l.Logf}},
c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false,
Details: nil,
Confidence: 5,
@ -336,8 +343,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false,
},
},
c: checker.Checker{Logf: l.Logf}},
c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false,
Details: nil,
Confidence: 9,
@ -378,8 +386,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: true,
},
},
c: checker.Checker{Logf: l.Logf}},
c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{
Name: branchProtectionStr,
Pass: false,
Details: nil,
Confidence: 9,
@ -419,8 +428,9 @@ func TestIsBranchProtected(t *testing.T) {
Enabled: false,
},
},
c: checker.Checker{Logf: l.Logf}},
c: checker.CheckRequest{Logf: l.Logf}},
want: checker.CheckResult{
Name: branchProtectionStr,
Pass: true,
Details: nil,
Confidence: 10,

View File

@ -26,30 +26,30 @@ import (
// CheckIfFileExists downloads the tar of the repository and calls the predicate to check
// 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 {
r, _, err := c.Client.Repositories.Get(c.Ctx, c.Owner, c.Repo)
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(checkName, err)
}
url := r.GetArchiveURL()
url = strings.Replace(url, "{archive_format}", "tarball/", 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.
//https://securego.io/docs/rules/g107.html
//nolint
resp, err := http.Get(url)
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(checkName, err)
}
defer resp.Body.Close()
gz, err := gzip.NewReader(resp.Body)
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(checkName, err)
}
tr := tar.NewReader(gz)
@ -58,7 +58,7 @@ func CheckIfFileExists(c checker.Checker, predicate func(name string,
if err == io.EOF {
break
} else if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(checkName, err)
}
// Strip the repo name
@ -70,11 +70,12 @@ func CheckIfFileExists(c checker.Checker, predicate func(name string,
name := names[1]
if predicate(name, c.Logf) {
return checker.PassResult
return checker.MakePassResult(checkName)
}
}
const confidence = 5
return checker.CheckResult{
Name: checkName,
Pass: false,
Confidence: confidence,
}

View File

@ -21,16 +21,18 @@ import (
"github.com/ossf/scorecard/checker"
)
const ciTestsStr = "CI-Tests"
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{
State: "closed",
})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(ciTestsStr, err)
}
const (
@ -56,7 +58,7 @@ func CITests(c checker.Checker) checker.CheckResult {
if usedSystem <= githubStatuses {
statuses, _, err := c.Client.Repositories.ListStatuses(c.Ctx, c.Owner, c.Repo, pr.GetHead().GetSHA(), &github.ListOptions{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(ciTestsStr, err)
}
for _, status := range statuses {
@ -81,7 +83,7 @@ func CITests(c checker.Checker) checker.CheckResult {
if usedSystem == githubCheckRuns || usedSystem == unknown {
crs, _, err := c.Client.Checks.ListCheckRunsForRef(c.Ctx, c.Owner, c.Repo, pr.GetHead().GetSHA(), &github.ListCheckRunsOptions{})
if err != nil || crs == nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(ciTestsStr, err)
}
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)
return checker.ProportionalResult(totalTested, totalMerged, .75)
return checker.MakeProportionalResult(ciTestsStr, totalTested, totalMerged, .75)
}
func isTest(s string) bool {

View File

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

View File

@ -21,8 +21,10 @@ import (
"github.com/ossf/scorecard/checker"
)
const codeReviewStr = "Code-Review"
func init() {
registerCheck("Code-Review", DoesCodeReview)
registerCheck(codeReviewStr, DoesCodeReview)
}
// 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
// - Checking if most of the recent merged PRs were "Approved"
// - Looking for other well-known review labels
func DoesCodeReview(c checker.Checker) checker.CheckResult {
func DoesCodeReview(c checker.CheckRequest) checker.CheckResult {
return checker.MultiCheck(
IsPrReviewRequired,
GithubCodeReview,
@ -39,13 +41,13 @@ func DoesCodeReview(c checker.Checker) checker.CheckResult {
)(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
prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{
State: "closed",
})
if err != nil {
return checker.InconclusiveResult
return checker.MakeInconclusiveResult(codeReviewStr)
}
totalMerged := 0
@ -91,39 +93,40 @@ func GithubCodeReview(c checker.Checker) checker.CheckResult {
if totalReviewed > 0 {
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.
r, _, err := c.Client.Repositories.Get(c.Ctx, c.Owner, c.Repo)
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.
bp, _, err := c.Client.Repositories.GetBranchProtection(c.Ctx, c.Owner, c.Repo, r.GetDefaultBranch())
if err != nil {
return checker.InconclusiveResult
return checker.MakeInconclusiveResult(codeReviewStr)
}
if bp.GetRequiredPullRequestReviews().RequiredApprovingReviewCount >= 1 {
c.Logf("pr review policy enforced")
const confidence = 5
return checker.CheckResult{
Name: codeReviewStr,
Pass: true,
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
prs, _, err := c.Client.PullRequests.List(c.Ctx, c.Owner, c.Repo, &github.PullRequestListOptions{
State: "closed",
})
if err != nil {
return checker.InconclusiveResult
return checker.MakeInconclusiveResult(codeReviewStr)
}
totalMerged := 0
@ -142,16 +145,16 @@ func ProwCodeReview(c checker.Checker) checker.CheckResult {
}
if totalReviewed == 0 {
return checker.InconclusiveResult
return checker.MakeInconclusiveResult(codeReviewStr)
}
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{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(codeReviewStr, err)
}
total := 0
@ -182,8 +185,8 @@ func CommitMessageHints(c checker.Checker) checker.CheckResult {
}
if totalReviewed == 0 {
return checker.InconclusiveResult
return checker.MakeInconclusiveResult(codeReviewStr)
}
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"
)
const (
minContributionsPerUser = 5
minOrganizationCount = 2
contributorsStr = "Contributors"
)
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{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(contributorsStr, err)
}
companies := map[string]struct{}{}
for _, contrib := range contribs {
const contributorsCount = 5
//nolint:nestif
if contrib.GetContributions() >= contributorsCount {
if contrib.GetContributions() >= minContributionsPerUser {
u, _, err := c.Client.Users.Get(c.Ctx, contrib.GetLogin())
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(contributorsStr, err)
}
orgs, _, err := c.Client.Organizations.List(c.Ctx, contrib.GetLogin(), nil)
if err != nil {
@ -65,16 +70,16 @@ func Contributors(c checker.Checker) checker.CheckResult {
names = append(names, c)
}
c.Logf("companies found: %v", strings.Join(names, ","))
const numContributors = 2
const confidence = 10
if len(companies) >= numContributors {
if len(companies) >= minOrganizationCount {
return checker.CheckResult{
Name: contributorsStr,
Pass: true,
Confidence: confidence,
Confidence: checker.MaxResultConfidence,
}
}
return checker.CheckResult{
Name: contributorsStr,
Pass: false,
Confidence: confidence,
Confidence: checker.MaxResultConfidence,
}
}

View File

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

View File

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

View File

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

View File

@ -21,14 +21,16 @@ import (
"github.com/ossf/scorecard/checker"
)
const pullRequestsStr = "Pull-Requests"
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{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(pullRequestsStr, err)
}
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{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(pullRequestsStr, err)
}
if len(prs) > 0 {
totalWithPrs++
@ -69,5 +71,5 @@ func PullRequests(c checker.Checker) checker.CheckResult {
}
}
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"
)
const sastStr = "SAST"
var sastTools map[string]bool = map[string]bool{"github-code-scanning": true, "sonarcloud": true}
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(
CodeQLInCheckDefinitions,
SASTToolInCheckRuns,
)(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{
State: "closed",
})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(sastStr, err)
}
totalMerged := 0
@ -49,10 +51,10 @@ func SASTToolInCheckRuns(c checker.Checker) checker.CheckResult {
totalMerged++
crs, _, err := c.Client.Checks.ListCheckRunsForRef(c.Ctx, c.Owner, c.Repo, pr.GetHead().GetSHA(), &github.ListCheckRunsOptions{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(sastStr, err)
}
if crs == nil {
return checker.InconclusiveResult
return checker.MakeInconclusiveResult(sastStr)
}
for _, cr := range crs.CheckRuns {
if cr.GetStatus() != "completed" {
@ -69,25 +71,25 @@ func SASTToolInCheckRuns(c checker.Checker) checker.CheckResult {
}
}
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)
results, _, err := c.Client.Search.Code(c.Ctx, searchQuery, &github.SearchOptions{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(sastStr, err)
}
for _, result := range results.CodeResults {
c.Logf("found CodeQL definition: %s", result.GetPath())
}
const confidence = 10
return checker.CheckResult{
Name: sastStr,
Pass: *results.Total > 0,
Confidence: confidence,
Confidence: checker.MaxResultConfidence,
}
}

View File

@ -20,13 +20,15 @@ import (
"github.com/ossf/scorecard/checker"
)
const securityPolicyStr = "Security-Policy"
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
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") {
logf("security policy : %s", name)
return true
@ -43,7 +45,7 @@ func SecurityPolicy(c checker.Checker) checker.CheckResult {
dotGitHub := c
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") {
logf("security policy within .github folder : %s", name)
return true

View File

@ -21,16 +21,19 @@ import (
"github.com/ossf/scorecard/checker"
)
var releaseLookBack int = 5
const (
signedReleasesStr = "Signed-Releases"
releaseLookBackDays = 5
)
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{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(signedReleasesStr, err)
}
artifactExtensions := []string{".asc", ".minisig", ".sig"}
@ -40,7 +43,7 @@ func SignedReleases(c checker.Checker) checker.CheckResult {
for _, r := range releases {
assets, _, err := c.Client.Repositories.ListReleaseAssets(c.Ctx, c.Owner, c.Repo, r.GetID(), &github.ListOptions{})
if err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(signedReleasesStr, err)
}
if len(assets) == 0 {
continue
@ -64,16 +67,16 @@ func SignedReleases(c checker.Checker) checker.CheckResult {
if !signed {
c.Logf("!! release %s has no signed artifacts", r.GetTagName())
}
if totalReleases > releaseLookBack {
if totalReleases > releaseLookBackDays {
break
}
}
if totalReleases == 0 {
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)
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"
)
var tagLookBack int = 5
const (
signedTagsStr = "Signed-Tags"
tagLookBack = 5
)
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 {
Name githubv4.String
Target struct {
@ -47,7 +50,7 @@ func SignedTags(c checker.Checker) checker.CheckResult {
}
if err := c.GraphClient.Query(c.Ctx, &query, variables); err != nil {
return checker.RetryResult(err)
return checker.MakeRetryResult(signedTagsStr, err)
}
totalTags := 0
totalSigned := 0
@ -69,9 +72,9 @@ func SignedTags(c checker.Checker) checker.CheckResult {
if totalTags == 0 {
c.Logf("no tags found")
return checker.InconclusiveResult
return checker.MakeInconclusiveResult(signedTagsStr)
}
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
sugar := logger.Sugar()
var outputFn func([]pkg.Result)
var outputFn func([]checker.CheckResult)
switch format {
case formatCSV:
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 {
checkNames := map[string]struct{}{}
for _, s := range checksToRun {
checkNames[s] = struct{}{}
}
for _, c := range checks.AllChecks {
if _, ok := checkNames[c.Name]; ok {
enabledChecks = append(enabledChecks, c)
for _, checkToRun := range checksToRun {
if checkFn, ok := checks.AllChecks[checkToRun]; ok {
enabledChecks[checkToRun] = checkFn
}
}
} else {
enabledChecks = checks.AllChecks
}
for _, c := range enabledChecks {
for checkName := range enabledChecks {
if format == formatDefault {
fmt.Fprintf(os.Stderr, "Starting [%s]\n", c.Name)
fmt.Fprintf(os.Stderr, "Starting [%s]\n", checkName)
}
}
ctx := context.Background()
resultsCh := pkg.RunScorecards(ctx, sugar, repo, enabledChecks)
// Collect results
results := []pkg.Result{}
results := []checker.CheckResult{}
for result := range resultsCh {
if format == formatDefault {
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 {
Objects []struct {
Package struct {
@ -182,11 +171,11 @@ type rubyGemsSearchResults struct {
type record struct {
Repo string
Date string
Checks []checkResult
Checks []checker.CheckResult
MetaData []string
}
func outputJSON(results []pkg.Result) {
func outputJSON(results []checker.CheckResult) {
d := time.Now()
or := record{
Repo: repo.String(),
@ -195,16 +184,15 @@ func outputJSON(results []pkg.Result) {
}
for _, r := range results {
var details []string
if showDetails {
details = r.Cr.Details
tmpResult := checker.CheckResult{
Name: r.Name,
Pass: r.Pass,
Confidence: r.Confidence,
}
or.Checks = append(or.Checks, checkResult{
CheckName: r.Name,
Pass: r.Cr.Pass,
Confidence: r.Cr.Confidence,
Details: details,
})
if showDetails {
tmpResult.Details = r.Details
}
or.Checks = append(or.Checks, tmpResult)
}
output, err := json.Marshal(or)
if err != nil {
@ -213,13 +201,13 @@ func outputJSON(results []pkg.Result) {
fmt.Println(string(output))
}
func outputCSV(results []pkg.Result) {
func outputCSV(results []checker.CheckResult) {
w := csv.NewWriter(os.Stdout)
record := []string{repo.String()}
columns := []string{"Repository"}
for _, r := range results {
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.Fprintf(os.Stderr, "%s\n", strings.Join(columns, ","))
@ -229,14 +217,14 @@ func outputCSV(results []pkg.Result) {
w.Flush()
}
func outputDefault(results []pkg.Result) {
func outputDefault(results []checker.CheckResult) {
fmt.Println()
fmt.Println("RESULTS")
fmt.Println("-------")
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 {
for _, d := range r.Cr.Details {
for _, d := range r.Details {
fmt.Println(" " + d)
}
}
@ -352,8 +340,8 @@ func init() {
rootCmd.Flags().BoolVar(&showDetails, "show-details", false, "show extra details about each check")
checkNames := []string{}
for _, c := range checks.AllChecks {
checkNames = append(checkNames, c.Name)
for checkName := range checks.AllChecks {
checkNames = append(checkNames, checkName)
}
rootCmd.Flags().StringSliceVar(&checksToRun, "checks", []string{},
fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ",")))

View File

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

BIN
cron/cron Executable file

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

3
go.mod
View File

@ -17,6 +17,7 @@ require (
go.uber.org/zap v1.16.0
gocloud.dev v0.22.0
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
)

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-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-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-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/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=
@ -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-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-20210101214203-2dba1e4ea05c h1:dS09fXwOFF9cXBnIzZexIuUBj95U1NyQjkEhkgidDow=
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
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-20191011141410-1b5146add898/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"
)
type Result struct {
Cr checker.CheckResult
Name string
MetaData []string
}
type RepoURL struct {
Host, Owner, Repo string
}
@ -80,11 +74,11 @@ func (r *RepoURL) Set(s string) error {
}
func RunScorecards(ctx context.Context, logger *zap.SugaredLogger,
repo RepoURL, checksToRun []checker.NamedCheck) <-chan Result {
resultsCh := make(chan Result)
repo RepoURL, checksToRun checker.CheckNameToFnMap) <-chan checker.CheckResult {
resultsCh := make(chan checker.CheckResult)
wg := sync.WaitGroup{}
for _, check := range checksToRun {
check := check
for _, checkFn := range checksToRun {
checkFn := checkFn
wg.Add(1)
go func() {
// Use our custom roundtripper
@ -96,7 +90,7 @@ func RunScorecards(ctx context.Context, logger *zap.SugaredLogger,
ghClient := github.NewClient(client)
graphClient := githubv4.NewClient(client)
c := checker.Checker{
c := checker.CheckRequest{
Ctx: ctx,
Client: ghClient,
HttpClient: client,
@ -105,12 +99,8 @@ func RunScorecards(ctx context.Context, logger *zap.SugaredLogger,
GraphClient: graphClient,
}
defer wg.Done()
runner := checker.Runner{Checker: c}
r := runner.Run(check.Fn)
resultsCh <- Result{
Name: check.Name,
Cr: r,
}
runner := checker.Runner{CheckRequest: c}
resultsCh <- runner.Run(checkFn)
}()
}
go func() {