From 0bc0ac1ae31bc5e1c7fdd8e64da8c9f902a0fd8a Mon Sep 17 00:00:00 2001 From: Devang Date: Tue, 13 Jul 2021 06:45:20 +0530 Subject: [PATCH] Do not initiate policy engine incase of --config-only flag --- pkg/cli/run.go | 16 ++-- pkg/cli/scan.go | 3 + pkg/http-server/file-scan.go | 9 +-- pkg/http-server/remote-repo.go | 19 ++--- pkg/initialize/run.go | 4 +- .../admission-webhook/validating-webhook.go | 2 +- pkg/runtime/executor.go | 21 ++++-- pkg/runtime/executor_test.go | 74 +++++++++++-------- 8 files changed, 88 insertions(+), 60 deletions(-) diff --git a/pkg/cli/run.go b/pkg/cli/run.go index bc04b03a0..3773b5ed5 100644 --- a/pkg/cli/run.go +++ b/pkg/cli/run.go @@ -185,7 +185,7 @@ func (s *ScanOptions) Run() error { } // executor output - results, err := executor.Execute() + results, err := executor.Execute(s.configOnly) if err != nil { return err } @@ -202,7 +202,7 @@ func (s *ScanOptions) Run() error { return err } - if results.Violations.ViolationStore.Summary.ViolatedPolicies != 0 && flag.Lookup("test.v") == nil { + if !s.configOnly && results.Violations.ViolationStore.Summary.ViolatedPolicies != 0 && flag.Lookup("test.v") == nil { os.RemoveAll(tempDir) os.Exit(3) } @@ -226,6 +226,13 @@ func (s *ScanOptions) downloadRemoteRepository(tempDir string) error { } func (s ScanOptions) writeResults(results runtime.Output) error { + + outputWriter := NewOutputWriter(s.UseColors) + + if s.configOnly { + return writer.Write(s.outputType, results.ResourceConfig, outputWriter) + } + // add verbose flag to the scan summary results.Violations.ViolationStore.Summary.ShowViolationDetails = s.verbose @@ -233,10 +240,5 @@ func (s ScanOptions) writeResults(results runtime.Output) error { results.Violations.ViolationStore.PassedRules = nil } - outputWriter := NewOutputWriter(s.UseColors) - - if s.configOnly { - return writer.Write(s.outputType, results.ResourceConfig, outputWriter) - } return writer.Write(s.outputType, results.Violations, outputWriter) } diff --git a/pkg/cli/scan.go b/pkg/cli/scan.go index 70fb5edd5..a367312de 100644 --- a/pkg/cli/scan.go +++ b/pkg/cli/scan.go @@ -36,6 +36,9 @@ var scanCmd = &cobra.Command{ Detect compliance and security violations across Infrastructure as Code to mitigate risk before provisioning cloud native infrastructure. `, PreRunE: func(cmd *cobra.Command, args []string) error { + if scanOptions.configOnly { + return nil + } return initial(cmd, args, true) }, RunE: scan, diff --git a/pkg/http-server/file-scan.go b/pkg/http-server/file-scan.go index 3e041e04a..92b4218fb 100644 --- a/pkg/http-server/file-scan.go +++ b/pkg/http-server/file-scan.go @@ -162,7 +162,7 @@ func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) { apiErrorResponse(w, err.Error(), http.StatusBadRequest) return } - normalized, err := executor.Execute() + normalized, err := executor.Execute(configOnly) if err != nil { errMsg := fmt.Sprintf("failed to scan uploaded file. error: '%v'", err) zap.S().Error(errMsg) @@ -172,14 +172,13 @@ func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) { var output interface{} - if !showPassed { - normalized.Violations.ViolationStore.PassedRules = nil - } - // if config only, return resource config else return violations if configOnly { output = normalized.ResourceConfig } else { + if !showPassed { + normalized.Violations.ViolationStore.PassedRules = nil + } output = normalized.Violations } diff --git a/pkg/http-server/remote-repo.go b/pkg/http-server/remote-repo.go index 7157616ca..67786b6c8 100644 --- a/pkg/http-server/remote-repo.go +++ b/pkg/http-server/remote-repo.go @@ -135,25 +135,26 @@ func (s *scanRemoteRepoReq) ScanRemoteRepo(iacType, iacVersion string, cloudType } // evaluate policies IaC for violations - results, err := executor.Execute() + results, err := executor.Execute(s.ConfigOnly) if err != nil { errMsg := fmt.Sprintf("failed to scan uploaded file. error: '%v'", err) zap.S().Error(errMsg) return output, isAdmissionDenied, err } - // set remote url in case remote repo is scanned - if s.RemoteURL != "" { - results.Violations.Summary.ResourcePath = s.RemoteURL - } - - if !s.ShowPassed { - results.Violations.ViolationStore.PassedRules = nil - } // if config only, return only config else return only violations if s.ConfigOnly { output = results.ResourceConfig } else { + // set remote url in case remote repo is scanned + if s.RemoteURL != "" { + results.Violations.Summary.ResourcePath = s.RemoteURL + } + + if !s.ShowPassed { + results.Violations.ViolationStore.PassedRules = nil + } + isAdmissionDenied = hasK8sAdmissionDeniedViolations(results) output = results.Violations } diff --git a/pkg/initialize/run.go b/pkg/initialize/run.go index 7302cadc1..3f9d197d4 100644 --- a/pkg/initialize/run.go +++ b/pkg/initialize/run.go @@ -36,8 +36,6 @@ const terrascanReadmeURL string = "https://raw.githubusercontent.com/accurics/te // Run initializes terrascan if not done already func Run(isNonInitCmd bool) error { - zap.S().Debug("initializing terrascan") - // check if policy paths exist if path, err := os.Stat(config.GetPolicyRepoPath()); err == nil && path.IsDir() { if isNonInitCmd { @@ -45,6 +43,8 @@ func Run(isNonInitCmd bool) error { } } + zap.S().Debug("initializing terrascan") + if !connected(terrascanReadmeURL) { return errNoConnection } diff --git a/pkg/k8s/admission-webhook/validating-webhook.go b/pkg/k8s/admission-webhook/validating-webhook.go index 4572fbc43..c2aac25ee 100644 --- a/pkg/k8s/admission-webhook/validating-webhook.go +++ b/pkg/k8s/admission-webhook/validating-webhook.go @@ -201,7 +201,7 @@ func (w ValidatingWebhook) scanK8sFile(filePath string) (runtime.Output, error) return result, err } - result, err = executor.Execute() + result, err = executor.Execute(false) if err != nil { zap.S().Error("failed to scan resource object. error: '%v'", err) return result, err diff --git a/pkg/runtime/executor.go b/pkg/runtime/executor.go index 0f3c88257..bcb985426 100644 --- a/pkg/runtime/executor.go +++ b/pkg/runtime/executor.go @@ -17,6 +17,7 @@ package runtime import ( + "github.com/accurics/terrascan/pkg/policy/opa" "sort" "go.uber.org/zap" @@ -26,7 +27,6 @@ import ( "github.com/accurics/terrascan/pkg/iac-providers/output" "github.com/accurics/terrascan/pkg/notifications" "github.com/accurics/terrascan/pkg/policy" - opa "github.com/accurics/terrascan/pkg/policy/opa" "github.com/hashicorp/go-multierror" ) @@ -139,6 +139,11 @@ func (e *Executor) Init() error { } } + zap.S().Debug("initialized executor") + return nil +} + +func (e *Executor) initPolicyEngines() (err error) { // create a new policy engine based on IaC type zap.S().Debugf("using policy path %v", e.policyPath) for _, policyPath := range e.policyPath { @@ -153,18 +158,16 @@ func (e *Executor) Init() error { // initialize the engine if err := engine.Init(policyPath, preloadFilter); err != nil { - zap.S().Errorf("%s", err) + zap.S().Errorf("failed to initialize policy engine for path %s, error: %s", policyPath, err) return err } e.policyEngines = append(e.policyEngines, engine) } - - zap.S().Debug("initialized executor") return nil } // Execute validates the inputs, processes the IaC, creates json output -func (e *Executor) Execute() (results Output, err error) { +func (e *Executor) Execute(configOnly bool) (results Output, err error) { var merr *multierror.Error var resourceConfig output.AllResourceConfigs @@ -194,6 +197,14 @@ func (e *Executor) Execute() (results Output, err error) { // update results with resource config results.ResourceConfig = resourceConfig + if configOnly { + return results, nil + } + + if err := e.initPolicyEngines(); err != nil { + return results, err + } + if err := e.findViolations(&results); err != nil { return results, err } diff --git a/pkg/runtime/executor_test.go b/pkg/runtime/executor_test.go index 41bbe5790..71018c1f9 100644 --- a/pkg/runtime/executor_test.go +++ b/pkg/runtime/executor_test.go @@ -178,7 +178,49 @@ func TestExecute(t *testing.T) { for _, tt := range table { t.Run(tt.name, func(t *testing.T) { - _, gotErr := tt.executor.Execute() + _, gotErr := tt.executor.Execute(false) + if !reflect.DeepEqual(gotErr, tt.wantErr) { + t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr) + } + }) + } +} + +func TestInitPolicyEngine(t *testing.T) { + table := []struct { + name string + executor Executor + wantErr error + }{ + { + name: "invalid policy path", + executor: Executor{ + filePath: filepath.Join(testDataDir, "testfile"), + dirPath: "", + policyTypes: []string{"aws"}, + iacType: "terraform", + iacVersion: "v14", + policyPath: []string{filepath.Join(testDataDir, "notthere")}, + }, + wantErr: fmt.Errorf("failed to initialize OPA policy engine"), + }, + { + name: "invalid policy path", + executor: Executor{ + filePath: filepath.Join(testDataDir, "testfile"), + dirPath: "", + policyTypes: []string{"aws"}, + iacType: "terraform", + iacVersion: "v12", + policyPath: []string{filepath.Join(testDataDir, "notthere")}, + }, + wantErr: fmt.Errorf("failed to initialize OPA policy engine"), + }, + } + + for _, tt := range table { + t.Run(tt.name, func(t *testing.T) { + gotErr := tt.executor.initPolicyEngines() if !reflect.DeepEqual(gotErr, tt.wantErr) { t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr) } @@ -273,21 +315,6 @@ func TestInit(t *testing.T) { wantErr: config.ErrNotPresent, wantIacProvider: []iacProvider.IacProvider{&tfv14.TfV14{}}, }, - { - name: "invalid policy path", - executor: Executor{ - filePath: filepath.Join(testDataDir, "testfile"), - dirPath: "", - policyTypes: []string{"aws"}, - iacType: "terraform", - iacVersion: "v14", - policyPath: []string{filepath.Join(testDataDir, "notthere")}, - }, - configFile: filepath.Join(testDataDir, "webhook.toml"), - wantErr: fmt.Errorf("failed to initialize OPA policy engine"), - wantIacProvider: []iacProvider.IacProvider{&tfv14.TfV14{}}, - wantNotifiers: []notifications.Notifier{&webhook.Webhook{}}, - }, { name: "config file with invalid category", executor: Executor{ @@ -358,21 +385,6 @@ func TestInit(t *testing.T) { wantErr: config.ErrNotPresent, wantIacProvider: []iacProvider.IacProvider{&tfv12.TfV12{}}, }, - { - name: "invalid policy path", - executor: Executor{ - filePath: filepath.Join(testDataDir, "testfile"), - dirPath: "", - policyTypes: []string{"aws"}, - iacType: "terraform", - iacVersion: "v12", - policyPath: []string{filepath.Join(testDataDir, "notthere")}, - }, - configFile: filepath.Join(testDataDir, "webhook.toml"), - wantErr: fmt.Errorf("failed to initialize OPA policy engine"), - wantIacProvider: []iacProvider.IacProvider{&tfv12.TfV12{}}, - wantNotifiers: []notifications.Notifier{&webhook.Webhook{}}, - }, } for _, tt := range table {