From 84cdc8cbec4325bc528f9c3c8904f1b82bd567df Mon Sep 17 00:00:00 2001 From: "Stephen Augustus (he/him)" Date: Wed, 2 Mar 2022 00:18:44 -0500 Subject: [PATCH] :sparkles: cmd: Refactor to make importable (#1696) * cmd: Refactor to make importable * options: Add support for parsing via environment variables * options: Support setting feature flags via option * cmd: Replace `version` with sigs.k8s.io/release-utils/version * cmd: Move option validation into pre-run function Signed-off-by: Stephen Augustus --- cmd/root.go | 104 +++++++++++------------------------ cmd/serve.go | 126 +++++++++++++++++++++---------------------- cmd/version.go | 44 --------------- go.mod | 7 ++- go.sum | 26 +++++++++ main.go | 10 +++- options/flags.go | 132 +++++++++++++++++++++++++++++++++++++++++++++ options/options.go | 93 +++++++++++++++++++++++--------- 8 files changed, 333 insertions(+), 209 deletions(-) delete mode 100644 cmd/version.go create mode 100644 options/flags.go diff --git a/cmd/root.go b/cmd/root.go index 5d8db411791..6c811981ad9 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -24,9 +24,9 @@ import ( "strings" "github.com/spf13/cobra" + "sigs.k8s.io/release-utils/version" "github.com/ossf/scorecard/v4/checker" - "github.com/ossf/scorecard/v4/checks" "github.com/ossf/scorecard/v4/clients" docs "github.com/ossf/scorecard/v4/docs/checks" sclog "github.com/ossf/scorecard/v4/log" @@ -35,6 +35,8 @@ import ( "github.com/ossf/scorecard/v4/policy" ) +var opts = options.New() + const ( scorecardLong = "A program that shows security scorecard for an open source software." scorecardUse = `./scorecard [--repo=] [--local=folder] [--checks=check1,...] @@ -43,80 +45,36 @@ const ( scorecardShort = "Security Scorecards" ) -var rootCmd = &cobra.Command{ - Use: scorecardUse, - Short: scorecardShort, - Long: scorecardLong, - Run: scorecardCmd, -} - -var opts = options.New() - -//nolint:gochecknoinits -func init() { - rootCmd.Flags().StringVar(&opts.Repo, "repo", "", "repository to check") - rootCmd.Flags().StringVar(&opts.Local, "local", "", "local folder to check") - rootCmd.Flags().StringVar(&opts.Commit, "commit", options.DefaultCommit, "commit to analyze") - rootCmd.Flags().StringVar( - &opts.LogLevel, - "verbosity", - options.DefaultLogLevel, - "set the log level", - ) - rootCmd.Flags().StringVar( - &opts.NPM, "npm", "", - "npm package to check, given that the npm package has a GitHub repository") - rootCmd.Flags().StringVar( - &opts.PyPI, "pypi", "", - "pypi package to check, given that the pypi package has a GitHub repository") - rootCmd.Flags().StringVar( - &opts.RubyGems, "rubygems", "", - "rubygems package to check, given that the rubygems package has a GitHub repository") - rootCmd.Flags().StringSliceVar( - &opts.Metadata, "metadata", []string{}, "metadata for the project. It can be multiple separated by commas") - rootCmd.Flags().BoolVar(&opts.ShowDetails, "show-details", false, "show extra details about each check") - checkNames := []string{} - for checkName := range checks.GetAll() { - checkNames = append(checkNames, checkName) - } - rootCmd.Flags().StringSliceVar(&opts.ChecksToRun, "checks", []string{}, - fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ","))) - - // TODO(cmd): Extract logic - if options.IsSarifEnabled() { - rootCmd.Flags().StringVar(&opts.PolicyFile, "policy", "", "policy to enforce") - rootCmd.Flags().StringVar(&opts.Format, "format", options.FormatDefault, - "output format allowed values are [default, sarif, json]") - } else { - rootCmd.Flags().StringVar(&opts.Format, "format", options.FormatDefault, - "output format allowed values are [default, json]") - } -} - -// Execute runs the Scorecard commandline. -func Execute() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func scorecardCmd(cmd *cobra.Command, args []string) { - RunScorecard(args) +// New creates a new instance of the scorecard command. +func New() *cobra.Command { + cmd := &cobra.Command{ + Use: scorecardUse, + Short: scorecardShort, + Long: scorecardLong, + PreRunE: func(cmd *cobra.Command, args []string) error { + err := opts.Validate() + if err != nil { + return fmt.Errorf("validating options: %w", err) + } + + return nil + }, + // TODO(cmd): Consider using RunE here + Run: func(cmd *cobra.Command, args []string) { + rootCmd(opts) + }, + } + + opts.AddFlags(cmd) + + // Add sub-commands. + cmd.AddCommand(serveCmd()) + cmd.AddCommand(version.Version()) + return cmd } -// RunScorecard runs scorecard checks given a set of arguments. -// TODO(cmd): Is `args` required? -func RunScorecard(args []string) { - // TODO(cmd): Catch validation errors - valErrs := opts.Validate() - if len(valErrs) != 0 { - log.Panicf( - "the following validation errors occurred: %+v", - valErrs, - ) - } - +// rootCmd runs scorecard checks given a set of arguments. +func rootCmd(opts *options.Options) { // Set `repo` from package managers. pkgResp, err := fetchGitRepositoryFromPackageManagers(opts.NPM, opts.PyPI, opts.RubyGems) if err != nil { diff --git a/cmd/serve.go b/cmd/serve.go index 7036631259b..f9c770f72e6 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -30,79 +30,77 @@ import ( "github.com/ossf/scorecard/v4/pkg" ) -//nolint:gochecknoinits -func init() { - rootCmd.AddCommand(serveCmd) -} - -var serveCmd = &cobra.Command{ - Use: "serve", - Short: "Serve the scorecard program over http", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { - logger := log.NewLogger(log.ParseLevel(opts.LogLevel)) - - t, err := template.New("webpage").Parse(tpl) - if err != nil { - // TODO(log): Should this actually panic? - logger.Error(err, "parsing webpage template") - panic(err) - } +// TODO(cmd): Determine if this should be exported. +func serveCmd() *cobra.Command { + return &cobra.Command{ + Use: "serve", + Short: "Serve the scorecard program over http", + Long: ``, + Run: func(cmd *cobra.Command, args []string) { + logger := log.NewLogger(log.ParseLevel(opts.LogLevel)) - http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { - repoParam := r.URL.Query().Get("repo") - const length = 3 - s := strings.SplitN(repoParam, "/", length) - if len(s) != length { - rw.WriteHeader(http.StatusBadRequest) - } - repo, err := githubrepo.MakeGithubRepo(repoParam) + t, err := template.New("webpage").Parse(tpl) if err != nil { - rw.WriteHeader(http.StatusBadRequest) - } - ctx := r.Context() - repoClient := githubrepo.CreateGithubRepoClient(ctx, logger) - ossFuzzRepoClient, err := githubrepo.CreateOssFuzzRepoClient(ctx, logger) - vulnsClient := clients.DefaultVulnerabilitiesClient() - if err != nil { - logger.Error(err, "initializing clients") - rw.WriteHeader(http.StatusInternalServerError) - } - defer ossFuzzRepoClient.Close() - ciiClient := clients.DefaultCIIBestPracticesClient() - repoResult, err := pkg.RunScorecards( - ctx, repo, clients.HeadSHA /*commitSHA*/, false /*raw*/, checks.AllChecks, repoClient, - ossFuzzRepoClient, ciiClient, vulnsClient) - if err != nil { - logger.Error(err, "running enabled scorecard checks on repo") - rw.WriteHeader(http.StatusInternalServerError) + // TODO(log): Should this actually panic? + logger.Error(err, "parsing webpage template") + panic(err) } - if r.Header.Get("Content-Type") == "application/json" { - if err := repoResult.AsJSON(opts.ShowDetails, log.ParseLevel(opts.LogLevel), rw); err != nil { + http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { + repoParam := r.URL.Query().Get("repo") + const length = 3 + s := strings.SplitN(repoParam, "/", length) + if len(s) != length { + rw.WriteHeader(http.StatusBadRequest) + } + repo, err := githubrepo.MakeGithubRepo(repoParam) + if err != nil { + rw.WriteHeader(http.StatusBadRequest) + } + ctx := r.Context() + repoClient := githubrepo.CreateGithubRepoClient(ctx, logger) + ossFuzzRepoClient, err := githubrepo.CreateOssFuzzRepoClient(ctx, logger) + vulnsClient := clients.DefaultVulnerabilitiesClient() + if err != nil { + logger.Error(err, "initializing clients") + rw.WriteHeader(http.StatusInternalServerError) + } + defer ossFuzzRepoClient.Close() + ciiClient := clients.DefaultCIIBestPracticesClient() + repoResult, err := pkg.RunScorecards( + ctx, repo, clients.HeadSHA /*commitSHA*/, false /*raw*/, checks.AllChecks, repoClient, + ossFuzzRepoClient, ciiClient, vulnsClient) + if err != nil { + logger.Error(err, "running enabled scorecard checks on repo") + rw.WriteHeader(http.StatusInternalServerError) + } + + if r.Header.Get("Content-Type") == "application/json" { + if err := repoResult.AsJSON(opts.ShowDetails, log.ParseLevel(opts.LogLevel), rw); err != nil { + // TODO(log): Improve error message + logger.Error(err, "") + rw.WriteHeader(http.StatusInternalServerError) + } + return + } + if err := t.Execute(rw, repoResult); err != nil { // TODO(log): Improve error message logger.Error(err, "") - rw.WriteHeader(http.StatusInternalServerError) } - return + }) + port := os.Getenv("PORT") + if port == "" { + port = "8080" } - if err := t.Execute(rw, repoResult); err != nil { - // TODO(log): Improve error message - logger.Error(err, "") + fmt.Printf("Listening on localhost:%s\n", port) + err = http.ListenAndServe(fmt.Sprintf("0.0.0.0:%s", port), nil) + if err != nil { + // TODO(log): Should this actually panic? + logger.Error(err, "listening and serving") + panic(err) } - }) - port := os.Getenv("PORT") - if port == "" { - port = "8080" - } - fmt.Printf("Listening on localhost:%s\n", port) - err = http.ListenAndServe(fmt.Sprintf("0.0.0.0:%s", port), nil) - if err != nil { - // TODO(log): Should this actually panic? - logger.Error(err, "listening and serving") - panic(err) - } - }, + }, + } } const tpl = ` diff --git a/cmd/version.go b/cmd/version.go deleted file mode 100644 index d12e065021b..00000000000 --- a/cmd/version.go +++ /dev/null @@ -1,44 +0,0 @@ -// 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 cmd - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/ossf/scorecard/v4/pkg" -) - -//nolint:gochecknoinits -func init() { - rootCmd.AddCommand(versionCmd) -} - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print version information", - Long: ``, - Run: func(cmd *cobra.Command, args []string) { - // not using logger, since it prints timing info, etc - fmt.Printf("GitVersion:\t%s\n", pkg.GetTagVersion()) - fmt.Printf("GitCommit:\t%s\n", pkg.GetCommit()) - fmt.Printf("GitTreeState:\t%s\n", pkg.GetTreeState()) - fmt.Printf("BuildDate:\t%s\n", pkg.GetBuildDate()) - fmt.Printf("GoVersion:\t%s\n", pkg.GetGoVersion()) - fmt.Printf("Compiler:\t%s\n", pkg.GetCompiler()) - fmt.Printf("Platform:\t%s/%s\n", pkg.GetOS(), pkg.GetArch()) - }, -} diff --git a/go.mod b/go.mod index 7667ce44166..deeef06d3f7 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,11 @@ require ( mvdan.cc/sh/v3 v3.4.3 ) -require github.com/onsi/ginkgo/v2 v2.1.3 +require ( + github.com/caarlos0/env/v6 v6.9.1 + github.com/onsi/ginkgo/v2 v2.1.3 + sigs.k8s.io/release-utils v0.5.0 +) require ( cloud.google.com/go v0.100.2 // indirect @@ -56,6 +60,7 @@ require ( github.com/acomagu/bufpipe v1.0.3 // indirect github.com/aws/aws-sdk-go v1.40.34 // indirect github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect + github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect github.com/containerd/stargz-snapshotter/estargz v0.10.1 // indirect github.com/containerd/typeurl v1.0.2 // indirect github.com/docker/cli v20.10.12+incompatible // indirect diff --git a/go.sum b/go.sum index c93c4ad6dd1..31d63dea67e 100644 --- a/go.sum +++ b/go.sum @@ -125,6 +125,7 @@ github.com/Azure/go-amqp v0.13.0/go.mod h1:qj+o8xPCz9tMSbQ83Vp8boHahuRDl5mkNHyt1 github.com/Azure/go-amqp v0.13.11/go.mod h1:D5ZrjQqB1dyp1A+G73xeL/kNn7D5qHJIIsNNps7YNmk= github.com/Azure/go-amqp v0.13.12/go.mod h1:D5ZrjQqB1dyp1A+G73xeL/kNn7D5qHJIIsNNps7YNmk= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.15.5+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= @@ -229,6 +230,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -303,7 +305,10 @@ github.com/bradleyfalzon/ghinstallation/v2 v2.0.4 h1:tXKVfhE7FcSkhkv0UwkLvPDeZ4k github.com/bradleyfalzon/ghinstallation/v2 v2.0.4/go.mod h1:B40qPqJxWE0jDZgOR1JmaMy+4AY1eBP+IByOvqyAKp0= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= +github.com/caarlos0/env/v6 v6.9.1 h1:zOkkjM0F6ltnQ5eBX6IPI41UP/KDGEK7rRPwGCNos8k= +github.com/caarlos0/env/v6 v6.9.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= +github.com/carolynvs/magex v0.6.0/go.mod h1:hqaEkr9TAv+kFb/5wgDiTdszF13rpe0Q+bWHmTe6N74= github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -338,6 +343,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= +github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= @@ -499,6 +506,8 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/libnetwork v0.8.0-dev.2.0.20200917202933-d0951081b35f/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvyukov/go-fuzz v0.0.0-20210914135545-4980593459a1/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= @@ -673,6 +682,7 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= @@ -925,6 +935,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= @@ -932,6 +943,7 @@ github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -957,6 +969,7 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= +github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -1002,7 +1015,9 @@ github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpe github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/maxbrunsfeld/counterfeiter/v6 v6.4.1/go.mod h1:DK1Cjkc0E49ShgRVs5jy5ASrM15svSnem3K/hiSGD8o= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc= github.com/miekg/dns v1.1.25-0.20191211073109-8ebf2e419df7/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= @@ -1035,6 +1050,7 @@ github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGq github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2/go.mod h1:TjQg8pa4iejrUrjiz0MCtMV38jdMNW4doKSiBrEvCQQ= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -1053,6 +1069,7 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+ github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -1084,6 +1101,7 @@ github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= @@ -1130,6 +1148,7 @@ github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1210,6 +1229,7 @@ github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43 github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= github.com/satori/go.uuid v1.2.1-0.20181016170032-d91630c85102/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/securego/gosec v0.0.0-20200103095621-79fbf3af8d83/go.mod h1:vvbZ2Ae7AzSq3/kywjUDxSNq2SJ27RxCz2un0H3ePqE= @@ -1522,12 +1542,14 @@ golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= +golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= @@ -2028,6 +2050,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -2130,6 +2153,7 @@ k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuB k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= @@ -2150,6 +2174,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/release-utils v0.5.0 h1:TVJUoFLjfYYdJ11+mIw6eb44XIOC5BI3QQKiKYCtk/8= +sigs.k8s.io/release-utils v0.5.0/go.mod h1:t9pL38kZkTBVDcjL1y7ajrkNQFLiArVAjOVO0sxzFF0= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= diff --git a/main.go b/main.go index 9c9b5959b62..85612083d2c 100644 --- a/main.go +++ b/main.go @@ -15,8 +15,14 @@ // Package main of OSSF Scoreard. package main -import "github.com/ossf/scorecard/v4/cmd" +import ( + "log" + + "github.com/ossf/scorecard/v4/cmd" +) func main() { - cmd.Execute() + if err := cmd.New().Execute(); err != nil { + log.Fatalf("error during command execution: %v", err) + } } diff --git a/options/flags.go b/options/flags.go new file mode 100644 index 00000000000..f0a204104b5 --- /dev/null +++ b/options/flags.go @@ -0,0 +1,132 @@ +// Copyright OpenSSF 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 options + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + + "github.com/ossf/scorecard/v4/checks" +) + +// Command is an interface for handling options for command-line utilities. +type Command interface { + // AddFlags adds this options' flags to the cobra command. + AddFlags(cmd *cobra.Command) +} + +// AddFlags adds this options' flags to the cobra command. +func (o *Options) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVar( + &o.Repo, + "repo", + "", + "repository to check", + ) + + cmd.Flags().StringVar( + &o.Local, + "local", + "", + "local folder to check", + ) + + // TODO(v5): Should this be behind a feature flag? + cmd.Flags().StringVar( + &o.Commit, + "commit", + DefaultCommit, + "commit to analyze", + ) + + cmd.Flags().StringVar( + &o.LogLevel, + "verbosity", + DefaultLogLevel, + "set the log level", + ) + + cmd.Flags().StringVar( + &o.NPM, + "npm", + "", + "npm package to check, given that the npm package has a GitHub repository", + ) + + cmd.Flags().StringVar( + &o.PyPI, + "pypi", + "", + "pypi package to check, given that the pypi package has a GitHub repository", + ) + + cmd.Flags().StringVar( + &o.RubyGems, + "rubygems", + "", + "rubygems package to check, given that the rubygems package has a GitHub repository", + ) + + cmd.Flags().StringSliceVar( + &o.Metadata, + "metadata", + []string{}, + "metadata for the project. It can be multiple separated by commas", + ) + + cmd.Flags().BoolVar( + &o.ShowDetails, + "show-details", + false, + "show extra details about each check", + ) + + checkNames := []string{} + for checkName := range checks.GetAll() { + checkNames = append(checkNames, checkName) + } + cmd.Flags().StringSliceVar( + &o.ChecksToRun, + "checks", + []string{}, + fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ",")), + ) + + // TODO(options): Extract logic + if o.isSarifEnabled() { + cmd.Flags().StringVar( + &o.PolicyFile, + "policy", + "", + "policy to enforce", + ) + + cmd.Flags().StringVar( + &o.Format, + "format", + FormatDefault, + "output format allowed values are [default, sarif, json]", + ) + } else { + cmd.Flags().StringVar( + &o.Format, + "format", + FormatDefault, + "output format allowed values are [default, json]", + ) + } +} diff --git a/options/options.go b/options/options.go index 84846ec5ed7..488d251dda7 100644 --- a/options/options.go +++ b/options/options.go @@ -17,31 +17,48 @@ package options import ( "errors" + "fmt" "os" + "github.com/caarlos0/env/v6" + "github.com/ossf/scorecard/v4/clients" "github.com/ossf/scorecard/v4/log" ) // Options define common options for configuring scorecard. type Options struct { - Repo string - Local string - Commit string - LogLevel string - Format string - NPM string - PyPI string - RubyGems string - PolicyFile string - ChecksToRun []string + Repo string `env:"GITHUB_REPOSITORY"` + Local string + Commit string `env:"GITHUB_REF"` + LogLevel string + Format string `env:"SCORECARD_RESULTS_FORMAT"` + NPM string + PyPI string + RubyGems string + PolicyFile string `env:"SCORECARD_POLICY_FILE"` + // TODO(action): Add logic for writing results to file + ResultsFile string `env:"SCORECARD_RESULTS_FILE"` + ChecksToRun []string `env:"SCORECARD_ENABLED_CHECKS"` Metadata []string ShowDetails bool + // TODO(action): Add logic for determining if results should be published. + PublishResults bool `env:"SCORECARD_PUBLISH_RESULTS"` + + // Feature flags. + EnableSarif bool `env:"ENABLE_SARIF"` + EnableScorecardV5 bool `env:"SCORECARD_V5"` + EnableScorecardV6 bool `env:"SCORECARD_V6"` } // New creates a new instance of `Options`. func New() *Options { - return &Options{} + opts := &Options{} + if err := env.Parse(opts); err != nil { + fmt.Printf("could not parse env vars, using default options: %v", err) + } + + return opts } const ( @@ -64,6 +81,9 @@ const ( // EnvVarEnableSarif is the environment variable which controls enabling // SARIF logging. EnvVarEnableSarif = "ENABLE_SARIF" + // EnvVarScorecardV5 is the environment variable which enables scorecard v5 + // options. + EnvVarScorecardV5 = "SCORECARD_V5" // EnvVarScorecardV6 is the environment variable which enables scorecard v6 // options. EnvVarScorecardV6 = "SCORECARD_V6" @@ -82,11 +102,12 @@ var ( "exactly one of `repo`, `npm`, `pypi`, `rubygems` or `local` must be set", ) errSARIFNotSupported = errors.New("SARIF format is not supported yet") + errValidate = errors.New("some options could not be validated") ) // Validate validates scorecard configuration options. // TODO(options): Cleanup error messages. -func (o *Options) Validate() []error { +func (o *Options) Validate() error { var errs []error // Validate exactly one of `--repo`, `--npm`, `--pypi`, `--rubygems`, `--local` is enabled. @@ -102,7 +123,7 @@ func (o *Options) Validate() []error { } // Validate SARIF features are flag-guarded. - if !IsSarifEnabled() { + if !o.isSarifEnabled() { if o.Format == FormatSarif { errs = append( errs, @@ -117,8 +138,13 @@ func (o *Options) Validate() []error { } } + // Validate V5 features are flag-guarded. + if !o.isV5Enabled() { //nolint:staticcheck + // TODO(v5): Populate v5 feature flags. + } + // Validate V6 features are flag-guarded. - if !isV6Enabled() { + if !o.isV6Enabled() { if o.Format == FormatRaw { errs = append( errs, @@ -149,7 +175,15 @@ func (o *Options) Validate() []error { ) } - return errs + if len(errs) != 0 { + return fmt.Errorf( + "%w: %+v", + errValidate, + errs, + ) + } + + return nil } func boolSum(bools ...bool) int { @@ -162,19 +196,28 @@ func boolSum(bools ...bool) int { return sum } -// IsSarifEnabled returns true if `EnvVarEnableSarif` is specified. -// TODO(options): This probably doesn't need to be exported. -func IsSarifEnabled() bool { +// Feature flags. + +// isSarifEnabled returns true if SARIF format was specified in options or via +// environment variable. +func (o *Options) isSarifEnabled() bool { // UPGRADEv4: remove. - var sarifEnabled bool - _, sarifEnabled = os.LookupEnv(EnvVarEnableSarif) - return sarifEnabled + _, enabled := os.LookupEnv(EnvVarEnableSarif) + return o.EnableSarif || enabled +} + +// isV5Enabled returns true if v5 functionality was specified in options or via +// environment variable. +func (o *Options) isV5Enabled() bool { + _, enabled := os.LookupEnv(EnvVarScorecardV5) + return o.EnableScorecardV5 || enabled } -func isV6Enabled() bool { - var v6 bool - _, v6 = os.LookupEnv(EnvVarScorecardV6) - return v6 +// isV6Enabled returns true if v6 functionality was specified in options or via +// environment variable. +func (o *Options) isV6Enabled() bool { + _, enabled := os.LookupEnv(EnvVarScorecardV6) + return o.EnableScorecardV6 || enabled } func validateFormat(format string) bool {