Repository: tenable/terrascan (language: python)

Issue:
Add --severity options
I've explore `terrascan` tools to filter an output by severity level but can't found it, it will be good if the tools can filter an output by risks and possible to embeded into CI/CD pipeline.


Discussion / hints:
Thanks for the suggestion @myugan. As a workaround while this gets implemented, you can use a tool like [jq](https://stedolan.github.io/jq/) and filter the json output like this:

``` bash
terrascan scan -o json | jq '.results.violations[] | select(.severity=="HIGH")'
```

Fix patch:
diff --git a/pkg/cli/run.go b/pkg/cli/run.go
index 55118c401..d6118eaca 100644
--- a/pkg/cli/run.go
+++ b/pkg/cli/run.go
@@ -81,6 +81,8 @@ type ScanOptions struct {
 	// SkipRules is the array of rules to skip while scanning
 	skipRules []string
 
+	// severity is the level of severity of policy violations that should be reported
+	severity string
 	// Verbose indicates whether to display all fields in default human readlbe output
 	Verbose bool
 }
@@ -167,7 +169,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.configFile, s.policyPath, s.scanRules, s.skipRules)
+		s.iacFilePath, s.iacDirPath, s.configFile, s.policyPath, s.scanRules, s.skipRules, s.severity)
 	if err != nil {
 		return err
 	}
diff --git a/pkg/cli/scan.go b/pkg/cli/scan.go
index 14461cc18..55870bb30 100644
--- a/pkg/cli/scan.go
+++ b/pkg/cli/scan.go
@@ -63,5 +63,6 @@ func init() {
 	scanCmd.Flags().BoolVarP(&scanOptions.Verbose, "verbose", "v", false, "will show violations with details (applicable for default output)")
 	scanCmd.Flags().StringSliceVarP(&scanOptions.scanRules, "scan-rules", "", []string{}, "one or more rules to scan (example: --scan-rules=\"ruleID1,ruleID2\")")
 	scanCmd.Flags().StringSliceVarP(&scanOptions.skipRules, "skip-rules", "", []string{}, "one or more rules to skip while scanning (example: --skip-rules=\"ruleID1,ruleID2\")")
+	scanCmd.Flags().StringVar(&scanOptions.severity, "severity", "", "minimum severity level of the policy violations to be reported by terrascan")
 	RegisterCommand(rootCmd, scanCmd)
 }
diff --git a/pkg/config/config-reader.go b/pkg/config/config-reader.go
index 1c8cc5715..f33edf02a 100644
--- a/pkg/config/config-reader.go
+++ b/pkg/config/config-reader.go
@@ -82,3 +82,8 @@ func (r TerrascanConfigReader) GetNotifications() map[string]Notifier {
 func (r TerrascanConfigReader) GetRules() Rules {
 	return r.config.Rules
 }
+
+// GetSeverity will return the level of severity specified in the terrascan config file
+func (r TerrascanConfigReader) GetSeverity() Severity {
+	return r.config.Severity
+}
diff --git a/pkg/config/types.go b/pkg/config/types.go
index 2939f786b..9c5144698 100644
--- a/pkg/config/types.go
+++ b/pkg/config/types.go
@@ -24,6 +24,12 @@ type TerrascanConfig struct {
 	Policy        `toml:"policy,omitempty"`
 	Notifications map[string]Notifier `toml:"notifications,omitempty"`
 	Rules         `toml:"rules,omitempty"`
+	Severity      `toml:"severity,omitempty"`
+}
+
+// Severity defines the minimum level of severity of violations that you want to be reported
+type Severity struct {
+	Level string `toml:"level"`
 }
 
 // Policy struct defines policy specific configurations
diff --git a/pkg/http-server/file-scan.go b/pkg/http-server/file-scan.go
index f51a5899d..899845031 100644
--- a/pkg/http-server/file-scan.go
+++ b/pkg/http-server/file-scan.go
@@ -25,6 +25,7 @@ import (
 	"strings"
 
 	"github.com/accurics/terrascan/pkg/runtime"
+	"github.com/accurics/terrascan/pkg/utils"
 	"github.com/gorilla/mux"
 	"go.uber.org/zap"
 )
@@ -89,6 +90,9 @@ func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) {
 	scanRulesValue := r.FormValue("scan_rules")
 	skipRulesValue := r.FormValue("skip_rules")
 
+	// severity is the minimum severity level of violations that the user want to get informed about: low, medium or high
+	severity := r.FormValue("severity")
+
 	if scanRulesValue != "" {
 		scanRules = strings.Split(scanRulesValue, ",")
 	}
@@ -97,14 +101,18 @@ func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) {
 		skipRules = strings.Split(skipRulesValue, ",")
 	}
 
+	if severity != "" {
+		severity = utils.EnsureUpperCaseTrimmed(severity)
+	}
+
 	// create a new runtime executor for scanning the uploaded file
 	var executor *runtime.Executor
 	if g.test {
 		executor, err = runtime.NewExecutor(iacType, iacVersion, cloudType,
-			tempFile.Name(), "", "", []string{"./testdata/testpolicies"}, scanRules, skipRules)
+			tempFile.Name(), "", "", []string{"./testdata/testpolicies"}, scanRules, skipRules, severity)
 	} else {
 		executor, err = runtime.NewExecutor(iacType, iacVersion, cloudType,
-			tempFile.Name(), "", "", []string{}, scanRules, skipRules)
+			tempFile.Name(), "", "", []string{}, scanRules, skipRules, severity)
 	}
 	if err != nil {
 		zap.S().Error(err)
diff --git a/pkg/http-server/remote-repo.go b/pkg/http-server/remote-repo.go
index 3c40721ab..864219614 100644
--- a/pkg/http-server/remote-repo.go
+++ b/pkg/http-server/remote-repo.go
@@ -38,6 +38,7 @@ type scanRemoteRepoReq struct {
 	ConfigOnly bool     `json:"config_only"`
 	ScanRules  []string `json:"scan_rules"`
 	SkipRules  []string `json:"skip_rules"`
+	Severity   string   `json:"severity"`
 	d          downloader.Downloader
 }
 
@@ -114,7 +115,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)
+		"", iacDirPath, "", policyPath, s.ScanRules, s.SkipRules, s.Severity)
 	if err != nil {
 		zap.S().Error(err)
 		return output, err
diff --git a/pkg/policy/interface.go b/pkg/policy/interface.go
index 5755cafec..cc2b9cd45 100644
--- a/pkg/policy/interface.go
+++ b/pkg/policy/interface.go
@@ -18,9 +18,9 @@ package policy
 
 // Engine Policy Engine interface
 type Engine interface {
-	//Init method to initialize engine with policy path, scan and skip rules
-	Init(string, []string, []string) error
-	FilterRules(string, []string, []string)
+	//Init method to initialize engine with policy path, scan and skip rules, and severity level
+	Init(string, []string, []string, string) error
+	FilterRules(string, []string, []string, string)
 	Configure() error
 	Evaluate(EngineInput) (EngineOutput, error)
 	GetResults() EngineOutput
diff --git a/pkg/policy/opa/engine.go b/pkg/policy/opa/engine.go
index e5c92a394..5dddd040d 100644
--- a/pkg/policy/opa/engine.go
+++ b/pkg/policy/opa/engine.go
@@ -243,7 +243,7 @@ func (e *Engine) CompileRegoFiles() error {
 
 // Init initializes the Opa engine
 // Handles loading all rules, filtering, compiling, and preparing for evaluation
-func (e *Engine) Init(policyPath string, scanRules, skipRules []string) error {
+func (e *Engine) Init(policyPath string, scanRules, skipRules []string, severity string) error {
 	e.context = context.Background()
 
 	if err := e.LoadRegoFiles(policyPath); err != nil {
@@ -251,8 +251,8 @@ func (e *Engine) Init(policyPath string, scanRules, skipRules []string) error {
 		return errInitFailed
 	}
 
-	// before compiling the rego files, filter the rules based on scan and skip rules supplied
-	e.FilterRules(policyPath, scanRules, skipRules)
+	// before compiling the rego files, filter the rules based on scan and skip rules, and severity level supplied
+	e.FilterRules(policyPath, scanRules, skipRules, severity)
 
 	// update the rule count
 	e.stats.ruleCount = len(e.regoDataMap)
@@ -419,8 +419,8 @@ func (e *Engine) Evaluate(engineInput policy.EngineInput) (policy.EngineOutput,
 	return e.results, nil
 }
 
-// FilterRules will apply the scan and skip rules
-func (e *Engine) FilterRules(policyPath string, scanRules, skipRules []string) {
+// FilterRules will apply the scan and skip rules, and severity level
+func (e *Engine) FilterRules(policyPath string, scanRules, skipRules []string, severity string) {
 	// apply scan rules
 	if len(scanRules) > 0 {
 		e.filterScanRules(policyPath, scanRules)
@@ -430,6 +430,10 @@ func (e *Engine) FilterRules(policyPath string, scanRules, skipRules []string) {
 	if len(skipRules) > 0 {
 		e.filterSkipRules(policyPath, skipRules)
 	}
+
+	if len(severity) > 0 {
+		e.filterBySeverity(policyPath, severity)
+	}
 }
 
 func (e *Engine) filterScanRules(policyPath string, scanRules []string) {
@@ -465,3 +469,21 @@ func (e *Engine) filterSkipRules(policyPath string, skipRules []string) {
 		}
 	}
 }
+
+func (e *Engine) filterBySeverity(policyPath, severity string) {
+
+	// temporary map to store data from original rego data map
+	tempMap := make(map[string]*RegoData)
+	for ruleID, regoData := range e.regoDataMap {
+
+		if utils.CheckSeverity(regoData.Metadata.Severity, severity) {
+			tempMap[ruleID] = regoData
+		}
+	}
+	if len(tempMap) == 0 {
+		zap.S().Debugf("policy path: %s, doesn't have any rule matching the severity level : %s", policyPath, severity)
+	}
+
+	// the regoDataMap should only contain regoData for required minimum severity level
+	e.regoDataMap = tempMap
+}
diff --git a/pkg/runtime/executor.go b/pkg/runtime/executor.go
index 69d7d9881..f66742795 100644
--- a/pkg/runtime/executor.go
+++ b/pkg/runtime/executor.go
@@ -27,22 +27,23 @@ import (
 
 // Executor object
 type Executor struct {
-	filePath     string
-	dirPath      string
-	policyPath   []string
-	cloudType    []string
-	iacType      string
-	iacVersion   string
-	configFile   string
-	scanRules    []string
-	skipRules    []string
-	iacProvider  iacProvider.IacProvider
-	policyEngine []policy.Engine
-	notifiers    []notifications.Notifier
+	filePath      string
+	dirPath       string
+	policyPath    []string
+	cloudType     []string
+	iacType       string
+	iacVersion    string
+	configFile    string
+	scanRules     []string
+	skipRules     []string
+	iacProvider   iacProvider.IacProvider
+	policyEngines []policy.Engine
+	notifiers     []notifications.Notifier
+	severity      string
 }
 
 // NewExecutor creates a runtime object
-func NewExecutor(iacType, iacVersion string, cloudType []string, filePath, dirPath, configFile string, policyPath, scanRules, skipRules []string) (e *Executor, err error) {
+func NewExecutor(iacType, iacVersion string, cloudType []string, filePath, dirPath, configFile string, policyPath, scanRules, skipRules []string, severity string) (e *Executor, err error) {
 	e = &Executor{
 		filePath:   filePath,
 		dirPath:    dirPath,
@@ -51,8 +52,24 @@ func NewExecutor(iacType, iacVersion string, cloudType []string, filePath, dirPa
 		iacType:    iacType,
 		iacVersion: iacVersion,
 		configFile: configFile,
-		scanRules:  scanRules,
-		skipRules:  skipRules,
+	}
+
+	// read config file and update scan and skip rules
+	if err := e.initRuleSetFromConfigFile(); err != nil {
+		zap.S().Error("error initialising scan and skip rules", zap.Error(err))
+		return nil, err
+	}
+
+	if len(scanRules) > 0 {
+		e.scanRules = scanRules
+	}
+
+	if len(skipRules) > 0 {
+		e.skipRules = skipRules
+	}
+
+	if len(severity) > 0 {
+		e.severity = severity
 	}
 
 	// initialize executor
@@ -72,12 +89,6 @@ func (e *Executor) Init() error {
 		return err
 	}
 
-	// read config file and update scan and skip rules
-	if err := e.initRules(); err != nil {
-		zap.S().Error("error initialising scan and skip rules", zap.Error(err))
-		return err
-	}
-
 	// create new IacProvider
 	e.iacProvider, err = iacProvider.NewIacProvider(e.iacType, e.iacVersion)
 	if err != nil {
@@ -106,11 +117,11 @@ func (e *Executor) Init() error {
 		}
 
 		// initialize the engine
-		if err := engine.Init(policyPath, e.scanRules, e.skipRules); err != nil {
+		if err := engine.Init(policyPath, e.scanRules, e.skipRules, e.severity); err != nil {
 			zap.S().Errorf("%s", err)
 			return err
 		}
-		e.policyEngine = append(e.policyEngine, engine)
+		e.policyEngines = append(e.policyEngines, engine)
 	}
 
 	zap.S().Debug("initialized executor")
@@ -133,7 +144,7 @@ func (e *Executor) Execute() (results Output, err error) {
 	// evaluate policies
 	results.Violations = policy.EngineOutput{}
 	violations := results.Violations.AsViolationStore()
-	for _, engine := range e.policyEngine {
+	for _, engine := range e.policyEngines {
 		output, err := engine.Evaluate(policy.EngineInput{InputData: &results.ResourceConfig})
 		if err != nil {
 			return results, err
diff --git a/pkg/runtime/rules.go b/pkg/runtime/rules.go
index 17773efc2..e53e722d4 100644
--- a/pkg/runtime/rules.go
+++ b/pkg/runtime/rules.go
@@ -6,7 +6,7 @@ import (
 )
 
 // read the config file and update scan and skip rules
-func (e *Executor) initRules() error {
+func (e *Executor) initRuleSetFromConfigFile() error {
 	if e.configFile == "" {
 		return nil
 	}
@@ -26,5 +26,10 @@ func (e *Executor) initRules() error {
 	if len(configReader.GetRules().SkipRules) > 0 {
 		e.skipRules = append(e.skipRules, configReader.GetRules().SkipRules...)
 	}
+
+	// specify severity of violations to be reported
+	if len(configReader.GetSeverity().Level) > 0 {
+		e.severity = configReader.GetSeverity().Level
+	}
 	return nil
 }
diff --git a/pkg/runtime/validate.go b/pkg/runtime/validate.go
index 2513c4a44..cbc374110 100644
--- a/pkg/runtime/validate.go
+++ b/pkg/runtime/validate.go
@@ -28,11 +28,12 @@ import (
 )
 
 var (
-	errEmptyIacPath      = fmt.Errorf("empty iac path, either use '-f' or '-d' option")
-	errDirNotExists      = fmt.Errorf("directory does not exist")
-	errFileNotExists     = fmt.Errorf("file does not exist")
-	errIacNotSupported   = fmt.Errorf("iac type or version not supported")
-	errCloudNotSupported = fmt.Errorf("cloud type not supported")
+	errEmptyIacPath         = fmt.Errorf("empty iac path, either use '-f' or '-d' option")
+	errDirNotExists         = fmt.Errorf("directory does not exist")
+	errFileNotExists        = fmt.Errorf("file does not exist")
+	errIacNotSupported      = fmt.Errorf("iac type or version not supported")
+	errCloudNotSupported    = fmt.Errorf("cloud type not supported")
+	errSeverityNotSupported = fmt.Errorf("severity level not supported")
 )
 
 // ValidateInputs validates the inputs to the executor object
@@ -102,6 +103,11 @@ func (e *Executor) ValidateInputs() error {
 	}
 	zap.S().Debugf("using policy path %v", e.policyPath)
 
+	if len(e.severity) > 0 && !utils.ValidateSeverityInput(e.severity) {
+		return errSeverityNotSupported
+	}
+	zap.S().Debugf("using severity level %v", e.severity)
+
 	// successful
 	zap.S().Debug("input validation successful")
 	return nil
diff --git a/pkg/utils/severity.go b/pkg/utils/severity.go
new file mode 100644
index 000000000..de356ba70
--- /dev/null
+++ b/pkg/utils/severity.go
@@ -0,0 +1,32 @@
+package utils
+
+const (
+	// HighSeverity high
+	HighSeverity = "HIGH"
+	// MediumSeverity medium
+	MediumSeverity = "MEDIUM"
+	// LowSeverity low
+	LowSeverity = "LOW"
+)
+
+// ValidateSeverityInput validates input for --severity flag
+func ValidateSeverityInput(severity string) bool {
+	severity = EnsureUpperCaseTrimmed(severity)
+	return severity == LowSeverity || severity == MediumSeverity || severity == HighSeverity
+}
+
+// CheckSeverity validates if the severity of policy rule is equal or above the desired severity
+func CheckSeverity(ruleSeverity, desiredSeverity string) bool {
+	ruleSeverity = EnsureUpperCaseTrimmed(ruleSeverity)
+	desiredSeverity = EnsureUpperCaseTrimmed(desiredSeverity)
+
+	if desiredSeverity == LowSeverity {
+		return true
+	}
+
+	if desiredSeverity == MediumSeverity {
+		return ruleSeverity == MediumSeverity || ruleSeverity == HighSeverity
+	}
+
+	return ruleSeverity == HighSeverity
+}
diff --git a/pkg/utils/slice.go b/pkg/utils/slice.go
new file mode 100644
index 000000000..17ddaf858
--- /dev/null
+++ b/pkg/utils/slice.go
@@ -0,0 +1,14 @@
+package utils
+
+// IsSliceEqual checks if two slices of string are equal or not
+func IsSliceEqual(list1, list2 []string) bool {
+	if len(list1) != len(list2) {
+		return false
+	}
+	for i := range list1 {
+		if list1[i] != list2[i] {
+			return false
+		}
+	}
+	return true
+}
diff --git a/pkg/utils/string.go b/pkg/utils/string.go
new file mode 100644
index 000000000..f95a5c6cc
--- /dev/null
+++ b/pkg/utils/string.go
@@ -0,0 +1,8 @@
+package utils
+
+import "strings"
+
+// EnsureUpperCaseTrimmed make sure the string is in UPPERCASE and TRIMMED
+func EnsureUpperCaseTrimmed(s string) string {
+	return strings.TrimSpace(strings.ToUpper(s))
+}


Test patch:
diff --git a/pkg/config/config-reader_test.go b/pkg/config/config-reader_test.go
index c0aeb674d..1d30014dc 100644
--- a/pkg/config/config-reader_test.go
+++ b/pkg/config/config-reader_test.go
@@ -39,9 +39,12 @@ func TestNewTerrascanConfigReader(t *testing.T) {
 		SkipRules: []string{"rule.1"},
 	}
 
+	highSeverity := Severity{Level: "high"}
+
 	type args struct {
 		fileName string
 	}
+
 	tests := []struct {
 		name          string
 		args          args
@@ -107,6 +110,28 @@ func TestNewTerrascanConfigReader(t *testing.T) {
 			Policy: testPolicy,
 			Rules:  testRules,
 		},
+		{
+			name: "valid toml config file with all fields and severity defined",
+			args: args{
+				fileName: "testdata/terrascan-config-severity.toml",
+			},
+			want: &TerrascanConfigReader{
+				config: TerrascanConfig{
+					Policy: testPolicy,
+					Notifications: map[string]Notifier{
+						"webhook1": testNotifier,
+					},
+					Rules:    testRules,
+					Severity: highSeverity,
+				},
+			},
+			assertGetters: true,
+			notifications: map[string]Notifier{
+				"webhook1": testNotifier,
+			},
+			Policy: testPolicy,
+			Rules:  testRules,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/pkg/config/testdata/terrascan-config-severity.toml b/pkg/config/testdata/terrascan-config-severity.toml
new file mode 100644
index 000000000..58fc9e5b1
--- /dev/null
+++ b/pkg/config/testdata/terrascan-config-severity.toml
@@ -0,0 +1,26 @@
+[policy]
+path = "custom-path"
+rego_subdir = "rego-subdir"
+repo_url = "https://repository/url"
+branch = "branch-name"
+
+[notifications]
+[notifications.webhook1]
+type = 'webhook'
+[notifications.webhook1.config]
+url = 'testurl1'
+
+[rules]
+scan-rules = [
+    "rule.1",
+    "rule.2",
+    "rule.3",
+    "rule.4",
+    "rule.5",
+]
+skip-rules = [
+    "rule.1"
+]
+
+[severity]
+level = "high"
\ No newline at end of file
diff --git a/pkg/http-server/file-scan_test.go b/pkg/http-server/file-scan_test.go
index 72fe4a467..04c3bb047 100644
--- a/pkg/http-server/file-scan_test.go
+++ b/pkg/http-server/file-scan_test.go
@@ -31,6 +31,7 @@ func TestUpload(t *testing.T) {
 		cloudType  string
 		scanRules  []string
 		skipRules  []string
+		severity   string
 		wantStatus int
 	}{
 		{
@@ -57,6 +58,15 @@ func TestUpload(t *testing.T) {
 			cloudType:  testCloudType,
 			wantStatus: http.StatusOK,
 		},
+		{
+			name:       "valid file scan default iac version, with invalid severity level input",
+			path:       testFilePath,
+			param:      testParamName,
+			iacType:    testIacType,
+			severity:   "HGIH",
+			cloudType:  testCloudType,
+			wantStatus: http.StatusBadRequest,
+		},
 		{
 			name:       "invalid iacType",
 			path:       testFilePath,
@@ -102,6 +112,72 @@ func TestUpload(t *testing.T) {
 				"AWS.CloudFront.Logging.Medium.0567", "AWS.CloudFront.Network Security.Low.0568"},
 			skipRules: []string{"AWS.CloudFront.Network Security.Low.0568"},
 		},
+		{
+			name:       "valid file scan default iac version",
+			path:       testFilePath,
+			param:      testParamName,
+			iacType:    testIacType,
+			cloudType:  testCloudType,
+			severity:   "low ",
+			wantStatus: http.StatusOK,
+		},
+		{
+			name:       "valid file scan default iac version  with MEDIUM severity",
+			path:       testFilePath,
+			param:      testParamName,
+			iacType:    testIacType,
+			cloudType:  testCloudType,
+			severity:   " MEDIUM ",
+			wantStatus: http.StatusOK,
+		},
+		{
+			name:       "valid file scan default iac version with high severity",
+			path:       testFilePath,
+			param:      testParamName,
+			iacType:    testIacType,
+			cloudType:  testCloudType,
+			severity:   "high",
+			wantStatus: http.StatusOK,
+		},
+		{
+			name:       "valid file scan with scan and skip rules with low severity",
+			path:       testFilePath,
+			param:      testParamName,
+			iacType:    testIacType,
+			iacVersion: testIacVersion,
+			cloudType:  testCloudType,
+			wantStatus: http.StatusOK,
+			severity:   "low ",
+			scanRules: []string{"AWS.CloudFront.EncryptionandKeyManagement.High.0407", "AWS.CloudFront.EncryptionandKeyManagement.High.0408",
+				"AWS.CloudFront.Logging.Medium.0567", "AWS.CloudFront.Network Security.Low.0568"},
+			skipRules: []string{"AWS.CloudFront.Network Security.Low.0568"},
+		},
+		{
+			name:       "valid file scan with scan and skip rules with medium severity",
+			path:       testFilePath,
+			param:      testParamName,
+			iacType:    testIacType,
+			iacVersion: testIacVersion,
+			cloudType:  testCloudType,
+			wantStatus: http.StatusOK,
+			severity:   " medium",
+			scanRules: []string{"AWS.CloudFront.EncryptionandKeyManagement.High.0407", "AWS.CloudFront.EncryptionandKeyManagement.High.0408",
+				"AWS.CloudFront.Logging.Medium.0567", "AWS.CloudFront.Network Security.Low.0568"},
+			skipRules: []string{"AWS.CloudFront.Network Security.Low.0568"},
+		},
+		{
+			name:       "valid file scan with scan and skip rules with HIGH severity",
+			path:       testFilePath,
+			param:      testParamName,
+			iacType:    testIacType,
+			iacVersion: testIacVersion,
+			cloudType:  testCloudType,
+			wantStatus: http.StatusOK,
+			severity:   "HIGH",
+			scanRules: []string{"AWS.CloudFront.EncryptionandKeyManagement.High.0407", "AWS.CloudFront.EncryptionandKeyManagement.High.0408",
+				"AWS.CloudFront.Logging.Medium.0567", "AWS.CloudFront.Network Security.Low.0568"},
+			skipRules: []string{"AWS.CloudFront.Network Security.Low.0568"},
+		},
 	}
 
 	for _, tt := range table {
@@ -114,7 +190,6 @@ func TestUpload(t *testing.T) {
 				t.Error(err)
 			}
 			defer file.Close()
-
 			// use buffer to store response body
 			body := &bytes.Buffer{}
 			writer := multipart.NewWriter(body)
@@ -137,6 +212,14 @@ func TestUpload(t *testing.T) {
 					t.Error(err)
 				}
 			}
+
+			if len(tt.severity) > 0 {
+				if err = writer.WriteField("severity", tt.severity); err != nil {
+					writer.Close()
+					t.Error(err)
+				}
+			}
+
 			writer.Close()
 
 			// http request of the type "/v1/{iacType}/{iacVersion}/{cloudType}/file/scan"
@@ -154,7 +237,7 @@ func TestUpload(t *testing.T) {
 			h.scanFile(res, req)
 
 			if res.Code != tt.wantStatus {
-				t.Errorf("incorrect status code, got: '%v', want: '%v', error: '%v'", res.Code, http.StatusOK, res.Body)
+				t.Errorf("incorrect status code, got: '%v', want: '%v', error: '%v'", res.Code, tt.wantStatus, res.Body)
 			}
 		})
 	}
diff --git a/pkg/policy/opa/engine_test.go b/pkg/policy/opa/engine_test.go
index 0c097e7ce..0ff3cf9f4 100644
--- a/pkg/policy/opa/engine_test.go
+++ b/pkg/policy/opa/engine_test.go
@@ -3,16 +3,21 @@ package opa
 import (
 	"fmt"
 	"testing"
+
+	"github.com/accurics/terrascan/pkg/utils"
 )
 
+var testPolicyPath string = "test"
+
+type args struct {
+	policyPath string
+	scanRules  []string
+	skipRules  []string
+	severity   string
+}
+
 func TestFilterRules(t *testing.T) {
-	testPolicyPath := "test"
 
-	type args struct {
-		policyPath string
-		scanRules  []string
-		skipRules  []string
-	}
 	tests := []struct {
 		name        string
 		args        args
@@ -76,13 +81,212 @@ func TestFilterRules(t *testing.T) {
 			assert:      true,
 			regoMapSize: 7,
 		},
+		{
+			name: "both scan and skip rules supplied, with desired severity : low and rule severity : blank",
+			args: args{
+				policyPath: testPolicyPath,
+				scanRules:  []string{"Rule.6", "Rule.7", "Rule.8", "Rule.15", "Rule.31", "Rule.32", "Rule.40", "Rule.41", "Rule.42"},
+				skipRules:  []string{"Rule.31", "Rule.32", "Rule.38"},
+				severity:   "LOW",
+			},
+			regoDataMap: getTestRegoDataMap(50),
+			assert:      true,
+			regoMapSize: 7,
+		},
+		{
+			name: "both scan and skip rules supplied, with desired severity : high and rule severity : high",
+			args: args{
+				policyPath: testPolicyPath,
+				scanRules:  []string{"Rule.6", "Rule.7", "Rule.8", "Rule.15", "Rule.31", "Rule.32", "Rule.40", "Rule.41", "Rule.42"},
+				skipRules:  []string{"Rule.31", "Rule.32", "Rule.38"},
+				severity:   "HIGH",
+			},
+			regoDataMap: getTestRegoDataMapHighSeverity(50),
+			assert:      true,
+			regoMapSize: 7,
+		},
+		{
+			name: "both scan and skip rules supplied, with desired severity : high and rule severity : high",
+			args: args{
+				policyPath: testPolicyPath,
+				scanRules:  []string{"Rule.6", "Rule.7", "Rule.8", "Rule.15", "Rule.31", "Rule.32", "Rule.40", "Rule.41", "Rule.42"},
+				skipRules:  []string{"Rule.31", "Rule.32", "Rule.38"},
+				severity:   "HIGH",
+			},
+			regoDataMap: getTestRegoDataMapLowSeverity(50),
+			assert:      true,
+			regoMapSize: 0,
+		},
+		{
+			name: "both scan and skip rules supplied, with desired severity : high and rule severity : medium",
+			args: args{
+				policyPath: testPolicyPath,
+				scanRules:  []string{"Rule.6", "Rule.7", "Rule.8", "Rule.15", "Rule.31", "Rule.32", "Rule.40", "Rule.41", "Rule.42"},
+				skipRules:  []string{"Rule.31", "Rule.32", "Rule.38"},
+				severity:   "high",
+			},
+			regoDataMap: getTestRegoDataMapMediumSeverity(50),
+			assert:      true,
+			regoMapSize: 0,
+		},
+		{
+			name: "both scan and skip rules supplied, with desired severity : medium and rule severity : low",
+			args: args{
+				policyPath: testPolicyPath,
+				scanRules:  []string{"Rule.6", "Rule.7", "Rule.8", "Rule.15", "Rule.31", "Rule.32", "Rule.40", "Rule.41", "Rule.42"},
+				skipRules:  []string{"Rule.31", "Rule.32", "Rule.38"},
+				severity:   "MEDIUM",
+			},
+			regoDataMap: getTestRegoDataMapLowSeverity(50),
+			assert:      true,
+			regoMapSize: 0,
+		},
+		{
+			name: "both scan and skip rules supplied, with desired severity : medium and rule severity : medium",
+			args: args{
+				policyPath: testPolicyPath,
+				scanRules:  []string{"Rule.6", "Rule.7", "Rule.8", "Rule.15", "Rule.31", "Rule.32", "Rule.40", "Rule.41", "Rule.42"},
+				skipRules:  []string{"Rule.31", "Rule.32", "Rule.38"},
+				severity:   "MEDIUM",
+			},
+			regoDataMap: getTestRegoDataMapMediumSeverity(50),
+			assert:      true,
+			regoMapSize: 7,
+		},
+		{
+			name: "both scan and skip rules supplied, with desired severity : low and rule severity : low",
+			args: args{
+				policyPath: testPolicyPath,
+				scanRules:  []string{"Rule.6", "Rule.7", "Rule.8", "Rule.15", "Rule.31", "Rule.32", "Rule.40", "Rule.41", "Rule.42"},
+				skipRules:  []string{"Rule.31", "Rule.32", "Rule.38"},
+				severity:   "low",
+			},
+			regoDataMap: getTestRegoDataMapLowSeverity(50),
+			assert:      true,
+			regoMapSize: 7,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			e := &Engine{
 				regoDataMap: tt.regoDataMap,
 			}
-			e.FilterRules(tt.args.policyPath, tt.args.scanRules, tt.args.skipRules)
+			e.FilterRules(tt.args.policyPath, tt.args.scanRules, tt.args.skipRules, tt.args.severity)
+			if tt.assert {
+				if len(e.regoDataMap) != tt.regoMapSize {
+					t.Errorf("filterRules(): expected regoDataMap size = %d, got = %d", tt.regoMapSize, len(e.regoDataMap))
+				}
+			}
+		})
+	}
+}
+
+func TestFilterRulesWithEquallyDividedSeverity(t *testing.T) {
+	tests := []struct {
+		name        string
+		args        args
+		assert      bool
+		regoMapSize int
+		regoDataMap map[string]*RegoData
+	}{
+		{
+			name: "no scan and skip rules supplied, with desired severity: low and rules severities: low, medium, high",
+			args: args{
+				policyPath: testPolicyPath,
+				severity:   "low",
+			},
+			regoDataMap: getTestRegoDataMapWithEquallyDividedSeverity(30, []string{"LOW", "MEDIUM", "HIGH"}),
+			assert:      true,
+			regoMapSize: 30,
+		},
+		{
+			name: "no scan and skip rules supplied, with desired severity: medium and rules severities: low, medium, high",
+			args: args{
+				policyPath: testPolicyPath,
+				severity:   "medium",
+			},
+			regoDataMap: getTestRegoDataMapWithEquallyDividedSeverity(30, []string{"LOW", "MEDIUM", "HIGH"}),
+			assert:      true,
+			regoMapSize: 20,
+		},
+		{
+			name: "no scan and skip rules supplied, with desired severity: high and rules severities: low, medium, high",
+			args: args{
+				policyPath: testPolicyPath,
+				severity:   "high",
+			},
+			regoDataMap: getTestRegoDataMapWithEquallyDividedSeverity(30, []string{"LOW", "MEDIUM", "HIGH"}),
+			assert:      true,
+			regoMapSize: 10,
+		},
+		{
+			name: "no scan and skip rules supplied, with desired severity: high and rules severities: low, medium",
+			args: args{
+				policyPath: testPolicyPath,
+				severity:   "high",
+			},
+			regoDataMap: getTestRegoDataMapWithEquallyDividedSeverity(30, []string{"LOW", "MEDIUM"}),
+			assert:      true,
+			regoMapSize: 0,
+		},
+		{
+			name: "no scan and skip rules supplied, with desired severity: high and rules severities: low, medium",
+			args: args{
+				policyPath: testPolicyPath,
+				severity:   "MEDIUM",
+			},
+			regoDataMap: getTestRegoDataMapWithEquallyDividedSeverity(30, []string{"LOW", "MEDIUM"}),
+			assert:      true,
+			regoMapSize: 15,
+		},
+		{
+			name: "no scan and skip rules supplied, with desired severity: high and rules severities: low, medium",
+			args: args{
+				policyPath: testPolicyPath,
+				severity:   "LOW",
+			},
+			regoDataMap: getTestRegoDataMapWithEquallyDividedSeverity(30, []string{"LOW", "MEDIUM"}),
+			assert:      true,
+			regoMapSize: 30,
+		},
+		{
+			name: "no scan and skip rules supplied, with desired severity: low and rules severities: low",
+			args: args{
+				policyPath: testPolicyPath,
+				severity:   "LOW",
+			},
+			regoDataMap: getTestRegoDataMapWithEquallyDividedSeverity(10, []string{"MEDIUM"}),
+			assert:      true,
+			regoMapSize: 10,
+		},
+		{
+			name: "no scan and skip rules supplied, with desired severity : medium and rules severities: medium",
+			args: args{
+				policyPath: testPolicyPath,
+				severity:   "MEDIUM",
+			},
+			regoDataMap: getTestRegoDataMapWithEquallyDividedSeverity(10, []string{"MEDIUM"}),
+			assert:      true,
+			regoMapSize: 10,
+		},
+		{
+			name: "no scan and skip rules supplied, with desired severity: high and rules severities: medium",
+			args: args{
+				policyPath: testPolicyPath,
+				severity:   "HIGH",
+			},
+			regoDataMap: getTestRegoDataMapWithEquallyDividedSeverity(10, []string{"MEDIUM"}),
+			assert:      true,
+			regoMapSize: 0,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			e := &Engine{
+				regoDataMap: tt.regoDataMap,
+			}
+			e.FilterRules(tt.args.policyPath, tt.args.scanRules, tt.args.skipRules, tt.args.severity)
 			if tt.assert {
 				if len(e.regoDataMap) != tt.regoMapSize {
 					t.Errorf("filterRules(): expected regoDataMap size = %d, got = %d", tt.regoMapSize, len(e.regoDataMap))
@@ -101,3 +305,52 @@ func getTestRegoDataMap(size int) map[string]*RegoData {
 	}
 	return testRegoDataMap
 }
+
+// helper func to generate test rego data map of given size with severity levels attached in equal proportion
+func getTestRegoDataMapWithEquallyDividedSeverity(size int, severities []string) map[string]*RegoData {
+
+	severitytypes := len(severities)
+
+	if severitytypes == 0 {
+		return getTestRegoDataMap(size)
+	}
+
+	severitypartitionsizes := size / severitytypes
+	severitycounter := 0
+	testRegoDataMap := make(map[string]*RegoData)
+
+	for i := 0; i < size; i++ {
+		ruleID := fmt.Sprintf("Rule.%d", i)
+		testRegoDataMap[ruleID] = &RegoData{Metadata: RegoMetadata{Severity: severities[severitycounter]}}
+		if (i+1)%severitypartitionsizes == 0 {
+			severitycounter = severitycounter + 1
+		}
+	}
+
+	return testRegoDataMap
+}
+
+// helper func to generate test rego data map of given size with required severity
+func getTestRegoDataMapWithSeverity(size int, severity string) map[string]*RegoData {
+	testRegoDataMap := getTestRegoDataMap(size)
+
+	for _, regoData := range testRegoDataMap {
+		regoData.Metadata.Severity = severity
+	}
+	return testRegoDataMap
+}
+
+// helper func to generate test rego data map of given size with high severity
+func getTestRegoDataMapHighSeverity(size int) map[string]*RegoData {
+	return getTestRegoDataMapWithSeverity(size, utils.HighSeverity)
+}
+
+// helper func to generate test rego data map of given size with medium severity
+func getTestRegoDataMapMediumSeverity(size int) map[string]*RegoData {
+	return getTestRegoDataMapWithSeverity(size, utils.MediumSeverity)
+}
+
+// helper func to generate test rego data map of given size with low severity
+func getTestRegoDataMapLowSeverity(size int) map[string]*RegoData {
+	return getTestRegoDataMapWithSeverity(size, utils.LowSeverity)
+}
diff --git a/pkg/runtime/executor_test.go b/pkg/runtime/executor_test.go
index db1a50fcc..79cb7d511 100644
--- a/pkg/runtime/executor_test.go
+++ b/pkg/runtime/executor_test.go
@@ -29,6 +29,7 @@ import (
 	"github.com/accurics/terrascan/pkg/notifications"
 	"github.com/accurics/terrascan/pkg/notifications/webhook"
 	"github.com/accurics/terrascan/pkg/policy"
+	"github.com/accurics/terrascan/pkg/utils"
 )
 
 var (
@@ -56,11 +57,11 @@ type MockPolicyEngine struct {
 	err error
 }
 
-func (m MockPolicyEngine) Init(input string, scanRules, skipRules []string) error {
+func (m MockPolicyEngine) Init(input string, scanRules, skipRules []string, severity string) error {
 	return m.err
 }
 
-func (m MockPolicyEngine) FilterRules(input string, scanRules, skipRules []string) {
+func (m MockPolicyEngine) FilterRules(input string, scanRules, skipRules []string, severity string) {
 	/*
 		This method does nothing. Required to fullfil the Engine interface contract
 	*/
@@ -101,9 +102,9 @@ func TestExecute(t *testing.T) {
 		{
 			name: "test LoadIacDir no error",
 			executor: Executor{
-				dirPath:      "./testdata/testdir",
-				iacProvider:  MockIacProvider{err: nil},
-				policyEngine: []policy.Engine{MockPolicyEngine{err: nil}},
+				dirPath:       "./testdata/testdir",
+				iacProvider:   MockIacProvider{err: nil},
+				policyEngines: []policy.Engine{MockPolicyEngine{err: nil}},
 			},
 			wantErr: nil,
 		},
@@ -118,45 +119,45 @@ func TestExecute(t *testing.T) {
 		{
 			name: "test LoadIacFile no error",
 			executor: Executor{
-				filePath:     "./testdata/testfile",
-				iacProvider:  MockIacProvider{err: nil},
-				policyEngine: []policy.Engine{MockPolicyEngine{err: nil}},
+				filePath:      "./testdata/testfile",
+				iacProvider:   MockIacProvider{err: nil},
+				policyEngines: []policy.Engine{MockPolicyEngine{err: nil}},
 			},
 			wantErr: nil,
 		},
 		{
 			name: "test SendNofitications no error",
 			executor: Executor{
-				iacProvider:  MockIacProvider{err: nil},
-				notifiers:    []notifications.Notifier{&MockNotifier{err: nil}},
-				policyEngine: []policy.Engine{MockPolicyEngine{err: nil}},
+				iacProvider:   MockIacProvider{err: nil},
+				notifiers:     []notifications.Notifier{&MockNotifier{err: nil}},
+				policyEngines: []policy.Engine{MockPolicyEngine{err: nil}},
 			},
 			wantErr: nil,
 		},
 		{
 			name: "test SendNofitications mock error",
 			executor: Executor{
-				iacProvider:  MockIacProvider{err: nil},
-				notifiers:    []notifications.Notifier{&MockNotifier{err: errMockNotifier}},
-				policyEngine: []policy.Engine{MockPolicyEngine{err: nil}},
+				iacProvider:   MockIacProvider{err: nil},
+				notifiers:     []notifications.Notifier{&MockNotifier{err: errMockNotifier}},
+				policyEngines: []policy.Engine{MockPolicyEngine{err: nil}},
 			},
 			wantErr: errMockNotifier,
 		},
 		{
 			name: "test policy enginer no error",
 			executor: Executor{
-				iacProvider:  MockIacProvider{err: nil},
-				notifiers:    []notifications.Notifier{&MockNotifier{err: nil}},
-				policyEngine: []policy.Engine{MockPolicyEngine{err: nil}},
+				iacProvider:   MockIacProvider{err: nil},
+				notifiers:     []notifications.Notifier{&MockNotifier{err: nil}},
+				policyEngines: []policy.Engine{MockPolicyEngine{err: nil}},
 			},
 			wantErr: nil,
 		},
 		{
 			name: "test policy engine error",
 			executor: Executor{
-				iacProvider:  MockIacProvider{err: nil},
-				notifiers:    []notifications.Notifier{&MockNotifier{err: nil}},
-				policyEngine: []policy.Engine{MockPolicyEngine{err: errMockPolicyEngine}},
+				iacProvider:   MockIacProvider{err: nil},
+				notifiers:     []notifications.Notifier{&MockNotifier{err: nil}},
+				policyEngines: []policy.Engine{MockPolicyEngine{err: errMockPolicyEngine}},
 			},
 			wantErr: errMockPolicyEngine,
 		},
@@ -235,7 +236,7 @@ func TestInit(t *testing.T) {
 				configFile: "./testdata/does-not-exist",
 			},
 			wantErr:         config.ErrNotPresent,
-			wantIacProvider: nil,
+			wantIacProvider: &tfv14.TfV14{},
 		},
 		{
 			name: "invalid policy path",
@@ -332,7 +333,7 @@ func TestInit(t *testing.T) {
 				configFile: "./testdata/does-not-exist",
 			},
 			wantErr:         config.ErrNotPresent,
-			wantIacProvider: nil,
+			wantIacProvider: &tfv12.TfV12{},
 		},
 		{
 			name: "invalid policy path",
@@ -368,3 +369,144 @@ func TestInit(t *testing.T) {
 		})
 	}
 }
+
+type flagSet struct {
+	iacType    string
+	iacVersion string
+	filePath   string
+	dirPath    string
+	policyPath []string
+	cloudType  []string
+	severity   string
+	scanRules  []string
+	skipRules  []string
+}
+
+func TestNewExecutor(t *testing.T) {
+	table := []struct {
+		name          string
+		wantErr       error
+		configfile    string
+		flags         flagSet
+		wantScanRules []string
+		wantSkipRules []string
+		wantSeverity  string
+	}{
+		{
+			name:       "values passed through flag should override configfile value",
+			configfile: "./testdata/scan-skip-rules-low-severity.toml",
+			wantErr:    nil,
+			flags: flagSet{
+				severity:   "high",
+				scanRules:  []string{"AWS.S3Bucket.DS.High.1043"},
+				skipRules:  []string{"accurics.kubernetes.IAM.109"},
+				dirPath:    "./testdata/testdir",
+				policyPath: []string{"./testdata/testpolicies"},
+				cloudType:  []string{"aws"},
+			},
+			wantScanRules: []string{
+				"AWS.S3Bucket.DS.High.1043",
+			},
+			wantSkipRules: []string{
+				"accurics.kubernetes.IAM.109",
+			},
+			wantSeverity: "high",
+		},
+		{
+			name:       "skipRules passed through flag should override configfile value",
+			configfile: "./testdata/scan-skip-rules-low-severity.toml",
+			wantErr:    nil,
+			flags: flagSet{
+				skipRules:  []string{"accurics.kubernetes.IAM.109"},
+				dirPath:    "./testdata/testdir",
+				policyPath: []string{"./testdata/testpolicies"},
+				cloudType:  []string{"aws"},
+			},
+			wantScanRules: []string{
+				"AWS.S3Bucket.DS.High.1043",
+				"accurics.kubernetes.IAM.107",
+			},
+			wantSkipRules: []string{
+				"accurics.kubernetes.IAM.109",
+			},
+			wantSeverity: "low",
+		},
+		{
+			name:       "scanRules passed through flag should override configfile value",
+			configfile: "./testdata/scan-skip-rules-low-severity.toml",
+			wantErr:    nil,
+			flags: flagSet{
+				scanRules:  []string{"AWS.S3Bucket.DS.High.1043"},
+				dirPath:    "./testdata/testdir",
+				policyPath: []string{"./testdata/testpolicies"},
+				cloudType:  []string{"aws"},
+			},
+			wantScanRules: []string{
+				"AWS.S3Bucket.DS.High.1043",
+			},
+			wantSkipRules: []string{
+				"AWS.S3Bucket.IAM.High.0370",
+				"accurics.kubernetes.IAM.5",
+				"accurics.kubernetes.OPS.461",
+				"accurics.kubernetes.IAM.109",
+			},
+			wantSeverity: "low",
+		},
+		{
+			name:       "severity passed through flag should override configfile value",
+			configfile: "./testdata/scan-skip-rules-low-severity.toml",
+			wantErr:    nil,
+			flags: flagSet{
+				severity:   "medium",
+				dirPath:    "./testdata/testdir",
+				policyPath: []string{"./testdata/testpolicies"},
+				cloudType:  []string{"aws"},
+			},
+			wantScanRules: []string{
+				"AWS.S3Bucket.DS.High.1043",
+				"accurics.kubernetes.IAM.107",
+			},
+			wantSkipRules: []string{
+				"AWS.S3Bucket.IAM.High.0370",
+				"accurics.kubernetes.IAM.5",
+				"accurics.kubernetes.OPS.461",
+				"accurics.kubernetes.IAM.109",
+			},
+			wantSeverity: "medium",
+		},
+		{
+			name:       "configfile value will be used if no flags are passed",
+			configfile: "./testdata/scan-skip-rules-low-severity.toml",
+			wantErr:    nil,
+			flags: flagSet{
+				dirPath:    "./testdata/testdir",
+				policyPath: []string{"./testdata/testpolicies"},
+				cloudType:  []string{"aws"},
+			},
+			wantScanRules: []string{
+				"AWS.S3Bucket.DS.High.1043",
+				"accurics.kubernetes.IAM.107",
+			},
+			wantSkipRules: []string{
+				"AWS.S3Bucket.IAM.High.0370",
+				"accurics.kubernetes.IAM.5",
+				"accurics.kubernetes.OPS.461",
+				"accurics.kubernetes.IAM.109",
+			},
+			wantSeverity: "low",
+		},
+	}
+
+	for _, tt := range table {
+		t.Run(tt.name, func(t *testing.T) {
+			gotExecutor, gotErr := NewExecutor(tt.flags.iacType, tt.flags.iacVersion, tt.flags.cloudType, tt.flags.filePath, tt.flags.dirPath, tt.configfile, tt.flags.policyPath, tt.flags.scanRules, tt.flags.skipRules, tt.flags.severity)
+
+			if !reflect.DeepEqual(tt.wantErr, gotErr) {
+				t.Errorf("Mismatch in error => got: '%v', want: '%v'", gotErr, tt.wantErr)
+			}
+			if utils.IsSliceEqual(gotExecutor.scanRules, tt.wantScanRules) && utils.IsSliceEqual(gotExecutor.skipRules, tt.wantSkipRules) && gotExecutor.severity != tt.wantSeverity {
+				t.Errorf("got: 'scanRules = %v, skipRules = %v, severity = %s', want: 'scanRules = %v, skipRules = %v, severity = %s'", gotExecutor.scanRules, gotExecutor.skipRules, gotExecutor.severity, tt.wantScanRules, tt.wantSkipRules, tt.wantSeverity)
+			}
+		})
+	}
+}
diff --git a/pkg/runtime/rules_test.go b/pkg/runtime/rules_test.go
index b042318ad..8f3aa50b8 100644
--- a/pkg/runtime/rules_test.go
+++ b/pkg/runtime/rules_test.go
@@ -4,11 +4,12 @@ import (
 	"testing"
 )
 
-func TestExecutorInitRules(t *testing.T) {
+func TestExecutorInitRulesAndSeverity(t *testing.T) {
 	type fields struct {
 		configFile string
 		scanRules  []string
 		skipRules  []string
+		severity   string
 	}
 	tests := []struct {
 		name         string
@@ -17,6 +18,7 @@ func TestExecutorInitRules(t *testing.T) {
 		assert       bool
 		lenScanRules int
 		lenSkipRules int
+		severity     string
 	}{
 		{
 			name:   "no config file",
@@ -52,6 +54,18 @@ func TestExecutorInitRules(t *testing.T) {
 			lenScanRules: 4,
 			lenSkipRules: 5,
 		},
+		{
+			name: "valid config file with scan and skip rules with low severity",
+			fields: fields{
+				configFile: "testdata/scan-skip-rules-low-severity.toml",
+				scanRules:  []string{"testRuleA", "testRuleB"},
+				skipRules:  []string{"testRuleC"},
+				severity:   "low",
+			},
+			assert:       true,
+			lenScanRules: 4,
+			lenSkipRules: 5,
+		},
 		{
 			name: "valid config file with invalid scan rules",
 			fields: fields{
@@ -66,6 +80,13 @@ func TestExecutorInitRules(t *testing.T) {
 			},
 			wantErr: true,
 		},
+		{
+			name: "valid config file with invalid severity",
+			fields: fields{
+				configFile: "testdata/invalid-severity.toml",
+			},
+			wantErr: true,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -74,12 +95,12 @@ func TestExecutorInitRules(t *testing.T) {
 				scanRules:  tt.fields.scanRules,
 				skipRules:  tt.fields.skipRules,
 			}
-			if err := e.initRules(); (err != nil) != tt.wantErr {
-				t.Errorf("Executor.initRules() error = %v, wantErr %v", err, tt.wantErr)
+			if err := e.initRuleSetFromConfigFile(); (err != nil) != tt.wantErr {
+				t.Errorf("Executor.initRulesAndSeverity() error = %v, wantErr %v", err, tt.wantErr)
 			}
 			if tt.assert {
-				if len(e.scanRules) != tt.lenScanRules && len(e.skipRules) != tt.lenSkipRules {
-					t.Errorf("Executor.initRules() expected scanRules: %d and skipRules: %d, got scanRules: %d and skipRules: %d", tt.lenScanRules, tt.lenSkipRules, len(e.scanRules), len(e.skipRules))
+				if len(e.scanRules) != tt.lenScanRules && len(e.skipRules) != tt.lenSkipRules && e.severity != tt.severity {
+					t.Errorf("Executor.initRulesAndSeverity() expected scanRules: %d , skipRules: %d & severity : %s, got scanRules: %d , skipRules: %d and severity: %s", tt.lenScanRules, tt.lenSkipRules, tt.severity, len(e.scanRules), len(e.skipRules), e.severity)
 				}
 			}
 		})
diff --git a/pkg/runtime/testdata/invalid-severity.toml b/pkg/runtime/testdata/invalid-severity.toml
new file mode 100644
index 000000000..e183b310d
--- /dev/null
+++ b/pkg/runtime/testdata/invalid-severity.toml
@@ -0,0 +1,3 @@
+[severity]
+level = HIGH
+# string value has to be "wrapped" in quotes
diff --git a/pkg/runtime/testdata/scan-skip-rules-low-severity.toml b/pkg/runtime/testdata/scan-skip-rules-low-severity.toml
new file mode 100644
index 000000000..3f4d71b4a
--- /dev/null
+++ b/pkg/runtime/testdata/scan-skip-rules-low-severity.toml
@@ -0,0 +1,14 @@
+[rules]
+    scan-rules = [
+        "AWS.S3Bucket.DS.High.1043",
+        "accurics.kubernetes.IAM.107"
+    ]
+    skip-rules = [
+        "AWS.S3Bucket.IAM.High.0370",
+        "accurics.kubernetes.IAM.5",
+        "accurics.kubernetes.OPS.461",
+        "accurics.kubernetes.IAM.109"
+    ]
+
+[severity]
+level = "low"
\ No newline at end of file
diff --git a/pkg/runtime/validate_test.go b/pkg/runtime/validate_test.go
index 23534884b..f82fa5f92 100644
--- a/pkg/runtime/validate_test.go
+++ b/pkg/runtime/validate_test.go
@@ -50,6 +50,42 @@ func TestValidateInputs(t *testing.T) {
 			},
 			wantErr: nil,
 		},
+		{
+			name: "valid filePath",
+			executor: Executor{
+				filePath:   "./testdata/testfile",
+				dirPath:    "",
+				cloudType:  []string{"aws"},
+				iacType:    "terraform",
+				iacVersion: "v14",
+				severity:   "high",
+			},
+			wantErr: nil,
+		},
+		{
+			name: "valid dirPath",
+			executor: Executor{
+				filePath:   "",
+				dirPath:    "./testdata/testdir",
+				cloudType:  []string{"aws"},
+				iacType:    "terraform",
+				iacVersion: "v14",
+				severity:   "MEDIUM",
+			},
+			wantErr: nil,
+		},
+		{
+			name: "valid dirPath",
+			executor: Executor{
+				filePath:   "",
+				dirPath:    "./testdata/testdir",
+				cloudType:  []string{"aws"},
+				iacType:    "terraform",
+				iacVersion: "v12",
+				severity:   " LOW ",
+			},
+			wantErr: nil,
+		},
 		{
 			name: "empty iac path",
 			executor: Executor{
@@ -94,6 +130,18 @@ func TestValidateInputs(t *testing.T) {
 			},
 			wantErr: errIacNotSupported,
 		},
+		{
+			name: "invalid severity",
+			executor: Executor{
+				filePath:   "",
+				dirPath:    "./testdata/testdir",
+				cloudType:  []string{"aws"},
+				iacType:    "terraform",
+				iacVersion: "v14",
+				severity:   "HGIH",
+			},
+			wantErr: errSeverityNotSupported,
+		},
 	}
 
 	for _, tt := range table {