diff --git a/README.md b/README.md index 1d2c137..0d66c29 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Sheriff is a tool to scan repositories and generate security reports. ## Quick Usage ```sh -sheriff patrol --gitlab-groups your-namespace-or-group --report-gitlab-issue +sheriff patrol --url gitlab://your-namespace-or-group --report-to-issue ``` ## How it works diff --git a/internal/cli/patrol.go b/internal/cli/patrol.go index 47a1af3..9118b31 100644 --- a/internal/cli/patrol.go +++ b/internal/cli/patrol.go @@ -4,11 +4,13 @@ import ( "errors" "fmt" "net/url" + "os/exec" "sheriff/internal/git" "sheriff/internal/gitlab" "sheriff/internal/patrol" "sheriff/internal/scanner" "sheriff/internal/slack" + "strings" "github.com/urfave/cli/v2" "github.com/urfave/cli/v2/altsrc" @@ -35,6 +37,7 @@ const gitlabTokenFlag = "gitlab-token" const slackTokenFlag = "slack-token" var sensitiveFlags = []string{gitlabTokenFlag, slackTokenFlag} +var necessaryScanners = []string{scanner.OsvCommandName} var PatrolFlags = []cli.Flag{ &cli.StringFlag{ @@ -122,6 +125,12 @@ func PatrolAction(cCtx *cli.Context) error { patrolService := patrol.New(gitlabService, slackService, gitService, osvService) + // Check whether the necessary scanners are available + missingScanners := getMissingScanners(necessaryScanners) + if len(missingScanners) > 0 { + return fmt.Errorf("Cannot find all necessary scanners in $PATH, missing: %v", strings.Join(missingScanners, ", ")) + } + // Do the patrol if warn, err := patrolService.Patrol( patrol.PatrolArgs{ @@ -173,3 +182,14 @@ func parseUrls(uris []string) ([]patrol.ProjectLocation, error) { return locations, nil } + +func getMissingScanners(necessary []string) []string { + missingScanners := make([]string, 0, len(necessary)) + for _, scanner := range necessary { + if _, err := exec.LookPath(scanner); err != nil { + missingScanners = append(missingScanners, scanner) + } + } + + return missingScanners +} diff --git a/internal/cli/patrol_test.go b/internal/cli/patrol_test.go index e5028c4..8d54c9f 100644 --- a/internal/cli/patrol_test.go +++ b/internal/cli/patrol_test.go @@ -11,6 +11,14 @@ import ( ) func TestPatrolActionEmptyRun(t *testing.T) { + // Monkey patch necessaryScanners to avoid missing scanners + // during testing + origNecessaryScanners := necessaryScanners + necessaryScanners = []string{} + defer func() { + necessaryScanners = origNecessaryScanners + }() + context := cli.NewContext(cli.NewApp(), flag.NewFlagSet("flagset", flag.ContinueOnError), nil) err := PatrolAction(context) @@ -46,3 +54,20 @@ func TestParseUrls(t *testing.T) { } } } + +func TestGetMissingScanners(t *testing.T) { + testCases := []struct { + scanners []string + want []string + }{ + {[]string{"ls", "missing"}, []string{"missing"}}, + {[]string{"echo", "ls", "missing", "missing-another"}, []string{"missing", "missing-another"}}, + {[]string{"ls"}, []string{}}, + } + + for _, tc := range testCases { + missingScanners := getMissingScanners(tc.scanners) + + assert.Equal(t, tc.want, missingScanners) + } +} diff --git a/internal/scanner/osv.go b/internal/scanner/osv.go index 44fd877..a61e40c 100644 --- a/internal/scanner/osv.go +++ b/internal/scanner/osv.go @@ -12,14 +12,14 @@ import ( gogitlab "github.com/xanzy/go-gitlab" ) -const osvTimeout = 30 * time.Second - type osvReferenceKind string const ( - AdvisoryKind osvReferenceKind = "ADVISORY" - WebKind osvReferenceKind = "WEB" - PackageKind osvReferenceKind = "PACKAGE" + OsvCommandName = "osv-scanner" + AdvisoryKind osvReferenceKind = "ADVISORY" + WebKind osvReferenceKind = "WEB" + PackageKind osvReferenceKind = "PACKAGE" + osvTimeout = 30 * time.Second ) type osvSource struct { @@ -109,7 +109,7 @@ func (s *osvScanner) Scan(dir string) (*OsvReport, error) { cmdOut, err := shell.ShellCommandRunner.Run( shell.CommandInput{ - Name: "osv-scanner", + Name: OsvCommandName, Args: []string{"-r", "--verbosity", "error", "--format", "json", dir}, Timeout: osvTimeout, },