Skip to content

Commit

Permalink
sccmdrefactor: Move option validation to options package
Browse files Browse the repository at this point in the history
Signed-off-by: Stephen Augustus <[email protected]>
  • Loading branch information
justaugustus committed Feb 16, 2022
1 parent d06fff8 commit 2e42e85
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 92 deletions.
114 changes: 114 additions & 0 deletions sccmdrefactor/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
package options

import (
"fmt"
"os"

"github.com/ossf/scorecard/v4/clients"
"github.com/ossf/scorecard/v4/log"
)
Expand All @@ -41,8 +44,119 @@ func New() *Options {

const (
DefaultCommit = clients.HeadSHA

// Formats
FormatJSON = "json"
FormatSarif = "sarif"
FormatDefault = "default"
FormatRaw = "raw"

// Environment variables
EnvVarEnableSarif = "ENABLE_SARIF"
EnvVarScorecardV6 = "SCORECARD_V6"
)

var (
DefaultLogLevel = log.DefaultLevel.String()
)

// TODO(options): Create explicit error types
// TODO(options): Cleanup error messages
func (o *Options) Validate() []error {
var errs []error

// Validate exactly one of `--repo`, `--npm`, `--pypi`, `--rubygems`, `--local` is enabled.
if boolSum(o.Repo != "",
o.NPM != "",
o.PyPI != "",
o.RubyGems != "",
o.Local != "") != 1 {
errs = append(
errs,
fmt.Errorf("Exactly one of `--repo`, `--npm`, `--pypi`, `--rubygems` or `--local` must be set"),
)
}

// Validate SARIF features are flag-guarded.
if !IsSarifEnabled() {
if o.Format == FormatSarif {
errs = append(
errs,
fmt.Errorf("sarif format not supported yet"),
)
}
if o.PolicyFile != "" {
errs = append(
errs,
fmt.Errorf("policy file not supported yet"),
)
}
}

// Validate V6 features are flag-guarded.
if !isV6Enabled() {
if o.Format == FormatRaw {
errs = append(
errs,
fmt.Errorf("raw option not supported yet"),
)
}
if o.Commit != clients.HeadSHA {
errs = append(
errs,
fmt.Errorf("--commit option not supported yet"),
)
}
}

// Validate format.
if !validateFormat(o.Format) {
errs = append(
errs,
fmt.Errorf("unsupported format '%s'", o.Format),
)
}

// Validate `commit` is non-empty.
if o.Commit == "" {
errs = append(
errs,
fmt.Errorf("commit should be non-empty"),
)
}

return errs
}

func boolSum(bools ...bool) int {
sum := 0
for _, b := range bools {
if b {
sum++
}
}
return sum
}

// TODO(options): This probably doesn't need to be exported
func IsSarifEnabled() bool {
// UPGRADEv4: remove.
var sarifEnabled bool
_, sarifEnabled = os.LookupEnv(EnvVarEnableSarif)
return sarifEnabled
}

func isV6Enabled() bool {
var v6 bool
_, v6 = os.LookupEnv(EnvVarScorecardV6)
return v6
}

func validateFormat(format string) bool {
switch format {
case FormatJSON, FormatSarif, FormatDefault, FormatRaw:
return true
default:
return false
}
}
111 changes: 19 additions & 92 deletions sccmdrefactor/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@ import (
)

const (
formatJSON = "json"
formatSarif = "sarif"
formatDefault = "default"
formatRaw = "raw"

cliEnableSarif = "ENABLE_SARIF"

scorecardLong = "A program that shows security scorecard for an open source software."
scorecardUse = `./scorecard [--repo=<repo_url>] [--local=folder] [--checks=check1,...]
[--show-details] or ./scorecard --{npm,pypi,rubygems}=<package_name>
Expand Down Expand Up @@ -92,12 +85,13 @@ func init() {
rootCmd.Flags().StringSliceVar(&opts.ChecksToRun, "checks", []string{},
fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ",")))

if isSarifEnabled() {
// TODO(cmd): Extract logic
if options.IsSarifEnabled() {
rootCmd.Flags().StringVar(&opts.PolicyFile, "policy", "", "policy to enforce")
rootCmd.Flags().StringVar(&opts.Format, "format", formatDefault,
rootCmd.Flags().StringVar(&opts.Format, "format", options.FormatDefault,
"output format allowed values are [default, sarif, json]")
} else {
rootCmd.Flags().StringVar(&opts.Format, "format", formatDefault,
rootCmd.Flags().StringVar(&opts.Format, "format", options.FormatDefault,
"output format allowed values are [default, json]")
}
}
Expand All @@ -116,8 +110,14 @@ func scorecardCmd(cmd *cobra.Command, args []string) {

// TODO(cmd): Is `args` required?
func RunScorecard(args []string) {
// TODO(cmd): Extract logic
validateCmdFlags()
// TODO(cmd): Catch validation errors
valErrs := opts.Validate()
if len(valErrs) != 0 {
log.Panicf(
"the following validation errors occurred: %+v",
valErrs,
)
}

// Set `repo` from package managers.
pkgResp, err := fetchGitRepositoryFromPackageManagers(opts.NPM, opts.PyPI, opts.RubyGems)
Expand Down Expand Up @@ -163,13 +163,13 @@ func RunScorecard(args []string) {
log.Panic(err)
}

if opts.Format == formatDefault {
if opts.Format == options.FormatDefault {
for checkName := range enabledChecks {
fmt.Fprintf(os.Stderr, "Starting [%s]\n", checkName)
}
}

repoResult, err := pkg.RunScorecards(ctx, repoURI, opts.Commit, opts.Format == formatRaw, enabledChecks, repoClient,
repoResult, err := pkg.RunScorecards(ctx, repoURI, opts.Commit, opts.Format == options.FormatRaw, enabledChecks, repoClient,
ossFuzzRepoClient, ciiClient, vulnsClient)
if err != nil {
log.Panic(err)
Expand All @@ -181,22 +181,22 @@ func RunScorecard(args []string) {
return repoResult.Checks[i].Name < repoResult.Checks[j].Name
})

if opts.Format == formatDefault {
if opts.Format == options.FormatDefault {
for checkName := range enabledChecks {
fmt.Fprintf(os.Stderr, "Finished [%s]\n", checkName)
}
fmt.Println("\nRESULTS\n-------")
}

switch opts.Format {
case formatDefault:
case options.FormatDefault:
err = repoResult.AsString(opts.ShowDetails, sclog.Level(opts.LogLevel), checkDocs, os.Stdout)
case formatSarif:
case options.FormatSarif:
// TODO: support config files and update checker.MaxResultScore.
err = repoResult.AsSARIF(opts.ShowDetails, sclog.Level(opts.LogLevel), os.Stdout, checkDocs, policy)
case formatJSON:
case options.FormatJSON:
err = repoResult.AsJSON2(opts.ShowDetails, sclog.Level(opts.LogLevel), checkDocs, os.Stdout)
case formatRaw:
case options.FormatRaw:
err = repoResult.AsRawJSON(os.Stdout)
default:
err = sce.WithMessage(sce.ErrScorecardInternal,
Expand All @@ -207,79 +207,6 @@ func RunScorecard(args []string) {
}
}

func validateCmdFlags() {
// Validate exactly one of `--repo`, `--npm`, `--pypi`, `--rubygems`, `--local` is enabled.
if boolSum(opts.Repo != "",
opts.NPM != "",
opts.PyPI != "",
opts.RubyGems != "",
opts.Local != "") != 1 {
log.Panic("Exactly one of `--repo`, `--npm`, `--pypi`, `--rubygems` or `--local` must be set")
}

// Validate SARIF features are flag-guarded.
if !isSarifEnabled() {
if opts.Format == formatSarif {
log.Panic("sarif format not supported yet")
}
if opts.PolicyFile != "" {
log.Panic("policy file not supported yet")
}
}

// Validate V6 features are flag-guarded.
if !isV6Enabled() {
if opts.Format == formatRaw {
log.Panic("raw option not supported yet")
}
if opts.Commit != clients.HeadSHA {
log.Panic("--commit option not supported yet")
}
}

// Validate format.
if !validateFormat(opts.Format) {
log.Panicf("unsupported format '%s'", opts.Format)
}

// Validate `commit` is non-empty.
if opts.Commit == "" {
log.Panic("commit should be non-empty")
}
}

func boolSum(bools ...bool) int {
sum := 0
for _, b := range bools {
if b {
sum++
}
}
return sum
}

func isSarifEnabled() bool {
// UPGRADEv4: remove.
var sarifEnabled bool
_, sarifEnabled = os.LookupEnv(cliEnableSarif)
return sarifEnabled
}

func isV6Enabled() bool {
var v6 bool
_, v6 = os.LookupEnv("SCORECARD_V6")
return v6
}

func validateFormat(format string) bool {
switch format {
case formatJSON, formatSarif, formatDefault, formatRaw:
return true
default:
return false
}
}

func readPolicy() (*spol.ScorecardPolicy, error) {
if opts.PolicyFile != "" {
data, err := os.ReadFile(opts.PolicyFile)
Expand Down

0 comments on commit 2e42e85

Please sign in to comment.