Refactor to improve readability (#1394)

Co-authored-by: Azeem Shaikh <azeems@google.com>
This commit is contained in:
Azeem Shaikh 2021-12-15 18:01:34 -05:00 committed by GitHub
parent bbbca2bd87
commit ecc96576f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 431 additions and 381 deletions

View File

@ -20,32 +20,33 @@ import (
"math"
)
// UPGRADEv2: to remove.
const (
MaxResultConfidence = 10
// MaxResultConfidence implies full certainty about a check result.
// TODO(#1393): remove after deprecation.
MaxResultConfidence = 10
// HalfResultConfidence signifies uncertainty about a check's score.
// TODO(#1393): remove after deprecation.
HalfResultConfidence = 5
MinResultConfidence = 0
)
// MinResultConfidence signifies no confidence in the check result.
// TODO(#1393): remove after deprecation.
MinResultConfidence = 0
// TODO(#1393): remove after deprecation.
migrationThresholdPassValue = 8
// UPGRADEv2: to remove.
const migrationThresholdPassValue = 8
// MaxResultScore is the best score that can be given by a check.
MaxResultScore = 10
// MinResultScore is the worst score that can be given by a check.
MinResultScore = 0
// InconclusiveResultScore is returned when no reliable information can be retrieved by a check.
InconclusiveResultScore = -1
// DetailType is the type of details.
type DetailType int
const (
// DetailInfo is info-level log.
DetailInfo DetailType = iota
// DetailWarn is warn log.
DetailWarn
// DetailDebug is debug log.
DetailDebug
)
// FileType is the type of a file.
type FileType int
const (
// FileTypeNone is a default, not defined.
FileTypeNone FileType = iota
// FileTypeSource is for source code files.
@ -56,55 +57,16 @@ const (
FileTypeText
// FileTypeURL for URLs.
FileTypeURL
)
// OffsetDefault is used if we can't determine the offset, for example when referencing a file but not a
// specific location in the file.
const OffsetDefault = 1
// LogMessage is a structure that encapsulates detail's information.
// This allows updating the definition easily.
//nolint
type LogMessage struct {
Text string // A short string explaining why the detail was recorded/logged.
Path string // Fullpath to the file.
Type FileType // Type of file.
Offset int // Offset in the file of Path (line for source/text files).
Snippet string // Snippet of code
// UPGRADEv3: to remove.
Version int // `3` to indicate the detail was logged using new structure.
}
// CheckDetail contains information for each detail.
type CheckDetail struct {
Msg LogMessage
Type DetailType // Any of DetailWarn, DetailInfo, DetailDebug.
}
// DetailLogger logs a CheckDetail struct.
type DetailLogger interface {
Info(desc string, args ...interface{})
Warn(desc string, args ...interface{})
Debug(desc string, args ...interface{})
// Functions to use for moving to SARIF format.
// UPGRADEv3: to rename.
Info3(msg *LogMessage)
Warn3(msg *LogMessage)
Debug3(msg *LogMessage)
}
//nolint
const (
MaxResultScore = 10
MinResultScore = 0
InconclusiveResultScore = -1
// OffsetDefault is used if we can't determine the offset, for example when referencing a file but not a
// specific location in the file.
OffsetDefault = 1
)
// CheckResult captures result from a check run.
// nolint
// nolint:govet
type CheckResult struct {
// Old structure
// TODO(#1393): Remove old structure after deprecation.
Error error `json:"-"`
Name string
Details []string
@ -118,81 +80,32 @@ type CheckResult struct {
Details2 []CheckDetail `json:"-"` // Details of tests and sub-checks
Score int `json:"-"` // {[-1,0...10], -1 = Inconclusive}
Reason string `json:"-"` // A sentence describing the check result (score, etc)
}
// ====== Raw results for checks =========.
// CheckDetail contains information for each detail.
type CheckDetail struct {
Msg LogMessage
Type DetailType // Any of DetailWarn, DetailInfo, DetailDebug.
}
// File represents a file.
type File struct {
Path string
Snippet string // Snippet of code
Offset int // Offset in the file of Path (line for source/text files).
// LogMessage is a structure that encapsulates detail's information.
// This allows updating the definition easily.
// nolint:govet
type LogMessage struct {
Text string // A short string explaining why the detail was recorded/logged.
Path string // Fullpath to the file.
Type FileType // Type of file.
// TODO: add hash.
Offset int // Offset in the file of Path (line for source/text files).
Snippet string // Snippet of code
// UPGRADEv3: to remove.
Version int // `3` to indicate the detail was logged using new structure.
}
// SecurityPolicyData contains the raw results
// for the Security-Policy check.
type SecurityPolicyData struct {
// Files contains a list of files.
Files []File
}
// DetailType is the type of details.
type DetailType int
// Run represents a run.
type Run struct {
URL string
// TODO: add fields, e.g., Result=["success", "failure"]
}
// Issue represents an issue.
type Issue struct {
URL string
// TODO: add fields, e.g., state=[opened|closed]
}
// MergeRequest represents a merge request.
type MergeRequest struct {
URL string
// TODO: add fields, e.g., State=["merged"|"closed"]
}
// Tool represents a tool.
type Tool struct {
// Runs of the tool.
Runs []Run
// Issues created by the tool.
Issues []Issue
// Merges requests created by the tool.
MergeRequests []MergeRequest
Name string
URL string
Desc string
ConfigFiles []File
}
// BinaryArtifactData contains the raw results
// for the Binary-Artifact check.
type BinaryArtifactData struct {
// Files contains a list of files.
Files []File
}
// DependencyUpdateToolData contains the raw results
// for the Dependency-Update-Tool check.
type DependencyUpdateToolData struct {
// Tools contains a list of tools.
// Note: we only populate one entry at most.
Tools []Tool
}
// RawResults contains results before a policy
// is applied.
type RawResults struct {
BinaryArtifactResults BinaryArtifactData
SecurityPolicyResults SecurityPolicyData
DependencyUpdateToolResults DependencyUpdateToolData
}
// FileType is the type of a file.
type FileType int
// CreateProportionalScore creates a proportional score.
func CreateProportionalScore(success, total int) int {

View File

@ -42,55 +42,6 @@ type CheckFn func(*CheckRequest) CheckResult
// CheckNameToFnMap defined here for convenience.
type CheckNameToFnMap map[string]CheckFn
// UPGRADEv2: messages2 will ultimately
// be renamed to messages.
type logger struct {
messages2 []CheckDetail
}
func (l *logger) Info(desc string, args ...interface{}) {
cd := CheckDetail{Type: DetailInfo, Msg: LogMessage{Text: fmt.Sprintf(desc, args...)}}
l.messages2 = append(l.messages2, cd)
}
func (l *logger) Warn(desc string, args ...interface{}) {
cd := CheckDetail{Type: DetailWarn, Msg: LogMessage{Text: fmt.Sprintf(desc, args...)}}
l.messages2 = append(l.messages2, cd)
}
func (l *logger) Debug(desc string, args ...interface{}) {
cd := CheckDetail{Type: DetailDebug, Msg: LogMessage{Text: fmt.Sprintf(desc, args...)}}
l.messages2 = append(l.messages2, cd)
}
// UPGRADEv3: to rename.
func (l *logger) Info3(msg *LogMessage) {
cd := CheckDetail{
Type: DetailInfo,
Msg: *msg,
}
cd.Msg.Version = 3
l.messages2 = append(l.messages2, cd)
}
func (l *logger) Warn3(msg *LogMessage) {
cd := CheckDetail{
Type: DetailWarn,
Msg: *msg,
}
cd.Msg.Version = 3
l.messages2 = append(l.messages2, cd)
}
func (l *logger) Debug3(msg *LogMessage) {
cd := CheckDetail{
Type: DetailDebug,
Msg: *msg,
}
cd.Msg.Version = 3
l.messages2 = append(l.messages2, cd)
}
func logStats(ctx context.Context, startTime time.Time, result *CheckResult) error {
runTimeInSecs := time.Now().Unix() - startTime.Unix()
opencensusstats.Record(ctx, stats.CheckRuntimeInSec.M(runTimeInSecs))

28
checker/detail_logger.go Normal file
View File

@ -0,0 +1,28 @@
// 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
// DetailLogger logs a CheckDetail struct.
type DetailLogger interface {
Info(desc string, args ...interface{})
Warn(desc string, args ...interface{})
Debug(desc string, args ...interface{})
// Functions to use for moving to SARIF format.
// UPGRADEv3: to rename.
Info3(msg *LogMessage)
Warn3(msg *LogMessage)
Debug3(msg *LogMessage)
}

View File

@ -0,0 +1,68 @@
// 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"
)
// UPGRADEv2: messages2 will ultimately
// be renamed to messages.
type logger struct {
messages2 []CheckDetail
}
func (l *logger) Info(desc string, args ...interface{}) {
cd := CheckDetail{Type: DetailInfo, Msg: LogMessage{Text: fmt.Sprintf(desc, args...)}}
l.messages2 = append(l.messages2, cd)
}
func (l *logger) Warn(desc string, args ...interface{}) {
cd := CheckDetail{Type: DetailWarn, Msg: LogMessage{Text: fmt.Sprintf(desc, args...)}}
l.messages2 = append(l.messages2, cd)
}
func (l *logger) Debug(desc string, args ...interface{}) {
cd := CheckDetail{Type: DetailDebug, Msg: LogMessage{Text: fmt.Sprintf(desc, args...)}}
l.messages2 = append(l.messages2, cd)
}
// UPGRADEv3: to rename.
func (l *logger) Info3(msg *LogMessage) {
cd := CheckDetail{
Type: DetailInfo,
Msg: *msg,
}
cd.Msg.Version = 3
l.messages2 = append(l.messages2, cd)
}
func (l *logger) Warn3(msg *LogMessage) {
cd := CheckDetail{
Type: DetailWarn,
Msg: *msg,
}
cd.Msg.Version = 3
l.messages2 = append(l.messages2, cd)
}
func (l *logger) Debug3(msg *LogMessage) {
cd := CheckDetail{
Type: DetailDebug,
Msg: *msg,
}
cd.Msg.Version = 3
l.messages2 = append(l.messages2, cd)
}

86
checker/raw_result.go Normal file
View File

@ -0,0 +1,86 @@
// 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
// RawResults contains results before a policy
// is applied.
type RawResults struct {
BinaryArtifactResults BinaryArtifactData
SecurityPolicyResults SecurityPolicyData
DependencyUpdateToolResults DependencyUpdateToolData
}
// BinaryArtifactData contains the raw results
// for the Binary-Artifact check.
type BinaryArtifactData struct {
// Files contains a list of files.
Files []File
}
// DependencyUpdateToolData contains the raw results
// for the Dependency-Update-Tool check.
type DependencyUpdateToolData struct {
// Tools contains a list of tools.
// Note: we only populate one entry at most.
Tools []Tool
}
// SecurityPolicyData contains the raw results
// for the Security-Policy check.
type SecurityPolicyData struct {
// Files contains a list of files.
Files []File
}
// File represents a file.
type File struct {
Path string
Snippet string // Snippet of code
Offset int // Offset in the file of Path (line for source/text files).
Type FileType // Type of file.
// TODO: add hash.
}
// Run represents a run.
type Run struct {
URL string
// TODO: add fields, e.g., Result=["success", "failure"]
}
// Issue represents an issue.
type Issue struct {
URL string
// TODO: add fields, e.g., state=[opened|closed]
}
// MergeRequest represents a merge request.
type MergeRequest struct {
URL string
// TODO: add fields, e.g., State=["merged"|"closed"]
}
// Tool represents a tool.
type Tool struct {
// Runs of the tool.
Runs []Run
// Issues created by the tool.
Issues []Issue
// Merges requests created by the tool.
MergeRequests []MergeRequest
Name string
URL string
Desc string
ConfigFiles []File
}

View File

@ -55,22 +55,24 @@ var (
rubygems string
showDetails bool
policyFile string
rootCmd = &cobra.Command{
Use: scorecardUse,
Short: scorecardShort,
Long: scorecardLong,
Run: scorecardCmd,
}
)
const (
formatJSON = "json"
formatSarif = "sarif"
formatDefault = "default"
)
// These strings must be the same as the ones used in
// checks.yaml for the "repos" field.
const (
// These strings must be the same as the ones used in
// checks.yaml for the "repos" field.
repoTypeLocal = "local"
repoTypeGitHub = "GitHub"
)
const (
scorecardLong = "A program that shows security scorecard for an open source software."
scorecardUse = `./scorecard [--repo=<repo_url>] [--local=folder] [--checks=check1,...]
[--show-details] [--policy=file] or ./scorecard --{npm,pypi,rubygems}=<package_name>
@ -78,6 +80,207 @@ const (
scorecardShort = "Security Scorecards"
)
//nolint:gochecknoinits
func init() {
// Add the zap flag manually
rootCmd.PersistentFlags().AddGoFlagSet(goflag.CommandLine)
rootCmd.Flags().StringVar(&repo, "repo", "", "repository to check")
rootCmd.Flags().StringVar(&local, "local", "", "local folder to check")
rootCmd.Flags().StringVar(
&npm, "npm", "",
"npm package to check, given that the npm package has a GitHub repository")
rootCmd.Flags().StringVar(
&pypi, "pypi", "",
"pypi package to check, given that the pypi package has a GitHub repository")
rootCmd.Flags().StringVar(
&rubygems, "rubygems", "",
"rubygems package to check, given that the rubygems package has a GitHub repository")
rootCmd.Flags().StringVar(&format, "format", formatDefault,
"output format. allowed values are [default, sarif, json]")
rootCmd.Flags().StringSliceVar(
&metaData, "metadata", []string{}, "metadata for the project. It can be multiple separated by commas")
rootCmd.Flags().BoolVar(&showDetails, "show-details", false, "show extra details about each check")
checkNames := []string{}
for checkName := range getAllChecks() {
checkNames = append(checkNames, checkName)
}
rootCmd.Flags().StringSliceVar(&checksToRun, "checks", []string{},
fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ",")))
rootCmd.Flags().StringVar(&policyFile, "policy", "", "policy to enforce")
var v6 bool
_, v6 = os.LookupEnv("SCORECARD_V6")
if v6 {
rootCmd.Flags().BoolVar(&raw, "raw", false, "generate raw results")
}
}
// Execute runs the Scorecard commandline.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
// nolint: gocognit, gocyclo
func scorecardCmd(cmd *cobra.Command, args []string) {
// UPGRADEv4: remove.
var v4 bool
_, v4 = os.LookupEnv("SCORECARD_V4")
if format == formatSarif && !v4 {
log.Panic("sarif not supported yet")
}
if policyFile != "" && !v4 {
log.Panic("policy not supported yet")
}
if local != "" && !v4 {
log.Panic("--local option not supported yet")
}
var v6 bool
_, v6 = os.LookupEnv("SCORECARD_V6")
if raw && !v6 {
log.Panic("--raw option not supported yet")
}
// Validate format.
if !validateFormat(format) {
log.Panicf("unsupported format '%s'", format)
}
policy, err := readPolicy()
if err != nil {
log.Panicf("readPolicy: %v", err)
}
// Get the URI.
uri, err := getURI(repo, local)
if err != nil {
log.Panic(err)
}
// Set `repo` from package managers.
exists, gitRepo, err := fetchGitRepositoryFromPackageManagers(npm, pypi, rubygems)
if err != nil {
log.Panic(err)
}
if exists {
if err := cmd.Flags().Set("repo", gitRepo); err != nil {
log.Panic(err)
}
}
// Sanity check that `repo` is set.
if err := cmd.MarkFlagRequired("repo"); err != nil {
log.Panic(err)
}
ctx := context.Background()
logger, err := githubrepo.NewLogger(*logLevel)
if err != nil {
log.Panic(err)
}
// nolint: errcheck
defer logger.Sync() // Flushes buffer, if any.
repoURI, repoClient, ossFuzzRepoClient, ciiClient, repoType, err := getRepoAccessors(ctx, uri, logger)
if err != nil {
log.Panic(err)
}
defer repoClient.Close()
if ossFuzzRepoClient != nil {
defer ossFuzzRepoClient.Close()
}
// Read docs.
checkDocs, err := docs.Read()
if err != nil {
log.Panicf("cannot read yaml file: %v", err)
}
supportedChecks, err := getSupportedChecks(repoType, checkDocs)
if err != nil {
log.Panicf("cannot read supported checks: %v", err)
}
enabledChecks, err := getEnabledChecks(policy, checksToRun, supportedChecks, repoType)
if err != nil {
log.Panic(err)
}
if format == formatDefault {
for checkName := range enabledChecks {
fmt.Fprintf(os.Stderr, "Starting [%s]\n", checkName)
}
}
if raw && format != "json" {
log.Panicf("only json format is supported")
}
repoResult, err := pkg.RunScorecards(ctx, repoURI, raw, enabledChecks, repoClient, ossFuzzRepoClient, ciiClient)
if err != nil {
log.Panic(err)
}
repoResult.Metadata = append(repoResult.Metadata, metaData...)
// Sort them by name
sort.Slice(repoResult.Checks, func(i, j int) bool {
return repoResult.Checks[i].Name < repoResult.Checks[j].Name
})
if format == formatDefault {
for checkName := range enabledChecks {
fmt.Fprintf(os.Stderr, "Finished [%s]\n", checkName)
}
fmt.Println("\nRESULTS\n-------")
}
switch format {
case formatDefault:
err = repoResult.AsString(showDetails, *logLevel, checkDocs, os.Stdout)
case formatSarif:
// TODO: support config files and update checker.MaxResultScore.
err = repoResult.AsSARIF(showDetails, *logLevel, os.Stdout, checkDocs, policy)
case formatJSON:
if raw {
err = repoResult.AsRawJSON(os.Stdout)
} else {
err = repoResult.AsJSON2(showDetails, *logLevel, checkDocs, os.Stdout)
}
default:
err = sce.WithMessage(sce.ErrScorecardInternal,
fmt.Sprintf("invalid format flag: %v. Expected [default, json]", format))
}
if err != nil {
log.Panicf("Failed to output results: %v", err)
}
}
func fetchGitRepositoryFromPackageManagers(npm, pypi, rubygems string) (bool, string, error) {
if npm != "" {
gitRepo, err := fetchGitRepositoryFromNPM(npm)
return true, gitRepo, err
}
if pypi != "" {
gitRepo, err := fetchGitRepositoryFromPYPI(pypi)
return true, gitRepo, err
}
if rubygems != "" {
gitRepo, err := fetchGitRepositoryFromRubyGems(rubygems)
return false, gitRepo, err
}
return false, "", nil
}
func readPolicy() (*spol.ScorecardPolicy, error) {
if policyFile != "" {
data, err := os.ReadFile(policyFile)
@ -251,162 +454,6 @@ func getURI(repo, local string) (string, error) {
return repo, nil
}
var rootCmd = &cobra.Command{
Use: scorecardUse,
Short: scorecardShort,
Long: scorecardLong,
Run: func(cmd *cobra.Command, args []string) {
// UPGRADEv4: remove.
var v4 bool
_, v4 = os.LookupEnv("SCORECARD_V4")
if format == formatSarif && !v4 {
log.Fatal("sarif not supported yet")
}
if policyFile != "" && !v4 {
log.Fatal("policy not supported yet")
}
if local != "" && !v4 {
log.Fatal("--local option not supported yet")
}
var v6 bool
_, v6 = os.LookupEnv("SCORECARD_V6")
if raw && !v6 {
log.Fatal("--raw option not supported yet")
}
// Validate format.
if !validateFormat(format) {
log.Fatalf("unsupported format '%s'", format)
}
policy, err := readPolicy()
if err != nil {
log.Fatalf("readPolicy: %v", err)
}
// Get the URI.
uri, err := getURI(repo, local)
if err != nil {
log.Fatal(err)
}
if npm != "" {
if git, err := fetchGitRepositoryFromNPM(npm); err != nil {
log.Fatal(err)
} else {
if err := cmd.Flags().Set("repo", git); err != nil {
log.Fatal(err)
}
}
} else if pypi != "" {
if git, err := fetchGitRepositoryFromPYPI(pypi); err != nil {
log.Fatal(err)
} else {
if err := cmd.Flags().Set("repo", git); err != nil {
log.Fatal(err)
}
}
} else if rubygems != "" {
if git, err := fetchGitRepositoryFromRubyGems(rubygems); err != nil {
log.Fatal(err)
} else {
if err := cmd.Flags().Set("repo", git); err != nil {
log.Fatal(err)
}
}
} else {
if err := cmd.MarkFlagRequired("repo"); err != nil {
log.Fatal(err)
}
}
ctx := context.Background()
logger, err := githubrepo.NewLogger(*logLevel)
if err != nil {
log.Fatal(err)
}
// nolint
defer logger.Sync() // Flushes buffer, if any.
repoURI, repoClient, ossFuzzRepoClient, ciiClient, repoType, err := getRepoAccessors(ctx, uri, logger)
if err != nil {
log.Fatal(err)
}
defer repoClient.Close()
if ossFuzzRepoClient != nil {
defer ossFuzzRepoClient.Close()
}
// Read docs.
checkDocs, err := docs.Read()
if err != nil {
log.Fatalf("cannot read yaml file: %v", err)
}
supportedChecks, err := getSupportedChecks(repoType, checkDocs)
if err != nil {
log.Fatalf("cannot read supported checks: %v", err)
}
enabledChecks, err := getEnabledChecks(policy, checksToRun, supportedChecks, repoType)
if err != nil {
log.Fatal(err)
}
if format == formatDefault {
for checkName := range enabledChecks {
fmt.Fprintf(os.Stderr, "Starting [%s]\n", checkName)
}
}
if raw && format != "json" {
log.Fatalf("only json format is supported")
}
repoResult, err := pkg.RunScorecards(ctx, repoURI, raw, enabledChecks, repoClient, ossFuzzRepoClient, ciiClient)
if err != nil {
log.Fatal(err)
}
repoResult.Metadata = append(repoResult.Metadata, metaData...)
// Sort them by name
sort.Slice(repoResult.Checks, func(i, j int) bool {
return repoResult.Checks[i].Name < repoResult.Checks[j].Name
})
if format == formatDefault {
for checkName := range enabledChecks {
fmt.Fprintf(os.Stderr, "Finished [%s]\n", checkName)
}
fmt.Println("\nRESULTS\n-------")
}
switch format {
case formatDefault:
err = repoResult.AsString(showDetails, *logLevel, checkDocs, os.Stdout)
case formatSarif:
// TODO: support config files and update checker.MaxResultScore.
err = repoResult.AsSARIF(showDetails, *logLevel, os.Stdout, checkDocs, policy)
case formatJSON:
if raw {
err = repoResult.AsRawJSON(os.Stdout)
} else {
err = repoResult.AsJSON2(showDetails, *logLevel, checkDocs, os.Stdout)
}
default:
err = sce.WithMessage(sce.ErrScorecardInternal,
fmt.Sprintf("invalid format flag: %v. Expected [default, json]", format))
}
if err != nil {
log.Fatalf("Failed to output results: %v", err)
}
},
}
type npmSearchResults struct {
Objects []struct {
Package struct {
@ -429,14 +476,6 @@ type rubyGemsSearchResults struct {
SourceCodeURI string `json:"source_code_uri"`
}
// Execute runs the Scorecard commandline.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
// Gets the GitHub repository URL for the npm package.
//nolint:noctx
func fetchGitRepositoryFromNPM(packageName string) (string, error) {
@ -526,38 +565,3 @@ func enableCheck(checkName string, enabledChecks *checker.CheckNameToFnMap) bool
}
return false
}
//nolint:gochecknoinits
func init() {
// Add the zap flag manually
rootCmd.PersistentFlags().AddGoFlagSet(goflag.CommandLine)
rootCmd.Flags().StringVar(&repo, "repo", "", "repository to check")
rootCmd.Flags().StringVar(&local, "local", "", "local folder to check")
rootCmd.Flags().StringVar(
&npm, "npm", "",
"npm package to check, given that the npm package has a GitHub repository")
rootCmd.Flags().StringVar(
&pypi, "pypi", "",
"pypi package to check, given that the pypi package has a GitHub repository")
rootCmd.Flags().StringVar(
&rubygems, "rubygems", "",
"rubygems package to check, given that the rubygems package has a GitHub repository")
rootCmd.Flags().StringVar(&format, "format", formatDefault,
"output format. allowed values are [default, sarif, json]")
rootCmd.Flags().StringSliceVar(
&metaData, "metadata", []string{}, "metadata for the project. It can be multiple separated by commas")
rootCmd.Flags().BoolVar(&showDetails, "show-details", false, "show extra details about each check")
checkNames := []string{}
for checkName := range getAllChecks() {
checkNames = append(checkNames, checkName)
}
rootCmd.Flags().StringSliceVar(&checksToRun, "checks", []string{},
fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ",")))
rootCmd.Flags().StringVar(&policyFile, "policy", "", "policy to enforce")
var v6 bool
_, v6 = os.LookupEnv("SCORECARD_V6")
if v6 {
rootCmd.Flags().BoolVar(&raw, "raw", false, "generate raw results")
}
}