Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 68 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@ import (
"github.com/ossf/scorecard/v5/policy"
)

// errChecksFailed is returned when one or more checks produced a runtime
// error during execution.
var errChecksFailed = errors.New("one or more checks failed during execution")
var (
// errChecksFailed is returned when one or more checks produced a runtime
// error during execution.
errChecksFailed = errors.New("one or more checks failed during execution")
errNoChecksSupported = errors.New("no checks support repository type")
)

const (
scorecardLong = "A program that shows the OpenSSF scorecard for an open source software."
Expand Down Expand Up @@ -235,6 +238,51 @@ func printCheckResults(repo string, enabledChecks checker.CheckNameToFnMap) {
}
}

func printSkippedChecks(repo string, skippedChecks []string) {
for _, checkName := range skippedChecks {
fmt.Fprintf(os.Stderr, "Skipping (%s) [%s]\n", repo, checkName)
}
}

func filterUnsupportedChecks(enabledChecks checker.CheckNameToFnMap, repo clients.Repo) []string {
var skippedChecks []string

repoType := scorecard.GetRepoType(repo)
if repoType == scorecard.RepoUnknown {
return skippedChecks
}

checksDocs, err := docs.Read()
if err != nil {
return skippedChecks
}

for checkName := range enabledChecks {
checkDoc, err := checksDocs.GetCheck(checkName)
if err != nil {
continue
}

checkRepos := checkDoc.GetSupportedRepoTypes()
var supported bool
for _, cr := range checkRepos {
checkRepo := scorecard.RepoTypeFromString(cr)

if checkRepo == repoType {
supported = true
break
}
}

if !supported {
skippedChecks = append(skippedChecks, checkName)
delete(enabledChecks, checkName)
}
}

return skippedChecks
}

// makeRepo helps turn a URI into the appropriate clients.Repo.
// currently this is a decision between GitHub, GitLab, and Azure DevOps,
// but may expand in the future.
Expand Down Expand Up @@ -295,6 +343,23 @@ func processRepo(
}
}

if o.SkipUnsupportedChecks {
skippedChecks := filterUnsupportedChecks(enabledChecks, repo)
if len(enabledChecks) == 0 {
return nil, errNoChecksSupported
}
if o.Format == options.FormatDefault {
printSkippedChecks(uri, skippedChecks)
}

filteredChecks := make([]string, 0, len(enabledChecks))
for c := range enabledChecks {
filteredChecks = append(filteredChecks, c)
}
// overwrites enabled checks
opts = append(opts, scorecard.WithChecks(filteredChecks))
}

// Start banners with repo uri (show banners in default format only)
if o.Format == options.FormatDefault {
if len(enabledProbes) > 0 {
Expand Down
11 changes: 11 additions & 0 deletions options/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ const (
FlagCommitDepth = "commit-depth"

FlagProbes = "probes"

// FlagSkipUnsupportedChecks is the flag name for skipping checks that are
// not supported by the target repo type.
FlagSkipUnsupportedChecks = "skip-unsupported-checks"
)

// Command is an interface for handling options for command-line utilities.
Expand Down Expand Up @@ -208,6 +212,13 @@ func (o *Options) AddFlags(cmd *cobra.Command) {
"Probes to run.",
)

cmd.Flags().BoolVar(
&o.SkipUnsupportedChecks,
FlagSkipUnsupportedChecks,
o.SkipUnsupportedChecks,
"skip checks that don't support the repository type",
)

// TODO(options): Extract logic
allowedFormats := []string{
FormatDefault,
Expand Down
36 changes: 23 additions & 13 deletions options/flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,20 @@ func TestOptions_AddFlags(t *testing.T) {
{
name: "custom options",
opts: &Options{
Repo: "owner/repo",
Local: "/path/to/local",
Commit: "1234567890abcdef",
LogLevel: "debug",
NPM: "npm-package",
PyPI: "pypi-package",
RubyGems: "rubygems-package",
Metadata: []string{"key1=value1", "key2=value2"},
ShowDetails: true,
ChecksToRun: []string{"check1", "check2"},
PolicyFile: "policy-file",
Format: "json",
ResultsFile: "result.json",
Repo: "owner/repo",
Local: "/path/to/local",
Commit: "1234567890abcdef",
LogLevel: "debug",
NPM: "npm-package",
PyPI: "pypi-package",
RubyGems: "rubygems-package",
Metadata: []string{"key1=value1", "key2=value2"},
ShowDetails: true,
ChecksToRun: []string{"check1", "check2"},
PolicyFile: "policy-file",
Format: "json",
ResultsFile: "result.json",
SkipUnsupportedChecks: true,
},
},
}
Expand Down Expand Up @@ -114,6 +115,15 @@ func TestOptions_AddFlags(t *testing.T) {
t.Errorf("expected ShorthandFlagResultsFile to be %q, but got %q", ShorthandFlagResultsFile,
cmd.Flag(FlagResultsFile).Shorthand)
}

// check FlagSkipUnsupportedChecks
value, err := cmd.Flags().GetBool(FlagSkipUnsupportedChecks)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if tt.opts.SkipUnsupportedChecks != value {
t.Errorf("expected FlagSkipUnsupportedChecks to be %t, got %t", tt.opts.SkipUnsupportedChecks, value)
}
})
}
}
Expand Down
41 changes: 21 additions & 20 deletions options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,27 @@ import (

// Options define common options for configuring scorecard.
type Options struct {
Repo string
Repos []string
Org string
Local string
Commit string
LogLevel string
Format string
NPM string
PyPI string
RubyGems string
Nuget string
PolicyFile string
ResultsFile string
FileMode string
ChecksToRun []string
ProbesToRun []string
Metadata []string
CommitDepth int
ShowDetails bool
ShowAnnotations bool
Repo string
Repos []string
Org string
Local string
Commit string
LogLevel string
Format string
NPM string
PyPI string
RubyGems string
Nuget string
PolicyFile string
ResultsFile string
FileMode string
ChecksToRun []string
ProbesToRun []string
Metadata []string
CommitDepth int
ShowDetails bool
ShowAnnotations bool
SkipUnsupportedChecks bool
// Feature flags.
EnableSarif bool `env:"ENABLE_SARIF"`
EnableScorecardV6 bool `env:"SCORECARD_V6"`
Expand Down
47 changes: 47 additions & 0 deletions pkg/scorecard/repo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package scorecard

import (
"strings"

"github.com/ossf/scorecard/v5/clients"
"github.com/ossf/scorecard/v5/clients/azuredevopsrepo"
"github.com/ossf/scorecard/v5/clients/githubrepo"
"github.com/ossf/scorecard/v5/clients/gitlabrepo"
"github.com/ossf/scorecard/v5/clients/localdir"
)

type RepoType string

const (
RepoUnknown RepoType = "unknown"
RepoLocal RepoType = "local"
RepoGitLocal RepoType = "git-local" // is not supported by any check yet.
RepoGitHub RepoType = "github"
RepoGitLab RepoType = "gitlab"
RepoAzureDevOPs RepoType = "azuredevops"
)

func GetRepoType(repo clients.Repo) RepoType {
switch repo.(type) {
case *localdir.Repo:
return RepoLocal
case *githubrepo.Repo:
return RepoGitHub
case *gitlabrepo.Repo:
return RepoGitLab
case *azuredevopsrepo.Repo:
return RepoAzureDevOPs
default:
return RepoUnknown
}
}

func RepoTypeFromString(repo string) RepoType {
rt := RepoType(strings.ToLower(strings.TrimSpace(repo)))
switch rt {
case RepoLocal, RepoGitLocal, RepoGitHub, RepoGitLab, RepoAzureDevOPs:
return rt
default:
return RepoUnknown
}
}
Loading