Skip to content

Commit

Permalink
chore: make engine pluggable
Browse files Browse the repository at this point in the history
  • Loading branch information
didroe committed May 29, 2024
1 parent 9947948 commit 2e33681
Show file tree
Hide file tree
Showing 45 changed files with 1,224 additions and 1,056 deletions.
4 changes: 3 additions & 1 deletion cmd/bearer/bearer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (

"github.com/bearer/bearer/cmd/bearer/build"
"github.com/bearer/bearer/internal/commands"
engine "github.com/bearer/bearer/internal/engine/implementation"
"github.com/bearer/bearer/internal/languages"
)

func main() {
app := commands.NewApp(build.Version, build.CommitSHA)
app := commands.NewApp(build.Version, build.CommitSHA, engine.New(languages.Default()))
if err := app.Execute(); err != nil {
// error messages are printed by the framework
os.Exit(1)
Expand Down
5 changes: 3 additions & 2 deletions internal/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ import (
"github.com/spf13/cobra"

"github.com/bearer/bearer/cmd/bearer/build"
"github.com/bearer/bearer/internal/engine"
)

// NewApp is the factory method to return CLI
func NewApp(version string, commitSHA string) *cobra.Command {
func NewApp(version string, commitSHA string, engine engine.Engine) *cobra.Command {
rootCmd := NewRootCommand()
rootCmd.AddCommand(
NewCompletionCommand(),
NewProcessingWorkerCommand(),
NewInitCommand(),
NewScanCommand(),
NewScanCommand(engine),
NewIgnoreCommand(),
NewVersionCommand(version, commitSHA),
)
Expand Down
60 changes: 24 additions & 36 deletions internal/commands/artifact/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import (
"github.com/bearer/bearer/internal/commands/process/filelist"
"github.com/bearer/bearer/internal/commands/process/filelist/files"
"github.com/bearer/bearer/internal/commands/process/gitrepository"
"github.com/bearer/bearer/internal/commands/process/orchestrator"
"github.com/bearer/bearer/internal/commands/process/orchestrator/work"
"github.com/bearer/bearer/internal/commands/process/settings"
settingsloader "github.com/bearer/bearer/internal/commands/process/settings/loader"
"github.com/bearer/bearer/internal/engine"
"github.com/bearer/bearer/internal/flag"
flagtypes "github.com/bearer/bearer/internal/flag/types"
"github.com/bearer/bearer/internal/report/basebranchfindings"
Expand Down Expand Up @@ -71,6 +71,7 @@ type runner struct {
scanSettings settings.Config
stats *scannerstats.Stats
gitContext *gitrepository.Context
engine engine.Engine
}

// NewRunner initializes Runner that provides scanning functionalities.
Expand All @@ -81,13 +82,15 @@ func NewRunner(
targetPath string,
goclocResult *gocloc.Result,
stats *scannerstats.Stats,
engine engine.Engine,
) (Runner, error) {
r := &runner{
scanSettings: scanSettings,
targetPath: targetPath,
goclocResult: goclocResult,
stats: stats,
gitContext: gitContext,
engine: engine,
}

scanID, err := scanid.Build(scanSettings, gitContext)
Expand Down Expand Up @@ -160,24 +163,13 @@ func (r *runner) Scan(ctx context.Context, opts flagtypes.Options) ([]files.File
return nil, nil, err
}

orchestrator, err := orchestrator.New(
work.Repository{Dir: r.targetPath},
r.scanSettings,
r.stats,
len(fileList.Files),
)
if err != nil {
return nil, nil, err
}
defer orchestrator.Close()

var baseBranchFindings *basebranchfindings.Findings
if err := repository.WithBaseBranch(func() error {
if !opts.Quiet {
outputhandler.StdErrLog(fmt.Sprintf("\nScanning base branch %s", r.gitContext.BaseBranch))
}

baseBranchFindings, err = r.scanBaseBranch(orchestrator, fileList)
baseBranchFindings, err = r.scanBaseBranch(fileList)
if err != nil {
return err
}
Expand All @@ -191,24 +183,21 @@ func (r *runner) Scan(ctx context.Context, opts flagtypes.Options) ([]files.File
return nil, nil, err
}

if err := orchestrator.Scan(r.reportPath, fileList.Files); err != nil {
if err := r.engine.Scan(r.stats, r.reportPath, r.targetPath, fileList.Files); err != nil {
return nil, nil, err
}

return fileList.Files, baseBranchFindings, nil
}

func (r *runner) scanBaseBranch(
orchestrator *orchestrator.Orchestrator,
fileList *files.List,
) (*basebranchfindings.Findings, error) {
func (r *runner) scanBaseBranch(fileList *files.List) (*basebranchfindings.Findings, error) {
result := basebranchfindings.New(fileList)

if len(fileList.BaseFiles) == 0 {
return result, nil
}

if err := orchestrator.Scan(r.reportPath+".base", fileList.BaseFiles); err != nil {
if err := r.engine.Scan(r.stats, r.reportPath+".base", r.targetPath, fileList.BaseFiles); err != nil {
return nil, err
}

Expand Down Expand Up @@ -263,7 +252,7 @@ func getIgnoredFingerprints(client *api.API, settings settings.Config, gitContex
}

// Run performs artifact scanning
func Run(ctx context.Context, opts flagtypes.Options) (err error) {
func Run(ctx context.Context, opts flagtypes.Options, engine engine.Engine) (err error) {
targetPath, err := file.CanonicalPath(opts.Target)
if err != nil {
return fmt.Errorf("failed to get absolute target: %w", err)
Expand Down Expand Up @@ -302,7 +291,7 @@ func Run(ctx context.Context, opts flagtypes.Options) (err error) {
outputhandler.StdErrLog("Loading rules")
}

scanSettings, err := settings.FromOptions(opts, versionMeta)
scanSettings, err := settingsloader.FromOptions(opts, versionMeta, engine)
scanSettings.Target = opts.Target
if err != nil {
return err
Expand All @@ -317,6 +306,10 @@ func Run(ctx context.Context, opts flagtypes.Options) (err error) {
return err
}

if err := engine.Initialize(&scanSettings); err != nil {
return fmt.Errorf("failed to initialize engine: %w", err)
}

ctx, cancel := context.WithTimeout(ctx, scanSettings.Worker.Timeout)
defer cancel()

Expand All @@ -331,7 +324,7 @@ func Run(ctx context.Context, opts flagtypes.Options) (err error) {
stats = scannerstats.New()
}

r, err := NewRunner(ctx, scanSettings, gitContext, targetPath, inputgocloc, stats)
r, err := NewRunner(ctx, scanSettings, gitContext, targetPath, inputgocloc, stats, engine)
if err != nil {
return err
}
Expand Down Expand Up @@ -407,11 +400,7 @@ func (r *runner) Report(

endTime := time.Now()

reportSupported, err := anySupportedLanguagesPresent(report.Inputgocloc, r.scanSettings)
if err != nil {
return false, err
}

reportSupported := anySupportedLanguagesPresent(r.engine, report.Inputgocloc, r.scanSettings)
if !reportSupported && r.scanSettings.Report.Report != flag.ReportPrivacy && !r.scanSettings.Scan.Quiet {
var placeholderStr *strings.Builder
placeholderStr, err = getPlaceholderOutput(reportData, report, r.scanSettings, report.Inputgocloc)
Expand All @@ -426,6 +415,7 @@ func (r *runner) Report(
formatStr, err := reportoutput.FormatOutput(
reportData,
r.scanSettings,
r.engine,
report.Inputgocloc,
startTime,
endTime,
Expand Down Expand Up @@ -463,9 +453,9 @@ func (r *runner) ReportPath() string {
return r.reportPath
}

func anySupportedLanguagesPresent(inputgocloc *gocloc.Result, config settings.Config) (bool, error) {
func anySupportedLanguagesPresent(engine engine.Engine, inputgocloc *gocloc.Result, config settings.Config) bool {
if inputgocloc == nil {
return true, nil
return true
}

ruleLanguages := make(map[string]bool)
Expand All @@ -480,16 +470,14 @@ func anySupportedLanguagesPresent(inputgocloc *gocloc.Result, config settings.Co
foundLanguages[strings.ToLower(language.Name)] = true
}

for _, supportedLanguage := range maps.Keys(settings.GetSupportedRuleLanguages()) {
_, supportedLangPresent := foundLanguages[supportedLanguage]

if supportedLangPresent && settings.GetSupportedRuleLanguages()[supportedLanguage] {
return true, nil
for _, supportedLanguage := range engine.GetLanguages() {
if _, supportedLangPresent := foundLanguages[supportedLanguage.ID()]; supportedLangPresent {
return true
}
}

log.Debug().Msg("No language found for which rules are applicable")
return false, nil
return false
}

func getPlaceholderOutput(reportData *outputtypes.ReportData, report types.Report, config settings.Config, inputgocloc *gocloc.Result) (outputStr *strings.Builder, err error) {
Expand Down
2 changes: 1 addition & 1 deletion internal/commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func NewInitCommand() *cobra.Command {
Use: "init",
Short: "Generates a default config to `bearer.yml`",
RunE: func(cmd *cobra.Command, args []string) error {
if err := ScanFlags.BindForConfigInit(NewScanCommand()); err != nil {
if err := ScanFlags.BindForConfigInit(NewScanCommand(nil)); err != nil {
return fmt.Errorf("flag bind error: %w", err)
}

Expand Down
6 changes: 3 additions & 3 deletions internal/commands/process/orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (

type Orchestrator struct {
repository work.Repository
config settings.Config
config *settings.Config
maxWorkersSemaphore chan struct{}
done chan struct{}
pool *pool.Pool
Expand All @@ -33,7 +33,7 @@ type Orchestrator struct {

func New(
repository work.Repository,
config settings.Config,
config *settings.Config,
stats *stats.Stats,
estimatedFileCount int,
) (*Orchestrator, error) {
Expand Down Expand Up @@ -202,7 +202,7 @@ func (orchestrator *Orchestrator) writeFileError(reportFile *os.File, file files
orchestrator.reportMutex.Unlock()
}

func getParallel(fileCount int, config settings.Config) int {
func getParallel(fileCount int, config *settings.Config) int {
if config.Scan.Parallel != 0 {
return config.Scan.Parallel
}
Expand Down
2 changes: 1 addition & 1 deletion internal/commands/process/orchestrator/pool/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Pool struct {
available []*Process
}

func New(config settings.Config, stats *stats.Stats) *Pool {
func New(config *settings.Config, stats *stats.Stats) *Pool {
executable, err := os.Executable()
if err != nil {
output.Fatal(fmt.Sprintf("failed to get current command executable %s", err))
Expand Down
6 changes: 3 additions & 3 deletions internal/commands/process/orchestrator/pool/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type Process struct {
type ProcessOptions struct {
executable string
baseArguments []string
config settings.Config
config *settings.Config
}

func newProcess(options *ProcessOptions, id string) (*Process, error) {
Expand Down Expand Up @@ -88,7 +88,7 @@ func newProcess(options *ProcessOptions, id string) (*Process, error) {
return process, nil
}

func (process *Process) start(config settings.Config) error {
func (process *Process) start(config *settings.Config) error {
if err := process.command.Start(); err != nil {
close(process.exitChannel)
return err
Expand Down Expand Up @@ -201,7 +201,7 @@ func (process *Process) reduceMemoryUsage() {
}
}

func (process *Process) initialize(config settings.Config) error {
func (process *Process) initialize(config *settings.Config) error {
log.Debug().Msgf("%s initializing", process.id)
start := time.Now()
killTime := time.Now().Add(config.Worker.TimeoutWorkerOnline)
Expand Down
78 changes: 78 additions & 0 deletions internal/commands/process/settings/loader/loader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package loader

import (
"errors"
"fmt"
"slices"

"github.com/bearer/bearer/internal/commands/process/settings"
"github.com/bearer/bearer/internal/commands/process/settings/policies"
"github.com/bearer/bearer/internal/commands/process/settings/rules"
"github.com/bearer/bearer/internal/engine"
"github.com/bearer/bearer/internal/flag"
flagtypes "github.com/bearer/bearer/internal/flag/types"
"github.com/bearer/bearer/internal/util/ignore"
"github.com/bearer/bearer/internal/version_check"
)

func FromOptions(
opts flagtypes.Options,
versionMeta *version_check.VersionMeta,
engine engine.Engine,
) (settings.Config, error) {
policies, err := policies.Load()
if err != nil {
return settings.Config{}, fmt.Errorf("failed to load policies: %w", err)
}

result, err := rules.Load(
opts.ExternalRuleDir,
opts.RuleOptions,
versionMeta,
engine,
opts.ScanOptions.Force,
)
if err != nil {
return settings.Config{}, err
}

ignoredFingerprints, _, _, err := ignore.GetIgnoredFingerprints(opts.GeneralOptions.IgnoreFile, &opts.ScanOptions.Target)
if err != nil {
return settings.Config{}, err
}

config := settings.Config{
Client: opts.Client,
Worker: settings.WorkerOptions{
Timeout: settings.Timeout,
TimeoutFileMinimum: settings.TimeoutFileMinimum,
TimeoutFileMaximum: settings.TimeoutFileMaximum,
TimeoutFileBytesPerSecond: settings.TimeoutFileBytesPerSecond,
TimeoutWorkerOnline: settings.TimeoutWorkerOnline,
FileSizeMaximum: settings.FileSizeMaximum,
ExistingWorker: settings.ExistingWorker,
},
Scan: opts.ScanOptions,
Report: opts.ReportOptions,
IgnoredFingerprints: ignoredFingerprints,
NoColor: opts.GeneralOptions.NoColor || opts.ReportOptions.Output != "",
DebugProfile: opts.GeneralOptions.DebugProfile,
Debug: opts.GeneralOptions.Debug,
LogLevel: opts.GeneralOptions.LogLevel,
IgnoreFile: opts.GeneralOptions.IgnoreFile,
IgnoreGit: opts.GeneralOptions.IgnoreGit,
Policies: policies,
Rules: result.Rules,
BuiltInRules: result.BuiltInRules,
CacheUsed: result.CacheUsed,
BearerRulesVersion: result.BearerRulesVersion,
}

if config.Scan.Diff {
if !slices.Contains([]string{flag.ReportSecurity, flag.ReportSaaS}, config.Report.Report) {
return settings.Config{}, errors.New("diff base branch is only supported for the security report")
}
}

return config, nil
}
Loading

0 comments on commit 2e33681

Please sign in to comment.