Skip to content

Commit

Permalink
[Breaking Changes] Switch to Use Cobra/Viper for CLI and Config Handl…
Browse files Browse the repository at this point in the history
…ing (#64)
  • Loading branch information
SUSTAPLE117 authored May 8, 2024
1 parent e0d6048 commit a7fa79b
Show file tree
Hide file tree
Showing 10 changed files with 428 additions and 248 deletions.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
### Usage
``` bash
poutine [options] [command] [arguments]
poutine [command] [arguments] [options]
```

#### Analyze a local repository
Expand All @@ -77,31 +77,31 @@ poutine analyze_local .
#### Analyze a remote GitHub repository

```bash
poutine -token "$GH_TOKEN" analyze_repo org/repo
poutine analyze_repo org/repo --token "$GH_TOKEN"
```

#### Analyze all repositories in a GitHub organization

```bash
poutine -token "$GH_TOKEN" analyze_org org
poutine analyze_org org --token "$GH_TOKEN"
```


#### Analyze all projects in a self-hosted Gitlab instance

``` bash
poutine -token "$GL_TOKEN" -scm gitlab -scm-base-uri https://gitlab.example.com analyze_org my-org/project
poutine analyze_org my-org/project --token "$GL_TOKEN" --scm gitlab --scm-base-uri https://gitlab.example.com
```

### Configuration Options

```
-token SCM access token (required for the commands analyze_repo, analyze_org) (env: GH_TOKEN)
-format Output format (default: pretty, json, sarif)
-scm SCM platform (default: github, gitlab)
-scm-base-uri Base URI of the self-hosted SCM instance
-threads Number of threads to use (default: 2)
-verbose Enable debug logging
--token SCM access token (required for the commands analyze_repo, analyze_org) (env: GH_TOKEN)
--format Output format (default: pretty, json, sarif)
--scm SCM platform (default: github, gitlab)
--scm-base-uri Base URI of the self-hosted SCM instance
--threads Number of threads to use (default: 2)
--verbose Enable debug logging
```

## Building from source
Expand All @@ -120,7 +120,7 @@ For examples of vulnerabilities in GitHub Actions workflows, you can explore the

To get started with some hints, try using `poutine` to analyze the `messypoutine` organization:
``` bash
poutine -token `gh auth token` analyze_org messypoutine
poutine analyze_org messypoutine --token `gh auth token`
```

You may submit the flags you find in a [private vulnerability disclosure](https://github.com/messypoutine/.github/security/advisories/new).
Expand Down
30 changes: 6 additions & 24 deletions analyze/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,14 @@ import (
"sync"
"time"

"github.com/rs/zerolog/log"
"gopkg.in/yaml.v3"

"github.com/boostsecurityio/poutine/opa"
"github.com/boostsecurityio/poutine/providers/pkgsupply"
"github.com/boostsecurityio/poutine/scanner"
"github.com/rs/zerolog/log"
"github.com/schollz/progressbar/v3"
)

const TEMP_DIR_PREFIX = "poutine-*"
const CONFIG_PATH = ".poutine.yml"

type Repository interface {
GetProviderName() string
Expand Down Expand Up @@ -53,12 +50,15 @@ type GitClient interface {
GetRepoHeadBranchName(ctx context.Context, repoPath string) (string, error)
}

func NewAnalyzer(scmClient ScmClient, gitClient GitClient, formatter Formatter) *Analyzer {
func NewAnalyzer(scmClient ScmClient, gitClient GitClient, formatter Formatter, config *models.Config) *Analyzer {
if config == nil {
config = &models.Config{}
}
return &Analyzer{
ScmClient: scmClient,
GitClient: gitClient,
Formatter: formatter,
Config: &models.Config{},
Config: config,
}
}

Expand Down Expand Up @@ -267,24 +267,6 @@ func (a *Analyzer) AnalyzeLocalRepo(ctx context.Context, repoPath string) error
return a.finalizeAnalysis(ctx, inventory)
}

func (a *Analyzer) LoadConfig(path string) error {
f, err := os.Open(path)
if err != nil {
if os.IsNotExist(err) {
log.Debug().Msgf("Config file `%s` not found, using default config", path)
return nil
}
return err
}

err = yaml.NewDecoder(f).Decode(a.Config)
if err != nil {
return err
}

return nil
}

type Formatter interface {
Format(ctx context.Context, report *opa.FindingsResult, packages []*models.PackageInsights) error
}
Expand Down
45 changes: 45 additions & 0 deletions cmd/analyzeLocal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package cmd

import (
"fmt"
"github.com/boostsecurityio/poutine/analyze"
"github.com/boostsecurityio/poutine/providers/gitops"
"github.com/boostsecurityio/poutine/providers/local"

"github.com/spf13/cobra"
)

// analyzeLocalCmd represents the analyzeLocal command
var analyzeLocalCmd = &cobra.Command{
Use: "analyze_local",
Short: "Analyzes a local repository for supply chain vulnerabilities",
Long: `Analyzes a local repository for supply chain vulnerabilities
Example: poutine analyze_local /path/to/repo`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
repoPath := args[0]

formatter := GetFormatter()

localScmClient, err := local.NewGitSCMClient(ctx, repoPath, nil)
if err != nil {
return fmt.Errorf("failed to create local SCM client: %w", err)
}

localGitClient := gitops.NewLocalGitClient(nil)

analyzer := analyze.NewAnalyzer(localScmClient, localGitClient, formatter, config)

err = analyzer.AnalyzeLocalRepo(ctx, repoPath)
if err != nil {
return fmt.Errorf("failed to analyze repoPath %s: %w", repoPath, err)
}

return nil
},
}

func init() {
rootCmd.AddCommand(analyzeLocalCmd)
}
52 changes: 52 additions & 0 deletions cmd/analyzeOrg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package cmd

import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var threads int

// analyzeOrgCmd represents the analyzeOrg command
var analyzeOrgCmd = &cobra.Command{
Use: "analyze_org",
Short: "Analyzes an organization's repositories for supply chain vulnerabilities",
Long: `Analyzes an organization's repositories for supply chain vulnerabilities
Example: poutine analyze_org org --token "$GH_TOKEN"
Analyze All Projects in a Self-Hosted Gitlab Organization:
poutine analyze_org my-org/project --token "$GL_TOKEN" --scm gitlab --scm-base-uri https://gitlab.example.com
Note: This command will scan all repositories in the organization except those that are Archived.
`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
token = viper.GetString("token")
ctx := cmd.Context()
analyzer, err := GetAnalyzer(ctx, "analyze_org")
if err != nil {
return err
}

org := args[0]

err = analyzer.AnalyzeOrg(ctx, org, &threads)
if err != nil {
return fmt.Errorf("failed to analyze org %s: %w", org, err)
}

return nil
},
}

func init() {
rootCmd.AddCommand(analyzeOrgCmd)

analyzeOrgCmd.Flags().StringVarP(&token, "token", "t", "", "SCM access token (env: GH_TOKEN)")

analyzeOrgCmd.Flags().IntVarP(&threads, "threads", "j", 2, "Parallelization factor for scanning organizations")

viper.BindPFlag("token", analyzeOrgCmd.Flags().Lookup("token"))
viper.BindEnv("token", "GH_TOKEN")
}
42 changes: 42 additions & 0 deletions cmd/analyzeRepo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cmd

import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// analyzeRepoCmd represents the analyzeRepo command
var analyzeRepoCmd = &cobra.Command{
Use: "analyze_repo",
Short: "Analyzes a remote repository for supply chain vulnerabilities",
Long: `Analyzes a remote repository for supply chain vulnerabilities
Example Scanning a remote Github Repository: poutine analyze_repo org/repo --token "$GH_TOKEN"`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
token = viper.GetString("token")
ctx := cmd.Context()
analyzer, err := GetAnalyzer(ctx, "analyze_repo")
if err != nil {
return err
}

repo := args[0]

err = analyzer.AnalyzeRepo(ctx, repo)
if err != nil {
return fmt.Errorf("failed to analyze repo %s: %w", repo, err)
}

return nil
},
}

func init() {
rootCmd.AddCommand(analyzeRepoCmd)

analyzeRepoCmd.Flags().StringVarP(&token, "token", "t", "", "SCM access token (env: GH_TOKEN)")

viper.BindPFlag("token", analyzeOrgCmd.Flags().Lookup("token"))
viper.BindEnv("token", "GH_TOKEN")
}
Loading

0 comments on commit a7fa79b

Please sign in to comment.