Skip to content

Commit

Permalink
accept notification webhook configs as CLI args
Browse files Browse the repository at this point in the history
  • Loading branch information
nasir-rabbani committed Oct 6, 2021
1 parent 56b6964 commit f7cce6a
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 76 deletions.
8 changes: 7 additions & 1 deletion pkg/cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ type ScanOptions struct {

// FindVulnerabilities gives option to scan container images for vulnerabilities
findVulnerabilities bool

// notificationWebhookURL is the URL where terrascan will send the scan report and normalized config json
notificationWebhookURL string

// notificationWebhookToken is the auth token to call the notification webhook URL
notificationWebhookToken string
}

// NewScanOptions returns a new pointer to ScanOptions
Expand Down Expand Up @@ -187,7 +193,7 @@ func (s *ScanOptions) Run() error {

// create a new runtime executor for processing IaC
executor, err := runtime.NewExecutor(s.iacType, s.iacVersion, s.policyType,
s.iacFilePath, s.iacDirPath, s.policyPath, s.scanRules, s.skipRules, s.categories, s.severity, s.nonRecursive, s.useTerraformCache, s.findVulnerabilities)
s.iacFilePath, s.iacDirPath, s.policyPath, s.scanRules, s.skipRules, s.categories, s.severity, s.nonRecursive, s.useTerraformCache, s.findVulnerabilities, s.notificationWebhookURL, s.notificationWebhookToken)
if err != nil {
return err
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/cli/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,7 @@ func init() {
scanCmd.Flags().BoolVarP(&scanOptions.nonRecursive, "non-recursive", "", false, "do not scan directories and modules recursively")
scanCmd.Flags().BoolVarP(&scanOptions.useTerraformCache, "use-terraform-cache", "", false, "use terraform init cache for remote modules (when used directory scan will be non recursive, flag applicable only with terraform IaC provider)")
scanCmd.Flags().BoolVarP(&scanOptions.findVulnerabilities, "find-vuln", "", false, "fetches vulnerabilities identified in Docker images")
scanCmd.Flags().StringVarP(&scanOptions.notificationWebhookURL, "notification-webhook-url", "", "", "the URL where terrascan will send the scan report and normalized config json")
scanCmd.Flags().StringVarP(&scanOptions.notificationWebhookToken, "notification-webhook-token", "", "", "the auth token to call the notification webhook URL")
RegisterCommand(rootCmd, scanCmd)
}
6 changes: 4 additions & 2 deletions pkg/http-server/file-scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) {
// scan and skip rules are comma separated rule id's in the request body
scanRulesValue := r.FormValue("scan_rules")
skipRulesValue := r.FormValue("skip_rules")
notificationWebhookURL := r.FormValue("notificationWebhookURL")
notificationWebhookToken := r.FormValue("notificationWebhookToken")

// categories is the list categories of violations that the user want to get informed about: low, medium or high
categoriesValue := r.FormValue("categories")
Expand Down Expand Up @@ -164,10 +166,10 @@ func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) {
var executor *runtime.Executor
if g.test {
executor, err = runtime.NewExecutor(iacType, iacVersion, cloudType,
tempFile.Name(), "", []string{"./testdata/testpolicies"}, scanRules, skipRules, categories, severity, false, false, false)
tempFile.Name(), "", []string{"./testdata/testpolicies"}, scanRules, skipRules, categories, severity, false, false, false, notificationWebhookURL, notificationWebhookToken)
} else {
executor, err = runtime.NewExecutor(iacType, iacVersion, cloudType,
tempFile.Name(), "", getPolicyPathFromConfig(), scanRules, skipRules, categories, severity, false, false, findVulnerabilities)
tempFile.Name(), "", getPolicyPathFromConfig(), scanRules, skipRules, categories, severity, false, false, findVulnerabilities, notificationWebhookURL, notificationWebhookToken)
}
if err != nil {
zap.S().Error(err)
Expand Down
26 changes: 14 additions & 12 deletions pkg/http-server/remote-repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@ import (

// scanRemoteRepoReq contains request body for remote repository scanning
type scanRemoteRepoReq struct {
RemoteType string `json:"remote_type"`
RemoteURL string `json:"remote_url"`
ConfigOnly bool `json:"config_only"`
ScanRules []string `json:"scan_rules"`
SkipRules []string `json:"skip_rules"`
Categories []string `json:"categories"`
Severity string `json:"severity"`
ShowPassed bool `json:"show_passed"`
NonRecursive bool `json:"non_recursive"`
FindVulnerabilities bool `json:"find_vulnerabilities"`
d downloader.Downloader
RemoteType string `json:"remote_type"`
RemoteURL string `json:"remote_url"`
ConfigOnly bool `json:"config_only"`
ScanRules []string `json:"scan_rules"`
SkipRules []string `json:"skip_rules"`
Categories []string `json:"categories"`
Severity string `json:"severity"`
ShowPassed bool `json:"show_passed"`
NonRecursive bool `json:"non_recursive"`
FindVulnerabilities bool `json:"find_vulnerabilities"`
d downloader.Downloader
notificationWebhookURL string `json:"notification_webhook_url"`
notificationWebhookToken string `json:"notification_webhook_token"`
}

// scanRemoteRepo downloads the remote Iac repository and scans it for
Expand Down Expand Up @@ -129,7 +131,7 @@ func (s *scanRemoteRepoReq) ScanRemoteRepo(iacType, iacVersion string, cloudType

// create a new runtime executor for scanning the remote repo
executor, err := runtime.NewExecutor(iacType, iacVersion, cloudType,
"", iacDirPath, policyPath, s.ScanRules, s.SkipRules, s.Categories, s.Severity, s.NonRecursive, false, s.FindVulnerabilities)
"", iacDirPath, policyPath, s.ScanRules, s.SkipRules, s.Categories, s.Severity, s.NonRecursive, false, s.FindVulnerabilities, s.notificationWebhookURL, s.notificationWebhookToken)
if err != nil {
zap.S().Error(err)
return output, isAdmissionDenied, err
Expand Down
4 changes: 2 additions & 2 deletions pkg/k8s/admission-webhook/validating-webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,10 @@ func (w ValidatingWebhook) scanK8sFile(filePath string) (runtime.Output, error)

if flag.Lookup("test.v") != nil {
executor, err = runtime.NewExecutor("k8s", "v1", []string{"k8s"},
filePath, "", []string{testPoliciesPath}, []string{}, []string{}, []string{}, "", false, false, false)
filePath, "", []string{testPoliciesPath}, []string{}, []string{}, []string{}, "", false, false, false, "", "")
} else {
executor, err = runtime.NewExecutor("k8s", "v1", []string{"k8s"},
filePath, "", []string{}, []string{}, []string{}, []string{}, "", false, false, false)
filePath, "", []string{}, []string{}, []string{}, []string{}, "", false, false, false, "", "")
}
if err != nil {
zap.S().Errorf("failed to create runtime executer: '%v'", err)
Expand Down
60 changes: 32 additions & 28 deletions pkg/runtime/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,38 +39,42 @@ const (

// Executor object
type Executor struct {
filePath string
dirPath string
policyPath []string
iacType string
iacVersion string
scanRules []string
skipRules []string
iacProviders []iacProvider.IacProvider
policyEngines []policy.Engine
notifiers []notifications.Notifier
categories []string
policyTypes []string
severity string
nonRecursive bool
useTerraformCache bool
findVulnerabilities bool
vulnerabilityEngine vulnerability.Engine
filePath string
dirPath string
policyPath []string
iacType string
iacVersion string
scanRules []string
skipRules []string
iacProviders []iacProvider.IacProvider
policyEngines []policy.Engine
notifiers []notifications.Notifier
categories []string
policyTypes []string
severity string
nonRecursive bool
useTerraformCache bool
findVulnerabilities bool
vulnerabilityEngine vulnerability.Engine
notificationWebhookURL string
notificationWebhookToken string
}

// NewExecutor creates a runtime object
func NewExecutor(iacType, iacVersion string, policyTypes []string, filePath, dirPath string, policyPath, scanRules, skipRules, categories []string, severity string, nonRecursive, useTerraformCache, findVulnerabilities bool) (e *Executor, err error) {
func NewExecutor(iacType, iacVersion string, policyTypes []string, filePath, dirPath string, policyPath, scanRules, skipRules, categories []string, severity string, nonRecursive, useTerraformCache, findVulnerabilities bool, notificationWebhookURL, notificationWebhookToken string) (e *Executor, err error) {
e = &Executor{
filePath: filePath,
dirPath: dirPath,
policyPath: policyPath,
policyTypes: policyTypes,
iacType: iacType,
iacVersion: iacVersion,
iacProviders: make([]iacProvider.IacProvider, 0),
nonRecursive: nonRecursive,
useTerraformCache: useTerraformCache,
findVulnerabilities: findVulnerabilities,
filePath: filePath,
dirPath: dirPath,
policyPath: policyPath,
policyTypes: policyTypes,
iacType: iacType,
iacVersion: iacVersion,
iacProviders: make([]iacProvider.IacProvider, 0),
nonRecursive: nonRecursive,
useTerraformCache: useTerraformCache,
findVulnerabilities: findVulnerabilities,
notificationWebhookURL: notificationWebhookURL,
notificationWebhookToken: notificationWebhookToken,
}

// assigning vulnerabilityEngine
Expand Down
24 changes: 13 additions & 11 deletions pkg/runtime/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,16 +449,18 @@ func TestInit(t *testing.T) {
}

type flagSet struct {
iacType string
iacVersion string
filePath string
dirPath string
policyPath []string
policyTypes []string
categories []string
severity string
scanRules []string
skipRules []string
iacType string
iacVersion string
filePath string
dirPath string
policyPath []string
policyTypes []string
categories []string
severity string
scanRules []string
skipRules []string
notificationWebhookURL string
notificationWebhookToken string
}

func TestNewExecutor(t *testing.T) {
Expand Down Expand Up @@ -587,7 +589,7 @@ func TestNewExecutor(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
config.LoadGlobalConfig(tt.configfile)

gotExecutor, gotErr := NewExecutor(tt.flags.iacType, tt.flags.iacVersion, tt.flags.policyTypes, tt.flags.filePath, tt.flags.dirPath, tt.flags.policyPath, tt.flags.scanRules, tt.flags.skipRules, tt.flags.categories, tt.flags.severity, false, false, false)
gotExecutor, gotErr := NewExecutor(tt.flags.iacType, tt.flags.iacVersion, tt.flags.policyTypes, tt.flags.filePath, tt.flags.dirPath, tt.flags.policyPath, tt.flags.scanRules, tt.flags.skipRules, tt.flags.categories, tt.flags.severity, false, false, false, tt.flags.notificationWebhookURL, tt.flags.notificationWebhookToken)

if !reflect.DeepEqual(tt.wantErr, gotErr) {
t.Errorf("Mismatch in error => got: '%v', want: '%v'", gotErr, tt.wantErr)
Expand Down
15 changes: 15 additions & 0 deletions pkg/runtime/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,27 @@
package runtime

import (
"github.com/accurics/terrascan/pkg/notifications/webhook"
"github.com/accurics/terrascan/pkg/utils"
)

// SendNotifications sends notifications via all the configured notifiers
func (e *Executor) SendNotifications(data interface{}) error {
var allErrs error

// send notifications using CLI arguments
if e.notificationWebhookURL != "" {
w := webhook.Webhook{
URL: e.notificationWebhookURL,
Token: e.notificationWebhookToken,
}
err := w.SendNotification(data)
if err != nil {
allErrs = utils.WrapError(err, allErrs)
}
return allErrs
}

// send notifications using configured notifiers
for _, notifier := range e.notifiers {
err := notifier.SendNotification(data)
Expand Down
42 changes: 22 additions & 20 deletions test/e2e/help/golden/help_scan.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,28 @@ Usage:
terrascan scan [flags]

Flags:
--categories strings list of categories of violations to be reported by terrascan (example: --categories="category1,category2")
--config-only will output resource config (should only be used for debugging purposes)
--find-vuln fetches vulnerabilities identified in Docker images
-h, --help help for scan
-d, --iac-dir string path to a directory containing one or more IaC files (default ".")
-f, --iac-file string path to a single IaC file
-i, --iac-type string iac type (arm, cft, docker, helm, k8s, kustomize, terraform, tfplan)
--iac-version string iac version (arm: v1, cft: v1, docker: v1, helm: v3, k8s: v1, kustomize: v2, v3, v4, terraform: v12, v13, v14, v15, tfplan: v1)
--non-recursive do not scan directories and modules recursively
-p, --policy-path stringArray policy path directory
-t, --policy-type strings policy type (all, aws, azure, docker, gcp, github, k8s) (default [all])
-r, --remote-type string type of remote backend (git, s3, gcs, http, terraform-registry)
-u, --remote-url string url pointing to remote IaC repository
--scan-rules strings one or more rules to scan (example: --scan-rules="ruleID1,ruleID2")
--severity string minimum severity level of the policy violations to be reported by terrascan
--show-passed display passed rules, along with violations
--skip-rules strings one or more rules to skip while scanning (example: --skip-rules="ruleID1,ruleID2")
--use-colors string color output (auto, t, f) (default "auto")
--use-terraform-cache use terraform init cache for remote modules (when used directory scan will be non recursive, flag applicable only with terraform IaC provider)
-v, --verbose will show violations with details (applicable for default output)
--categories strings list of categories of violations to be reported by terrascan (example: --categories="category1,category2")
--config-only will output resource config (should only be used for debugging purposes)
--find-vuln fetches vulnerabilities identified in Docker images
-h, --help help for scan
-d, --iac-dir string path to a directory containing one or more IaC files (default ".")
-f, --iac-file string path to a single IaC file
-i, --iac-type string iac type (arm, cft, docker, helm, k8s, kustomize, terraform, tfplan)
--iac-version string iac version (arm: v1, cft: v1, docker: v1, helm: v3, k8s: v1, kustomize: v2, v3, v4, terraform: v12, v13, v14, v15, tfplan: v1)
--non-recursive do not scan directories and modules recursively
--notification-webhook-token string the auth token to call the notification webhook URL
--notification-webhook-url string the URL where terrascan will send the scan report and normalized config json
-p, --policy-path stringArray policy path directory
-t, --policy-type strings policy type (all, aws, azure, docker, gcp, github, k8s) (default [all])
-r, --remote-type string type of remote backend (git, s3, gcs, http, terraform-registry)
-u, --remote-url string url pointing to remote IaC repository
--scan-rules strings one or more rules to scan (example: --scan-rules="ruleID1,ruleID2")
--severity string minimum severity level of the policy violations to be reported by terrascan
--show-passed display passed rules, along with violations
--skip-rules strings one or more rules to skip while scanning (example: --skip-rules="ruleID1,ruleID2")
--use-colors string color output (auto, t, f) (default "auto")
--use-terraform-cache use terraform init cache for remote modules (when used directory scan will be non recursive, flag applicable only with terraform IaC provider)
-v, --verbose will show violations with details (applicable for default output)

Global Flags:
-c, --config-path string config file path
Expand Down

0 comments on commit f7cce6a

Please sign in to comment.