mirror of
https://github.com/ossf/scorecard.git
synced 2024-09-11 08:55:27 +03:00
Add CIIClient interface (#1262)
Co-authored-by: Azeem Shaikh <azeems@google.com>
This commit is contained in:
parent
d4904555b4
commit
6223b6620a
16
Makefile
16
Makefile
@ -109,14 +109,16 @@ cron/data/metadata.pb.go: cron/data/metadata.proto | $(PROTOC)
|
||||
protoc --go_out=../../../ cron/data/metadata.proto
|
||||
|
||||
generate-mocks: ## Compiles and generates all mocks using mockgen.
|
||||
generate-mocks: clients/mockrepo/client.go clients/mockrepo/repo.go
|
||||
clients/mockrepo/client.go: clients/repo_client.go
|
||||
generate-mocks: clients/mockclients/repo_client.go clients/mockclients/repo.go clients/mockclients/cii_client.go
|
||||
clients/mockclients/repo_client.go: clients/repo_client.go
|
||||
# Generating MockRepoClient
|
||||
$(MOCKGEN) -source=clients/repo_client.go -destination clients/mockrepo/client.go -package mockrepo -copyright_file clients/mockrepo/license.txt
|
||||
clients/mockrepo/repo.go: clients/repo.go
|
||||
# Generating MockRepoClient
|
||||
$(MOCKGEN) -source=clients/repo.go -destination clients/mockrepo/repo.go -package mockrepo -copyright_file clients/mockrepo/license.txt
|
||||
|
||||
$(MOCKGEN) -source=clients/repo_client.go -destination=clients/mockclients/repo_client.go -package=mockrepo -copyright_file=clients/mockclients/license.txt
|
||||
clients/mockclients/repo.go: clients/repo.go
|
||||
# Generating MockRepo
|
||||
$(MOCKGEN) -source=clients/repo.go -destination=clients/mockclients/repo.go -package=mockrepo -copyright_file=clients/mockclients/license.txt
|
||||
clients/mockclients/cii_client.go: clients/cii_client.go
|
||||
# Generating MockCIIClient
|
||||
$(MOCKGEN) -source=clients/cii_client.go -destination=clients/mockclients/cii_client.go -package=mockrepo -copyright_file=clients/mockclients/license.txt
|
||||
|
||||
generate-docs: ## Generates docs
|
||||
generate-docs: validate-docs docs/checks.md
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
type CheckRequest struct {
|
||||
Ctx context.Context
|
||||
RepoClient clients.RepoClient
|
||||
CIIClient clients.CIIBestPracticesClient
|
||||
Dlogger DetailLogger
|
||||
Repo clients.Repo
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
|
||||
"github.com/ossf/scorecard/v3/checker"
|
||||
"github.com/ossf/scorecard/v3/clients"
|
||||
"github.com/ossf/scorecard/v3/clients/mockrepo"
|
||||
mockrepo "github.com/ossf/scorecard/v3/clients/mockclients"
|
||||
sce "github.com/ossf/scorecard/v3/errors"
|
||||
scut "github.com/ossf/scorecard/v3/utests"
|
||||
)
|
||||
|
@ -15,111 +15,47 @@
|
||||
package checks
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ossf/scorecard/v3/checker"
|
||||
"github.com/ossf/scorecard/v3/clients"
|
||||
sce "github.com/ossf/scorecard/v3/errors"
|
||||
)
|
||||
|
||||
// CheckCIIBestPractices is the registered name for CIIBestPractices.
|
||||
const CheckCIIBestPractices = "CII-Best-Practices"
|
||||
|
||||
var errTooManyRequests = errors.New("failed after exponential backoff")
|
||||
const (
|
||||
// CheckCIIBestPractices is the registered name for CIIBestPractices.
|
||||
CheckCIIBestPractices = "CII-Best-Practices"
|
||||
silverScore = 7
|
||||
passingScore = 5
|
||||
inProgressScore = 2
|
||||
)
|
||||
|
||||
//nolint:gochecknoinits
|
||||
func init() {
|
||||
registerCheck(CheckCIIBestPractices, CIIBestPractices)
|
||||
}
|
||||
|
||||
type expBackoffTransport struct {
|
||||
numRetries uint8
|
||||
}
|
||||
|
||||
func (transport *expBackoffTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
for i := 0; i < int(transport.numRetries); i++ {
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil || resp.StatusCode != http.StatusTooManyRequests {
|
||||
// nolint: wrapcheck
|
||||
return resp, err
|
||||
}
|
||||
time.Sleep(time.Duration(math.Pow(2, float64(i))) * time.Second)
|
||||
}
|
||||
return nil, errTooManyRequests
|
||||
}
|
||||
|
||||
type response struct {
|
||||
BadgeLevel string `json:"badge_level"`
|
||||
}
|
||||
|
||||
// CIIBestPractices runs CII-Best-Practices check.
|
||||
func CIIBestPractices(c *checker.CheckRequest) checker.CheckResult {
|
||||
// TODO: not supported for local clients.
|
||||
repoURI := fmt.Sprintf("https://%s", c.Repo.URI())
|
||||
url := fmt.Sprintf("https://bestpractices.coreinfrastructure.org/projects.json?url=%s", repoURI)
|
||||
req, err := http.NewRequestWithContext(c.Ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("http.NewRequestWithContext: %v", err))
|
||||
return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e)
|
||||
}
|
||||
|
||||
httpClient := http.Client{
|
||||
Transport: &expBackoffTransport{
|
||||
numRetries: 3,
|
||||
},
|
||||
}
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("http.NewRequestWithContext: %v", err))
|
||||
return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("io.ReadAll: %v", err))
|
||||
return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e)
|
||||
}
|
||||
|
||||
parsedResponse := []response{}
|
||||
if err := json.Unmarshal(b, &parsedResponse); err != nil {
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal,
|
||||
fmt.Sprintf("json.Unmarshal on %s - %s: %v", resp.Status, parsedResponse, err))
|
||||
return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e)
|
||||
}
|
||||
|
||||
if len(parsedResponse) < 1 {
|
||||
return checker.CreateMinScoreResult(CheckCIIBestPractices, "no badge found")
|
||||
}
|
||||
|
||||
result := parsedResponse[0]
|
||||
|
||||
if result.BadgeLevel != "" {
|
||||
// Three levels: passing, silver and gold,
|
||||
// https://bestpractices.coreinfrastructure.org/en/criteria.
|
||||
const silverScore = 7
|
||||
const passingScore = 5
|
||||
const inProgressScore = 2
|
||||
switch {
|
||||
default:
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("unsupported badge: %v", result.BadgeLevel))
|
||||
return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e)
|
||||
case strings.Contains(result.BadgeLevel, "in_progress"):
|
||||
badgeLevel, err := c.CIIClient.GetBadgeLevel(c.Ctx, c.Repo.URI())
|
||||
if err == nil {
|
||||
switch badgeLevel {
|
||||
case clients.NotFound:
|
||||
return checker.CreateMinScoreResult(CheckCIIBestPractices, "no badge detected")
|
||||
case clients.InProgress:
|
||||
return checker.CreateResultWithScore(CheckCIIBestPractices, "badge detected: in_progress", inProgressScore)
|
||||
case strings.Contains(result.BadgeLevel, "silver"):
|
||||
return checker.CreateResultWithScore(CheckCIIBestPractices, "badge detected: silver", silverScore)
|
||||
case strings.Contains(result.BadgeLevel, "gold"):
|
||||
return checker.CreateMaxScoreResult(CheckCIIBestPractices, "badge detected: gold")
|
||||
case strings.Contains(result.BadgeLevel, "passing"):
|
||||
case clients.Passing:
|
||||
return checker.CreateResultWithScore(CheckCIIBestPractices, "badge detected: passing", passingScore)
|
||||
case clients.Silver:
|
||||
return checker.CreateResultWithScore(CheckCIIBestPractices, "badge detected: silver", silverScore)
|
||||
case clients.Gold:
|
||||
return checker.CreateMaxScoreResult(CheckCIIBestPractices, "badge detected: gold")
|
||||
case clients.Unknown:
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("unsupported badge: %v", badgeLevel))
|
||||
return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e)
|
||||
}
|
||||
}
|
||||
|
||||
return checker.CreateMinScoreResult(CheckCIIBestPractices, "no badge detected")
|
||||
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
|
||||
return checker.CreateRuntimeErrorResult(CheckCIIBestPractices, e)
|
||||
}
|
||||
|
131
checks/cii_best_practices_test.go
Normal file
131
checks/cii_best_practices_test.go
Normal file
@ -0,0 +1,131 @@
|
||||
// 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 checks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/ossf/scorecard/v3/checker"
|
||||
"github.com/ossf/scorecard/v3/clients"
|
||||
mockrepo "github.com/ossf/scorecard/v3/clients/mockclients"
|
||||
sce "github.com/ossf/scorecard/v3/errors"
|
||||
scut "github.com/ossf/scorecard/v3/utests"
|
||||
)
|
||||
|
||||
var errTest = errors.New("test error")
|
||||
|
||||
func TestCIIBestPractices(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
err error
|
||||
name string
|
||||
uri string
|
||||
expected scut.TestReturn
|
||||
badgeLevel clients.BadgeLevel
|
||||
}{
|
||||
{
|
||||
name: "CheckURIUsed",
|
||||
uri: "github.com/owner/repo",
|
||||
badgeLevel: clients.NotFound,
|
||||
expected: scut.TestReturn{
|
||||
Score: checker.MinResultScore,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CheckErrorHandling",
|
||||
err: errTest,
|
||||
expected: scut.TestReturn{
|
||||
Score: -1,
|
||||
Error: sce.ErrScorecardInternal,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NotFoundBadge",
|
||||
badgeLevel: clients.NotFound,
|
||||
expected: scut.TestReturn{
|
||||
Score: checker.MinResultScore,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "InProgressBadge",
|
||||
badgeLevel: clients.InProgress,
|
||||
expected: scut.TestReturn{
|
||||
Score: inProgressScore,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PassingBadge",
|
||||
badgeLevel: clients.Passing,
|
||||
expected: scut.TestReturn{
|
||||
Score: passingScore,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SilverBadge",
|
||||
badgeLevel: clients.Silver,
|
||||
expected: scut.TestReturn{
|
||||
Score: silverScore,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GoldBadge",
|
||||
badgeLevel: clients.Gold,
|
||||
expected: scut.TestReturn{
|
||||
Score: checker.MaxResultScore,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "UnknownBadge",
|
||||
badgeLevel: clients.Unknown,
|
||||
expected: scut.TestReturn{
|
||||
Score: -1,
|
||||
Error: sce.ErrScorecardInternal,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt // Re-initializing variable so it is not changed while executing the closure below
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
mockRepo := mockrepo.NewMockRepo(ctrl)
|
||||
mockRepo.EXPECT().URI().Return(tt.uri).AnyTimes()
|
||||
|
||||
mockCIIClient := mockrepo.NewMockCIIBestPracticesClient(ctrl)
|
||||
mockCIIClient.EXPECT().GetBadgeLevel(gomock.Any(), tt.uri).DoAndReturn(
|
||||
func(context.Context, string) (clients.BadgeLevel, error) {
|
||||
return tt.badgeLevel, tt.err
|
||||
}).MinTimes(1)
|
||||
|
||||
req := checker.CheckRequest{
|
||||
Repo: mockRepo,
|
||||
CIIClient: mockCIIClient,
|
||||
}
|
||||
res := CIIBestPractices(&req)
|
||||
dl := scut.TestDetailLogger{}
|
||||
if !scut.ValidateTestReturn(t, tt.name, &tt.expected, &res, &dl) {
|
||||
t.Fail()
|
||||
}
|
||||
ctrl.Finish()
|
||||
})
|
||||
}
|
||||
}
|
48
clients/cii_client.go
Normal file
48
clients/cii_client.go
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2021 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 clients
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// BadgeLevel corresponds to CII-Best-Practices badge levels.
|
||||
// https://bestpractices.coreinfrastructure.org/en
|
||||
type BadgeLevel uint
|
||||
|
||||
const (
|
||||
// Unknown or non-parsable CII Best Practices badge.
|
||||
Unknown BadgeLevel = iota
|
||||
// NotFound represents when CII Best Practices returns an empty response for a project.
|
||||
NotFound
|
||||
// InProgress state of CII Best Practices badge.
|
||||
InProgress
|
||||
// Passing level for CII Best Practices badge.
|
||||
Passing
|
||||
// Silver level for CII Best Practices badge.
|
||||
Silver
|
||||
// Gold level for CII Best Practices badge.
|
||||
Gold
|
||||
)
|
||||
|
||||
// CIIBestPracticesClient interface returns the BadgeLevel for a repo URL.
|
||||
type CIIBestPracticesClient interface {
|
||||
GetBadgeLevel(ctx context.Context, uri string) (BadgeLevel, error)
|
||||
}
|
||||
|
||||
// DefaultCIIBestPracticesClient returns HTTPClientCIIBestPractices implementation of the interface.
|
||||
func DefaultCIIBestPracticesClient() CIIBestPracticesClient {
|
||||
return &HTTPClientCIIBestPractices{}
|
||||
}
|
112
clients/cii_http_client.go
Normal file
112
clients/cii_http_client.go
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2021 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 clients
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
inProgressResp = "in_progress"
|
||||
passingResp = "passing"
|
||||
silverResp = "silver"
|
||||
goldResp = "gold"
|
||||
)
|
||||
|
||||
var (
|
||||
errTooManyRequests = errors.New("failed after exponential backoff")
|
||||
errUnsupportedBadge = errors.New("unsupported badge")
|
||||
)
|
||||
|
||||
// HTTPClientCIIBestPractices implements the CIIBestPracticesClient interface.
|
||||
// A HTTP client with exponential backoff is used to communicate with the CII Best Practices servers.
|
||||
type HTTPClientCIIBestPractices struct{}
|
||||
|
||||
type response struct {
|
||||
BadgeLevel string `json:"badge_level"`
|
||||
}
|
||||
|
||||
type expBackoffTransport struct {
|
||||
numRetries uint8
|
||||
}
|
||||
|
||||
func (transport *expBackoffTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
for i := 0; i < int(transport.numRetries); i++ {
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil || resp.StatusCode != http.StatusTooManyRequests {
|
||||
// nolint: wrapcheck
|
||||
return resp, err
|
||||
}
|
||||
time.Sleep(time.Duration(math.Pow(2, float64(i))) * time.Second)
|
||||
}
|
||||
return nil, errTooManyRequests
|
||||
}
|
||||
|
||||
// GetBadgeLevel implements CIIBestPracticesClient.GetBadgeLevel.
|
||||
func (client *HTTPClientCIIBestPractices) GetBadgeLevel(ctx context.Context, uri string) (BadgeLevel, error) {
|
||||
repoURI := fmt.Sprintf("https://%s", uri)
|
||||
url := fmt.Sprintf("https://bestpractices.coreinfrastructure.org/projects.json?url=%s", repoURI)
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
return Unknown, fmt.Errorf("error during http.NewRequestWithContext: %w", err)
|
||||
}
|
||||
|
||||
httpClient := http.Client{
|
||||
Transport: &expBackoffTransport{
|
||||
numRetries: 3,
|
||||
},
|
||||
}
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return Unknown, fmt.Errorf("error during http.Do: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return Unknown, fmt.Errorf("error during io.ReadAll: %w", err)
|
||||
}
|
||||
|
||||
parsedResponse := []response{}
|
||||
if err := json.Unmarshal(b, &parsedResponse); err != nil {
|
||||
return Unknown, fmt.Errorf("error during json.Unmarshal: %w", err)
|
||||
}
|
||||
|
||||
if len(parsedResponse) < 1 {
|
||||
return NotFound, nil
|
||||
}
|
||||
badgeLevel := parsedResponse[0].BadgeLevel
|
||||
if strings.Contains(badgeLevel, inProgressResp) {
|
||||
return InProgress, nil
|
||||
}
|
||||
if strings.Contains(badgeLevel, passingResp) {
|
||||
return Passing, nil
|
||||
}
|
||||
if strings.Contains(badgeLevel, silverResp) {
|
||||
return Silver, nil
|
||||
}
|
||||
if strings.Contains(badgeLevel, goldResp) {
|
||||
return Gold, nil
|
||||
}
|
||||
return Unknown, fmt.Errorf("%w: %s", errUnsupportedBadge, badgeLevel)
|
||||
}
|
66
clients/mockclients/cii_client.go
Normal file
66
clients/mockclients/cii_client.go
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2021 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.
|
||||
//
|
||||
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: clients/cii_client.go
|
||||
|
||||
// Package mockrepo is a generated GoMock package.
|
||||
package mockrepo
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
clients "github.com/ossf/scorecard/v3/clients"
|
||||
)
|
||||
|
||||
// MockCIIBestPracticesClient is a mock of CIIBestPracticesClient interface.
|
||||
type MockCIIBestPracticesClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCIIBestPracticesClientMockRecorder
|
||||
}
|
||||
|
||||
// MockCIIBestPracticesClientMockRecorder is the mock recorder for MockCIIBestPracticesClient.
|
||||
type MockCIIBestPracticesClientMockRecorder struct {
|
||||
mock *MockCIIBestPracticesClient
|
||||
}
|
||||
|
||||
// NewMockCIIBestPracticesClient creates a new mock instance.
|
||||
func NewMockCIIBestPracticesClient(ctrl *gomock.Controller) *MockCIIBestPracticesClient {
|
||||
mock := &MockCIIBestPracticesClient{ctrl: ctrl}
|
||||
mock.recorder = &MockCIIBestPracticesClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockCIIBestPracticesClient) EXPECT() *MockCIIBestPracticesClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetBadgeLevel mocks base method.
|
||||
func (m *MockCIIBestPracticesClient) GetBadgeLevel(ctx context.Context, uri string) (clients.BadgeLevel, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetBadgeLevel", ctx, uri)
|
||||
ret0, _ := ret[0].(clients.BadgeLevel)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetBadgeLevel indicates an expected call of GetBadgeLevel.
|
||||
func (mr *MockCIIBestPracticesClientMockRecorder) GetBadgeLevel(ctx, uri interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBadgeLevel", reflect.TypeOf((*MockCIIBestPracticesClient)(nil).GetBadgeLevel), ctx, uri)
|
||||
}
|
@ -121,7 +121,7 @@ func (mr *MockRepoMockRecorder) String() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockRepo)(nil).String))
|
||||
}
|
||||
|
||||
// URL mocks base method.
|
||||
// URI mocks base method.
|
||||
func (m *MockRepo) URI() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "URI")
|
@ -305,6 +305,8 @@ var rootCmd = &cobra.Command{
|
||||
}
|
||||
defer repoClient.Close()
|
||||
|
||||
ciiClient := clients.DefaultCIIBestPracticesClient()
|
||||
|
||||
// Read docs.
|
||||
checkDocs, err := docs.Read()
|
||||
if err != nil {
|
||||
@ -326,7 +328,7 @@ var rootCmd = &cobra.Command{
|
||||
fmt.Fprintf(os.Stderr, "Starting [%s]\n", checkName)
|
||||
}
|
||||
}
|
||||
repoResult, err := pkg.RunScorecards(ctx, repoURI, enabledChecks, repoClient)
|
||||
repoResult, err := pkg.RunScorecards(ctx, repoURI, enabledChecks, repoClient, ciiClient)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/ossf/scorecard/v3/checks"
|
||||
"github.com/ossf/scorecard/v3/clients"
|
||||
"github.com/ossf/scorecard/v3/clients/githubrepo"
|
||||
"github.com/ossf/scorecard/v3/pkg"
|
||||
)
|
||||
@ -64,7 +65,8 @@ var serveCmd = &cobra.Command{
|
||||
}
|
||||
ctx := r.Context()
|
||||
repoClient := githubrepo.CreateGithubRepoClient(ctx, logger)
|
||||
repoResult, err := pkg.RunScorecards(ctx, repo, checks.AllChecks, repoClient)
|
||||
ciiClient := clients.DefaultCIIBestPracticesClient()
|
||||
repoResult, err := pkg.RunScorecards(ctx, repo, checks.AllChecks, repoClient, ciiClient)
|
||||
if err != nil {
|
||||
sugar.Error(err)
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
|
@ -51,7 +51,7 @@ var ignoreRuntimeErrors = flag.Bool("ignoreRuntimeErrors", false, "if set to tru
|
||||
func processRequest(ctx context.Context,
|
||||
batchRequest *data.ScorecardBatchRequest, checksToRun checker.CheckNameToFnMap,
|
||||
bucketURL, bucketURL2 string, checkDocs docs.Doc,
|
||||
repoClient clients.RepoClient, logger *zap.Logger) error {
|
||||
repoClient clients.RepoClient, ciiClient clients.CIIBestPracticesClient, logger *zap.Logger) error {
|
||||
filename := data.GetBlobFilename(
|
||||
fmt.Sprintf("shard-%07d", batchRequest.GetShardNum()),
|
||||
batchRequest.GetJobTime().AsTime())
|
||||
@ -82,7 +82,7 @@ func processRequest(ctx context.Context,
|
||||
continue
|
||||
}
|
||||
repo.AppendMetadata(repo.Metadata()...)
|
||||
result, err := pkg.RunScorecards(ctx, repo, checksToRun, repoClient)
|
||||
result, err := pkg.RunScorecards(ctx, repo, checksToRun, repoClient, ciiClient)
|
||||
if errors.Is(err, sce.ErrRepoUnreachable) {
|
||||
// Not accessible repo - continue.
|
||||
continue
|
||||
@ -177,6 +177,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
repoClient := githubrepo.CreateGithubRepoClient(ctx, logger)
|
||||
ciiClient := clients.DefaultCIIBestPracticesClient()
|
||||
|
||||
exporter, err := startMetricsExporter()
|
||||
if err != nil {
|
||||
@ -207,7 +208,7 @@ func main() {
|
||||
}
|
||||
if err := processRequest(ctx, req, checksToRun,
|
||||
bucketURL, bucketURL2, checkDocs,
|
||||
repoClient, logger); err != nil {
|
||||
repoClient, ciiClient, logger); err != nil {
|
||||
logger.Warn(fmt.Sprintf("error processing request: %v", err))
|
||||
// Nack the message so that another worker can retry.
|
||||
subscriber.Nack()
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/ossf/scorecard/v3/checker"
|
||||
"github.com/ossf/scorecard/v3/checks"
|
||||
"github.com/ossf/scorecard/v3/clients"
|
||||
"github.com/ossf/scorecard/v3/clients/githubrepo"
|
||||
scut "github.com/ossf/scorecard/v3/utests"
|
||||
)
|
||||
@ -32,10 +33,12 @@ var _ = Describe("E2E TEST:CIIBestPractices", func() {
|
||||
dl := scut.TestDetailLogger{}
|
||||
repo, err := githubrepo.MakeGithubRepo("tensorflow/tensorflow")
|
||||
Expect(err).Should(BeNil())
|
||||
ciiClient := clients.DefaultCIIBestPracticesClient()
|
||||
|
||||
req := checker.CheckRequest{
|
||||
Ctx: context.Background(),
|
||||
RepoClient: nil,
|
||||
CIIClient: ciiClient,
|
||||
Repo: repo,
|
||||
Dlogger: &dl,
|
||||
}
|
||||
|
@ -28,11 +28,13 @@ import (
|
||||
)
|
||||
|
||||
func runEnabledChecks(ctx context.Context,
|
||||
repo clients.Repo, checksToRun checker.CheckNameToFnMap, repoClient clients.RepoClient,
|
||||
repo clients.Repo, checksToRun checker.CheckNameToFnMap,
|
||||
repoClient clients.RepoClient, ciiClient clients.CIIBestPracticesClient,
|
||||
resultsCh chan checker.CheckResult) {
|
||||
request := checker.CheckRequest{
|
||||
Ctx: ctx,
|
||||
RepoClient: repoClient,
|
||||
CIIClient: ciiClient,
|
||||
Repo: repo,
|
||||
}
|
||||
wg := sync.WaitGroup{}
|
||||
@ -71,7 +73,7 @@ func getRepoCommitHash(r clients.RepoClient) (string, error) {
|
||||
func RunScorecards(ctx context.Context,
|
||||
repo clients.Repo,
|
||||
checksToRun checker.CheckNameToFnMap,
|
||||
repoClient clients.RepoClient) (ScorecardResult, error) {
|
||||
repoClient clients.RepoClient, ciiClient clients.CIIBestPracticesClient) (ScorecardResult, error) {
|
||||
if err := repoClient.InitRepo(repo); err != nil {
|
||||
// No need to call sce.WithMessage() since InitRepo will do that for us.
|
||||
//nolint:wrapcheck
|
||||
@ -96,7 +98,7 @@ func RunScorecards(ctx context.Context,
|
||||
Date: time.Now(),
|
||||
}
|
||||
resultsCh := make(chan checker.CheckResult)
|
||||
go runEnabledChecks(ctx, repo, checksToRun, repoClient, resultsCh)
|
||||
go runEnabledChecks(ctx, repo, checksToRun, repoClient, ciiClient, resultsCh)
|
||||
for result := range resultsCh {
|
||||
ret.Checks = append(ret.Checks, result)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user