Cleanup errors and log (#782)

* cleanup

* text

* add errors

* fixes

* more

* fixes

* linnter

* comments

* name
This commit is contained in:
laurentsimon 2021-08-02 15:38:42 -07:00 committed by GitHub
parent 9b2f3f5270
commit 6718939a08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 157 additions and 215 deletions

View File

@ -31,8 +31,6 @@ type CheckRequest struct {
GraphClient *githubv4.Client
HTTPClient *http.Client
RepoClient clients.RepoClient
// UPGRADEv2: Logf will be removed.
Logf func(s string, f ...interface{})
Dlogger DetailLogger
Owner, Repo string
}

View File

@ -16,7 +16,6 @@
package checker
import (
"errors"
"fmt"
"math"
)
@ -31,11 +30,7 @@ const (
// UPGRADEv2: to remove.
const migrationThresholdPassValue = 8
// ErrorDemoninatorZero indicates the denominator for a proportional result is 0.
// UPGRADEv2: to remove.
var ErrorDemoninatorZero = errors.New("internal error: denominator is 0")
// DetailType defines types of details.
// DetailType is the type of details.
type DetailType int
const (
@ -72,12 +67,11 @@ const (
// nolint
type CheckResult struct {
// Old structure
Error error `json:"-"`
Name string
Details []string
Confidence int
Pass bool
ShouldRetry bool `json:"-"`
Error error `json:"-"`
Name string
Details []string
Confidence int
Pass bool
// UPGRADEv2: New structure. Omitting unchanged Name field
// for simplicity.
@ -137,10 +131,9 @@ func CreateResultWithScore(name, reason string, score int) CheckResult {
return CheckResult{
Name: name,
// Old structure.
Error: nil,
Confidence: MaxResultScore,
Pass: pass,
ShouldRetry: false,
Error: nil,
Confidence: MaxResultScore,
Pass: pass,
// New structure.
//nolint
Version: 2,
@ -164,10 +157,9 @@ func CreateProportionalScoreResult(name, reason string, b, t int) CheckResult {
return CheckResult{
Name: name,
// Old structure.
Error: nil,
Confidence: MaxResultConfidence,
Pass: pass,
ShouldRetry: false,
Error: nil,
Confidence: MaxResultConfidence,
Pass: pass,
// New structure.
//nolint
Version: 2,
@ -198,9 +190,8 @@ func CreateInconclusiveResult(name, reason string) CheckResult {
return CheckResult{
Name: name,
// Old structure.
Confidence: 0,
Pass: false,
ShouldRetry: false,
Confidence: 0,
Pass: false,
// New structure.
//nolint
Version: 2,
@ -214,10 +205,9 @@ func CreateRuntimeErrorResult(name string, e error) CheckResult {
return CheckResult{
Name: name,
// Old structure.
Error: e,
Confidence: 0,
Pass: false,
ShouldRetry: false,
Error: e,
Confidence: 0,
Pass: false,
// New structure.
//nolint
Version: 2,

View File

@ -16,14 +16,14 @@ package checker
import (
"context"
"errors"
"fmt"
"strings"
"time"
opencensusstats "go.opencensus.io/stats"
"go.opencensus.io/tag"
scorecarderrors "github.com/ossf/scorecard/v2/errors"
sce "github.com/ossf/scorecard/v2/errors"
"github.com/ossf/scorecard/v2/stats"
)
@ -45,7 +45,6 @@ type CheckNameToFnMap map[string]CheckFn
// UPGRADEv2: messages2 will ultimately
// be renamed to messages.
type logger struct {
messages []string
messages2 []CheckDetail
}
@ -64,19 +63,15 @@ func (l *logger) Debug(desc string, args ...interface{}) {
l.messages2 = append(l.messages2, cd)
}
// UPGRADEv2: to remove.
func (l *logger) Logf(s string, f ...interface{}) {
l.messages = append(l.messages, fmt.Sprintf(s, f...))
}
func logStats(ctx context.Context, startTime time.Time, result *CheckResult) error {
runTimeInSecs := time.Now().Unix() - startTime.Unix()
opencensusstats.Record(ctx, stats.CheckRuntimeInSec.M(runTimeInSecs))
if result.Error != nil {
ctx, err := tag.New(ctx, tag.Upsert(stats.ErrorName, scorecarderrors.GetErrorName(result.Error)))
ctx, err := tag.New(ctx, tag.Upsert(stats.ErrorName, sce.GetName(result.Error2)))
if err != nil {
return fmt.Errorf("%w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("tag.New: %v", err))
}
opencensusstats.Record(ctx, stats.CheckErrors.M(1))
}
@ -97,19 +92,14 @@ func (r *Runner) Run(ctx context.Context, f CheckFn) CheckResult {
checkRequest := r.CheckRequest
checkRequest.Ctx = ctx
l = logger{}
// UPGRADEv2: to remove.
checkRequest.Logf = l.Logf
checkRequest.Dlogger = &l
res = f(&checkRequest)
// UPGRADEv2: to fix using proper error check.
if res.ShouldRetry && !strings.Contains(res.Error.Error(), "invalid header field value") {
checkRequest.Logf("error, retrying: %s", res.Error)
if res.Error2 != nil && errors.Is(res.Error2, sce.ErrRepoUnreachable) {
checkRequest.Dlogger.Warn("%v", res.Error2)
continue
}
break
}
// UPGRADEv2: to remove.
res.Details = l.messages
res.Details2 = l.messages2
if err := logStats(ctx, startTime, &res); err != nil {

View File

@ -29,6 +29,8 @@ import (
"strings"
"github.com/google/go-github/v32/github"
sce "github.com/ossf/scorecard/v2/errors"
)
const (
@ -47,7 +49,6 @@ func extractAndValidateArchivePath(path, dest string) (string, error) {
// Discard the directory and only keep the actual files.
names := strings.SplitN(path, "/", splitLength)
if len(names) < splitLength {
log.Printf("Unable to split path: %s", path)
return dest, nil
}
if names[1] == "" {
@ -56,7 +57,8 @@ func extractAndValidateArchivePath(path, dest string) (string, error) {
// Check for ZipSlip: https://snyk.io/research/zip-slip-vulnerability
cleanpath := filepath.Join(dest, names[1])
if !strings.HasPrefix(cleanpath, filepath.Clean(dest)+string(os.PathSeparator)) {
return "", fmt.Errorf("%w: %s", errZipSlip, names[1])
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("%v: %v", errZipSlip, names[1]))
}
return cleanpath, nil
}
@ -75,18 +77,13 @@ func (handler *tarballHandler) init(ctx context.Context, repo *github.Repository
// Setup temp dir/files and download repo tarball.
if err := handler.getTarball(ctx, repo); errors.Is(err, errTarballNotFound) {
log.Printf("%v", err)
return nil
} else if err != nil {
return fmt.Errorf("error getting githurepo tarball: %w", err)
return err
}
// Extract file names and content from tarball.
if err := handler.extractTarball(); err != nil {
return fmt.Errorf("error extracting githubrepo tarball: %w", err)
}
return nil
return handler.extractTarball()
}
func (handler *tarballHandler) getTarball(ctx context.Context, repo *github.Repository) error {
@ -95,32 +92,38 @@ func (handler *tarballHandler) getTarball(ctx context.Context, repo *github.Repo
url = strings.Replace(url, "{/ref}", "", 1)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return fmt.Errorf("http.NewRequestWithContext: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("http.NewRequestWithContext: %v", err))
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("http.DefaultClient.Do: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("http.DefaultClient.Do: %v", err))
}
defer resp.Body.Close()
// Handle 400/404 errors
switch resp.StatusCode {
case http.StatusNotFound, http.StatusBadRequest:
return fmt.Errorf("%w: %s", errTarballNotFound, *repo.URL)
//nolint:wrapcheck
return sce.CreateInternal(errTarballNotFound, fmt.Sprintf("%v: %v: %v", errTarballNotFound, *repo.URL, err))
}
// Create a temp file. This automatically appends a random number to the name.
tempDir, err := ioutil.TempDir("", repoDir)
if err != nil {
return fmt.Errorf("error creating TempDir in githubrepo: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("ioutil.TempDir: %v", err))
}
repoFile, err := ioutil.TempFile(tempDir, repoFilename)
if err != nil {
return fmt.Errorf("error during ioutil.TempFile in githubrepo: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("ioutil.TempFile: %v", err))
}
defer repoFile.Close()
if _, err := io.Copy(repoFile, resp.Body); err != nil {
return fmt.Errorf("error during io.Copy in githubrepo tarball: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("io.Copy: %v", err))
}
handler.tempDir = tempDir
@ -133,11 +136,13 @@ func (handler *tarballHandler) extractTarball() error {
// nolint: gomnd
in, err := os.OpenFile(handler.tempTarFile, os.O_RDONLY, 0o644)
if err != nil {
return fmt.Errorf("error opening %s: %w", handler.tempTarFile, err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("os.OpenFile: %v", err))
}
gz, err := gzip.NewReader(in)
if err != nil {
return fmt.Errorf("error reading %s: %w", handler.tempTarFile, err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("gzip.NewReader: %v: %v", handler.tempTarFile, err))
}
tr := tar.NewReader(gz)
for {
@ -146,14 +151,15 @@ func (handler *tarballHandler) extractTarball() error {
break
}
if err != nil {
return fmt.Errorf("error in tarReader.Next(): %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("tarReader.Next: %v", err))
}
switch header.Typeflag {
case tar.TypeDir:
dirpath, err := extractAndValidateArchivePath(header.Name, handler.tempDir)
if err != nil {
return fmt.Errorf("error extracting dirpath: %w", err)
return err
}
if dirpath == filepath.Clean(handler.tempDir) {
continue
@ -168,25 +174,28 @@ func (handler *tarballHandler) extractTarball() error {
}
filenamepath, err := extractAndValidateArchivePath(header.Name, handler.tempDir)
if err != nil {
return fmt.Errorf("error extracting file path: %w", err)
return err
}
if _, err := os.Stat(filepath.Dir(filenamepath)); os.IsNotExist(err) {
// nolint: gomnd
if err := os.Mkdir(filepath.Dir(filenamepath), 0o755); err != nil {
return fmt.Errorf("error during os.Mkdir: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("os.Mkdir: %v", err))
}
}
outFile, err := os.Create(filenamepath)
if err != nil {
return fmt.Errorf("error during os.Create: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("os.Create: %v", err))
}
// nolint: gosec
// Potential for DoS vulnerability via decompression bomb.
// Since such an attack will only impact a single shard, ignoring this for now.
if _, err := io.Copy(outFile, tr); err != nil {
return fmt.Errorf("error during io.Copy: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("io.Copy: %v", err))
}
outFile.Close()
handler.files = append(handler.files,
@ -218,14 +227,16 @@ func (handler *tarballHandler) listFiles(predicate func(string) (bool, error)) (
func (handler *tarballHandler) getFileContent(filename string) ([]byte, error) {
content, err := ioutil.ReadFile(filepath.Join(handler.tempDir, filename))
if err != nil {
return content, fmt.Errorf("error trying to ReadFile: %w", err)
//nolint:wrapcheck
return content, sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("ioutil.ReadFile: %v", err))
}
return content, nil
}
func (handler *tarballHandler) cleanup() error {
if err := os.RemoveAll(handler.tempDir); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("os.Remove: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("os.Remove: %v", err))
}
// Remove old files so we don't iterate through them.
handler.files = nil

View File

@ -18,7 +18,6 @@ package cmd
import (
"context"
"encoding/json"
"errors"
goflag "flag"
"fmt"
"log"
@ -36,6 +35,7 @@ import (
"github.com/ossf/scorecard/v2/checker"
"github.com/ossf/scorecard/v2/checks"
"github.com/ossf/scorecard/v2/clients/githubrepo"
sce "github.com/ossf/scorecard/v2/errors"
"github.com/ossf/scorecard/v2/pkg"
"github.com/ossf/scorecard/v2/repos"
"github.com/ossf/scorecard/v2/roundtripper"
@ -52,8 +52,6 @@ var (
pypi string
rubygems string
showDetails bool
// ErrorInvalidFormatFlag indicates an invalid option was passed for the 'format' argument.
ErrorInvalidFormatFlag = errors.New("invalid format flag")
)
const (
@ -165,7 +163,8 @@ or ./scorecard --{npm,pypi,rubgems}=<package_name> [--checks=check1,...] [--show
case formatJSON:
err = repoResult.AsJSON(showDetails, *logLevel, os.Stdout)
default:
err = fmt.Errorf("%w %s. allowed values are: [default, csv, json]", ErrorInvalidFormatFlag, format)
err = sce.Create(sce.ErrScorecardInternal,
fmt.Sprintf("invalid format flag: %v. Expected [default, csv, json]", format))
}
if err != nil {
log.Fatalf("Failed to output results: %v", err)
@ -204,7 +203,7 @@ func Execute() {
}
// Gets the GitHub repository URL for the npm package.
//nolint:noctx,goerr113
//nolint:noctx
func fetchGitRepositoryFromNPM(packageName string) (string, error) {
npmSearchURL := "https://registry.npmjs.org/-/v1/search?text=%s&size=1"
const timeout = 10
@ -213,23 +212,27 @@ func fetchGitRepositoryFromNPM(packageName string) (string, error) {
}
resp, err := client.Get(fmt.Sprintf(npmSearchURL, packageName))
if err != nil {
return "", fmt.Errorf("failed to get npm package json: %w", err)
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("failed to get npm package json: %v", err))
}
defer resp.Body.Close()
v := &npmSearchResults{}
err = json.NewDecoder(resp.Body).Decode(v)
if err != nil {
return "", fmt.Errorf("failed to parse npm package json: %w", err)
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("failed to parse npm package json: %v", err))
}
if len(v.Objects) == 0 {
return "", fmt.Errorf("could not find source repo for npm package: %s", packageName)
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal,
fmt.Sprintf("could not find source repo for npm package: %s", packageName))
}
return v.Objects[0].Package.Links.Repository, nil
}
// Gets the GitHub repository URL for the pypi package.
//nolint:noctx,goerr113
//nolint:noctx
func fetchGitRepositoryFromPYPI(packageName string) (string, error) {
pypiSearchURL := "https://pypi.org/pypi/%s/json"
const timeout = 10
@ -238,23 +241,27 @@ func fetchGitRepositoryFromPYPI(packageName string) (string, error) {
}
resp, err := client.Get(fmt.Sprintf(pypiSearchURL, packageName))
if err != nil {
return "", fmt.Errorf("failed to get pypi package json: %w", err)
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("failed to get pypi package json: %v", err))
}
defer resp.Body.Close()
v := &pypiSearchResults{}
err = json.NewDecoder(resp.Body).Decode(v)
if err != nil {
return "", fmt.Errorf("failed to parse pypi package json: %w", err)
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("failed to parse pypi package json: %v", err))
}
if v.Info.ProjectUrls.Source == "" {
return "", fmt.Errorf("could not find source repo for pypi package: %s", packageName)
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal,
fmt.Sprintf("could not find source repo for pypi package: %s", packageName))
}
return v.Info.ProjectUrls.Source, nil
}
// Gets the GitHub repository URL for the rubygems package.
//nolint:noctx,goerr113
//nolint:noctx
func fetchGitRepositoryFromRubyGems(packageName string) (string, error) {
rubyGemsSearchURL := "https://rubygems.org/api/v1/gems/%s.json"
const timeout = 10
@ -263,17 +270,20 @@ func fetchGitRepositoryFromRubyGems(packageName string) (string, error) {
}
resp, err := client.Get(fmt.Sprintf(rubyGemsSearchURL, packageName))
if err != nil {
return "", fmt.Errorf("failed to get ruby gem json: %w", err)
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("failed to get ruby gem json: %v", err))
}
defer resp.Body.Close()
v := &rubyGemsSearchResults{}
err = json.NewDecoder(resp.Body).Decode(v)
if err != nil {
return "", fmt.Errorf("failed to parse ruby gem json: %w", err)
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("failed to parse ruby gem json: %v", err))
}
if v.SourceCodeURI == "" {
return "", fmt.Errorf("could not find source repo for ruby gem: %s", packageName)
//nolint:wrapcheck
return "", sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("could not find source repo for ruby gem: %v", err))
}
return v.SourceCodeURI, nil
}

21
errors/internal.go Normal file
View File

@ -0,0 +1,21 @@
// 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 errors
// CreateInternal creates internal error, not using
// any of the errors listed in public.go.
func CreateInternal(e error, msg string) error {
return Create(e, msg)
}

View File

@ -1,45 +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 errors
import (
"errors"
)
const (
// RetryError occurs when checks fail after exhausting all retry attempts.
RetryError = "RetryError"
// LowConfidenceError shows a low-confidence result.
LowConfidenceError = "LowConfidenceError"
// UnknownError for all error types not handled.
UnknownError = "UnknownError"
)
var (
errRetry *ErrRetry
errLowConfidence *ErrLowConfidence
)
// GetErrorName returns the name of the error.
func GetErrorName(err error) string {
switch {
case errors.As(err, &errRetry):
return RetryError
case errors.As(err, &errLowConfidence):
return LowConfidenceError
default:
return UnknownError
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2020 Security Scorecard Authors
// 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.
@ -19,7 +19,6 @@ import (
"fmt"
)
// UPGRADEv2: delete other files in folder.
//nolint
var (
ErrScorecardInternal = errors.New("internal error")
@ -37,8 +36,14 @@ func Create(e error, msg string) error {
return fmt.Errorf("%w", e)
}
// CreateInternal creates an internal error, not using
// any of the errors listed above.
func CreateInternal(e error, msg string) error {
return Create(e, msg)
// GetName returns the name of the error.
func GetName(err error) string {
switch {
case errors.Is(err, ErrScorecardInternal):
return "ErrScorecardInternal"
case errors.Is(err, ErrRepoUnreachable):
return "ErrRepoUnreachable"
default:
return "ErrUnknown"
}
}

View File

@ -1,60 +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 errors defines all errors returned to users by Scorecard library.
package errors
import (
"fmt"
)
type (
// ErrRetry is returned when a check failed after maximum num_retries.
ErrRetry struct{ wrappedError }
// ErrLowConfidence is returned when check result is inconclusive.
ErrLowConfidence struct{ wrappedError }
)
// MakeRetryError returns a wrapped error of type ErrRetry.
func MakeRetryError(err error) error {
return &ErrRetry{
wrappedError{
msg: "unable to run check, retry",
innerError: err,
},
}
}
// MakeLowConfidenceError returns a wrapped error of type ErrLowConfidence.
func MakeLowConfidenceError(err error) error {
return &ErrLowConfidence{
wrappedError{
msg: "low confidence check result",
innerError: err,
},
}
}
type wrappedError struct {
innerError error
msg string
}
func (err *wrappedError) Error() string {
return fmt.Sprintf("%s: %v", err.msg, err.innerError)
}
func (err *wrappedError) Unwrap() error {
return err.innerError
}

1
go.mod
View File

@ -20,7 +20,6 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.14.0
github.com/pkg/errors v0.9.1
github.com/shurcooL/githubv4 v0.0.0-20201206200315-234843c633fa
github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a // indirect
github.com/spf13/cobra v1.2.1

View File

@ -29,6 +29,7 @@ import (
"github.com/ossf/scorecard/v2/checker"
"github.com/ossf/scorecard/v2/clients"
sce "github.com/ossf/scorecard/v2/errors"
"github.com/ossf/scorecard/v2/repos"
"github.com/ossf/scorecard/v2/stats"
)
@ -80,12 +81,15 @@ func RunScorecards(ctx context.Context,
graphClient *githubv4.Client) (ScorecardResult, error) {
ctx, err := tag.New(ctx, tag.Upsert(stats.Repo, repo.URL()))
if err != nil {
return ScorecardResult{}, fmt.Errorf("error during tag.New: %w", err)
//nolint:wrapcheck
return ScorecardResult{}, sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("tag.New: %v", err))
}
defer logStats(ctx, time.Now())
if err := repoClient.InitRepo(repo.Owner, repo.Repo); err != nil {
return ScorecardResult{}, fmt.Errorf("error during InitRepo for %s: %w", repo.URL(), err)
// No need to call sce.Create() since InitRepo will do that for us.
//nolint:wrapcheck
return ScorecardResult{}, err
}
ret := ScorecardResult{

View File

@ -27,6 +27,7 @@ import (
"go.uber.org/zap/zapcore"
"github.com/ossf/scorecard/v2/checker"
sce "github.com/ossf/scorecard/v2/errors"
)
// ScorecardResult struct is returned on a successful Scorecard run.
@ -43,7 +44,8 @@ func (r *ScorecardResult) AsJSON(showDetails bool, logLevel zapcore.Level, write
encoder := json.NewEncoder(writer)
if showDetails {
if err := encoder.Encode(r); err != nil {
return fmt.Errorf("error encoding repo result as detailed JSON: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("encoder.Encode: %v", err))
}
return nil
}
@ -63,7 +65,8 @@ func (r *ScorecardResult) AsJSON(showDetails bool, logLevel zapcore.Level, write
out.Checks = append(out.Checks, tmpResult)
}
if err := encoder.Encode(out); err != nil {
return fmt.Errorf("error encoding repo result as JSON: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("encoder.Encode: %v", err))
}
return nil
}
@ -86,11 +89,13 @@ func (r *ScorecardResult) AsCSV(showDetails bool, logLevel zapcore.Level, writer
}
fmt.Fprintf(writer, "%s\n", strings.Join(columns, ","))
if err := w.Write(record); err != nil {
return fmt.Errorf("error writing repo result as CSV: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("csv.Write: %v", err))
}
w.Flush()
if err := w.Error(); err != nil {
return fmt.Errorf("error flushing repo result as CSV: %w", err)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("csv.Flush: %v", err))
}
return nil
}

View File

@ -20,6 +20,8 @@ import (
"fmt"
"net/url"
"strings"
sce "github.com/ossf/scorecard/v2/errors"
)
var (
@ -31,7 +33,7 @@ var (
ErrorInvalidURL = errors.New("invalid repo flag")
)
// RepoURL represents a URL of a repo.
//nolint:revive
type RepoURL struct {
Host, Owner, Repo string
Metadata []string
@ -61,13 +63,15 @@ func (r *RepoURL) Set(s string) error {
u, e := url.Parse(s)
if e != nil {
return fmt.Errorf("error parsing repo URL: %w", e)
//nolint:wrapcheck
return sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("url.Parse: %v", e))
}
const splitLen = 2
split := strings.SplitN(strings.Trim(u.Path, "/"), "/", splitLen)
if len(split) != splitLen {
return fmt.Errorf("%w: [%s], pass the full repository URL", ErrorInvalidURL, s)
//nolint:wrapcheck
return sce.Create(ErrorInvalidURL, fmt.Sprintf("%v. Exepted full repository url", s))
}
r.Host, r.Owner, r.Repo = u.Host, split[0], split[1]
@ -79,11 +83,14 @@ func (r *RepoURL) ValidGitHubURL() error {
switch r.Host {
case "github.com":
default:
return fmt.Errorf("%w: %s", ErrorUnsupportedHost, r.Host)
//nolint:wrapcheck
return sce.Create(ErrorUnsupportedHost, r.Host)
}
if strings.TrimSpace(r.Owner) == "" || strings.TrimSpace(r.Repo) == "" {
return fmt.Errorf("%w: [%s], pass the full repository URL", ErrorInvalidGithubURL, r.URL())
//nolint:wrapcheck
return sce.Create(ErrorInvalidGithubURL,
fmt.Sprintf("%v. Expected the full reposiroty url", r.URL()))
}
return nil
}

View File

@ -23,6 +23,7 @@ import (
opencensusstats "go.opencensus.io/stats"
"go.opencensus.io/tag"
sce "github.com/ossf/scorecard/v2/errors"
"github.com/ossf/scorecard/v2/stats"
)
@ -44,18 +45,21 @@ type censusTransport struct {
func (ct *censusTransport) RoundTrip(r *http.Request) (*http.Response, error) {
ctx, err := tag.New(r.Context(), tag.Upsert(stats.RequestTag, "requested"))
if err != nil {
return nil, fmt.Errorf("error during tag.New: %w", err)
//nolint:wrapcheck
return nil, sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("tag.New: %v", err))
}
r = r.WithContext(ctx)
resp, err := ct.innerTransport.RoundTrip(r)
if err != nil {
return nil, fmt.Errorf("error in RoundTrip: %w", err)
//nolint:wrapcheck
return nil, sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("innerTransport.RoundTrip: %v", err))
}
if resp.Header.Get(httpcache.XFromCache) != "" {
ctx, err = tag.New(ctx, tag.Upsert(stats.RequestTag, httpcache.XFromCache))
if err != nil {
return nil, fmt.Errorf("error during tag.New: %w", err)
//nolint:wrapcheck
return nil, sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("tag.New: %v", err))
}
}
opencensusstats.Record(ctx, stats.HTTPRequests.M(1))

View File

@ -15,12 +15,14 @@
package roundtripper
import (
"fmt"
"net/http"
"strconv"
"time"
"github.com/pkg/errors"
"go.uber.org/zap"
sce "github.com/ossf/scorecard/v2/errors"
)
// MakeRateLimitedTransport returns a RoundTripper which rate limits GitHub requests.
@ -41,7 +43,8 @@ type rateLimitTransport struct {
func (gh *rateLimitTransport) RoundTrip(r *http.Request) (*http.Response, error) {
resp, err := gh.innerTransport.RoundTrip(r)
if err != nil {
return nil, errors.Wrap(err, "error in round trip")
//nolint:wrapcheck
return nil, sce.Create(sce.ErrScorecardInternal, fmt.Sprintf("innerTransport.RoundTrip: %v", err))
}
rateLimit := resp.Header.Get("X-RateLimit-Remaining")
remaining, err := strconv.Atoi(rateLimit)