Repository: aquasecurity/tfsec
Pull request #1376 (2022-01-24 19:03:54)

Reorganise project structure and update defsec for new formatters
![rc1](https://user-images.githubusercontent.com/1187060/150855194-59a4a436-70a7-40cc-a252-cc15929d5f30.png)



Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 14b16187d..610ff2bb8 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -32,7 +32,7 @@ linters-settings:
 
 issues:
   exclude-rules:
-    - path: internal/app/tfsec/funcs/
+    - path: internal/pkg/funcs/
       linters:
         - cyclop
         - errorlint
diff --git a/cmd/tfsec-docs/main.go b/cmd/tfsec-docs/main.go
index d7844c54d..e2442c39d 100644
--- a/cmd/tfsec-docs/main.go
+++ b/cmd/tfsec-docs/main.go
@@ -6,8 +6,8 @@ import (
 	"sort"
 	"strings"
 
-	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	_ "github.com/aquasecurity/tfsec/internal/pkg/rules"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 	"github.com/spf13/cobra"
 )
 
diff --git a/cmd/tfsec/main.go b/cmd/tfsec/main.go
index f3b39e8ea..7a5c63db3 100644
--- a/cmd/tfsec/main.go
+++ b/cmd/tfsec/main.go
@@ -3,596 +3,13 @@ package main
 import (
 	"fmt"
 	"os"
-	"path/filepath"
-	"runtime"
-	"strings"
 
-	"github.com/aquasecurity/defsec/formatters"
-	"github.com/aquasecurity/defsec/metrics"
-	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/defsec/severity"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/config"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/custom"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/ignores"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/legacy"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
-	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/updater"
-	"github.com/aquasecurity/tfsec/version"
-	"github.com/liamg/tml"
-	"github.com/spf13/cobra"
+	"github.com/aquasecurity/tfsec/internal/app/tfsec/cmd"
 )
 
-var showVersion = false
-var runUpdate = false
-var disableColours = false
-var format string
-var softFail = false
-var filterResults string
-var excludedRuleIDs string
-var tfvarsPaths []string
-var excludePaths []string
-var outputFlag string
-var customCheckDir string
-var configFile string
-var tfsecConfig = &config.Config{}
-var conciseOutput = false
-var excludeDownloaded = false
-var detailedExitCode = false
-var includePassed = false
-var includeIgnored = false
-var ignoreWarnings = false
-var ignoreInfo = false
-var allDirs = false
-var migrateIgnores = false
-var runStatistics bool
-var ignoreHCLErrors bool
-var stopOnCheckError bool
-var workspace string
-var passingGif bool
-var singleThreadedMode bool
-
-func init() {
-	rootCmd.Flags().BoolVar(&singleThreadedMode, "single-thread", singleThreadedMode, "Run checks using a single thread")
-	rootCmd.Flags().BoolVar(&ignoreHCLErrors, "ignore-hcl-errors", ignoreHCLErrors, "Stop and report an error if an HCL parse error is encountered")
-	rootCmd.Flags().BoolVar(&disableColours, "no-colour", disableColours, "Disable coloured output")
-	rootCmd.Flags().BoolVar(&disableColours, "no-color", disableColours, "Disable colored output (American style!)")
-	rootCmd.Flags().BoolVarP(&showVersion, "version", "v", showVersion, "Show version information and exit")
-	rootCmd.Flags().BoolVar(&runUpdate, "update", runUpdate, "Update to latest version")
-	rootCmd.Flags().BoolVar(&migrateIgnores, "migrate-ignores", migrateIgnores, "Migrate ignore codes to the new ID structure")
-	rootCmd.Flags().StringVarP(&format, "format", "f", format, "Select output format: default, json, csv, checkstyle, junit, sarif")
-	rootCmd.Flags().StringVarP(&excludedRuleIDs, "exclude", "e", excludedRuleIDs, "Provide comma-separated list of rule IDs to exclude from run.")
-	rootCmd.Flags().StringVar(&filterResults, "filter-results", filterResults, "Filter results to return specific checks only (supports comma-delimited input).")
-	rootCmd.Flags().BoolVarP(&softFail, "soft-fail", "s", softFail, "Runs checks but suppresses error code")
-	rootCmd.Flags().StringSliceVar(&tfvarsPaths, "tfvars-file", tfvarsPaths, "Path to .tfvars file, can be used multiple times and evaluated in order of specification")
-	rootCmd.Flags().StringSliceVar(&excludePaths, "exclude-path", excludePaths, "Folder path to exclude, can be used multiple times and evaluated in order of specification")
-	rootCmd.Flags().StringVar(&outputFlag, "out", outputFlag, "Set output file")
-	rootCmd.Flags().StringVar(&customCheckDir, "custom-check-dir", customCheckDir, "Explicitly the custom checks dir location")
-	rootCmd.Flags().StringVar(&configFile, "config-file", configFile, "Config file to use during run")
-	rootCmd.Flags().BoolVar(&debug.Enabled, "debug", debug.Enabled, "Enable debug logging (same as verbose)")
-	rootCmd.Flags().BoolVar(&debug.Enabled, "verbose", debug.Enabled, "Enable verbose logging (same as debug)")
-	rootCmd.Flags().BoolVar(&conciseOutput, "concise-output", conciseOutput, "Reduce the amount of output and no statistics")
-	rootCmd.Flags().BoolVar(&excludeDownloaded, "exclude-downloaded-modules", excludeDownloaded, "Remove results for downloaded modules in .terraform folder")
-	rootCmd.Flags().BoolVar(&detailedExitCode, "detailed-exit-code", detailedExitCode, "Produce more detailed exit status codes.")
-	rootCmd.Flags().BoolVar(&includePassed, "include-passed", includePassed, "Include passed checks in the result output")
-	rootCmd.Flags().BoolVar(&includeIgnored, "include-ignored", includeIgnored, "Include ignored checks in the result output")
-	rootCmd.Flags().BoolVar(&allDirs, "force-all-dirs", allDirs, "Don't search for tf files, include everything below provided directory.")
-	rootCmd.Flags().BoolVar(&runStatistics, "run-statistics", runStatistics, "View statistics table of current findings.")
-	rootCmd.Flags().BoolVar(&ignoreWarnings, "ignore-warnings", ignoreWarnings, "[DEPRECATED] Don't show warnings in the output.")
-	rootCmd.Flags().BoolVar(&ignoreInfo, "ignore-info", ignoreWarnings, "[DEPRECATED] Don't show info results in the output.")
-	rootCmd.Flags().BoolVarP(&stopOnCheckError, "allow-checks-to-panic", "p", stopOnCheckError, "Allow panics to propagate up from rule checking")
-	rootCmd.Flags().StringVarP(&workspace, "workspace", "w", workspace, "Specify a workspace for ignore limits")
-	rootCmd.Flags().BoolVar(&passingGif, "gif", passingGif, "Show a celebratory gif in the terminal if no problems are found (default formatter only)")
-}
-
 func main() {
-	if err := rootCmd.Execute(); err != nil {
+	if err := cmd.Root().Execute(); err != nil {
 		fmt.Println(err)
 		os.Exit(1)
 	}
 }
-
-type formatterInfo struct {
-	formatter  *formatters.Formatter
-	outputFile *os.File
-	format     string
-}
-
-var rootCmd = &cobra.Command{
-	Use:   "tfsec [directory]",
-	Short: "tfsec is a terraform security scanner",
-	Long:  `tfsec is a simple tool to detect potential security vulnerabilities in your terraformed infrastructure.`,
-	PersistentPreRun: func(_ *cobra.Command, args []string) {
-
-		// disable colour if running on windows - colour formatting doesn't work
-		if disableColours || runtime.GOOS == "windows" {
-			debug.Log("Disabled formatting.")
-			tml.DisableFormatting()
-		}
-
-		if showVersion {
-			if version.Version == "" {
-				fmt.Println("You are running a locally built version of tfsec.")
-			} else {
-				fmt.Println(version.Version)
-			}
-			os.Exit(0)
-		}
-
-		if runUpdate {
-			if err := updater.Update(); err != nil {
-				_ = tml.Printf("Not updating, %s\n", err.Error())
-			}
-			os.Exit(0)
-		}
-
-		if migrateIgnores {
-			var dir string
-			var err error
-
-			if len(args) == 1 {
-				dir, err = filepath.Abs(args[0])
-			} else {
-				dir, err = os.Getwd()
-			}
-			if err != nil {
-				_ = tml.Printf("The provided dir was not found")
-				os.Exit(1)
-			}
-
-			stats, err := ignores.RunMigration(dir)
-			if err != nil {
-				_ = tml.Printf("Errors occurred while running migration. %s", err.Error())
-				os.Exit(1)
-			}
-			if len(stats) > 0 {
-				for _, stat := range stats {
-					_ = tml.Printf("%s migrated from %s => %s\n", stat.Filename, stat.FromCode, stat.ToCode)
-				}
-			}
-			os.Exit(0)
-		}
-	},
-	RunE: func(_ *cobra.Command, args []string) error {
-
-		var dir string
-		var err error
-		var filterResultsList []string
-		var outputFiles []formatterInfo
-
-		if ignoreWarnings || ignoreInfo {
-			fmt.Fprint(os.Stderr, "WARNING: The --ignore-info and --ignore-warnings flags are deprecated and will soon be removed.\n")
-		}
-
-		if len(args) == 1 {
-			dir, err = filepath.Abs(args[0])
-		} else {
-			dir, err = os.Getwd()
-		}
-		if err != nil {
-			fmt.Println(err)
-			os.Exit(1)
-		}
-
-		if dirInfo, err := os.Stat(dir); err != nil {
-			if os.IsNotExist(err) {
-				fmt.Println("The provided path does not exist, exiting")
-				os.Exit(1)
-			}
-			fmt.Println(err)
-			os.Exit(1)
-		} else if !dirInfo.IsDir() {
-			fmt.Println("The provided path is not a dir, exiting")
-			os.Exit(1)
-		}
-
-		tfsecDir := fmt.Sprintf("%s/.tfsec", dir)
-
-		if len(configFile) > 0 {
-			tfsecConfig, err = loadConfigFile(configFile)
-			if err != nil {
-				return err
-			}
-		} else {
-			jsonConfigFile := fmt.Sprintf("%s/%s", tfsecDir, "config.json")
-			yamlConfigFile := fmt.Sprintf("%s/%s", tfsecDir, "config.yml")
-			if _, err = os.Stat(jsonConfigFile); err == nil {
-				tfsecConfig, err = loadConfigFile(jsonConfigFile)
-				if err != nil {
-					return err
-				}
-			} else if _, err = os.Stat(yamlConfigFile); err == nil {
-				tfsecConfig, err = loadConfigFile(yamlConfigFile)
-				if err != nil {
-					return err
-				}
-			} else {
-				tfsecConfig = &config.Config{}
-			}
-		}
-
-		debug.Log("Loading custom checks...")
-		if len(customCheckDir) == 0 {
-			debug.Log("Using the default custom check folder")
-			customCheckDir = tfsecDir
-		}
-		debug.Log("custom check directory set to %s", customCheckDir)
-		err = custom.Load(customCheckDir)
-		if err != nil {
-			_, _ = fmt.Fprintf(os.Stderr, "There were errors while processing custom check files. %s", err)
-			os.Exit(1)
-		}
-		debug.Log("Custom checks loaded")
-
-		if len(filterResults) > 0 {
-			filterResultsList = strings.Split(filterResults, ",")
-		}
-
-		formats := strings.Split(format, ",")
-		if outputFlag != "" {
-			if format == "" {
-				format = "text"
-			}
-
-			multipleFormats := false
-
-			if len(formats) > 1 {
-				outputFlag = strings.Split(outputFlag, ".")[0]
-				multipleFormats = true
-			}
-
-			for _, formatType := range formats {
-				var (
-					f          *os.File
-					err        error
-					outputPath string
-				)
-
-				if multipleFormats {
-					outputPath = filepath.Clean(outputFlag + "." + defaultExtensionForFormatter(formatType))
-				} else {
-					outputPath = filepath.Clean(outputFlag)
-				}
-
-				f, err = os.OpenFile(outputPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o600)
-
-				if err != nil {
-					fmt.Println(err)
-					os.Exit(1)
-				}
-
-				outputFiles = append(outputFiles, formatterInfo{
-					outputFile: f,
-					format:     formatType,
-				})
-			}
-
-			defer func() {
-				for _, file := range outputFiles {
-					_ = file.outputFile.Close()
-				}
-			}()
-		} else {
-			outputFiles = append(outputFiles, formatterInfo{
-				outputFile: os.Stdout,
-				format:     formats[0],
-			})
-		}
-
-		for i, fileFormat := range outputFiles {
-			formatter, err := getFormatter(fileFormat.format)
-			if err != nil {
-				fmt.Println(err)
-				os.Exit(1)
-			}
-
-			outputFiles[i].formatter = &formatter
-		}
-
-		if len(tfvarsPaths) == 0 && unusedTfvarsPresent(dir) {
-			fmt.Fprintf(os.Stderr, "Warning: A tfvars file was found but not automatically used. Did you mean to specify the --tfvars-file flag?\n")
-		}
-
-		debug.Log("Starting parser...")
-		modules, err := parser.New(dir, getParserOptions()...).ParseDirectory()
-		if err != nil {
-			fmt.Println(err)
-			os.Exit(1)
-		}
-
-		debug.Log("Starting scanner...")
-		results, err := scanner.New(getScannerOptions()...).Scan(modules)
-		if err != nil {
-			return fmt.Errorf("fatal error during scan: %w", err)
-		}
-		results = updateResultSeverity(results)
-		results = removeExcludedResults(results, ignoreWarnings, excludeDownloaded)
-		if len(filterResultsList) > 0 {
-			var filteredResult []rules.Result
-			for _, result := range results {
-				for _, ruleID := range filterResultsList {
-					if result.Rule().LongID() == ruleID {
-						filteredResult = append(filteredResult, result)
-					}
-				}
-			}
-			results = filteredResult
-		}
-
-		metrics.Counter("counts", "blocks").Increment(0)
-		metrics.Counter("counts", "modules").Increment(0)
-		metrics.Counter("counts", "files").Increment(parser.CountFiles())
-		metrics.Counter("results", "critical")
-		metrics.Counter("results", "high")
-		metrics.Counter("results", "medium")
-		metrics.Counter("results", "low")
-		for _, result := range results {
-			metrics.Counter("results", strings.ToLower(string(result.Rule().Severity))).Increment(1)
-		}
-
-		if runStatistics {
-			statistics := scanner.Statistics{}
-			for _, result := range results {
-				statistics = scanner.AddStatisticsCount(statistics, result)
-			}
-			statistics.PrintStatisticsTable()
-			return nil
-		}
-
-		for _, formatInfo := range outputFiles {
-			formatter := formatInfo.formatter
-			if formatter == nil {
-				return fmt.Errorf("could not access formatter for file format '%s'", formatInfo.format)
-			}
-
-			if err := (*formatter)(formatInfo.outputFile, results, dir, getFormatterOptions()...); err != nil {
-				return err
-			}
-		}
-
-		// Soft fail always takes precedence. If set, only execution errors
-		// produce a failure exit code (1).
-		if softFail {
-			return nil
-		}
-
-		if detailedExitCode {
-			os.Exit(getDetailedExitCode(results))
-		}
-
-		// If all failed rules are of LOW severity, then produce a success
-		// exit code (0).
-		if allInfo(results) {
-			return nil
-		}
-
-		os.Exit(1)
-		return nil
-	},
-}
-
-func getParserOptions() []parser.Option {
-	var opts []parser.Option
-	if allDirs {
-		opts = append(opts, parser.OptionDoNotSearchTfFiles())
-	}
-	var validTfVarFiles []string
-	if len(tfvarsPaths) > 0 {
-		for _, tfvarsPath := range tfvarsPaths {
-			tfvp, err := filepath.Abs(tfvarsPath)
-			if err != nil {
-				fmt.Println(err)
-			}
-			if _, err := os.Stat(tfvp); err == nil {
-				validTfVarFiles = append(validTfVarFiles, tfvp)
-			}
-		}
-		opts = append(opts, parser.OptionWithTFVarsPaths(validTfVarFiles))
-	}
-	var validExcludePaths []string
-	if len(excludePaths) > 0 {
-		for _, excludePath := range excludePaths {
-			exP, err := filepath.Abs(excludePath)
-			if err != nil {
-				fmt.Println(err)
-			}
-			if _, err := os.Stat(exP); err == nil {
-				validExcludePaths = append(validExcludePaths, exP)
-			}
-		}
-		opts = append(opts, parser.OptionWithExcludePaths(validExcludePaths))
-	}
-
-	if !ignoreHCLErrors {
-		opts = append(opts, parser.OptionStopOnHCLError())
-	}
-
-	if workspace != "" {
-		opts = append(opts, parser.OptionWithWorkspaceName(workspace))
-	}
-
-	return opts
-}
-
-func getDetailedExitCode(results rules.Results) int {
-	// If there are no failed rules, then produce a success exit code (0).
-	if len(results) == 0 || len(results) == countPassedResults(results) {
-		return 0
-	}
-
-	// If there are some failed rules but they are all of LOW severity, then
-	// produce a special failure exit code (2).
-	if allInfo(results) {
-		return 2
-	}
-
-	// If there is any failed check of HIGH or WARNING severity, then
-	// produce the regular failure exit code (1).
-	return 1
-}
-
-func removeExcludedResults(results rules.Results, ignoreWarnings bool, excludeDownloaded bool) rules.Results {
-	var returnVal rules.Results
-	for _, res := range results {
-		if excludeDownloaded && strings.Contains(res.NarrowestRange().GetFilename(), fmt.Sprintf("%c.terraform", os.PathSeparator)) {
-			continue
-		}
-
-		if ignoreWarnings && res.Rule().Severity == severity.Medium {
-			continue
-		}
-
-		if ignoreInfo && res.Rule().Severity == severity.Low {
-			continue
-		}
-
-		returnVal = append(returnVal, res)
-	}
-	return returnVal
-}
-
-func getFormatterOptions() []formatters.FormatterOption {
-	var options []formatters.FormatterOption
-	if conciseOutput {
-		options = append(options, formatters.ConciseOutput)
-	}
-	if passingGif {
-		options = append(options, formatters.PassingGif)
-	}
-	if debug.Enabled {
-		options = append(options, formatters.WithDebug)
-	}
-	return options
-}
-
-func getScannerOptions() []scanner.Option {
-	var options []scanner.Option
-	if includePassed {
-		options = append(options, scanner.OptionIncludePassed())
-	}
-	if includeIgnored {
-		options = append(options, scanner.OptionIncludeIgnored())
-	}
-	if workspace != "" {
-		options = append(options, scanner.OptionWithWorkspaceName(workspace))
-	}
-	options = append(options, scanner.OptionWithSingleThread(singleThreadedMode))
-	if stopOnCheckError {
-		options = append(options, scanner.OptionStopOnErrors())
-	}
-
-	var allExcludedRuleIDs []string
-	for _, exclude := range strings.Split(excludedRuleIDs, ",") {
-		allExcludedRuleIDs = append(allExcludedRuleIDs, strings.TrimSpace(exclude))
-	}
-	allExcludedRuleIDs = mergeWithoutDuplicates(allExcludedRuleIDs, tfsecConfig.ExcludedChecks)
-
-	options = append(options, scanner.OptionExcludeRules(allExcludedRuleIDs))
-	return options
-}
-
-func mergeWithoutDuplicates(left, right []string) []string {
-	var set = map[string]bool{}
-	for _, x := range append(left, right...) {
-		set[x] = true
-	}
-	var results []string
-	for x := range set {
-		results = append(results, x)
-	}
-
-	return results
-}
-
-func allInfo(results []rules.Result) bool {
-	for _, res := range results {
-		if res.Rule().Severity != severity.Low && res.Status() != rules.StatusPassed {
-			return false
-		}
-	}
-	return true
-}
-
-func updateResultSeverity(results []rules.Result) []rules.Result {
-	overrides := tfsecConfig.SeverityOverrides
-
-	if len(overrides) == 0 {
-		return results
-	}
-
-	var overriddenResults []rules.Result
-	for _, res := range results {
-		for code, sev := range overrides {
-			if res.Rule().LongID() == code || legacy.FindID(res.Rule().LongID()) == code {
-				overrides := rules.Results([]rules.Result{res})
-				override := res.Rule()
-				override.Severity = severity.Severity(sev)
-				overrides.SetRule(override)
-				res = overrides[0]
-			}
-		}
-		overriddenResults = append(overriddenResults, res)
-	}
-
-	return overriddenResults
-}
-
-func getFormatter(fileFormat string) (formatters.Formatter, error) {
-	switch strings.ToLower(fileFormat) {
-	case "", "default":
-		return formatters.FormatDefault, nil
-	case "json":
-		return formatters.FormatJSON, nil
-	case "csv":
-		return formatters.FormatCSV, nil
-	case "checkstyle":
-		return formatters.FormatCheckStyle, nil
-	case "junit":
-		return formatters.FormatJUnit, nil
-	case "text":
-		return formatters.FormatText, nil
-	case "sarif":
-		return formatters.FormatSarif, nil
-	case "gif":
-		return formatters.FormatGif, nil
-	default:
-		return nil, fmt.Errorf("invalid format specified: '%s'", fileFormat)
-	}
-}
-
-func defaultExtensionForFormatter(fileFormat string) string {
-	switch strings.ToLower(fileFormat) {
-	case "text":
-		return "txt"
-	default:
-		return fileFormat
-	}
-}
-
-func loadConfigFile(configFilePath string) (*config.Config, error) {
-	debug.Log("loading config file %s", configFilePath)
-	return config.LoadConfig(configFilePath)
-}
-
-func countPassedResults(results []rules.Result) int {
-	passed := 0
-
-	for _, res := range results {
-		if res.Status() == rules.StatusPassed {
-			passed++
-		}
-	}
-
-	return passed
-}
-
-func unusedTfvarsPresent(checkDir string) bool {
-	glob := fmt.Sprintf("%s/*.tfvars", checkDir)
-	debug.Log("checking for tfvars files using glob: %s", glob)
-	if matches, err := filepath.Glob(glob); err == nil && len(matches) > 0 {
-		return true
-	}
-	return false
-}
diff --git a/docs/getting-started/usage.md b/docs/getting-started/usage.md
index 3d2b4c4bc..0f7e7088e 100644
--- a/docs/getting-started/usage.md
+++ b/docs/getting-started/usage.md
@@ -15,17 +15,16 @@ For a richer experience, there are many additional command line arguments that y
 | Argument                                                 | Short Code | Description                                                                              |
 | :------------------------------------------------------- | :--------- | :--------------------------------------------------------------------------------------- |
 | `--allow-checks-to-panic`                                | `-p`       | Allow panics to propagate up from rule checking                                          |
-| `--concise-output`                                       |            | Reduce the amount of output and no statistics                                            |
+| `--concise-output`                                       |            | Reduce the amount of output and no metrics                                               |
 | `--config-file [path to config file]`                    |            | Config file to use during run                                                            |
 | `--custom-check-dir [path to checks dir]`                |            | Explicitly the custom checks dir location                                                |
 | `--debug`                                                |            | Enable verbose logging, same as `--verbose` but for people who prefer to say debug       |
-| `--detailed-exit-code`                                   |            | Produce more detailed exit status codes.                                                 |
 | `--exclude [comma,separated,rule,ids]`                   | `-e`       | Provide comma-separated list of rule IDs to exclude from run.                            |
 | `--exclude-path strings`                                 |            | Path to exclude from parser, can be used multiple times                                  |
 | `--exclude-downloaded-modules`                           |            | Remove results for downloaded modules in .terraform folder                               |
 | `--filter-results [comma,separated,riles,to,check]`      |            | Filter results to return specific checks only (supports comma-delimited input).          |
 | `--force-all-dirs`                                       |            | Don't search for tf files, include everything below provided directory.                  |
-| `--format [default,json,csv,checkstyle,junit,sarif,gif]` | `-f`       | Select output format: default, json, csv, checkstyle, junit, sarif                       |
+| `--format [default,json,csv,checkstyle,junit,sarif,gif]` | `-f`       | Select output format: default, json, csv, checkstyle, junit, sarif. To use multiple formats, separate with a comma and specify a base output filename with --out. A file will be written for each type. The first format will additionally be written stdout. |
 | `--help`                                                 | `-h`       | help for tfsec                                                                           |
 | `--ignore-hcl-errors`                                    |            | Stop and report an error if an HCL parse error is encountered                            |
 | `--include-ignored`                                      |            | Ignore comments with have no effect and all resources will be scanned                    |
@@ -33,7 +32,7 @@ For a richer experience, there are many additional command line arguments that y
 | `--migrate-ignores`                                      |            | Migrate ignore codes to the new ID structure eg; AWS077 to aws-s3-enable-versioning      |
 | `--no-color`                                             |            | Disable colored output (American style!)                                                 |
 | `--no-colour`                                            |            | Disable coloured output                                                                  |
-| `--out [filepath to output to]`                          |            | Set output file                                                                          |
+| `--out [filepath to output to]`                          |            | Set output file. This filename will have a format descriptor appended if multiple formats are specified with --format |
 | `--run-statistics`                                       |            | View statistics table of current findings.                                               |
 | `--soft-fail`                                            | `-s`       | Runs checks but suppresses error code                                                    |
 | `--sort-severity`                                        |            | Sort the results by severity from highest to lowest                                      |
diff --git a/go.mod b/go.mod
index 945bc09eb..5a41a2e2a 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.17
 
 require (
 	github.com/apparentlymart/go-cidr v1.1.0
-	github.com/aquasecurity/defsec v0.4.1
+	github.com/aquasecurity/defsec v0.5.2
 	github.com/bmatcuk/doublestar v1.3.4
 	github.com/google/go-cmp v0.5.6
 	github.com/google/uuid v1.3.0
@@ -13,7 +13,7 @@ require (
 	github.com/hashicorp/hcl/v2 v2.11.1
 	github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf
 	github.com/liamg/iamgo v0.0.2
-	github.com/liamg/tml v0.4.0
+	github.com/liamg/tml v0.6.0
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/olekukonko/tablewriter v0.0.5
 	github.com/owenrumney/squealer v0.3.1
diff --git a/go.sum b/go.sum
index f384a4653..60dd6947e 100644
--- a/go.sum
+++ b/go.sum
@@ -76,6 +76,46 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6
 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
 github.com/aquasecurity/defsec v0.4.1 h1:bqCQ4NrOPIU0GOb9wxzalNjXbChnOnBKDASHr8Q2gF0=
 github.com/aquasecurity/defsec v0.4.1/go.mod h1:k69jht4X6WIpU4Q9py0o9hYHs4lnGTsBb64ncWCuQvE=
+github.com/aquasecurity/defsec v0.4.2 h1:O/6PtuA8VNwnQzuZAG7pXZjQl63Qn4RxbbppviK+nuI=
+github.com/aquasecurity/defsec v0.4.2/go.mod h1:k69jht4X6WIpU4Q9py0o9hYHs4lnGTsBb64ncWCuQvE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124133253-67d65e7f4d32 h1:JXnADO/qR4GhPVJBTLx4fQaFITRAhT2dsamjzUqzVf0=
+github.com/aquasecurity/defsec v0.4.4-0.20220124133253-67d65e7f4d32/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124134109-6a36fbd8c3bf h1:TzKzxwuc7cTzhto5vKyB7rZVKbGtpJ4KNS2w9YX8KDo=
+github.com/aquasecurity/defsec v0.4.4-0.20220124134109-6a36fbd8c3bf/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124141450-f1af80313f9e h1:+anrXuKtWDP9x8fuR7858FQEOUF9IBRzdCLfLQiGlSU=
+github.com/aquasecurity/defsec v0.4.4-0.20220124141450-f1af80313f9e/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124145033-d9dbdc24799a h1:UDS64+bANZjLIQtrWCk3os5o1yu2vOZ6Rdz4Xs78Vf0=
+github.com/aquasecurity/defsec v0.4.4-0.20220124145033-d9dbdc24799a/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124145815-5dedb524b2fe h1:uAhvYIENi4SdFoMz955i7XPRKFe0QL51tGtMp2+DJ5c=
+github.com/aquasecurity/defsec v0.4.4-0.20220124145815-5dedb524b2fe/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124162258-be6dec64980c h1:2XmnH/MGlpNn5+Ij4mZJkZt8NyG0Z/bYwK9m0jNqScw=
+github.com/aquasecurity/defsec v0.4.4-0.20220124162258-be6dec64980c/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124162753-7e5ceaefae7b h1:nSagBGV3y2kWQvUPiUzPMHDn24hCh0TuU04YvQd3B4M=
+github.com/aquasecurity/defsec v0.4.4-0.20220124162753-7e5ceaefae7b/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124163600-99b5d63e66a2 h1:2QvpxBY79F/uyUIsPYyGYB/JfP0LLTzzJkFHmBo4nZs=
+github.com/aquasecurity/defsec v0.4.4-0.20220124163600-99b5d63e66a2/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124164139-798f49be67b9 h1:P7C6qRem+RcIjdpy0gVgHwNHSYjbRn3P7W2kkzgajwg=
+github.com/aquasecurity/defsec v0.4.4-0.20220124164139-798f49be67b9/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124164742-8a837dd01293 h1:jb+Eug3bceDFSwQId0Tj2lShHCc8Ls08g88WZj8mPlc=
+github.com/aquasecurity/defsec v0.4.4-0.20220124164742-8a837dd01293/go.mod h1:YFuJGNl/OxTngyBje1q97IaSFy5alnScQsZr9dbN2HE=
+github.com/aquasecurity/defsec v0.4.4-0.20220124165315-21a01f2fa479 h1:bWdRixBdT5zcksrlJVD/nxHrNBZvJ+gs/IxB++wxIUg=
+github.com/aquasecurity/defsec v0.4.4-0.20220124165315-21a01f2fa479/go.mod h1:r7EtkaLj2gpZ+hSxRyRjfbszt4MMIpHQX6+vLF6El6o=
+github.com/aquasecurity/defsec v0.4.4-0.20220124170205-d29a8a7d7625 h1:51ekCYXvMzrHVmvEiw+qryY2oYpmQ/exi8HfFoVBk2M=
+github.com/aquasecurity/defsec v0.4.4-0.20220124170205-d29a8a7d7625/go.mod h1:r7EtkaLj2gpZ+hSxRyRjfbszt4MMIpHQX6+vLF6El6o=
+github.com/aquasecurity/defsec v0.4.4-0.20220124170604-99b583ffc0c0 h1:nF0YvcAkOwj5RScgMCTtEswIi7zXW70FajeWETrM0ps=
+github.com/aquasecurity/defsec v0.4.4-0.20220124170604-99b583ffc0c0/go.mod h1:r7EtkaLj2gpZ+hSxRyRjfbszt4MMIpHQX6+vLF6El6o=
+github.com/aquasecurity/defsec v0.4.4-0.20220124170929-467095115161 h1:ekOg28ifkB5wm3EeG0saUS9xbnM/WyvoLuRIL8YSCEk=
+github.com/aquasecurity/defsec v0.4.4-0.20220124170929-467095115161/go.mod h1:r7EtkaLj2gpZ+hSxRyRjfbszt4MMIpHQX6+vLF6El6o=
+github.com/aquasecurity/defsec v0.4.4-0.20220124171724-e0a0aea2102d h1:ewzWlp1000Snd1anqzFpvc55Kta2jokTrrOOcHtbWvw=
+github.com/aquasecurity/defsec v0.4.4-0.20220124171724-e0a0aea2102d/go.mod h1:r7EtkaLj2gpZ+hSxRyRjfbszt4MMIpHQX6+vLF6El6o=
+github.com/aquasecurity/defsec v0.4.4-0.20220124172047-8ad829eb0a18 h1:ZJFhvU6TtYwe+cgr/i2z0OdpTZNJx2KsFtdeJYlPKDg=
+github.com/aquasecurity/defsec v0.4.4-0.20220124172047-8ad829eb0a18/go.mod h1:r7EtkaLj2gpZ+hSxRyRjfbszt4MMIpHQX6+vLF6El6o=
+github.com/aquasecurity/defsec v0.5.0 h1:o8XT1JZN4plKsTOqGwm7q2CoZSXfy1Yq896h93LQwRo=
+github.com/aquasecurity/defsec v0.5.0/go.mod h1:r7EtkaLj2gpZ+hSxRyRjfbszt4MMIpHQX6+vLF6El6o=
+github.com/aquasecurity/defsec v0.5.1 h1:s8GrA4wVv6w+sjg3cP88Wk5mJAK1yhy2t3yh3u6qkm4=
+github.com/aquasecurity/defsec v0.5.1/go.mod h1:r7EtkaLj2gpZ+hSxRyRjfbszt4MMIpHQX6+vLF6El6o=
+github.com/aquasecurity/defsec v0.5.2 h1:Jm9wujO5+iJoYF4/U/Yuu0F1IC97RIBgnLkhHAu0JSM=
+github.com/aquasecurity/defsec v0.5.2/go.mod h1:r7EtkaLj2gpZ+hSxRyRjfbszt4MMIpHQX6+vLF6El6o=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
@@ -349,6 +389,10 @@ github.com/liamg/iamgo v0.0.2/go.mod h1:qMGOfySmVFw77/NNCY1Lk5Ez2ER5Pwz0xizTLpIb
 github.com/liamg/tml v0.3.0/go.mod h1:0h4EAV/zBOsqI91EWONedjRpO8O0itjGJVd+wG5eC+E=
 github.com/liamg/tml v0.4.0 h1:iZwysIBOaGz6MuaPT/+PCZgvkpgoqBu3ZI6cgApK0zc=
 github.com/liamg/tml v0.4.0/go.mod h1:0h4EAV/zBOsqI91EWONedjRpO8O0itjGJVd+wG5eC+E=
+github.com/liamg/tml v0.5.0 h1:z77Ky04qEXLn3MMgyOLOHitYr0iAu9vl9HGXRHdMSyY=
+github.com/liamg/tml v0.5.0/go.mod h1:0h4EAV/zBOsqI91EWONedjRpO8O0itjGJVd+wG5eC+E=
+github.com/liamg/tml v0.6.0 h1:yOC/Q9p9Io3J11U9LdYVIwpRTnTE1GPMNFLrygkmE2Y=
+github.com/liamg/tml v0.6.0/go.mod h1:0h4EAV/zBOsqI91EWONedjRpO8O0itjGJVd+wG5eC+E=
 github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
 github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
diff --git a/internal/app/tfsec/adapter/adapt.go b/internal/app/tfsec/adapter/adapt.go
deleted file mode 100644
index f0479eadf..000000000
--- a/internal/app/tfsec/adapter/adapt.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package adapter
-
-import (
-	"github.com/aquasecurity/defsec/state"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/cloudstack"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/digitalocean"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/github"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/kubernetes"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/openstack"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/oracle"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-)
-
-func Adapt(modules block.Modules) *state.State {
-	return &state.State{
-		AWS:          aws.Adapt(modules),
-		Azure:        azure.Adapt(modules),
-		CloudStack:   cloudstack.Adapt(modules),
-		DigitalOcean: digitalocean.Adapt(modules),
-		GitHub:       github.Adapt(modules),
-		Google:       google.Adapt(modules),
-		Kubernetes:   kubernetes.Adapt(modules),
-		OpenStack:    openstack.Adapt(modules),
-		Oracle:       oracle.Adapt(modules),
-	}
-}
diff --git a/internal/app/tfsec/adapter/aws/adapt.go b/internal/app/tfsec/adapter/aws/adapt.go
deleted file mode 100644
index 1effcd78b..000000000
--- a/internal/app/tfsec/adapter/aws/adapt.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package aws
-
-import (
-	"github.com/aquasecurity/defsec/provider/aws"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/apigateway"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/athena"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/autoscaling"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/cloudfront"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/cloudtrail"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/cloudwatch"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/codebuild"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/config"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/documentdb"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/dynamodb"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/ebs"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/ec2"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/ecr"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/ecs"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/efs"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/eks"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/elasticache"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/elasticsearch"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/elb"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/kinesis"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/kms"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/lambda"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/mq"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/msk"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/neptune"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/rds"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/redshift"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/s3"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/sns"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/sqs"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/ssm"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/vpc"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/workspaces"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-)
-
-func Adapt(modules block.Modules) aws.AWS {
-	return aws.AWS{
-		APIGateway:    apigateway.Adapt(modules),
-		Athena:        athena.Adapt(modules),
-		Autoscaling:   autoscaling.Adapt(modules),
-		Cloudfront:    cloudfront.Adapt(modules),
-		CloudTrail:    cloudtrail.Adapt(modules),
-		CloudWatch:    cloudwatch.Adapt(modules),
-		CodeBuild:     codebuild.Adapt(modules),
-		Config:        config.Adapt(modules),
-		DocumentDB:    documentdb.Adapt(modules),
-		DynamoDB:      dynamodb.Adapt(modules),
-		EBS:           ebs.Adapt(modules),
-		EC2:           ec2.Adapt(modules),
-		ECR:           ecr.Adapt(modules),
-		ECS:           ecs.Adapt(modules),
-		EFS:           efs.Adapt(modules),
-		EKS:           eks.Adapt(modules),
-		ElastiCache:   elasticache.Adapt(modules),
-		Elasticsearch: elasticsearch.Adapt(modules),
-		ELB:           elb.Adapt(modules),
-		IAM:           iam.Adapt(modules),
-		Kinesis:       kinesis.Adapt(modules),
-		KMS:           kms.Adapt(modules),
-		Lambda:        lambda.Adapt(modules),
-		MQ:            mq.Adapt(modules),
-		MSK:           msk.Adapt(modules),
-		Neptune:       neptune.Adapt(modules),
-		RDS:           rds.Adapt(modules),
-		Redshift:      redshift.Adapt(modules),
-		S3:            s3.Adapt(modules),
-		SNS:           sns.Adapt(modules),
-		SQS:           sqs.Adapt(modules),
-		SSM:           ssm.Adapt(modules),
-		VPC:           vpc.Adapt(modules),
-		WorkSpaces:    workspaces.Adapt(modules),
-	}
-}
diff --git a/internal/app/tfsec/adapter/azure/adapt.go b/internal/app/tfsec/adapter/azure/adapt.go
deleted file mode 100644
index 7e81a1819..000000000
--- a/internal/app/tfsec/adapter/azure/adapt.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package azure
-
-import (
-	"github.com/aquasecurity/defsec/provider/azure"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/appservice"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/authorization"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/compute"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/container"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/database"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/datafactory"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/datalake"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/keyvault"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/monitor"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/network"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/securitycenter"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/storage"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/azure/synapse"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-)
-
-func Adapt(modules block.Modules) azure.Azure {
-	return azure.Azure{
-		AppService:     appservice.Adapt(modules),
-		Authorization:  authorization.Adapt(modules),
-		Compute:        compute.Adapt(modules),
-		Container:      container.Adapt(modules),
-		Database:       database.Adapt(modules),
-		DataFactory:    datafactory.Adapt(modules),
-		DataLake:       datalake.Adapt(modules),
-		KeyVault:       keyvault.Adapt(modules),
-		Monitor:        monitor.Adapt(modules),
-		Network:        network.Adapt(modules),
-		SecurityCenter: securitycenter.Adapt(modules),
-		Storage:        storage.Adapt(modules),
-		Synapse:        synapse.Adapt(modules),
-	}
-}
diff --git a/internal/app/tfsec/adapter/google/adapt.go b/internal/app/tfsec/adapter/google/adapt.go
deleted file mode 100644
index abf1c1198..000000000
--- a/internal/app/tfsec/adapter/google/adapt.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package google
-
-import (
-	"github.com/aquasecurity/defsec/provider/google"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google/bigquery"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google/compute"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google/dns"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google/gke"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google/kms"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google/sql"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google/storage"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-)
-
-func Adapt(modules block.Modules) google.Google {
-	return google.Google{
-		BigQuery: bigquery.Adapt(modules),
-		Compute:  compute.Adapt(modules),
-		DNS:      dns.Adapt(modules),
-		GKE:      gke.Adapt(modules),
-		KMS:      kms.Adapt(modules),
-		IAM:      iam.Adapt(modules),
-		SQL:      sql.Adapt(modules),
-		Storage:  storage.Adapt(modules),
-	}
-}
diff --git a/internal/app/tfsec/cmd/flags.go b/internal/app/tfsec/cmd/flags.go
new file mode 100644
index 000000000..4939df9ae
--- /dev/null
+++ b/internal/app/tfsec/cmd/flags.go
@@ -0,0 +1,64 @@
+package cmd
+
+import (
+	"github.com/aquasecurity/tfsec/internal/pkg/config"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
+)
+
+var showVersion = false
+var runUpdate = false
+var disableColours = false
+var format string
+var softFail = false
+var filterResults string
+var excludedRuleIDs string
+var tfvarsPaths []string
+var excludePaths []string
+var outputFlag string
+var customCheckDir string
+var configFile string
+var tfsecConfig = &config.Config{}
+var conciseOutput = false
+var excludeDownloaded = false
+var includePassed = false
+var includeIgnored = false
+var ignoreWarnings = false
+var ignoreInfo = false
+var allDirs = false
+var migrateIgnores = false
+var runStatistics bool
+var ignoreHCLErrors bool
+var stopOnCheckError bool
+var workspace string
+var singleThreadedMode bool
+
+func init() {
+	rootCmd.Flags().BoolVar(&singleThreadedMode, "single-thread", singleThreadedMode, "Run checks using a single thread")
+	rootCmd.Flags().BoolVar(&ignoreHCLErrors, "ignore-hcl-errors", ignoreHCLErrors, "Stop and report an error if an HCL parse error is encountered")
+	rootCmd.Flags().BoolVar(&disableColours, "no-colour", disableColours, "Disable coloured output")
+	rootCmd.Flags().BoolVar(&disableColours, "no-color", disableColours, "Disable colored output (American style!)")
+	rootCmd.Flags().BoolVarP(&showVersion, "version", "v", showVersion, "Show version information and exit")
+	rootCmd.Flags().BoolVar(&runUpdate, "update", runUpdate, "Update to latest version")
+	rootCmd.Flags().BoolVar(&migrateIgnores, "migrate-ignores", migrateIgnores, "Migrate ignore codes to the new ID structure")
+	rootCmd.Flags().StringVarP(&format, "format", "f", format, "Select output format: default, json, csv, checkstyle, junit, sarif. To use multiple formats, separate with a comma and specify a base output filename with --out. A file will be written for each type. The first format will additionally be written stdout.")
+	rootCmd.Flags().StringVarP(&excludedRuleIDs, "exclude", "e", excludedRuleIDs, "Provide comma-separated list of rule IDs to exclude from run.")
+	rootCmd.Flags().StringVar(&filterResults, "filter-results", filterResults, "Filter results to return specific checks only (supports comma-delimited input).")
+	rootCmd.Flags().BoolVarP(&softFail, "soft-fail", "s", softFail, "Runs checks but suppresses error code")
+	rootCmd.Flags().StringSliceVar(&tfvarsPaths, "tfvars-file", tfvarsPaths, "Path to .tfvars file, can be used multiple times and evaluated in order of specification")
+	rootCmd.Flags().StringSliceVar(&excludePaths, "exclude-path", excludePaths, "Folder path to exclude, can be used multiple times and evaluated in order of specification")
+	rootCmd.Flags().StringVarP(&outputFlag, "out", "O", outputFlag, "Set output file. This filename will have a format descriptor appended if multiple formats are specified with --format")
+	rootCmd.Flags().StringVar(&customCheckDir, "custom-check-dir", customCheckDir, "Explicitly the custom checks dir location")
+	rootCmd.Flags().StringVar(&configFile, "config-file", configFile, "Config file to use during run")
+	rootCmd.Flags().BoolVar(&debug.Enabled, "debug", debug.Enabled, "Enable debug logging (same as verbose)")
+	rootCmd.Flags().BoolVar(&debug.Enabled, "verbose", debug.Enabled, "Enable verbose logging (same as debug)")
+	rootCmd.Flags().BoolVar(&conciseOutput, "concise-output", conciseOutput, "Reduce the amount of output and no statistics")
+	rootCmd.Flags().BoolVar(&excludeDownloaded, "exclude-downloaded-modules", excludeDownloaded, "Remove results for downloaded modules in .terraform folder")
+	rootCmd.Flags().BoolVar(&includePassed, "include-passed", includePassed, "Include passed checks in the result output")
+	rootCmd.Flags().BoolVar(&includeIgnored, "include-ignored", includeIgnored, "Include ignored checks in the result output")
+	rootCmd.Flags().BoolVar(&allDirs, "force-all-dirs", allDirs, "Don't search for tf files, include everything below provided directory.")
+	rootCmd.Flags().BoolVar(&runStatistics, "run-statistics", runStatistics, "View statistics table of current findings.")
+	rootCmd.Flags().BoolVar(&ignoreWarnings, "ignore-warnings", ignoreWarnings, "[DEPRECATED] Don't show warnings in the output.")
+	rootCmd.Flags().BoolVar(&ignoreInfo, "ignore-info", ignoreWarnings, "[DEPRECATED] Don't show info results in the output.")
+	rootCmd.Flags().BoolVarP(&stopOnCheckError, "allow-checks-to-panic", "p", stopOnCheckError, "Allow panics to propagate up from rule checking")
+	rootCmd.Flags().StringVarP(&workspace, "workspace", "w", workspace, "Specify a workspace for ignore limits")
+}
diff --git a/internal/app/tfsec/cmd/output.go b/internal/app/tfsec/cmd/output.go
new file mode 100644
index 000000000..f8c44383d
--- /dev/null
+++ b/internal/app/tfsec/cmd/output.go
@@ -0,0 +1,99 @@
+package cmd
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"strings"
+
+	"github.com/aquasecurity/defsec/formatters"
+	"github.com/aquasecurity/defsec/rules"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
+	"github.com/liamg/tml"
+)
+
+func output(baseFilename string, formats []string, dir string, results []rules.Result) error {
+	if baseFilename == "" && len(formats) > 1 {
+		return fmt.Errorf("you must specify a base output filename with --out if you want to use multiple formats")
+	}
+
+	var files []string
+	for i, format := range formats {
+		if filename, err := outputFormat(i, baseFilename, format, dir, results); err != nil {
+			return err
+		} else if filename != "" {
+			files = append(files, filename)
+		}
+	}
+
+	if len(files) > 0 {
+		_ = tml.Fprintf(os.Stderr, "<bold>%d file(s) written: %s\n", len(files), strings.Join(files, ", "))
+	}
+
+	return nil
+}
+
+func outputFormat(i int, baseFilename string, format string, dir string, results []rules.Result) (string, error) {
+
+	formatter := formatters.New().
+		WithDebugEnabled(debug.Enabled).
+		WithColoursEnabled(!disableColours).
+		WithLinksFunc(func(result rules.Result) []string {
+			return result.Rule().Terraform.Links
+		}).
+		WithBaseDir(dir).
+		WithMetricsEnabled(!conciseOutput)
+
+	alsoStdout := i == 0
+
+	switch strings.ToLower(format) {
+	case "", "default":
+	case "json":
+		formatter.AsJSON()
+	case "csv":
+		formatter.AsCSV()
+	case "checkstyle":
+		formatter.AsCheckStyle()
+	case "junit":
+		formatter.AsJUnit()
+	case "text":
+		formatter.AsDefault().WithColoursEnabled(false)
+	case "sarif":
+		formatter.AsSARIF()
+	case "gif":
+		formatter.AsGIF()
+	default:
+		return "", fmt.Errorf("invalid format specified: '%s'", format)
+	}
+
+	var outputPath string
+	if baseFilename != "" {
+		outputPath = fmt.Sprintf("%s%s", baseFilename, getExtensionForFormat(format))
+		f, err := os.OpenFile(outputPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o600)
+		if err != nil {
+			return "", err
+		}
+		defer func() { _ = f.Close() }()
+		if alsoStdout {
+			m := io.MultiWriter(f, os.Stdout)
+			formatter.WithWriter(m)
+		} else {
+			formatter.WithWriter(f)
+		}
+	}
+
+	return outputPath, formatter.Build().Output(results)
+}
+
+func getExtensionForFormat(format string) string {
+	switch format {
+	case "sarif":
+		return ".sarif.json"
+	case "", "default":
+		return ".default.txt"
+	case "checkstyle":
+		return ".checkstyle.xml"
+	default:
+		return fmt.Sprintf(".%s", format)
+	}
+}
diff --git a/internal/app/tfsec/cmd/prerun.go b/internal/app/tfsec/cmd/prerun.go
new file mode 100644
index 000000000..bcd3897b7
--- /dev/null
+++ b/internal/app/tfsec/cmd/prerun.go
@@ -0,0 +1,68 @@
+package cmd
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"runtime"
+
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/ignores"
+	"github.com/aquasecurity/tfsec/internal/pkg/updater"
+	"github.com/aquasecurity/tfsec/version"
+	"github.com/liamg/tml"
+	"github.com/spf13/cobra"
+)
+
+func prerun(_ *cobra.Command, args []string) {
+
+	// disable colour if running on windows - colour formatting doesn't work
+	if disableColours || runtime.GOOS == "windows" {
+		debug.Log("Disabled formatting.")
+		tml.DisableFormatting()
+	}
+
+	if showVersion {
+		if version.Version == "" {
+			fmt.Println("You are running a locally built version of tfsec.")
+		} else {
+			fmt.Println(version.Version)
+		}
+		os.Exit(0)
+	}
+
+	if runUpdate {
+		if err := updater.Update(); err != nil {
+			fmt.Fprintf(os.Stderr, "Not updating, %s\n", err.Error())
+			os.Exit(1)
+		}
+		os.Exit(0)
+	}
+
+	if migrateIgnores {
+		var dir string
+		var err error
+
+		if len(args) == 1 {
+			dir, err = filepath.Abs(args[0])
+		} else {
+			dir, err = os.Getwd()
+		}
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Directory was not provided, and tfsec encountered an error trying to determine the current working directory: %s\n", err)
+			os.Exit(1)
+		}
+
+		stats, err := ignores.RunMigration(dir)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Errors occurred while running migration: %s", err.Error())
+			os.Exit(1)
+		}
+		if len(stats) > 0 {
+			for _, stat := range stats {
+				fmt.Printf("%s migrated from %s => %s\n", stat.Filename, stat.FromCode, stat.ToCode)
+			}
+		}
+		os.Exit(0)
+	}
+}
diff --git a/internal/app/tfsec/cmd/root.go b/internal/app/tfsec/cmd/root.go
new file mode 100644
index 000000000..1578b2345
--- /dev/null
+++ b/internal/app/tfsec/cmd/root.go
@@ -0,0 +1,346 @@
+package cmd
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/aquasecurity/defsec/metrics"
+	"github.com/aquasecurity/defsec/rules"
+	"github.com/aquasecurity/defsec/severity"
+	"github.com/aquasecurity/tfsec/internal/pkg/config"
+	"github.com/aquasecurity/tfsec/internal/pkg/custom"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/legacy"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
+	_ "github.com/aquasecurity/tfsec/internal/pkg/rules"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
+	"github.com/spf13/cobra"
+)
+
+func Root() *cobra.Command {
+	return rootCmd
+}
+
+var rootCmd = &cobra.Command{
+	Use:              "tfsec [directory]",
+	Short:            "tfsec is a terraform security scanner",
+	Long:             `tfsec is a simple tool to detect potential security vulnerabilities in your terraformed infrastructure.`,
+	PersistentPreRun: prerun,
+	RunE: func(_ *cobra.Command, args []string) error {
+
+		var dir string
+		var err error
+
+		if ignoreWarnings || ignoreInfo {
+			fmt.Fprint(os.Stderr, "WARNING: The --ignore-info and --ignore-warnings flags are deprecated and will soon be removed.\n")
+		}
+
+		if len(args) == 1 {
+			dir, err = filepath.Abs(args[0])
+			if err != nil {
+				failf("Error determining absolute path for provided path: %s", err)
+			}
+		} else {
+			dir, err = os.Getwd()
+			if err != nil {
+				failf("Error determining current directory: %s", err)
+			}
+		}
+
+		if dirInfo, err := os.Stat(dir); err != nil {
+			failf("Error accessing provided path: %s", err)
+		} else if !dirInfo.IsDir() {
+			failf("The provided path is not a dir, exiting")
+		}
+
+		tfsecDir := fmt.Sprintf("%s/.tfsec", dir)
+
+		if len(configFile) > 0 {
+			tfsecConfig, err = loadConfigFile(configFile)
+			if err != nil {
+				return err
+			}
+		} else {
+			jsonConfigFile := fmt.Sprintf("%s/%s", tfsecDir, "config.json")
+			yamlConfigFile := fmt.Sprintf("%s/%s", tfsecDir, "config.yml")
+			if _, err = os.Stat(jsonConfigFile); err == nil {
+				tfsecConfig, err = loadConfigFile(jsonConfigFile)
+				if err != nil {
+					return err
+				}
+			} else if _, err = os.Stat(yamlConfigFile); err == nil {
+				tfsecConfig, err = loadConfigFile(yamlConfigFile)
+				if err != nil {
+					return err
+				}
+			} else {
+				tfsecConfig = &config.Config{}
+			}
+		}
+
+		debug.Log("Loading custom checks...")
+		if len(customCheckDir) == 0 {
+			debug.Log("Using the default custom check folder")
+			customCheckDir = tfsecDir
+		}
+		debug.Log("custom check directory set to %s", customCheckDir)
+		err = custom.Load(customCheckDir)
+		if err != nil {
+			failf("There were errors while processing custom check files. %s", err)
+		}
+		debug.Log("Custom checks loaded")
+
+		var filterResultsList []string
+		if len(filterResults) > 0 {
+			filterResultsList = strings.Split(filterResults, ",")
+		}
+
+		if len(tfvarsPaths) == 0 && unusedTfvarsPresent(dir) {
+			fmt.Fprintf(os.Stderr, "WARNING: A tfvars file was found but not automatically used. Did you mean to specify the --tfvars-file flag?\n")
+		}
+
+		debug.Log("Starting parser...")
+		modules, err := parser.New(dir, getParserOptions()...).ParseDirectory()
+		if err != nil {
+			failf("Parse error: %s", err)
+		}
+
+		debug.Log("Starting scanner...")
+		results, err := scanner.New(getScannerOptions()...).Scan(modules)
+		if err != nil {
+			return fmt.Errorf("fatal error during scan: %w", err)
+		}
+		results = updateResultSeverity(results)
+		results = removeExcludedResults(results, ignoreWarnings, excludeDownloaded)
+		if len(filterResultsList) > 0 {
+			var filteredResult []rules.Result
+			for _, result := range results {
+				for _, ruleID := range filterResultsList {
+					if result.Rule().LongID() == ruleID {
+						filteredResult = append(filteredResult, result)
+					}
+				}
+			}
+			results = filteredResult
+		}
+
+		metrics.Counter("counts", "blocks").Increment(0)
+		metrics.Counter("counts", "modules").Increment(0)
+		metrics.Counter("counts", "files").Increment(parser.CountFiles())
+		metrics.Counter("results", "critical")
+		metrics.Counter("results", "high")
+		metrics.Counter("results", "medium")
+		metrics.Counter("results", "low")
+		for _, result := range results {
+			metrics.Counter("results", strings.ToLower(string(result.Rule().Severity))).Increment(1)
+		}
+
+		if runStatistics {
+			statistics := scanner.Statistics{}
+			for _, result := range results {
+				statistics = scanner.AddStatisticsCount(statistics, result)
+			}
+			statistics.PrintStatisticsTable()
+			return nil
+		}
+
+		formats := strings.Split(format, ",")
+		if err := output(outputFlag, formats, dir, results); err != nil {
+			failf("Failed to write output: %s", err)
+		}
+
+		// Soft fail always takes precedence. If set, only execution errors
+		// produce a failure exit code (1).
+		if softFail {
+			return nil
+		}
+
+		os.Exit(getDetailedExitCode(results))
+		return nil
+	},
+}
+
+func failf(format string, a ...interface{}) {
+	fmt.Fprintf(os.Stderr, format+"\n", a...)
+	os.Exit(1)
+}
+
+func getParserOptions() []parser.Option {
+	var opts []parser.Option
+	if allDirs {
+		opts = append(opts, parser.OptionDoNotSearchTfFiles())
+	}
+	var validTfVarFiles []string
+	if len(tfvarsPaths) > 0 {
+		for _, tfvarsPath := range tfvarsPaths {
+			tfvp, err := filepath.Abs(tfvarsPath)
+			if err != nil {
+				fmt.Println(err)
+			}
+			if _, err := os.Stat(tfvp); err == nil {
+				validTfVarFiles = append(validTfVarFiles, tfvp)
+			}
+		}
+		opts = append(opts, parser.OptionWithTFVarsPaths(validTfVarFiles))
+	}
+	var validExcludePaths []string
+	if len(excludePaths) > 0 {
+		for _, excludePath := range excludePaths {
+			exP, err := filepath.Abs(excludePath)
+			if err != nil {
+				fmt.Println(err)
+			}
+			if _, err := os.Stat(exP); err == nil {
+				validExcludePaths = append(validExcludePaths, exP)
+			}
+		}
+		opts = append(opts, parser.OptionWithExcludePaths(validExcludePaths))
+	}
+
+	if !ignoreHCLErrors {
+		opts = append(opts, parser.OptionStopOnHCLError())
+	}
+
+	if workspace != "" {
+		opts = append(opts, parser.OptionWithWorkspaceName(workspace))
+	}
+
+	return opts
+}
+
+func getDetailedExitCode(results rules.Results) int {
+	// If there are no failed rules, then produce a success exit code (0).
+	if len(results) == 0 || len(results) == countPassedResults(results) {
+		return 0
+	}
+
+	// If there are some failed rules but they are all of LOW severity, then
+	// produce a special failure exit code (2).
+	if allInfo(results) {
+		return 2
+	}
+
+	// If there is any failed check of HIGH or WARNING severity, then
+	// produce the regular failure exit code (1).
+	return 1
+}
+
+func removeExcludedResults(results rules.Results, ignoreWarnings bool, excludeDownloaded bool) rules.Results {
+	var returnVal rules.Results
+	for _, res := range results {
+		if excludeDownloaded && strings.Contains(res.NarrowestRange().GetFilename(), fmt.Sprintf("%c.terraform", os.PathSeparator)) {
+			continue
+		}
+
+		if ignoreWarnings && res.Rule().Severity == severity.Medium {
+			continue
+		}
+
+		if ignoreInfo && res.Rule().Severity == severity.Low {
+			continue
+		}
+
+		returnVal = append(returnVal, res)
+	}
+	return returnVal
+}
+
+func getScannerOptions() []scanner.Option {
+	var options []scanner.Option
+	if includePassed {
+		options = append(options, scanner.OptionIncludePassed())
+	}
+	if includeIgnored {
+		options = append(options, scanner.OptionIncludeIgnored())
+	}
+	if workspace != "" {
+		options = append(options, scanner.OptionWithWorkspaceName(workspace))
+	}
+	options = append(options, scanner.OptionWithSingleThread(singleThreadedMode))
+	if stopOnCheckError {
+		options = append(options, scanner.OptionStopOnErrors())
+	}
+
+	var allExcludedRuleIDs []string
+	for _, exclude := range strings.Split(excludedRuleIDs, ",") {
+		allExcludedRuleIDs = append(allExcludedRuleIDs, strings.TrimSpace(exclude))
+	}
+	allExcludedRuleIDs = mergeWithoutDuplicates(allExcludedRuleIDs, tfsecConfig.ExcludedChecks)
+
+	options = append(options, scanner.OptionExcludeRules(allExcludedRuleIDs))
+	return options
+}
+
+func mergeWithoutDuplicates(left, right []string) []string {
+	var set = map[string]bool{}
+	for _, x := range append(left, right...) {
+		set[x] = true
+	}
+	var results []string
+	for x := range set {
+		results = append(results, x)
+	}
+
+	return results
+}
+
+func allInfo(results []rules.Result) bool {
+	for _, res := range results {
+		if res.Rule().Severity != severity.Low && res.Status() != rules.StatusPassed {
+			return false
+		}
+	}
+	return true
+}
+
+func updateResultSeverity(results []rules.Result) []rules.Result {
+	overrides := tfsecConfig.SeverityOverrides
+
+	if len(overrides) == 0 {
+		return results
+	}
+
+	var overriddenResults []rules.Result
+	for _, res := range results {
+		for code, sev := range overrides {
+			if res.Rule().LongID() == code || legacy.FindID(res.Rule().LongID()) == code {
+				overrides := rules.Results([]rules.Result{res})
+				override := res.Rule()
+				override.Severity = severity.Severity(sev)
+				overrides.SetRule(override)
+				res = overrides[0]
+			}
+		}
+		overriddenResults = append(overriddenResults, res)
+	}
+
+	return overriddenResults
+}
+
+func loadConfigFile(configFilePath string) (*config.Config, error) {
+	debug.Log("loading config file %s", configFilePath)
+	return config.LoadConfig(configFilePath)
+}
+
+func countPassedResults(results []rules.Result) int {
+	passed := 0
+
+	for _, res := range results {
+		if res.Status() == rules.StatusPassed {
+			passed++
+		}
+	}
+
+	return passed
+}
+
+func unusedTfvarsPresent(checkDir string) bool {
+	glob := fmt.Sprintf("%s/*.tfvars", checkDir)
+	debug.Log("checking for tfvars files using glob: %s", glob)
+	if matches, err := filepath.Glob(glob); err == nil && len(matches) > 0 {
+		return true
+	}
+	return false
+}
diff --git a/internal/app/tfsec/rules/init.go b/internal/app/tfsec/rules/init.go
deleted file mode 100644
index d2380c093..000000000
--- a/internal/app/tfsec/rules/init.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package rules
-
-import (
-	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules/general/secrets"
-)
diff --git a/internal/pkg/adapter/adapt.go b/internal/pkg/adapter/adapt.go
new file mode 100644
index 000000000..a9041abbf
--- /dev/null
+++ b/internal/pkg/adapter/adapt.go
@@ -0,0 +1,29 @@
+package adapter
+
+import (
+	"github.com/aquasecurity/defsec/state"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/cloudstack"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/digitalocean"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/github"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/kubernetes"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/openstack"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/oracle"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+)
+
+func Adapt(modules block.Modules) *state.State {
+	return &state.State{
+		AWS:          aws.Adapt(modules),
+		Azure:        azure.Adapt(modules),
+		CloudStack:   cloudstack.Adapt(modules),
+		DigitalOcean: digitalocean.Adapt(modules),
+		GitHub:       github.Adapt(modules),
+		Google:       google.Adapt(modules),
+		Kubernetes:   kubernetes.Adapt(modules),
+		OpenStack:    openstack.Adapt(modules),
+		Oracle:       oracle.Adapt(modules),
+	}
+}
diff --git a/internal/pkg/adapter/aws/adapt.go b/internal/pkg/adapter/aws/adapt.go
new file mode 100644
index 000000000..b00a962f1
--- /dev/null
+++ b/internal/pkg/adapter/aws/adapt.go
@@ -0,0 +1,79 @@
+package aws
+
+import (
+	"github.com/aquasecurity/defsec/provider/aws"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/apigateway"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/athena"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/autoscaling"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/cloudfront"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/cloudtrail"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/cloudwatch"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/codebuild"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/config"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/documentdb"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/dynamodb"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/ebs"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/ec2"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/ecr"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/ecs"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/efs"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/eks"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/elasticache"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/elasticsearch"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/elb"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/iam"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/kinesis"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/kms"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/lambda"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/mq"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/msk"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/neptune"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/rds"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/redshift"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/s3"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/sns"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/sqs"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/ssm"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/vpc"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/workspaces"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+)
+
+func Adapt(modules block.Modules) aws.AWS {
+	return aws.AWS{
+		APIGateway:    apigateway.Adapt(modules),
+		Athena:        athena.Adapt(modules),
+		Autoscaling:   autoscaling.Adapt(modules),
+		Cloudfront:    cloudfront.Adapt(modules),
+		CloudTrail:    cloudtrail.Adapt(modules),
+		CloudWatch:    cloudwatch.Adapt(modules),
+		CodeBuild:     codebuild.Adapt(modules),
+		Config:        config.Adapt(modules),
+		DocumentDB:    documentdb.Adapt(modules),
+		DynamoDB:      dynamodb.Adapt(modules),
+		EBS:           ebs.Adapt(modules),
+		EC2:           ec2.Adapt(modules),
+		ECR:           ecr.Adapt(modules),
+		ECS:           ecs.Adapt(modules),
+		EFS:           efs.Adapt(modules),
+		EKS:           eks.Adapt(modules),
+		ElastiCache:   elasticache.Adapt(modules),
+		Elasticsearch: elasticsearch.Adapt(modules),
+		ELB:           elb.Adapt(modules),
+		IAM:           iam.Adapt(modules),
+		Kinesis:       kinesis.Adapt(modules),
+		KMS:           kms.Adapt(modules),
+		Lambda:        lambda.Adapt(modules),
+		MQ:            mq.Adapt(modules),
+		MSK:           msk.Adapt(modules),
+		Neptune:       neptune.Adapt(modules),
+		RDS:           rds.Adapt(modules),
+		Redshift:      redshift.Adapt(modules),
+		S3:            s3.Adapt(modules),
+		SNS:           sns.Adapt(modules),
+		SQS:           sqs.Adapt(modules),
+		SSM:           ssm.Adapt(modules),
+		VPC:           vpc.Adapt(modules),
+		WorkSpaces:    workspaces.Adapt(modules),
+	}
+}
diff --git a/internal/app/tfsec/adapter/aws/apigateway/adapt.go b/internal/pkg/adapter/aws/apigateway/adapt.go
similarity index 90%
rename from internal/app/tfsec/adapter/aws/apigateway/adapt.go
rename to internal/pkg/adapter/aws/apigateway/adapt.go
index 0c0b6a4ac..c88dedd9a 100644
--- a/internal/app/tfsec/adapter/aws/apigateway/adapt.go
+++ b/internal/pkg/adapter/aws/apigateway/adapt.go
@@ -2,7 +2,7 @@ package apigateway
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/apigateway"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) apigateway.APIGateway {
diff --git a/internal/app/tfsec/adapter/aws/apigateway/apiv1.go b/internal/pkg/adapter/aws/apigateway/apiv1.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/apigateway/apiv1.go
rename to internal/pkg/adapter/aws/apigateway/apiv1.go
index 9400400ba..d671c8917 100644
--- a/internal/app/tfsec/adapter/aws/apigateway/apiv1.go
+++ b/internal/pkg/adapter/aws/apigateway/apiv1.go
@@ -3,7 +3,7 @@ package apigateway
 import (
 	"github.com/aquasecurity/defsec/provider/aws/apigateway"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptAPIMethodsV1(modules block.Modules, apiBlock *block.Block) []apigateway.RESTMethod {
diff --git a/internal/app/tfsec/adapter/aws/apigateway/apiv2.go b/internal/pkg/adapter/aws/apigateway/apiv2.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/apigateway/apiv2.go
rename to internal/pkg/adapter/aws/apigateway/apiv2.go
index 8bdd2b0e4..058fd300c 100644
--- a/internal/app/tfsec/adapter/aws/apigateway/apiv2.go
+++ b/internal/pkg/adapter/aws/apigateway/apiv2.go
@@ -3,7 +3,7 @@ package apigateway
 import (
 	"github.com/aquasecurity/defsec/provider/aws/apigateway"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptAPIsV2(modules block.Modules) []apigateway.API {
diff --git a/internal/app/tfsec/adapter/aws/apigateway/namesv1.go b/internal/pkg/adapter/aws/apigateway/namesv1.go
similarity index 93%
rename from internal/app/tfsec/adapter/aws/apigateway/namesv1.go
rename to internal/pkg/adapter/aws/apigateway/namesv1.go
index da6fab50f..db538a82d 100644
--- a/internal/app/tfsec/adapter/aws/apigateway/namesv1.go
+++ b/internal/pkg/adapter/aws/apigateway/namesv1.go
@@ -3,7 +3,7 @@ package apigateway
 import (
 	"github.com/aquasecurity/defsec/provider/aws/apigateway"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptDomainNamesV1(modules block.Modules) []apigateway.DomainName {
diff --git a/internal/app/tfsec/adapter/aws/apigateway/namesv2.go b/internal/pkg/adapter/aws/apigateway/namesv2.go
similarity index 94%
rename from internal/app/tfsec/adapter/aws/apigateway/namesv2.go
rename to internal/pkg/adapter/aws/apigateway/namesv2.go
index 119408fe6..ecd35089f 100644
--- a/internal/app/tfsec/adapter/aws/apigateway/namesv2.go
+++ b/internal/pkg/adapter/aws/apigateway/namesv2.go
@@ -3,7 +3,7 @@ package apigateway
 import (
 	"github.com/aquasecurity/defsec/provider/aws/apigateway"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptDomainNamesV2(modules block.Modules) []apigateway.DomainName {
diff --git a/internal/app/tfsec/adapter/aws/athena/adapt.go b/internal/pkg/adapter/aws/athena/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/athena/adapt.go
rename to internal/pkg/adapter/aws/athena/adapt.go
index 3124fe019..b2e534f93 100644
--- a/internal/app/tfsec/adapter/aws/athena/adapt.go
+++ b/internal/pkg/adapter/aws/athena/adapt.go
@@ -3,7 +3,7 @@ package athena
 import (
 	"github.com/aquasecurity/defsec/provider/aws/athena"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) athena.Athena {
diff --git a/internal/app/tfsec/adapter/aws/autoscaling/adapt.go b/internal/pkg/adapter/aws/autoscaling/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/autoscaling/adapt.go
rename to internal/pkg/adapter/aws/autoscaling/adapt.go
index 12b0442fe..b90d78c30 100644
--- a/internal/app/tfsec/adapter/aws/autoscaling/adapt.go
+++ b/internal/pkg/adapter/aws/autoscaling/adapt.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/aws/autoscaling"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) autoscaling.Autoscaling {
diff --git a/internal/app/tfsec/adapter/aws/cloudfront/adapt.go b/internal/pkg/adapter/aws/cloudfront/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/cloudfront/adapt.go
rename to internal/pkg/adapter/aws/cloudfront/adapt.go
index 246185882..69b35112f 100644
--- a/internal/app/tfsec/adapter/aws/cloudfront/adapt.go
+++ b/internal/pkg/adapter/aws/cloudfront/adapt.go
@@ -3,7 +3,7 @@ package cloudfront
 import (
 	"github.com/aquasecurity/defsec/provider/aws/cloudfront"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) cloudfront.Cloudfront {
diff --git a/internal/app/tfsec/adapter/aws/cloudtrail/adapt.go b/internal/pkg/adapter/aws/cloudtrail/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/aws/cloudtrail/adapt.go
rename to internal/pkg/adapter/aws/cloudtrail/adapt.go
index f868fd08c..d2e4ed550 100644
--- a/internal/app/tfsec/adapter/aws/cloudtrail/adapt.go
+++ b/internal/pkg/adapter/aws/cloudtrail/adapt.go
@@ -2,7 +2,7 @@ package cloudtrail
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/cloudtrail"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) cloudtrail.CloudTrail {
diff --git a/internal/app/tfsec/adapter/aws/cloudwatch/adapt.go b/internal/pkg/adapter/aws/cloudwatch/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/aws/cloudwatch/adapt.go
rename to internal/pkg/adapter/aws/cloudwatch/adapt.go
index 041d2dc71..797f7d68f 100644
--- a/internal/app/tfsec/adapter/aws/cloudwatch/adapt.go
+++ b/internal/pkg/adapter/aws/cloudwatch/adapt.go
@@ -2,7 +2,7 @@ package cloudwatch
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/cloudwatch"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) cloudwatch.CloudWatch {
diff --git a/internal/app/tfsec/adapter/aws/codebuild/adapt.go b/internal/pkg/adapter/aws/codebuild/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/codebuild/adapt.go
rename to internal/pkg/adapter/aws/codebuild/adapt.go
index 00bdeeb8d..2e5107c10 100644
--- a/internal/app/tfsec/adapter/aws/codebuild/adapt.go
+++ b/internal/pkg/adapter/aws/codebuild/adapt.go
@@ -3,7 +3,7 @@ package codebuild
 import (
 	"github.com/aquasecurity/defsec/provider/aws/codebuild"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) codebuild.CodeBuild {
diff --git a/internal/app/tfsec/adapter/aws/config/adapt.go b/internal/pkg/adapter/aws/config/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/aws/config/adapt.go
rename to internal/pkg/adapter/aws/config/adapt.go
index b96d6e55a..6b1b7ffce 100644
--- a/internal/app/tfsec/adapter/aws/config/adapt.go
+++ b/internal/pkg/adapter/aws/config/adapt.go
@@ -3,7 +3,7 @@ package config
 import (
 	"github.com/aquasecurity/defsec/provider/aws/config"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) config.Config {
diff --git a/internal/app/tfsec/adapter/aws/documentdb/adapt.go b/internal/pkg/adapter/aws/documentdb/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/documentdb/adapt.go
rename to internal/pkg/adapter/aws/documentdb/adapt.go
index bf448cf0d..653077fc8 100644
--- a/internal/app/tfsec/adapter/aws/documentdb/adapt.go
+++ b/internal/pkg/adapter/aws/documentdb/adapt.go
@@ -3,7 +3,7 @@ package documentdb
 import (
 	"github.com/aquasecurity/defsec/provider/aws/documentdb"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) documentdb.DocumentDB {
diff --git a/internal/app/tfsec/adapter/aws/dynamodb/adapt.go b/internal/pkg/adapter/aws/dynamodb/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/dynamodb/adapt.go
rename to internal/pkg/adapter/aws/dynamodb/adapt.go
index c3b8219dc..236e435cf 100644
--- a/internal/app/tfsec/adapter/aws/dynamodb/adapt.go
+++ b/internal/pkg/adapter/aws/dynamodb/adapt.go
@@ -3,7 +3,7 @@ package dynamodb
 import (
 	"github.com/aquasecurity/defsec/provider/aws/dynamodb"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) dynamodb.DynamoDB {
diff --git a/internal/app/tfsec/adapter/aws/ebs/adapt.go b/internal/pkg/adapter/aws/ebs/adapt.go
similarity index 93%
rename from internal/app/tfsec/adapter/aws/ebs/adapt.go
rename to internal/pkg/adapter/aws/ebs/adapt.go
index 60794c4b6..20672f91a 100644
--- a/internal/app/tfsec/adapter/aws/ebs/adapt.go
+++ b/internal/pkg/adapter/aws/ebs/adapt.go
@@ -2,7 +2,7 @@ package ebs
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/ebs"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) ebs.EBS {
diff --git a/internal/app/tfsec/adapter/aws/ec2/adapt.go b/internal/pkg/adapter/aws/ec2/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/aws/ec2/adapt.go
rename to internal/pkg/adapter/aws/ec2/adapt.go
index 680816c1c..44a2aba7f 100644
--- a/internal/app/tfsec/adapter/aws/ec2/adapt.go
+++ b/internal/pkg/adapter/aws/ec2/adapt.go
@@ -3,7 +3,7 @@ package ec2
 import (
 	"github.com/aquasecurity/defsec/provider/aws/ec2"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) ec2.EC2 {
diff --git a/internal/app/tfsec/adapter/aws/ec2/adapt_test.go b/internal/pkg/adapter/aws/ec2/adapt_test.go
similarity index 100%
rename from internal/app/tfsec/adapter/aws/ec2/adapt_test.go
rename to internal/pkg/adapter/aws/ec2/adapt_test.go
diff --git a/internal/app/tfsec/adapter/aws/ecr/adapt.go b/internal/pkg/adapter/aws/ecr/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/ecr/adapt.go
rename to internal/pkg/adapter/aws/ecr/adapt.go
index 447337289..7dcf0f572 100644
--- a/internal/app/tfsec/adapter/aws/ecr/adapt.go
+++ b/internal/pkg/adapter/aws/ecr/adapt.go
@@ -3,7 +3,7 @@ package ecr
 import (
 	"github.com/aquasecurity/defsec/provider/aws/ecr"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) ecr.ECR {
diff --git a/internal/app/tfsec/adapter/aws/ecs/adapt.go b/internal/pkg/adapter/aws/ecs/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/ecs/adapt.go
rename to internal/pkg/adapter/aws/ecs/adapt.go
index 8ad5f5aa3..a5758765a 100644
--- a/internal/app/tfsec/adapter/aws/ecs/adapt.go
+++ b/internal/pkg/adapter/aws/ecs/adapt.go
@@ -3,7 +3,7 @@ package ecs
 import (
 	"github.com/aquasecurity/defsec/provider/aws/ecs"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) ecs.ECS {
diff --git a/internal/app/tfsec/adapter/aws/efs/adapt.go b/internal/pkg/adapter/aws/efs/adapt.go
similarity index 92%
rename from internal/app/tfsec/adapter/aws/efs/adapt.go
rename to internal/pkg/adapter/aws/efs/adapt.go
index 19b09deb1..5310658d2 100644
--- a/internal/app/tfsec/adapter/aws/efs/adapt.go
+++ b/internal/pkg/adapter/aws/efs/adapt.go
@@ -2,7 +2,7 @@ package efs
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/efs"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) efs.EFS {
diff --git a/internal/app/tfsec/adapter/aws/eks/adapt.go b/internal/pkg/adapter/aws/eks/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/eks/adapt.go
rename to internal/pkg/adapter/aws/eks/adapt.go
index 459ee437d..05c6229fe 100644
--- a/internal/app/tfsec/adapter/aws/eks/adapt.go
+++ b/internal/pkg/adapter/aws/eks/adapt.go
@@ -3,7 +3,7 @@ package eks
 import (
 	"github.com/aquasecurity/defsec/provider/aws/eks"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) eks.EKS {
diff --git a/internal/app/tfsec/adapter/aws/elasticache/adapt.go b/internal/pkg/adapter/aws/elasticache/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/elasticache/adapt.go
rename to internal/pkg/adapter/aws/elasticache/adapt.go
index d7757904a..048e08ce3 100644
--- a/internal/app/tfsec/adapter/aws/elasticache/adapt.go
+++ b/internal/pkg/adapter/aws/elasticache/adapt.go
@@ -2,7 +2,7 @@ package elasticache
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/elasticache"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) elasticache.ElastiCache {
diff --git a/internal/app/tfsec/adapter/aws/elasticsearch/adapt.go b/internal/pkg/adapter/aws/elasticsearch/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/elasticsearch/adapt.go
rename to internal/pkg/adapter/aws/elasticsearch/adapt.go
index 589beb295..651da5e30 100644
--- a/internal/app/tfsec/adapter/aws/elasticsearch/adapt.go
+++ b/internal/pkg/adapter/aws/elasticsearch/adapt.go
@@ -3,7 +3,7 @@ package elasticsearch
 import (
 	"github.com/aquasecurity/defsec/provider/aws/elasticsearch"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) elasticsearch.Elasticsearch {
diff --git a/internal/app/tfsec/adapter/aws/elb/adapt.go b/internal/pkg/adapter/aws/elb/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/elb/adapt.go
rename to internal/pkg/adapter/aws/elb/adapt.go
index 70fa5a890..e2f9fec8a 100644
--- a/internal/app/tfsec/adapter/aws/elb/adapt.go
+++ b/internal/pkg/adapter/aws/elb/adapt.go
@@ -3,7 +3,7 @@ package elb
 import (
 	"github.com/aquasecurity/defsec/provider/aws/elb"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) elb.ELB {
diff --git a/internal/app/tfsec/adapter/aws/iam/adapt.go b/internal/pkg/adapter/aws/iam/adapt.go
similarity index 85%
rename from internal/app/tfsec/adapter/aws/iam/adapt.go
rename to internal/pkg/adapter/aws/iam/adapt.go
index 16bb879cc..bb9485065 100644
--- a/internal/app/tfsec/adapter/aws/iam/adapt.go
+++ b/internal/pkg/adapter/aws/iam/adapt.go
@@ -2,7 +2,7 @@ package iam
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) iam.IAM {
diff --git a/internal/app/tfsec/adapter/aws/iam/convert.go b/internal/pkg/adapter/aws/iam/convert.go
similarity index 99%
rename from internal/app/tfsec/adapter/aws/iam/convert.go
rename to internal/pkg/adapter/aws/iam/convert.go
index 6d1200ad3..9c2768922 100644
--- a/internal/app/tfsec/adapter/aws/iam/convert.go
+++ b/internal/pkg/adapter/aws/iam/convert.go
@@ -6,7 +6,7 @@ import (
 
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/liamg/iamgo"
 )
 
diff --git a/internal/app/tfsec/adapter/aws/iam/groups.go b/internal/pkg/adapter/aws/iam/groups.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/iam/groups.go
rename to internal/pkg/adapter/aws/iam/groups.go
index 8224b00ba..c5780fc9f 100644
--- a/internal/app/tfsec/adapter/aws/iam/groups.go
+++ b/internal/pkg/adapter/aws/iam/groups.go
@@ -2,7 +2,7 @@ package iam
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptGroups(modules block.Modules) []iam.Group {
diff --git a/internal/app/tfsec/adapter/aws/iam/passwords.go b/internal/pkg/adapter/aws/iam/passwords.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/iam/passwords.go
rename to internal/pkg/adapter/aws/iam/passwords.go
index 6720b1e06..f19b16a1c 100644
--- a/internal/app/tfsec/adapter/aws/iam/passwords.go
+++ b/internal/pkg/adapter/aws/iam/passwords.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/aws/iam"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptPasswordPolicy(modules block.Modules) (policy iam.PasswordPolicy) {
diff --git a/internal/app/tfsec/adapter/aws/iam/policies.go b/internal/pkg/adapter/aws/iam/policies.go
similarity index 96%
rename from internal/app/tfsec/adapter/aws/iam/policies.go
rename to internal/pkg/adapter/aws/iam/policies.go
index e0471c8c6..643bbc106 100644
--- a/internal/app/tfsec/adapter/aws/iam/policies.go
+++ b/internal/pkg/adapter/aws/iam/policies.go
@@ -4,7 +4,7 @@ import (
 	"strings"
 
 	"github.com/aquasecurity/defsec/provider/aws/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func sameProvider(b1, b2 *block.Block) bool {
diff --git a/internal/app/tfsec/adapter/aws/iam/roles.go b/internal/pkg/adapter/aws/iam/roles.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/iam/roles.go
rename to internal/pkg/adapter/aws/iam/roles.go
index 658b28687..22f0d64c3 100644
--- a/internal/app/tfsec/adapter/aws/iam/roles.go
+++ b/internal/pkg/adapter/aws/iam/roles.go
@@ -2,7 +2,7 @@ package iam
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptRoles(modules block.Modules) []iam.Role {
diff --git a/internal/app/tfsec/adapter/aws/iam/users.go b/internal/pkg/adapter/aws/iam/users.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/iam/users.go
rename to internal/pkg/adapter/aws/iam/users.go
index 4e7be4f8a..8868ec44d 100644
--- a/internal/app/tfsec/adapter/aws/iam/users.go
+++ b/internal/pkg/adapter/aws/iam/users.go
@@ -2,7 +2,7 @@ package iam
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptUsers(modules block.Modules) []iam.User {
diff --git a/internal/app/tfsec/adapter/aws/kinesis/adapt.go b/internal/pkg/adapter/aws/kinesis/adapt.go
similarity index 94%
rename from internal/app/tfsec/adapter/aws/kinesis/adapt.go
rename to internal/pkg/adapter/aws/kinesis/adapt.go
index 6f03e59a0..84a346265 100644
--- a/internal/app/tfsec/adapter/aws/kinesis/adapt.go
+++ b/internal/pkg/adapter/aws/kinesis/adapt.go
@@ -2,7 +2,7 @@ package kinesis
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/kinesis"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) kinesis.Kinesis {
diff --git a/internal/app/tfsec/adapter/aws/kms/adapt.go b/internal/pkg/adapter/aws/kms/adapt.go
similarity index 93%
rename from internal/app/tfsec/adapter/aws/kms/adapt.go
rename to internal/pkg/adapter/aws/kms/adapt.go
index a40c94f28..e8fcbf6e2 100644
--- a/internal/app/tfsec/adapter/aws/kms/adapt.go
+++ b/internal/pkg/adapter/aws/kms/adapt.go
@@ -2,7 +2,7 @@ package kms
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/kms"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) kms.KMS {
diff --git a/internal/app/tfsec/adapter/aws/lambda/adapt.go b/internal/pkg/adapter/aws/lambda/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/lambda/adapt.go
rename to internal/pkg/adapter/aws/lambda/adapt.go
index 903154636..44f8005f2 100644
--- a/internal/app/tfsec/adapter/aws/lambda/adapt.go
+++ b/internal/pkg/adapter/aws/lambda/adapt.go
@@ -3,7 +3,7 @@ package lambda
 import (
 	"github.com/aquasecurity/defsec/provider/aws/lambda"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) lambda.Lambda {
diff --git a/internal/app/tfsec/adapter/aws/mq/adapt.go b/internal/pkg/adapter/aws/mq/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/aws/mq/adapt.go
rename to internal/pkg/adapter/aws/mq/adapt.go
index 338128ac5..04d2ce7d2 100644
--- a/internal/app/tfsec/adapter/aws/mq/adapt.go
+++ b/internal/pkg/adapter/aws/mq/adapt.go
@@ -3,7 +3,7 @@ package mq
 import (
 	"github.com/aquasecurity/defsec/provider/aws/mq"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) mq.MQ {
diff --git a/internal/app/tfsec/adapter/aws/msk/adapt.go b/internal/pkg/adapter/aws/msk/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/msk/adapt.go
rename to internal/pkg/adapter/aws/msk/adapt.go
index 8edca00fa..d733e86b8 100644
--- a/internal/app/tfsec/adapter/aws/msk/adapt.go
+++ b/internal/pkg/adapter/aws/msk/adapt.go
@@ -3,7 +3,7 @@ package msk
 import (
 	"github.com/aquasecurity/defsec/provider/aws/msk"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) msk.MSK {
diff --git a/internal/app/tfsec/adapter/aws/neptune/adapt.go b/internal/pkg/adapter/aws/neptune/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/aws/neptune/adapt.go
rename to internal/pkg/adapter/aws/neptune/adapt.go
index 77f11ba4e..e676ead81 100644
--- a/internal/app/tfsec/adapter/aws/neptune/adapt.go
+++ b/internal/pkg/adapter/aws/neptune/adapt.go
@@ -3,7 +3,7 @@ package neptune
 import (
 	"github.com/aquasecurity/defsec/provider/aws/neptune"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) neptune.Neptune {
diff --git a/internal/app/tfsec/adapter/aws/rds/adapt.go b/internal/pkg/adapter/aws/rds/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/aws/rds/adapt.go
rename to internal/pkg/adapter/aws/rds/adapt.go
index 8f6a371c6..7651d117a 100644
--- a/internal/app/tfsec/adapter/aws/rds/adapt.go
+++ b/internal/pkg/adapter/aws/rds/adapt.go
@@ -3,7 +3,7 @@ package rds
 import (
 	"github.com/aquasecurity/defsec/provider/aws/rds"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) rds.RDS {
diff --git a/internal/app/tfsec/adapter/aws/redshift/adapt.go b/internal/pkg/adapter/aws/redshift/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/redshift/adapt.go
rename to internal/pkg/adapter/aws/redshift/adapt.go
index 57963919e..45848c6fa 100644
--- a/internal/app/tfsec/adapter/aws/redshift/adapt.go
+++ b/internal/pkg/adapter/aws/redshift/adapt.go
@@ -2,7 +2,7 @@ package redshift
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/redshift"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) redshift.Redshift {
diff --git a/internal/app/tfsec/adapter/aws/s3/adapt.go b/internal/pkg/adapter/aws/s3/adapt.go
similarity index 84%
rename from internal/app/tfsec/adapter/aws/s3/adapt.go
rename to internal/pkg/adapter/aws/s3/adapt.go
index 89a547087..2f61ac01b 100644
--- a/internal/app/tfsec/adapter/aws/s3/adapt.go
+++ b/internal/pkg/adapter/aws/s3/adapt.go
@@ -2,7 +2,7 @@ package s3
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/s3"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) s3.S3 {
diff --git a/internal/app/tfsec/adapter/aws/s3/bucket.go b/internal/pkg/adapter/aws/s3/bucket.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/s3/bucket.go
rename to internal/pkg/adapter/aws/s3/bucket.go
index 523fc98af..dd25ee37c 100644
--- a/internal/app/tfsec/adapter/aws/s3/bucket.go
+++ b/internal/pkg/adapter/aws/s3/bucket.go
@@ -3,7 +3,7 @@ package s3
 import (
 	"github.com/aquasecurity/defsec/provider/aws/s3"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func getBuckets(modules block.Modules) []s3.Bucket {
diff --git a/internal/app/tfsec/adapter/aws/s3/public_access_block.go b/internal/pkg/adapter/aws/s3/public_access_block.go
similarity index 96%
rename from internal/app/tfsec/adapter/aws/s3/public_access_block.go
rename to internal/pkg/adapter/aws/s3/public_access_block.go
index 041c434af..f21e54a38 100644
--- a/internal/app/tfsec/adapter/aws/s3/public_access_block.go
+++ b/internal/pkg/adapter/aws/s3/public_access_block.go
@@ -4,7 +4,7 @@ import (
 	"strings"
 
 	"github.com/aquasecurity/defsec/provider/aws/s3"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func getPublicAccessBlocks(modules block.Modules, buckets []s3.Bucket) []s3.PublicAccessBlock {
diff --git a/internal/app/tfsec/adapter/aws/sns/adapt.go b/internal/pkg/adapter/aws/sns/adapt.go
similarity index 93%
rename from internal/app/tfsec/adapter/aws/sns/adapt.go
rename to internal/pkg/adapter/aws/sns/adapt.go
index cca2a2fa9..59a419ff0 100644
--- a/internal/app/tfsec/adapter/aws/sns/adapt.go
+++ b/internal/pkg/adapter/aws/sns/adapt.go
@@ -2,7 +2,7 @@ package sns
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/sns"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) sns.SNS {
diff --git a/internal/app/tfsec/adapter/aws/sqs/adapt.go b/internal/pkg/adapter/aws/sqs/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/aws/sqs/adapt.go
rename to internal/pkg/adapter/aws/sqs/adapt.go
index ea1d43772..c38315066 100644
--- a/internal/app/tfsec/adapter/aws/sqs/adapt.go
+++ b/internal/pkg/adapter/aws/sqs/adapt.go
@@ -5,8 +5,8 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/aws/sqs"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/aws/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/aws/iam"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/google/uuid"
 )
 
diff --git a/internal/app/tfsec/adapter/aws/ssm/adapt.go b/internal/pkg/adapter/aws/ssm/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/aws/ssm/adapt.go
rename to internal/pkg/adapter/aws/ssm/adapt.go
index c21485d96..9abb0962c 100644
--- a/internal/app/tfsec/adapter/aws/ssm/adapt.go
+++ b/internal/pkg/adapter/aws/ssm/adapt.go
@@ -3,7 +3,7 @@ package ssm
 import (
 	"github.com/aquasecurity/defsec/provider/aws/ssm"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) ssm.SSM {
diff --git a/internal/app/tfsec/adapter/aws/vpc/adapt.go b/internal/pkg/adapter/aws/vpc/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/vpc/adapt.go
rename to internal/pkg/adapter/aws/vpc/adapt.go
index c61f53d52..eb018a7dc 100644
--- a/internal/app/tfsec/adapter/aws/vpc/adapt.go
+++ b/internal/pkg/adapter/aws/vpc/adapt.go
@@ -3,7 +3,7 @@ package vpc
 import (
 	"github.com/aquasecurity/defsec/provider/aws/vpc"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) vpc.VPC {
@@ -11,11 +11,12 @@ func Adapt(modules block.Modules) vpc.VPC {
 	naclAdapter := naclAdapter{naclRuleIDs: modules.GetChildResourceIDMapByType("aws_network_acl_rule")}
 	sgAdapter := sgAdapter{sgRuleIDs: modules.GetChildResourceIDMapByType("aws_security_group_rule")}
 
-	return vpc.VPC{
+	rx := vpc.VPC{
 		DefaultVPCs:    adaptDefaultVPCs(modules),
 		SecurityGroups: sgAdapter.adaptSecurityGroups(modules),
 		NetworkACLs:    naclAdapter.adaptNetworkACLs(modules),
 	}
+	return rx
 }
 
 type naclAdapter struct {
@@ -137,7 +138,7 @@ func adaptSGRule(resource *block.Block, modules block.Modules) vpc.SecurityGroup
 		}
 	}
 
-	if cidrBlocks.IsNotNil() && cidrBlocks.IsIterable() {
+	if cidrBlocks.IsNotNil() {
 		cidrsList := cidrBlocks.ValueAsStrings()
 		for _, cidr := range cidrsList {
 			cidrs = append(cidrs, types.String(cidr, *cidrBlocks.GetMetadata()))
@@ -146,7 +147,7 @@ func adaptSGRule(resource *block.Block, modules block.Modules) vpc.SecurityGroup
 		cidrs = append(cidrs, cidrBlocks.AsStringValueOrDefault("", resource))
 	}
 
-	if ipv6cidrBlocks.IsNotNil() && ipv6cidrBlocks.IsIterable() {
+	if ipv6cidrBlocks.IsNotNil() {
 		cidrsList := ipv6cidrBlocks.ValueAsStrings()
 		for _, cidr := range cidrsList {
 			cidrs = append(cidrs, types.String(cidr, *ipv6cidrBlocks.GetMetadata()))
diff --git a/internal/app/tfsec/adapter/aws/workspaces/adapt.go b/internal/pkg/adapter/aws/workspaces/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/aws/workspaces/adapt.go
rename to internal/pkg/adapter/aws/workspaces/adapt.go
index 94a08aeca..24c5a6329 100644
--- a/internal/app/tfsec/adapter/aws/workspaces/adapt.go
+++ b/internal/pkg/adapter/aws/workspaces/adapt.go
@@ -2,7 +2,7 @@ package workspaces
 
 import (
 	"github.com/aquasecurity/defsec/provider/aws/workspaces"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) workspaces.WorkSpaces {
diff --git a/internal/pkg/adapter/azure/adapt.go b/internal/pkg/adapter/azure/adapt.go
new file mode 100644
index 000000000..86cea4e46
--- /dev/null
+++ b/internal/pkg/adapter/azure/adapt.go
@@ -0,0 +1,37 @@
+package azure
+
+import (
+	"github.com/aquasecurity/defsec/provider/azure"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/appservice"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/authorization"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/compute"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/container"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/database"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/datafactory"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/datalake"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/keyvault"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/monitor"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/network"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/securitycenter"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/storage"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/azure/synapse"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+)
+
+func Adapt(modules block.Modules) azure.Azure {
+	return azure.Azure{
+		AppService:     appservice.Adapt(modules),
+		Authorization:  authorization.Adapt(modules),
+		Compute:        compute.Adapt(modules),
+		Container:      container.Adapt(modules),
+		Database:       database.Adapt(modules),
+		DataFactory:    datafactory.Adapt(modules),
+		DataLake:       datalake.Adapt(modules),
+		KeyVault:       keyvault.Adapt(modules),
+		Monitor:        monitor.Adapt(modules),
+		Network:        network.Adapt(modules),
+		SecurityCenter: securitycenter.Adapt(modules),
+		Storage:        storage.Adapt(modules),
+		Synapse:        synapse.Adapt(modules),
+	}
+}
diff --git a/internal/app/tfsec/adapter/azure/appservice/adapt.go b/internal/pkg/adapter/azure/appservice/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/azure/appservice/adapt.go
rename to internal/pkg/adapter/azure/appservice/adapt.go
index 4bad27226..c4fd8ed5a 100644
--- a/internal/app/tfsec/adapter/azure/appservice/adapt.go
+++ b/internal/pkg/adapter/azure/appservice/adapt.go
@@ -3,7 +3,7 @@ package appservice
 import (
 	"github.com/aquasecurity/defsec/provider/azure/appservice"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) appservice.AppService {
diff --git a/internal/app/tfsec/adapter/azure/authorization/adapt.go b/internal/pkg/adapter/azure/authorization/adapt.go
similarity index 96%
rename from internal/app/tfsec/adapter/azure/authorization/adapt.go
rename to internal/pkg/adapter/azure/authorization/adapt.go
index af0c63bf0..28f028e91 100644
--- a/internal/app/tfsec/adapter/azure/authorization/adapt.go
+++ b/internal/pkg/adapter/azure/authorization/adapt.go
@@ -3,7 +3,7 @@ package authorization
 import (
 	"github.com/aquasecurity/defsec/provider/azure/authorization"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) authorization.Authorization {
diff --git a/internal/app/tfsec/adapter/azure/compute/adapt.go b/internal/pkg/adapter/azure/compute/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/azure/compute/adapt.go
rename to internal/pkg/adapter/azure/compute/adapt.go
index 841d7582c..6b000773d 100644
--- a/internal/app/tfsec/adapter/azure/compute/adapt.go
+++ b/internal/pkg/adapter/azure/compute/adapt.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/azure/compute"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) compute.Compute {
diff --git a/internal/app/tfsec/adapter/azure/container/adapt.go b/internal/pkg/adapter/azure/container/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/azure/container/adapt.go
rename to internal/pkg/adapter/azure/container/adapt.go
index b058f56f5..aeef768ba 100644
--- a/internal/app/tfsec/adapter/azure/container/adapt.go
+++ b/internal/pkg/adapter/azure/container/adapt.go
@@ -3,7 +3,7 @@ package container
 import (
 	"github.com/aquasecurity/defsec/provider/azure/container"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) container.Container {
diff --git a/internal/app/tfsec/adapter/azure/database/adapt.go b/internal/pkg/adapter/azure/database/adapt.go
similarity index 99%
rename from internal/app/tfsec/adapter/azure/database/adapt.go
rename to internal/pkg/adapter/azure/database/adapt.go
index 93b5cb9b2..37cb930f3 100644
--- a/internal/app/tfsec/adapter/azure/database/adapt.go
+++ b/internal/pkg/adapter/azure/database/adapt.go
@@ -3,7 +3,7 @@ package database
 import (
 	"github.com/aquasecurity/defsec/provider/azure/database"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) database.Database {
@@ -395,8 +395,9 @@ func adaptFirewallRule(resource *block.Block) database.FirewallRule {
 	endIPVal := endIPAttr.AsStringValueOrDefault("", resource)
 
 	return database.FirewallRule{
-		StartIP: startIPVal,
-		EndIP:   endIPVal,
+		Metadata: resource.Metadata(),
+		StartIP:  startIPVal,
+		EndIP:    endIPVal,
 	}
 }
 
diff --git a/internal/app/tfsec/adapter/azure/datafactory/adapt.go b/internal/pkg/adapter/azure/datafactory/adapt.go
similarity index 93%
rename from internal/app/tfsec/adapter/azure/datafactory/adapt.go
rename to internal/pkg/adapter/azure/datafactory/adapt.go
index 2cea09942..33aeec525 100644
--- a/internal/app/tfsec/adapter/azure/datafactory/adapt.go
+++ b/internal/pkg/adapter/azure/datafactory/adapt.go
@@ -2,7 +2,7 @@ package datafactory
 
 import (
 	"github.com/aquasecurity/defsec/provider/azure/datafactory"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) datafactory.DataFactory {
diff --git a/internal/app/tfsec/adapter/azure/datalake/adapt.go b/internal/pkg/adapter/azure/datalake/adapt.go
similarity index 93%
rename from internal/app/tfsec/adapter/azure/datalake/adapt.go
rename to internal/pkg/adapter/azure/datalake/adapt.go
index caa417657..d0d819903 100644
--- a/internal/app/tfsec/adapter/azure/datalake/adapt.go
+++ b/internal/pkg/adapter/azure/datalake/adapt.go
@@ -3,7 +3,7 @@ package datalake
 import (
 	"github.com/aquasecurity/defsec/provider/azure/datalake"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) datalake.DataLake {
diff --git a/internal/app/tfsec/adapter/azure/keyvault/adapt.go b/internal/pkg/adapter/azure/keyvault/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/azure/keyvault/adapt.go
rename to internal/pkg/adapter/azure/keyvault/adapt.go
index 0ce755380..9e518d971 100644
--- a/internal/app/tfsec/adapter/azure/keyvault/adapt.go
+++ b/internal/pkg/adapter/azure/keyvault/adapt.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/azure/keyvault"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) keyvault.KeyVault {
diff --git a/internal/app/tfsec/adapter/azure/monitor/adapt.go b/internal/pkg/adapter/azure/monitor/adapt.go
similarity index 96%
rename from internal/app/tfsec/adapter/azure/monitor/adapt.go
rename to internal/pkg/adapter/azure/monitor/adapt.go
index 6665cb8f9..fa343f62a 100644
--- a/internal/app/tfsec/adapter/azure/monitor/adapt.go
+++ b/internal/pkg/adapter/azure/monitor/adapt.go
@@ -3,7 +3,7 @@ package monitor
 import (
 	"github.com/aquasecurity/defsec/provider/azure/monitor"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) monitor.Monitor {
diff --git a/internal/app/tfsec/adapter/azure/network/adapt.go b/internal/pkg/adapter/azure/network/adapt.go
similarity index 99%
rename from internal/app/tfsec/adapter/azure/network/adapt.go
rename to internal/pkg/adapter/azure/network/adapt.go
index 09de82076..d37352a6a 100644
--- a/internal/app/tfsec/adapter/azure/network/adapt.go
+++ b/internal/pkg/adapter/azure/network/adapt.go
@@ -6,7 +6,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/azure/network"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/google/uuid"
 )
 
diff --git a/internal/app/tfsec/adapter/azure/securitycenter/adapt.go b/internal/pkg/adapter/azure/securitycenter/adapt.go
similarity index 96%
rename from internal/app/tfsec/adapter/azure/securitycenter/adapt.go
rename to internal/pkg/adapter/azure/securitycenter/adapt.go
index 5624f4ac8..5dcac115c 100644
--- a/internal/app/tfsec/adapter/azure/securitycenter/adapt.go
+++ b/internal/pkg/adapter/azure/securitycenter/adapt.go
@@ -2,7 +2,7 @@ package securitycenter
 
 import (
 	"github.com/aquasecurity/defsec/provider/azure/securitycenter"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) securitycenter.SecurityCenter {
diff --git a/internal/app/tfsec/adapter/azure/storage/adapt.go b/internal/pkg/adapter/azure/storage/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/azure/storage/adapt.go
rename to internal/pkg/adapter/azure/storage/adapt.go
index 11b486f34..14366ae7b 100644
--- a/internal/app/tfsec/adapter/azure/storage/adapt.go
+++ b/internal/pkg/adapter/azure/storage/adapt.go
@@ -3,7 +3,7 @@ package storage
 import (
 	"github.com/aquasecurity/defsec/provider/azure/storage"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) storage.Storage {
diff --git a/internal/app/tfsec/adapter/azure/synapse/adapt.go b/internal/pkg/adapter/azure/synapse/adapt.go
similarity index 93%
rename from internal/app/tfsec/adapter/azure/synapse/adapt.go
rename to internal/pkg/adapter/azure/synapse/adapt.go
index d6accd550..a3aa41955 100644
--- a/internal/app/tfsec/adapter/azure/synapse/adapt.go
+++ b/internal/pkg/adapter/azure/synapse/adapt.go
@@ -2,7 +2,7 @@ package synapse
 
 import (
 	"github.com/aquasecurity/defsec/provider/azure/synapse"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) synapse.Synapse {
diff --git a/internal/app/tfsec/adapter/cloudstack/adapt.go b/internal/pkg/adapter/cloudstack/adapt.go
similarity index 61%
rename from internal/app/tfsec/adapter/cloudstack/adapt.go
rename to internal/pkg/adapter/cloudstack/adapt.go
index 42d132987..6e63fec70 100644
--- a/internal/app/tfsec/adapter/cloudstack/adapt.go
+++ b/internal/pkg/adapter/cloudstack/adapt.go
@@ -2,8 +2,8 @@ package cloudstack
 
 import (
 	"github.com/aquasecurity/defsec/provider/cloudstack"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/cloudstack/compute"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/cloudstack/compute"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) cloudstack.CloudStack {
diff --git a/internal/app/tfsec/adapter/cloudstack/compute/adapt.go b/internal/pkg/adapter/cloudstack/compute/adapt.go
similarity index 94%
rename from internal/app/tfsec/adapter/cloudstack/compute/adapt.go
rename to internal/pkg/adapter/cloudstack/compute/adapt.go
index 93482aa43..d2dee325d 100644
--- a/internal/app/tfsec/adapter/cloudstack/compute/adapt.go
+++ b/internal/pkg/adapter/cloudstack/compute/adapt.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/cloudstack/compute"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) compute.Compute {
diff --git a/internal/app/tfsec/adapter/digitalocean/adapt.go b/internal/pkg/adapter/digitalocean/adapt.go
similarity index 54%
rename from internal/app/tfsec/adapter/digitalocean/adapt.go
rename to internal/pkg/adapter/digitalocean/adapt.go
index 6b82906ed..85a3403d1 100644
--- a/internal/app/tfsec/adapter/digitalocean/adapt.go
+++ b/internal/pkg/adapter/digitalocean/adapt.go
@@ -2,9 +2,9 @@ package digitalocean
 
 import (
 	"github.com/aquasecurity/defsec/provider/digitalocean"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/digitalocean/compute"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/digitalocean/spaces"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/digitalocean/compute"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/digitalocean/spaces"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) digitalocean.DigitalOcean {
diff --git a/internal/app/tfsec/adapter/digitalocean/compute/adapt.go b/internal/pkg/adapter/digitalocean/compute/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/digitalocean/compute/adapt.go
rename to internal/pkg/adapter/digitalocean/compute/adapt.go
index 16aa425ae..7954cbfd9 100644
--- a/internal/app/tfsec/adapter/digitalocean/compute/adapt.go
+++ b/internal/pkg/adapter/digitalocean/compute/adapt.go
@@ -3,7 +3,7 @@ package compute
 import (
 	"github.com/aquasecurity/defsec/provider/digitalocean/compute"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) compute.Compute {
diff --git a/internal/app/tfsec/adapter/digitalocean/spaces/adapt.go b/internal/pkg/adapter/digitalocean/spaces/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/digitalocean/spaces/adapt.go
rename to internal/pkg/adapter/digitalocean/spaces/adapt.go
index 5986a5b03..a17879e02 100644
--- a/internal/app/tfsec/adapter/digitalocean/spaces/adapt.go
+++ b/internal/pkg/adapter/digitalocean/spaces/adapt.go
@@ -3,7 +3,7 @@ package spaces
 import (
 	"github.com/aquasecurity/defsec/provider/digitalocean/spaces"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/google/uuid"
 )
 
diff --git a/internal/app/tfsec/adapter/github/adapt.go b/internal/pkg/adapter/github/adapt.go
similarity index 54%
rename from internal/app/tfsec/adapter/github/adapt.go
rename to internal/pkg/adapter/github/adapt.go
index 9c297ec2a..718a231d0 100644
--- a/internal/app/tfsec/adapter/github/adapt.go
+++ b/internal/pkg/adapter/github/adapt.go
@@ -2,9 +2,9 @@ package github
 
 import (
 	"github.com/aquasecurity/defsec/provider/github"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/github/repositories"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/github/secrets"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/github/repositories"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/github/secrets"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) github.GitHub {
diff --git a/internal/app/tfsec/adapter/github/repositories/adapt.go b/internal/pkg/adapter/github/repositories/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/github/repositories/adapt.go
rename to internal/pkg/adapter/github/repositories/adapt.go
index 6772a1fa8..85015d65d 100644
--- a/internal/app/tfsec/adapter/github/repositories/adapt.go
+++ b/internal/pkg/adapter/github/repositories/adapt.go
@@ -3,7 +3,7 @@ package repositories
 import (
 	"github.com/aquasecurity/defsec/provider/github"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) []github.Repository {
diff --git a/internal/app/tfsec/adapter/github/secrets/adapt.go b/internal/pkg/adapter/github/secrets/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/github/secrets/adapt.go
rename to internal/pkg/adapter/github/secrets/adapt.go
index 57a26b096..e4ea6863c 100644
--- a/internal/app/tfsec/adapter/github/secrets/adapt.go
+++ b/internal/pkg/adapter/github/secrets/adapt.go
@@ -2,7 +2,7 @@ package secrets
 
 import (
 	"github.com/aquasecurity/defsec/provider/github"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) []github.EnvironmentSecret {
diff --git a/internal/pkg/adapter/google/adapt.go b/internal/pkg/adapter/google/adapt.go
new file mode 100644
index 000000000..03d38f035
--- /dev/null
+++ b/internal/pkg/adapter/google/adapt.go
@@ -0,0 +1,27 @@
+package google
+
+import (
+	"github.com/aquasecurity/defsec/provider/google"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google/bigquery"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google/compute"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google/dns"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google/gke"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google/iam"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google/kms"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google/sql"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google/storage"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+)
+
+func Adapt(modules block.Modules) google.Google {
+	return google.Google{
+		BigQuery: bigquery.Adapt(modules),
+		Compute:  compute.Adapt(modules),
+		DNS:      dns.Adapt(modules),
+		GKE:      gke.Adapt(modules),
+		KMS:      kms.Adapt(modules),
+		IAM:      iam.Adapt(modules),
+		SQL:      sql.Adapt(modules),
+		Storage:  storage.Adapt(modules),
+	}
+}
diff --git a/internal/app/tfsec/adapter/google/bigquery/adapt.go b/internal/pkg/adapter/google/bigquery/adapt.go
similarity index 96%
rename from internal/app/tfsec/adapter/google/bigquery/adapt.go
rename to internal/pkg/adapter/google/bigquery/adapt.go
index 9c8f565e8..9217e5c47 100644
--- a/internal/app/tfsec/adapter/google/bigquery/adapt.go
+++ b/internal/pkg/adapter/google/bigquery/adapt.go
@@ -2,7 +2,7 @@ package bigquery
 
 import (
 	"github.com/aquasecurity/defsec/provider/google/bigquery"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) bigquery.BigQuery {
diff --git a/internal/app/tfsec/adapter/google/compute/adapt.go b/internal/pkg/adapter/google/compute/adapt.go
similarity index 87%
rename from internal/app/tfsec/adapter/google/compute/adapt.go
rename to internal/pkg/adapter/google/compute/adapt.go
index 0890ebf3e..efb0a1071 100644
--- a/internal/app/tfsec/adapter/google/compute/adapt.go
+++ b/internal/pkg/adapter/google/compute/adapt.go
@@ -2,7 +2,7 @@ package compute
 
 import (
 	"github.com/aquasecurity/defsec/provider/google/compute"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) compute.Compute {
diff --git a/internal/app/tfsec/adapter/google/compute/disks.go b/internal/pkg/adapter/google/compute/disks.go
similarity index 93%
rename from internal/app/tfsec/adapter/google/compute/disks.go
rename to internal/pkg/adapter/google/compute/disks.go
index 958d60209..96438a188 100644
--- a/internal/app/tfsec/adapter/google/compute/disks.go
+++ b/internal/pkg/adapter/google/compute/disks.go
@@ -3,7 +3,7 @@ package compute
 import (
 	"github.com/aquasecurity/defsec/provider/google/compute"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptDisks(modules block.Modules) (disks []compute.Disk) {
diff --git a/internal/app/tfsec/adapter/google/compute/instances.go b/internal/pkg/adapter/google/compute/instances.go
similarity index 98%
rename from internal/app/tfsec/adapter/google/compute/instances.go
rename to internal/pkg/adapter/google/compute/instances.go
index c4bb1b2d5..c33fd82dd 100644
--- a/internal/app/tfsec/adapter/google/compute/instances.go
+++ b/internal/pkg/adapter/google/compute/instances.go
@@ -3,7 +3,7 @@ package compute
 import (
 	"github.com/aquasecurity/defsec/provider/google/compute"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/zclconf/go-cty/cty"
 )
 
diff --git a/internal/app/tfsec/adapter/google/compute/metadata.go b/internal/pkg/adapter/google/compute/metadata.go
similarity index 92%
rename from internal/app/tfsec/adapter/google/compute/metadata.go
rename to internal/pkg/adapter/google/compute/metadata.go
index d1bdc3530..97f3d40c0 100644
--- a/internal/app/tfsec/adapter/google/compute/metadata.go
+++ b/internal/pkg/adapter/google/compute/metadata.go
@@ -3,7 +3,7 @@ package compute
 import (
 	"github.com/aquasecurity/defsec/provider/google/compute"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/zclconf/go-cty/cty"
 )
 
diff --git a/internal/app/tfsec/adapter/google/compute/networks.go b/internal/pkg/adapter/google/compute/networks.go
similarity index 98%
rename from internal/app/tfsec/adapter/google/compute/networks.go
rename to internal/pkg/adapter/google/compute/networks.go
index 7683c589a..44bc79443 100644
--- a/internal/app/tfsec/adapter/google/compute/networks.go
+++ b/internal/pkg/adapter/google/compute/networks.go
@@ -6,7 +6,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/google/compute"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptNetworks(modules block.Modules) (networks []compute.Network) {
diff --git a/internal/app/tfsec/adapter/google/compute/ssl.go b/internal/pkg/adapter/google/compute/ssl.go
similarity index 92%
rename from internal/app/tfsec/adapter/google/compute/ssl.go
rename to internal/pkg/adapter/google/compute/ssl.go
index 9b609f00d..83649686c 100644
--- a/internal/app/tfsec/adapter/google/compute/ssl.go
+++ b/internal/pkg/adapter/google/compute/ssl.go
@@ -2,7 +2,7 @@ package compute
 
 import (
 	"github.com/aquasecurity/defsec/provider/google/compute"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func adaptSSLPolicies(modules block.Modules) (policies []compute.SSLPolicy) {
diff --git a/internal/app/tfsec/adapter/google/dns/adapt.go b/internal/pkg/adapter/google/dns/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/google/dns/adapt.go
rename to internal/pkg/adapter/google/dns/adapt.go
index b0a7904f2..b971c2c18 100644
--- a/internal/app/tfsec/adapter/google/dns/adapt.go
+++ b/internal/pkg/adapter/google/dns/adapt.go
@@ -3,7 +3,7 @@ package dns
 import (
 	"github.com/aquasecurity/defsec/provider/google/dns"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) dns.DNS {
diff --git a/internal/app/tfsec/adapter/google/gke/adapt.go b/internal/pkg/adapter/google/gke/adapt.go
similarity index 99%
rename from internal/app/tfsec/adapter/google/gke/adapt.go
rename to internal/pkg/adapter/google/gke/adapt.go
index 7f3f7571e..564e69b08 100644
--- a/internal/app/tfsec/adapter/google/gke/adapt.go
+++ b/internal/pkg/adapter/google/gke/adapt.go
@@ -3,7 +3,7 @@ package gke
 import (
 	"github.com/aquasecurity/defsec/provider/google/gke"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/google/uuid"
 	"github.com/zclconf/go-cty/cty"
 )
diff --git a/internal/app/tfsec/adapter/google/iam/adapt.go b/internal/pkg/adapter/google/iam/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/google/iam/adapt.go
rename to internal/pkg/adapter/google/iam/adapt.go
index 3602cd21a..76d605333 100644
--- a/internal/app/tfsec/adapter/google/iam/adapt.go
+++ b/internal/pkg/adapter/google/iam/adapt.go
@@ -2,7 +2,7 @@ package iam
 
 import (
 	"github.com/aquasecurity/defsec/provider/google/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/google/uuid"
 )
 
diff --git a/internal/app/tfsec/adapter/google/iam/convert.go b/internal/pkg/adapter/google/iam/convert.go
similarity index 91%
rename from internal/app/tfsec/adapter/google/iam/convert.go
rename to internal/pkg/adapter/google/iam/convert.go
index 28f5138ea..f2e967a23 100644
--- a/internal/app/tfsec/adapter/google/iam/convert.go
+++ b/internal/pkg/adapter/google/iam/convert.go
@@ -3,7 +3,7 @@ package iam
 import (
 	"github.com/aquasecurity/defsec/provider/google/iam"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func ParsePolicyBlock(block *block.Block) []iam.Binding {
diff --git a/internal/app/tfsec/adapter/google/iam/folder_iam.go b/internal/pkg/adapter/google/iam/folder_iam.go
similarity index 100%
rename from internal/app/tfsec/adapter/google/iam/folder_iam.go
rename to internal/pkg/adapter/google/iam/folder_iam.go
diff --git a/internal/app/tfsec/adapter/google/iam/folders.go b/internal/pkg/adapter/google/iam/folders.go
similarity index 100%
rename from internal/app/tfsec/adapter/google/iam/folders.go
rename to internal/pkg/adapter/google/iam/folders.go
diff --git a/internal/app/tfsec/adapter/google/iam/org_iam.go b/internal/pkg/adapter/google/iam/org_iam.go
similarity index 100%
rename from internal/app/tfsec/adapter/google/iam/org_iam.go
rename to internal/pkg/adapter/google/iam/org_iam.go
diff --git a/internal/app/tfsec/adapter/google/iam/project_iam.go b/internal/pkg/adapter/google/iam/project_iam.go
similarity index 99%
rename from internal/app/tfsec/adapter/google/iam/project_iam.go
rename to internal/pkg/adapter/google/iam/project_iam.go
index 5424dcd5d..c1b52c579 100644
--- a/internal/app/tfsec/adapter/google/iam/project_iam.go
+++ b/internal/pkg/adapter/google/iam/project_iam.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/google/iam"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 // see https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_iam
diff --git a/internal/app/tfsec/adapter/google/iam/projects.go b/internal/pkg/adapter/google/iam/projects.go
similarity index 100%
rename from internal/app/tfsec/adapter/google/iam/projects.go
rename to internal/pkg/adapter/google/iam/projects.go
diff --git a/internal/app/tfsec/adapter/google/kms/adapt.go b/internal/pkg/adapter/google/kms/adapt.go
similarity index 95%
rename from internal/app/tfsec/adapter/google/kms/adapt.go
rename to internal/pkg/adapter/google/kms/adapt.go
index 23db63333..3054f6cdb 100644
--- a/internal/app/tfsec/adapter/google/kms/adapt.go
+++ b/internal/pkg/adapter/google/kms/adapt.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/google/kms"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) kms.KMS {
diff --git a/internal/app/tfsec/adapter/google/sql/adapt.go b/internal/pkg/adapter/google/sql/adapt.go
similarity index 99%
rename from internal/app/tfsec/adapter/google/sql/adapt.go
rename to internal/pkg/adapter/google/sql/adapt.go
index 5e67d5e48..380727a3b 100644
--- a/internal/app/tfsec/adapter/google/sql/adapt.go
+++ b/internal/pkg/adapter/google/sql/adapt.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/aquasecurity/defsec/provider/google/sql"
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) sql.SQL {
diff --git a/internal/app/tfsec/adapter/google/storage/adapt.go b/internal/pkg/adapter/google/storage/adapt.go
similarity index 98%
rename from internal/app/tfsec/adapter/google/storage/adapt.go
rename to internal/pkg/adapter/google/storage/adapt.go
index d680fcc7c..609b79f83 100644
--- a/internal/app/tfsec/adapter/google/storage/adapt.go
+++ b/internal/pkg/adapter/google/storage/adapt.go
@@ -2,7 +2,7 @@ package storage
 
 import (
 	"github.com/aquasecurity/defsec/provider/google/storage"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) storage.Storage {
diff --git a/internal/app/tfsec/adapter/google/storage/iam.go b/internal/pkg/adapter/google/storage/iam.go
similarity index 97%
rename from internal/app/tfsec/adapter/google/storage/iam.go
rename to internal/pkg/adapter/google/storage/iam.go
index 77b7679a3..66947d296 100644
--- a/internal/app/tfsec/adapter/google/storage/iam.go
+++ b/internal/pkg/adapter/google/storage/iam.go
@@ -2,7 +2,7 @@ package storage
 
 import (
 	iamTypes "github.com/aquasecurity/defsec/provider/google/iam"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/google/iam"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/google/iam"
 )
 
 type parentedBinding struct {
diff --git a/internal/app/tfsec/adapter/kubernetes/adapt.go b/internal/pkg/adapter/kubernetes/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/kubernetes/adapt.go
rename to internal/pkg/adapter/kubernetes/adapt.go
index a4df0fee1..ed547671c 100644
--- a/internal/app/tfsec/adapter/kubernetes/adapt.go
+++ b/internal/pkg/adapter/kubernetes/adapt.go
@@ -2,7 +2,7 @@ package kubernetes
 
 import (
 	"github.com/aquasecurity/defsec/provider/kubernetes"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) kubernetes.Kubernetes {
diff --git a/internal/app/tfsec/adapter/openstack/adapt.go b/internal/pkg/adapter/openstack/adapt.go
similarity index 97%
rename from internal/app/tfsec/adapter/openstack/adapt.go
rename to internal/pkg/adapter/openstack/adapt.go
index e58da2497..4ae17c437 100644
--- a/internal/app/tfsec/adapter/openstack/adapt.go
+++ b/internal/pkg/adapter/openstack/adapt.go
@@ -2,7 +2,7 @@ package openstack
 
 import (
 	"github.com/aquasecurity/defsec/provider/openstack"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) openstack.OpenStack {
diff --git a/internal/app/tfsec/adapter/oracle/adapt.go b/internal/pkg/adapter/oracle/adapt.go
similarity index 92%
rename from internal/app/tfsec/adapter/oracle/adapt.go
rename to internal/pkg/adapter/oracle/adapt.go
index 663fe7c87..4cbd2bfd6 100644
--- a/internal/app/tfsec/adapter/oracle/adapt.go
+++ b/internal/pkg/adapter/oracle/adapt.go
@@ -2,7 +2,7 @@ package oracle
 
 import (
 	"github.com/aquasecurity/defsec/provider/oracle"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func Adapt(modules block.Modules) oracle.Oracle {
diff --git a/internal/app/tfsec/block/attribute.go b/internal/pkg/block/attribute.go
similarity index 99%
rename from internal/app/tfsec/block/attribute.go
rename to internal/pkg/block/attribute.go
index de78fe72c..5a6fd9d13 100644
--- a/internal/app/tfsec/block/attribute.go
+++ b/internal/pkg/block/attribute.go
@@ -6,7 +6,7 @@ import (
 	"strings"
 
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
 	"github.com/hashicorp/hcl/v2"
 	"github.com/hashicorp/hcl/v2/hclsyntax"
 	"github.com/zclconf/go-cty/cty"
diff --git a/internal/app/tfsec/block/block.go b/internal/pkg/block/block.go
similarity index 98%
rename from internal/app/tfsec/block/block.go
rename to internal/pkg/block/block.go
index fe4e94326..2feaf155e 100644
--- a/internal/app/tfsec/block/block.go
+++ b/internal/pkg/block/block.go
@@ -5,8 +5,8 @@ import (
 	"strings"
 
 	"github.com/aquasecurity/defsec/types"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/schema"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/schema"
 	"github.com/google/uuid"
 	"github.com/hashicorp/hcl/v2"
 	"github.com/hashicorp/hcl/v2/hclsyntax"
diff --git a/internal/app/tfsec/block/blocks.go b/internal/pkg/block/blocks.go
similarity index 100%
rename from internal/app/tfsec/block/blocks.go
rename to internal/pkg/block/blocks.go
diff --git a/internal/app/tfsec/block/context.go b/internal/pkg/block/context.go
similarity index 100%
rename from internal/app/tfsec/block/context.go
rename to internal/pkg/block/context.go
diff --git a/internal/app/tfsec/block/context_test.go b/internal/pkg/block/context_test.go
similarity index 100%
rename from internal/app/tfsec/block/context_test.go
rename to internal/pkg/block/context_test.go
diff --git a/internal/app/tfsec/block/ignore.go b/internal/pkg/block/ignore.go
similarity index 100%
rename from internal/app/tfsec/block/ignore.go
rename to internal/pkg/block/ignore.go
diff --git a/internal/app/tfsec/block/module.go b/internal/pkg/block/module.go
similarity index 100%
rename from internal/app/tfsec/block/module.go
rename to internal/pkg/block/module.go
diff --git a/internal/app/tfsec/block/modules.go b/internal/pkg/block/modules.go
similarity index 100%
rename from internal/app/tfsec/block/modules.go
rename to internal/pkg/block/modules.go
diff --git a/internal/app/tfsec/block/range.go b/internal/pkg/block/range.go
similarity index 100%
rename from internal/app/tfsec/block/range.go
rename to internal/pkg/block/range.go
diff --git a/internal/app/tfsec/block/reference.go b/internal/pkg/block/reference.go
similarity index 100%
rename from internal/app/tfsec/block/reference.go
rename to internal/pkg/block/reference.go
diff --git a/internal/app/tfsec/block/reference_test.go b/internal/pkg/block/reference_test.go
similarity index 100%
rename from internal/app/tfsec/block/reference_test.go
rename to internal/pkg/block/reference_test.go
diff --git a/internal/app/tfsec/block/type.go b/internal/pkg/block/type.go
similarity index 100%
rename from internal/app/tfsec/block/type.go
rename to internal/pkg/block/type.go
diff --git a/internal/app/tfsec/block/value_functions.go b/internal/pkg/block/value_functions.go
similarity index 97%
rename from internal/app/tfsec/block/value_functions.go
rename to internal/pkg/block/value_functions.go
index 4a8edb777..0b8282ed1 100644
--- a/internal/app/tfsec/block/value_functions.go
+++ b/internal/pkg/block/value_functions.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"regexp"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
 	"github.com/zclconf/go-cty/cty"
 	"github.com/zclconf/go-cty/cty/gocty"
 )
diff --git a/internal/app/tfsec/cidr/cidr.go b/internal/pkg/cidr/cidr.go
similarity index 91%
rename from internal/app/tfsec/cidr/cidr.go
rename to internal/pkg/cidr/cidr.go
index 67f8051f7..d7c74f776 100644
--- a/internal/app/tfsec/cidr/cidr.go
+++ b/internal/pkg/cidr/cidr.go
@@ -3,7 +3,7 @@ package cidr
 import (
 	"strings"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/zclconf/go-cty/cty"
 )
 
diff --git a/internal/app/tfsec/custom/check_all_statements_test.go b/internal/pkg/custom/check_all_statements_test.go
similarity index 100%
rename from internal/app/tfsec/custom/check_all_statements_test.go
rename to internal/pkg/custom/check_all_statements_test.go
diff --git a/internal/app/tfsec/custom/complex_checks.go b/internal/pkg/custom/complex_checks.go
similarity index 94%
rename from internal/app/tfsec/custom/complex_checks.go
rename to internal/pkg/custom/complex_checks.go
index 68c826e5d..05cfdb60a 100644
--- a/internal/app/tfsec/custom/complex_checks.go
+++ b/internal/pkg/custom/complex_checks.go
@@ -3,7 +3,7 @@ package custom
 import (
 	"fmt"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 func checkTags(block *block.Block, spec *MatchSpec, module *block.Module) bool {
diff --git a/internal/app/tfsec/custom/custom_check.go b/internal/pkg/custom/custom_check.go
similarity index 100%
rename from internal/app/tfsec/custom/custom_check.go
rename to internal/pkg/custom/custom_check.go
diff --git a/internal/app/tfsec/custom/custom_context.go b/internal/pkg/custom/custom_context.go
similarity index 90%
rename from internal/app/tfsec/custom/custom_context.go
rename to internal/pkg/custom/custom_context.go
index e7fd19028..f28cd2f84 100644
--- a/internal/app/tfsec/custom/custom_context.go
+++ b/internal/pkg/custom/custom_context.go
@@ -1,6 +1,6 @@
 package custom
 
-import "github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+import "github.com/aquasecurity/tfsec/internal/pkg/block"
 
 type customCheckVariables map[string]string
 
diff --git a/internal/app/tfsec/custom/loader.go b/internal/pkg/custom/loader.go
similarity index 100%
rename from internal/app/tfsec/custom/loader.go
rename to internal/pkg/custom/loader.go
diff --git a/internal/app/tfsec/custom/multiple_submatches_test.go b/internal/pkg/custom/multiple_submatches_test.go
similarity index 100%
rename from internal/app/tfsec/custom/multiple_submatches_test.go
rename to internal/pkg/custom/multiple_submatches_test.go
diff --git a/internal/app/tfsec/custom/processing.go b/internal/pkg/custom/processing.go
similarity index 98%
rename from internal/app/tfsec/custom/processing.go
rename to internal/pkg/custom/processing.go
index 791d95df4..58a5e6c2e 100644
--- a/internal/app/tfsec/custom/processing.go
+++ b/internal/pkg/custom/processing.go
@@ -6,9 +6,9 @@ import (
 
 	"github.com/aquasecurity/defsec/provider"
 	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
 
diff --git a/internal/app/tfsec/custom/validate.go b/internal/pkg/custom/validate.go
similarity index 100%
rename from internal/app/tfsec/custom/validate.go
rename to internal/pkg/custom/validate.go
diff --git a/internal/app/tfsec/debug/debug.go b/internal/pkg/debug/debug.go
similarity index 100%
rename from internal/app/tfsec/debug/debug.go
rename to internal/pkg/debug/debug.go
diff --git a/internal/app/tfsec/funcs/cidr.go b/internal/pkg/funcs/cidr.go
similarity index 100%
rename from internal/app/tfsec/funcs/cidr.go
rename to internal/pkg/funcs/cidr.go
diff --git a/internal/app/tfsec/funcs/cidr_test.go b/internal/pkg/funcs/cidr_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/cidr_test.go
rename to internal/pkg/funcs/cidr_test.go
diff --git a/internal/app/tfsec/funcs/collection.go b/internal/pkg/funcs/collection.go
similarity index 100%
rename from internal/app/tfsec/funcs/collection.go
rename to internal/pkg/funcs/collection.go
diff --git a/internal/app/tfsec/funcs/collection_test.go b/internal/pkg/funcs/collection_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/collection_test.go
rename to internal/pkg/funcs/collection_test.go
diff --git a/internal/app/tfsec/funcs/conversion.go b/internal/pkg/funcs/conversion.go
similarity index 100%
rename from internal/app/tfsec/funcs/conversion.go
rename to internal/pkg/funcs/conversion.go
diff --git a/internal/app/tfsec/funcs/conversion_test.go b/internal/pkg/funcs/conversion_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/conversion_test.go
rename to internal/pkg/funcs/conversion_test.go
diff --git a/internal/app/tfsec/funcs/crypto.go b/internal/pkg/funcs/crypto.go
similarity index 100%
rename from internal/app/tfsec/funcs/crypto.go
rename to internal/pkg/funcs/crypto.go
diff --git a/internal/app/tfsec/funcs/crypto_test.go b/internal/pkg/funcs/crypto_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/crypto_test.go
rename to internal/pkg/funcs/crypto_test.go
diff --git a/internal/app/tfsec/funcs/datetime.go b/internal/pkg/funcs/datetime.go
similarity index 100%
rename from internal/app/tfsec/funcs/datetime.go
rename to internal/pkg/funcs/datetime.go
diff --git a/internal/app/tfsec/funcs/datetime_test.go b/internal/pkg/funcs/datetime_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/datetime_test.go
rename to internal/pkg/funcs/datetime_test.go
diff --git a/internal/app/tfsec/funcs/defaults.go b/internal/pkg/funcs/defaults.go
similarity index 100%
rename from internal/app/tfsec/funcs/defaults.go
rename to internal/pkg/funcs/defaults.go
diff --git a/internal/app/tfsec/funcs/encoding.go b/internal/pkg/funcs/encoding.go
similarity index 100%
rename from internal/app/tfsec/funcs/encoding.go
rename to internal/pkg/funcs/encoding.go
diff --git a/internal/app/tfsec/funcs/encoding_test.go b/internal/pkg/funcs/encoding_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/encoding_test.go
rename to internal/pkg/funcs/encoding_test.go
diff --git a/internal/app/tfsec/funcs/filesystem.go b/internal/pkg/funcs/filesystem.go
similarity index 100%
rename from internal/app/tfsec/funcs/filesystem.go
rename to internal/pkg/funcs/filesystem.go
diff --git a/internal/app/tfsec/funcs/filesystem_test.go b/internal/pkg/funcs/filesystem_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/filesystem_test.go
rename to internal/pkg/funcs/filesystem_test.go
diff --git a/internal/app/tfsec/funcs/marks.go b/internal/pkg/funcs/marks.go
similarity index 100%
rename from internal/app/tfsec/funcs/marks.go
rename to internal/pkg/funcs/marks.go
diff --git a/internal/app/tfsec/funcs/number.go b/internal/pkg/funcs/number.go
similarity index 100%
rename from internal/app/tfsec/funcs/number.go
rename to internal/pkg/funcs/number.go
diff --git a/internal/app/tfsec/funcs/number_test.go b/internal/pkg/funcs/number_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/number_test.go
rename to internal/pkg/funcs/number_test.go
diff --git a/internal/app/tfsec/funcs/sensitive.go b/internal/pkg/funcs/sensitive.go
similarity index 100%
rename from internal/app/tfsec/funcs/sensitive.go
rename to internal/pkg/funcs/sensitive.go
diff --git a/internal/app/tfsec/funcs/sensitive_test.go b/internal/pkg/funcs/sensitive_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/sensitive_test.go
rename to internal/pkg/funcs/sensitive_test.go
diff --git a/internal/app/tfsec/funcs/string.go b/internal/pkg/funcs/string.go
similarity index 100%
rename from internal/app/tfsec/funcs/string.go
rename to internal/pkg/funcs/string.go
diff --git a/internal/app/tfsec/funcs/string_test.go b/internal/pkg/funcs/string_test.go
similarity index 100%
rename from internal/app/tfsec/funcs/string_test.go
rename to internal/pkg/funcs/string_test.go
diff --git a/internal/app/tfsec/funcs/testdata/bare.tmpl b/internal/pkg/funcs/testdata/bare.tmpl
similarity index 100%
rename from internal/app/tfsec/funcs/testdata/bare.tmpl
rename to internal/pkg/funcs/testdata/bare.tmpl
diff --git a/internal/app/tfsec/funcs/testdata/func.tmpl b/internal/pkg/funcs/testdata/func.tmpl
similarity index 100%
rename from internal/app/tfsec/funcs/testdata/func.tmpl
rename to internal/pkg/funcs/testdata/func.tmpl
diff --git a/internal/app/tfsec/funcs/testdata/hello.tmpl b/internal/pkg/funcs/testdata/hello.tmpl
similarity index 100%
rename from internal/app/tfsec/funcs/testdata/hello.tmpl
rename to internal/pkg/funcs/testdata/hello.tmpl
diff --git a/internal/app/tfsec/funcs/testdata/hello.txt b/internal/pkg/funcs/testdata/hello.txt
similarity index 100%
rename from internal/app/tfsec/funcs/testdata/hello.txt
rename to internal/pkg/funcs/testdata/hello.txt
diff --git a/internal/app/tfsec/funcs/testdata/icon.png b/internal/pkg/funcs/testdata/icon.png
similarity index 100%
rename from internal/app/tfsec/funcs/testdata/icon.png
rename to internal/pkg/funcs/testdata/icon.png
diff --git a/internal/app/tfsec/funcs/testdata/list.tmpl b/internal/pkg/funcs/testdata/list.tmpl
similarity index 100%
rename from internal/app/tfsec/funcs/testdata/list.tmpl
rename to internal/pkg/funcs/testdata/list.tmpl
diff --git a/internal/app/tfsec/funcs/testdata/recursive.tmpl b/internal/pkg/funcs/testdata/recursive.tmpl
similarity index 100%
rename from internal/app/tfsec/funcs/testdata/recursive.tmpl
rename to internal/pkg/funcs/testdata/recursive.tmpl
diff --git a/internal/app/tfsec/ignores/migration.go b/internal/pkg/ignores/migration.go
similarity index 94%
rename from internal/app/tfsec/ignores/migration.go
rename to internal/pkg/ignores/migration.go
index 157e8a217..e706217bf 100644
--- a/internal/app/tfsec/ignores/migration.go
+++ b/internal/pkg/ignores/migration.go
@@ -7,8 +7,8 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/legacy"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/legacy"
 )
 
 type migrationStatistic struct {
diff --git a/internal/app/tfsec/legacy/map.go b/internal/pkg/legacy/map.go
similarity index 100%
rename from internal/app/tfsec/legacy/map.go
rename to internal/pkg/legacy/map.go
diff --git a/internal/app/tfsec/parser/evaluator.go b/internal/pkg/parser/evaluator.go
similarity index 99%
rename from internal/app/tfsec/parser/evaluator.go
rename to internal/pkg/parser/evaluator.go
index 05829a0e3..664188f1f 100644
--- a/internal/app/tfsec/parser/evaluator.go
+++ b/internal/pkg/parser/evaluator.go
@@ -5,8 +5,8 @@ import (
 	"reflect"
 
 	"github.com/aquasecurity/defsec/metrics"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
 	"github.com/hashicorp/hcl/v2"
 	"github.com/zclconf/go-cty/cty"
 	"github.com/zclconf/go-cty/cty/gocty"
diff --git a/internal/app/tfsec/parser/functions.go b/internal/pkg/parser/functions.go
similarity index 98%
rename from internal/app/tfsec/parser/functions.go
rename to internal/pkg/parser/functions.go
index ed58ca528..1cf3324d6 100644
--- a/internal/app/tfsec/parser/functions.go
+++ b/internal/pkg/parser/functions.go
@@ -1,7 +1,7 @@
 package parser
 
 import (
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/funcs"
+	"github.com/aquasecurity/tfsec/internal/pkg/funcs"
 	"github.com/hashicorp/hcl/v2/ext/tryfunc"
 	ctyyaml "github.com/zclconf/go-cty-yaml"
 	"github.com/zclconf/go-cty/cty"
diff --git a/internal/app/tfsec/parser/load_blocks.go b/internal/pkg/parser/load_blocks.go
similarity index 95%
rename from internal/app/tfsec/parser/load_blocks.go
rename to internal/pkg/parser/load_blocks.go
index 230b60cf5..7452b5b5f 100644
--- a/internal/app/tfsec/parser/load_blocks.go
+++ b/internal/pkg/parser/load_blocks.go
@@ -6,8 +6,8 @@ import (
 	"time"
 
 	"github.com/aquasecurity/defsec/metrics"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/schema"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/schema"
 	"github.com/hashicorp/hcl/v2"
 )
 
diff --git a/internal/app/tfsec/parser/load_dir.go b/internal/pkg/parser/load_dir.go
similarity index 100%
rename from internal/app/tfsec/parser/load_dir.go
rename to internal/pkg/parser/load_dir.go
diff --git a/internal/app/tfsec/parser/load_module.go b/internal/pkg/parser/load_module.go
similarity index 97%
rename from internal/app/tfsec/parser/load_module.go
rename to internal/pkg/parser/load_module.go
index 4189d70a8..286c985fe 100644
--- a/internal/app/tfsec/parser/load_module.go
+++ b/internal/pkg/parser/load_module.go
@@ -9,8 +9,8 @@ import (
 	"strings"
 
 	"github.com/aquasecurity/defsec/metrics"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
 	"github.com/hashicorp/hcl/v2"
 	"github.com/zclconf/go-cty/cty"
 )
diff --git a/internal/app/tfsec/parser/load_module_metadata.go b/internal/pkg/parser/load_module_metadata.go
similarity index 100%
rename from internal/app/tfsec/parser/load_module_metadata.go
rename to internal/pkg/parser/load_module_metadata.go
diff --git a/internal/app/tfsec/parser/load_vars.go b/internal/pkg/parser/load_vars.go
similarity index 95%
rename from internal/app/tfsec/parser/load_vars.go
rename to internal/pkg/parser/load_vars.go
index 083f4e65c..43b0c787d 100644
--- a/internal/app/tfsec/parser/load_vars.go
+++ b/internal/pkg/parser/load_vars.go
@@ -5,7 +5,7 @@ import (
 	"io/ioutil"
 
 	"github.com/aquasecurity/defsec/metrics"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
 	"github.com/hashicorp/hcl/v2"
 	"github.com/hashicorp/hcl/v2/hclsyntax"
 	"github.com/zclconf/go-cty/cty"
diff --git a/internal/app/tfsec/parser/option.go b/internal/pkg/parser/option.go
similarity index 100%
rename from internal/app/tfsec/parser/option.go
rename to internal/pkg/parser/option.go
diff --git a/internal/app/tfsec/parser/parser.go b/internal/pkg/parser/parser.go
similarity index 97%
rename from internal/app/tfsec/parser/parser.go
rename to internal/pkg/parser/parser.go
index 92041c60b..eb5ffa6d4 100644
--- a/internal/app/tfsec/parser/parser.go
+++ b/internal/pkg/parser/parser.go
@@ -9,8 +9,8 @@ import (
 	"strings"
 
 	"github.com/aquasecurity/defsec/metrics"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
 )
 
 // Parser is a tool for parsing terraform templates at a given file system location
diff --git a/internal/app/tfsec/parser/tfvars.go b/internal/pkg/parser/tfvars.go
similarity index 100%
rename from internal/app/tfsec/parser/tfvars.go
rename to internal/pkg/parser/tfvars.go
diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule.go b/internal/pkg/rules/general/secrets/sensitive_in_attribute_rule.go
similarity index 90%
rename from internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule.go
rename to internal/pkg/rules/general/secrets/sensitive_in_attribute_rule.go
index 3b7daa8ff..152597ffe 100644
--- a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule.go
+++ b/internal/pkg/rules/general/secrets/sensitive_in_attribute_rule.go
@@ -5,13 +5,13 @@ import (
 	"github.com/aquasecurity/defsec/rules/general/secrets"
 	"github.com/zclconf/go-cty/cty"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 
 	"github.com/aquasecurity/tfsec/pkg/rule"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/security"
+	"github.com/aquasecurity/tfsec/internal/pkg/security"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 )
 
 var sensitiveWhitelist = []struct {
diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule.go b/internal/pkg/rules/general/secrets/sensitive_in_attribute_value_rule.go
similarity index 82%
rename from internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule.go
rename to internal/pkg/rules/general/secrets/sensitive_in_attribute_value_rule.go
index 415d1d5e1..57799254d 100644
--- a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule.go
+++ b/internal/pkg/rules/general/secrets/sensitive_in_attribute_value_rule.go
@@ -3,9 +3,9 @@ package secrets
 import (
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/general/secrets"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/security"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/security"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
 
diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule.go b/internal/pkg/rules/general/secrets/sensitive_in_local_rule.go
similarity index 82%
rename from internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule.go
rename to internal/pkg/rules/general/secrets/sensitive_in_local_rule.go
index 670b25ca3..c062e55e9 100644
--- a/internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule.go
+++ b/internal/pkg/rules/general/secrets/sensitive_in_local_rule.go
@@ -5,9 +5,9 @@ import (
 	"github.com/zclconf/go-cty/cty"
 
 	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/security"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/security"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
 
diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule.go b/internal/pkg/rules/general/secrets/sensitive_in_variable_rule.go
similarity index 83%
rename from internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule.go
rename to internal/pkg/rules/general/secrets/sensitive_in_variable_rule.go
index 39538eed0..cbdc60033 100644
--- a/internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule.go
+++ b/internal/pkg/rules/general/secrets/sensitive_in_variable_rule.go
@@ -5,13 +5,13 @@ import (
 
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/general/secrets"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 
 	"github.com/aquasecurity/tfsec/pkg/rule"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/security"
+	"github.com/aquasecurity/tfsec/internal/pkg/security"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 )
 
 func init() {
diff --git a/internal/pkg/rules/init.go b/internal/pkg/rules/init.go
new file mode 100644
index 000000000..5e187b25e
--- /dev/null
+++ b/internal/pkg/rules/init.go
@@ -0,0 +1,5 @@
+package rules
+
+import (
+	_ "github.com/aquasecurity/tfsec/internal/pkg/rules/general/secrets"
+)
diff --git a/internal/app/tfsec/scanner/option.go b/internal/pkg/scanner/option.go
similarity index 100%
rename from internal/app/tfsec/scanner/option.go
rename to internal/pkg/scanner/option.go
diff --git a/internal/app/tfsec/scanner/pool.go b/internal/pkg/scanner/pool.go
similarity index 98%
rename from internal/app/tfsec/scanner/pool.go
rename to internal/pkg/scanner/pool.go
index aa4be68f1..2e95df2e3 100644
--- a/internal/app/tfsec/scanner/pool.go
+++ b/internal/pkg/scanner/pool.go
@@ -7,7 +7,7 @@ import (
 
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/state"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
 
diff --git a/internal/app/tfsec/scanner/registration.go b/internal/pkg/scanner/registration.go
similarity index 96%
rename from internal/app/tfsec/scanner/registration.go
rename to internal/pkg/scanner/registration.go
index 30929ecc2..3a035131c 100644
--- a/internal/app/tfsec/scanner/registration.go
+++ b/internal/pkg/scanner/registration.go
@@ -7,7 +7,7 @@ import (
 
 	_ "github.com/aquasecurity/defsec/loader"
 	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/legacy"
+	"github.com/aquasecurity/tfsec/internal/pkg/legacy"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
 
diff --git a/internal/app/tfsec/scanner/scanner.go b/internal/pkg/scanner/scanner.go
similarity index 93%
rename from internal/app/tfsec/scanner/scanner.go
rename to internal/pkg/scanner/scanner.go
index 87ed55b72..5317ed8fe 100644
--- a/internal/app/tfsec/scanner/scanner.go
+++ b/internal/pkg/scanner/scanner.go
@@ -6,10 +6,10 @@ import (
 
 	"github.com/aquasecurity/defsec/metrics"
 	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/legacy"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/legacy"
 )
 
 // Scanner scans HCL blocks by running all registered rules against them
diff --git a/internal/app/tfsec/updater/updater.go b/internal/pkg/updater/updater.go
similarity index 97%
rename from internal/app/tfsec/updater/updater.go
rename to internal/pkg/updater/updater.go
index 4c0f8677b..4666dbcaf 100644
--- a/internal/app/tfsec/updater/updater.go
+++ b/internal/pkg/updater/updater.go
@@ -6,7 +6,7 @@ import (
 	"net/http"
 	"runtime"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
 	"github.com/aquasecurity/tfsec/version"
 	semver "github.com/hashicorp/go-version"
 	"github.com/inconshreveable/go-update"
diff --git a/pkg/externalscan/external_scan.go b/pkg/externalscan/external_scan.go
index e9bb624f5..20a8a87f0 100644
--- a/pkg/externalscan/external_scan.go
+++ b/pkg/externalscan/external_scan.go
@@ -8,11 +8,11 @@ import (
 	"strings"
 
 	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/custom"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
-	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/custom"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
+	_ "github.com/aquasecurity/tfsec/internal/pkg/rules"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 )
 
 type ExternalScanner struct {
diff --git a/pkg/externalscan/options.go b/pkg/externalscan/options.go
index 2e9f86f75..d7d4b3b19 100644
--- a/pkg/externalscan/options.go
+++ b/pkg/externalscan/options.go
@@ -1,8 +1,8 @@
 package externalscan
 
 import (
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 )
 
 type Option func(e *ExternalScanner)
@@ -14,7 +14,7 @@ func OptionIncludePassed() Option {
 }
 
 func OptionDebugEnabled(debugEnabled bool) Option {
-	return func(e *ExternalScanner) {
+	return func(_ *ExternalScanner) {
 		debug.Enabled = debugEnabled
 	}
 }
diff --git a/pkg/rule/check.go b/pkg/rule/check.go
index 5d6c96332..4d80fc3d5 100644
--- a/pkg/rule/check.go
+++ b/pkg/rule/check.go
@@ -9,8 +9,8 @@ import (
 
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/state"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
 )
 
 func (r *Rule) CheckAgainstState(s *state.State) rules.Results {
diff --git a/pkg/rule/rule.go b/pkg/rule/rule.go
index cc764f752..7393646ff 100644
--- a/pkg/rule/rule.go
+++ b/pkg/rule/rule.go
@@ -2,7 +2,7 @@ package rule
 
 import (
 	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 )
 
 // Rule is a targeted security test which can be applied to terraform templates. It includes the types to run on e.g.
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/checkstyle.go b/vendor/github.com/aquasecurity/defsec/formatters/checkstyle.go
index efd7ecb5a..c039c2a35 100644
--- a/vendor/github.com/aquasecurity/defsec/formatters/checkstyle.go
+++ b/vendor/github.com/aquasecurity/defsec/formatters/checkstyle.go
@@ -2,7 +2,6 @@ package formatters
 
 import (
 	"encoding/xml"
-	"io"
 
 	"github.com/aquasecurity/defsec/rules"
 )
@@ -26,7 +25,7 @@ type checkstyleOutput struct {
 	Files   []checkstyleFile `xml:"file"`
 }
 
-func FormatCheckStyle(w io.Writer, results []rules.Result, _ string, _ ...FormatterOption) error {
+func outputCheckStyle(b configurableFormatter, results []rules.Result) error {
 
 	output := checkstyleOutput{}
 
@@ -37,8 +36,9 @@ func FormatCheckStyle(w io.Writer, results []rules.Result, _ string, _ ...Format
 			continue
 		}
 		var link string
-		if len(res.Rule().Links) > 0 {
-			link = res.Rule().Links[0]
+		links := b.GetLinks(res)
+		if len(links) > 0 {
+			link = links[0]
 		}
 
 		rng := res.CodeBlockMetadata().Range()
@@ -69,11 +69,11 @@ func FormatCheckStyle(w io.Writer, results []rules.Result, _ string, _ ...Format
 		)
 	}
 
-	if _, err := w.Write([]byte(xml.Header)); err != nil {
+	if _, err := b.Writer().Write([]byte(xml.Header)); err != nil {
 		return err
 	}
 
-	xmlEncoder := xml.NewEncoder(w)
+	xmlEncoder := xml.NewEncoder(b.Writer())
 	xmlEncoder.Indent("", "\t")
 
 	return xmlEncoder.Encode(output)
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/csv.go b/vendor/github.com/aquasecurity/defsec/formatters/csv.go
index 8aefaf031..9c0f15aff 100644
--- a/vendor/github.com/aquasecurity/defsec/formatters/csv.go
+++ b/vendor/github.com/aquasecurity/defsec/formatters/csv.go
@@ -3,13 +3,12 @@ package formatters
 import (
 	"encoding/csv"
 	"fmt"
-	"io"
 	"strconv"
 
 	"github.com/aquasecurity/defsec/rules"
 )
 
-func FormatCSV(w io.Writer, results []rules.Result, _ string, _ ...FormatterOption) error {
+func outputCSV(b configurableFormatter, results []rules.Result) error {
 
 	records := [][]string{
 		{"file", "start_line", "end_line", "rule_id", "severity", "description", "link", "passed"},
@@ -17,8 +16,9 @@ func FormatCSV(w io.Writer, results []rules.Result, _ string, _ ...FormatterOpti
 
 	for _, res := range results {
 		var link string
-		if len(res.Rule().Links) > 0 {
-			link = res.Rule().Links[0]
+		links := b.GetLinks(res)
+		if len(links) > 0 {
+			link = links[0]
 		}
 
 		rng := res.CodeBlockMetadata().Range()
@@ -38,7 +38,7 @@ func FormatCSV(w io.Writer, results []rules.Result, _ string, _ ...FormatterOpti
 		})
 	}
 
-	csvWriter := csv.NewWriter(w)
+	csvWriter := csv.NewWriter(b.Writer())
 
 	for _, record := range records {
 		if err := csvWriter.Write(record); err != nil {
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/default.go b/vendor/github.com/aquasecurity/defsec/formatters/default.go
index 2fd566dac..686f1a968 100644
--- a/vendor/github.com/aquasecurity/defsec/formatters/default.go
+++ b/vendor/github.com/aquasecurity/defsec/formatters/default.go
@@ -6,145 +6,139 @@ import (
 	"io/ioutil"
 	"strings"
 
-	"github.com/aquasecurity/defsec/metrics"
-
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/severity"
 	"github.com/liamg/clinch/terminal"
-	"github.com/liamg/gifwrap/pkg/ascii"
 	"github.com/liamg/tml"
 )
 
 var severityFormat map[severity.Severity]string
 
-func FormatDefault(_ io.Writer, results []rules.Result, _ string, options ...FormatterOption) error {
-
-	showDebug := false
-	showSuccessOutput := true
-	showMetrics := true
-
-	var showGif bool
-
-	for _, option := range options {
-		switch option {
-		case ConciseOutput:
-			showSuccessOutput = false
-			showMetrics = false
-		case PassingGif:
-			showGif = true
-			showMetrics = false
-		case NoColour:
-			tml.DisableFormatting()
-		case WithDebug:
-			showDebug = true
-		}
-	}
+func outputDefault(b configurableFormatter, results []rules.Result) error {
 
-	if severityFormat == nil {
-		severityFormat = map[severity.Severity]string{
-			severity.Low:      tml.Sprintf("<white>%s</white>", severity.Low),
-			severity.Medium:   tml.Sprintf("<yellow>%s</yellow>", severity.Medium),
-			severity.High:     tml.Sprintf("<red>%s</red>", severity.High),
-			severity.Critical: tml.Sprintf("<bold><red>%s</red></bold>", severity.Critical),
-			"":                tml.Sprintf("<white>UNKNOWN</white>"),
-		}
+	// we initialise the map here so we respect the colour-ignore options
+	severityFormat = map[severity.Severity]string{
+		severity.Low:      tml.Sprintf("<white>%s</white>", severity.Low),
+		severity.Medium:   tml.Sprintf("<yellow>%s</yellow>", severity.Medium),
+		severity.High:     tml.Sprintf("<red>%s</red>", severity.High),
+		severity.Critical: tml.Sprintf("<bold><red>%s</red></bold>", severity.Critical),
+		"":                tml.Sprintf("<white> UNKNOWN</white>"),
 	}
 
 	passCount := countPassedResults(results)
 
 	if len(results) == 0 || len(results) == passCount {
-		if showGif {
-			if renderer, err := ascii.FromURL("https://media.giphy.com/media/kyLYXonQYYfwYDIeZl/source.gif"); err == nil {
-				renderer.SetFill(true)
-				_ = renderer.PlayOnce()
-			}
-		}
-		if showSuccessOutput {
-			terminal.PrintSuccessf("\nNo problems detected!\n\n")
-		}
+		b.PrintMetrics()
+		tml.Fprintf(b.Writer(), "\n<green><bold>No problems detected!\n\n")
 		return nil
 	}
 
-	fmt.Println("")
+	fmt.Fprintln(b.Writer(), "")
 	for i, res := range results {
-		printResult(res, i)
+		printResult(b, res, i)
 	}
 
-	if showMetrics {
-		printMetrics(showDebug)
-	}
+	b.PrintMetrics()
 
 	var passInfo string
 	if passCount > 0 {
 		passInfo = fmt.Sprintf("%d passed, ", passCount)
 	}
-
-	terminal.PrintErrorf("\n  %s%d potential problems detected.\n\n", passInfo, len(results)-countPassedResults(results))
+	tml.Fprintf(b.Writer(), "\n  <red><bold>%s%d potential problems detected.\n\n", passInfo, len(results)-countPassedResults(results))
 
 	return nil
 
 }
 
-func printMetrics(debug bool) {
+const lineNoWidth = 7
 
-	categories := metrics.General()
+var indent = strings.Repeat(" ", lineNoWidth+2)
 
-	if debug {
-		categories = append(categories, metrics.Debug()...)
-	}
-
-	for _, category := range categories {
-		_ = tml.Printf("  <blue>%s</blue>\n  %s\n", category.Name(), strings.Repeat("-", 42))
-		for _, metric := range category.Metrics() {
-			_ = tml.Printf("  <blue>%-20s</blue> %s\n", metric.Name(), metric.Value())
-		}
-		fmt.Printf("\n")
-	}
-
-}
-
-func printResult(res rules.Result, i int) {
-
-	resultHeader := fmt.Sprintf("  <underline>Result %d</underline>\n", i+1)
+func printResult(b configurableFormatter, res rules.Result, i int) {
 
 	var severityFormatted string
 	if res.Status() == rules.StatusPassed {
-		terminal.PrintSuccessf(resultHeader)
 		severityFormatted = tml.Sprintf("<green>PASSED</green>")
 	} else {
-		terminal.PrintErrorf(resultHeader)
 		severityFormatted = severityFormat[res.Severity()]
 	}
 
+	width, _ := terminal.Size()
+	if width <= 0 {
+		width = 80
+	}
+
+	w := b.Writer()
+
+	tml.Fprintf(
+		w,
+		" <italic>#%d</italic> %s <bold>%s</bold>\n",
+		i+1,
+		severityFormatted,
+		res.Description(),
+	)
+
 	rng := res.CodeBlockMetadata().Range()
 	if res.IssueBlockMetadata() != nil {
 		rng = res.IssueBlockMetadata().Range()
 	}
+	lineInfo := fmt.Sprintf("Line %d", rng.GetStartLine())
+	if rng.GetStartLine() < rng.GetEndLine() {
+		lineInfo = fmt.Sprintf("Lines %d-%d", rng.GetStartLine(), rng.GetEndLine())
+	}
 
-	_ = tml.Printf(`
-  <blue>[</blue>%s<blue>]</blue> %s
-  <blue>%s</blue>
-
-`, severityFormatted, res.Description(), rng)
-
-	if err := highlightCode(res); err != nil {
-		_ = tml.Printf("<red>Failed to render source code: %s</red>\n", err)
+	tml.Fprintf(
+		w,
+		"<dim>%s\n",
+		strings.Repeat("─", width),
+	)
+	tml.Fprintf(
+		w,
+		" <italic>%s <dim>%s\n",
+		rng.GetFilename(),
+		lineInfo,
+	)
+
+	tml.Fprintf(
+		w,
+		"<dim>%s%s%s</dim>\n",
+		strings.Repeat("─", lineNoWidth),
+		"┬",
+		strings.Repeat("─", width-lineNoWidth-1),
+	)
+
+	if err := highlightCode(b, res); err != nil {
+		printCodeLine(w, -1, tml.Sprintf("<red><bold>Failed to render code:</bold> %s", err))
 	}
 
-	_ = tml.Printf("  <white>ID:         </white><blue>%s</blue>\n", res.Rule().LongID())
+	tml.Fprintf(
+		w,
+		"<dim>%s┴%s</dim>\n",
+		strings.Repeat("─", lineNoWidth),
+		strings.Repeat("─", width-lineNoWidth-1),
+	)
+
+	_ = tml.Fprintf(w, "  <dim>        ID</dim> <italic>%s\n", res.Rule().LongID())
 	if res.Rule().Impact != "" {
-		_ = tml.Printf("  <white>Impact:     </white><blue>%s</blue>\n", res.Rule().Impact)
+		_ = tml.Fprintf(w, "  <dim>    Impact</dim> %s\n", res.Rule().Impact)
 	}
 	if res.Rule().Resolution != "" {
-		_ = tml.Printf("  <white>Resolution: </white><blue>%s</blue>\n", res.Rule().Resolution)
+		_ = tml.Fprintf(w, "  <dim>Resolution</dim> %s\n", res.Rule().Resolution)
 	}
-	if len(res.Rule().Links) > 0 {
-		_ = tml.Printf("\n  <white>More Info:</white>")
+
+	links := b.GetLinks(res)
+	if len(links) > 0 {
+		_ = tml.Fprintf(w, "\n  <dim>More Information</dim>")
 	}
-	for _, link := range res.Rule().Links {
-		_ = tml.Printf("\n  -<blue> %s </blue>", link)
+	for _, link := range links {
+		_ = tml.Fprintf(w, "\n  <dim>-</dim> <blue>%s", link)
 	}
-	fmt.Printf("\n\n")
+
+	tml.Fprintf(
+		w,
+		"\n<dim>%s</dim>\n\n\n",
+		strings.Repeat("─", width),
+	)
 }
 
 func countPassedResults(results []rules.Result) int {
@@ -159,7 +153,16 @@ func countPassedResults(results []rules.Result) int {
 	return passed
 }
 
-func highlightCode(result rules.Result) error {
+func printCodeLine(w io.Writer, i int, code string) {
+	_ = tml.Fprintf(
+		w,
+		"<dim>%5d</dim>  <dim>│</dim> %s\n",
+		i,
+		code,
+	)
+}
+
+func highlightCode(b configurableFormatter, result rules.Result) error {
 
 	outerRange := result.CodeBlockMetadata().Range()
 	innerRange := outerRange
@@ -174,6 +177,8 @@ func highlightCode(result rules.Result) error {
 
 	hasAnnotation := result.Annotation() != ""
 
+	w := b.Writer()
+
 	for i, bodyString := range strings.Split(string(content), "\n") {
 
 		line := i + 1
@@ -186,23 +191,69 @@ func highlightCode(result rules.Result) error {
 		// if we're not rendering json, we have an annotation, and we're rendering the line to show the annotation on,
 		// render the line with the annotation afterwards
 		if !strings.HasSuffix(outerRange.GetFilename(), ".json") && hasAnnotation && line == innerRange.GetStartLine() {
-			annotation := tml.Sprintf("<blue>[%s]</blue>", result.Annotation())
-			_ = tml.Printf("<blue>% 5d</blue> <dim>┃</dim> <red>%s    %s</red>\n", line, bodyString, annotation)
+			printCodeLine(w, line, tml.Sprintf("<red>%s</red>        <italic>%s", bodyString, result.Annotation()))
 			continue
 		}
 
 		// if we're rendering the actual issue lines, use red
 		if i+1 >= innerRange.GetStartLine() && i < innerRange.GetEndLine() {
 			if result.Status() == rules.StatusPassed {
-				_ = tml.Printf("<blue>% 5d</blue> <dim>┃</dim> <green>%s</green>\n", line, bodyString)
+				printCodeLine(w, line, tml.Sprintf("<green>%s", bodyString))
 			} else {
-				_ = tml.Printf("<blue>% 5d</blue> <dim>┃</dim> <red>%s</red>\n", line, bodyString)
+				printCodeLine(w, line, tml.Sprintf("<red>%s", bodyString))
 			}
 		} else {
-			_ = tml.Printf("<blue>% 5d</blue> <dim>┃</dim> <yellow>%s</yellow>\n", line, bodyString)
+			printCodeLine(w, line, tml.Sprintf("<yellow>%s", bodyString))
 		}
 	}
 
-	fmt.Printf("\n\n")
 	return nil
 }
+
+func printResultLegacy(b configurableFormatter, res rules.Result, i int) {
+
+	resultHeader := fmt.Sprintf("  <underline>Result %d</underline>\n", i+1)
+
+	var severityFormatted string
+	if res.Status() == rules.StatusPassed {
+		terminal.PrintSuccessf(resultHeader)
+		severityFormatted = tml.Sprintf("<green>PASSED</green>")
+	} else {
+		terminal.PrintErrorf(resultHeader)
+		severityFormatted = severityFormat[res.Severity()]
+	}
+
+	rng := res.CodeBlockMetadata().Range()
+	if res.IssueBlockMetadata() != nil {
+		rng = res.IssueBlockMetadata().Range()
+	}
+
+	w := b.Writer()
+
+	_ = tml.Fprintf(w, `
+  <blue>[</blue>%s<blue>]</blue> %s
+  <blue>%s</blue>
+
+`, severityFormatted, res.Description(), rng)
+
+	if err := highlightCode(b, res); err != nil {
+		_ = tml.Fprintf(w, "<red>Failed to render source code: %s</red>\n", err)
+	}
+
+	_ = tml.Fprintf(w, "  <white>ID:         </white><blue>%s</blue>\n", res.Rule().LongID())
+	if res.Rule().Impact != "" {
+		_ = tml.Fprintf(w, "  <white>Impact:     </white><blue>%s</blue>\n", res.Rule().Impact)
+	}
+	if res.Rule().Resolution != "" {
+		_ = tml.Fprintf(w, "  <white>Resolution: </white><blue>%s</blue>\n", res.Rule().Resolution)
+	}
+
+	links := b.GetLinks(res)
+	if len(links) > 0 {
+		_ = tml.Fprintf(w, "\n  <white>More Info:</white>")
+	}
+	for _, link := range links {
+		_ = tml.Fprintf(w, "\n  -<blue> %s </blue>", link)
+	}
+	fmt.Fprintf(w, "\n\n")
+}
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/factory.go b/vendor/github.com/aquasecurity/defsec/formatters/factory.go
new file mode 100644
index 000000000..f2948c7b4
--- /dev/null
+++ b/vendor/github.com/aquasecurity/defsec/formatters/factory.go
@@ -0,0 +1,91 @@
+package formatters
+
+import (
+	"io"
+
+	"github.com/aquasecurity/defsec/rules"
+)
+
+func New() *factory {
+	return &factory{
+		base: newBase(),
+	}
+}
+
+type factory struct {
+	base *base
+}
+
+func (f *factory) Build() Formatter {
+	return f.base
+}
+
+func (f *factory) WithMetricsEnabled(enabled bool) *factory {
+	f.base.enableMetrics = enabled
+	return f
+}
+
+func (f *factory) WithDebugEnabled(enabled bool) *factory {
+	f.base.enableDebug = enabled
+	return f
+}
+
+func (f *factory) WithColoursEnabled(enabled bool) *factory {
+	f.base.enableColours = enabled
+	return f
+}
+
+func (f *factory) WithBaseDir(dir string) *factory {
+	f.base.baseDir = dir
+	return f
+}
+
+func (f *factory) WithCustomFormatterFunc(fn func(configurableFormatter, []rules.Result) error) *factory {
+	f.base.outputOverride = fn
+	return f
+}
+
+func (f *factory) WithLinksFunc(fn func(result rules.Result) []string) *factory {
+	f.base.linksOverride = fn
+	return f
+}
+
+func (f *factory) WithWriter(w io.Writer) *factory {
+	f.base.writer = w
+	return f
+}
+
+func (f *factory) AsJSON() *factory {
+	f.base.outputOverride = outputJSON
+	return f
+}
+
+func (f *factory) AsCheckStyle() *factory {
+	f.base.outputOverride = outputCheckStyle
+	return f
+}
+
+func (f *factory) AsDefault() *factory {
+	f.base.outputOverride = outputDefault
+	return f
+}
+
+func (f *factory) AsCSV() *factory {
+	f.base.outputOverride = outputCSV
+	return f
+}
+
+func (f *factory) AsGIF() *factory {
+	f.base.outputOverride = outputGif
+	return f
+}
+
+func (f *factory) AsJUnit() *factory {
+	f.base.outputOverride = outputJUnit
+	return f
+}
+
+func (f *factory) AsSARIF() *factory {
+	f.base.outputOverride = outputSARIF
+	return f
+}
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/formatter.go b/vendor/github.com/aquasecurity/defsec/formatters/formatter.go
index 3d2ed306d..9b820b1ca 100644
--- a/vendor/github.com/aquasecurity/defsec/formatters/formatter.go
+++ b/vendor/github.com/aquasecurity/defsec/formatters/formatter.go
@@ -1,19 +1,93 @@
 package formatters
 
 import (
+	"fmt"
 	"io"
+	"os"
+	"strings"
 
+	"github.com/aquasecurity/defsec/metrics"
 	"github.com/aquasecurity/defsec/rules"
+	"github.com/liamg/tml"
 )
 
-type FormatterOption int
+type Formatter interface {
+	Output(results []rules.Result) error
+}
 
-const (
-	ConciseOutput FormatterOption = iota
-	PassingGif
-	NoColour
-	WithDebug
-)
+type configurableFormatter interface {
+	Writer() io.Writer
+	GetLinks(rules.Result) []string
+	PrintMetrics()
+	BaseDir() string
+	DebugEnabled() bool
+}
+
+type base struct {
+	enableMetrics  bool
+	enableColours  bool
+	enableDebug    bool
+	baseDir        string
+	writer         io.Writer
+	outputOverride func(b configurableFormatter, results []rules.Result) error
+	linksOverride  func(result rules.Result) []string
+}
+
+func newBase() *base {
+	return &base{
+		enableMetrics:  true,
+		enableColours:  true,
+		enableDebug:    false,
+		baseDir:        ".",
+		writer:         os.Stdout,
+		outputOverride: outputDefault,
+		linksOverride: func(result rules.Result) []string {
+			return result.Rule().Links
+		},
+	}
+}
+
+func (b *base) Writer() io.Writer {
+	return b.writer
+}
+
+func (b *base) DebugEnabled() bool {
+	return b.enableDebug
+}
+
+func (b *base) GetLinks(result rules.Result) []string {
+	return b.linksOverride(result)
+}
+
+func (b *base) BaseDir() string {
+	return b.baseDir
+}
+
+func (b *base) Output(results []rules.Result) error {
+	if !b.enableColours {
+		tml.DisableFormatting()
+	}
+	return b.outputOverride(b, results)
+}
+
+func (b *base) PrintMetrics() {
+
+	if !b.enableMetrics {
+		return
+	}
+
+	categories := metrics.General()
+
+	if b.enableDebug {
+		categories = append(categories, metrics.Debug()...)
+	}
+
+	for _, category := range categories {
+		tml.Fprintf(b.Writer(), "  <bold>%s</bold>\n  %s\n", category.Name(), strings.Repeat("─", 42))
+		for _, metric := range category.Metrics() {
+			_ = tml.Fprintf(b.Writer(), "  <dim>%-20s</dim> %s\n", metric.Name(), metric.Value())
+		}
+		fmt.Fprintf(b.Writer(), "\n")
+	}
 
-// Formatter formats scan results into a specific format
-type Formatter func(w io.Writer, results []rules.Result, baseDir string, options ...FormatterOption) error
+}
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/gif.go b/vendor/github.com/aquasecurity/defsec/formatters/gif.go
index d5b183cc5..7210f92ca 100644
--- a/vendor/github.com/aquasecurity/defsec/formatters/gif.go
+++ b/vendor/github.com/aquasecurity/defsec/formatters/gif.go
@@ -1,11 +1,24 @@
 package formatters
 
 import (
-	"io"
-
 	"github.com/aquasecurity/defsec/rules"
+	"github.com/liamg/gifwrap/pkg/ascii"
 )
 
-func FormatGif(w io.Writer, results []rules.Result, baseDir string, options ...FormatterOption) error {
-	return FormatDefault(w, results, baseDir, append(options, PassingGif)...)
+func outputGif(b configurableFormatter, results []rules.Result) error {
+
+	failCount := len(results) - countPassedResults(results)
+
+	gifSrc := "https://media.giphy.com/media/kyLYXonQYYfwYDIeZl/source.gif"
+
+	if failCount > 0 {
+		gifSrc = "https://i.giphy.com/media/A1SxC5HRrD3MY/source.gif"
+	}
+
+	if renderer, err := ascii.FromURL(gifSrc); err == nil {
+		renderer.SetFill(true)
+		_ = renderer.PlayOnce()
+	}
+
+	return outputDefault(b, results)
 }
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/json.go b/vendor/github.com/aquasecurity/defsec/formatters/json.go
index 2b2609ddc..684e5a08f 100644
--- a/vendor/github.com/aquasecurity/defsec/formatters/json.go
+++ b/vendor/github.com/aquasecurity/defsec/formatters/json.go
@@ -2,21 +2,20 @@ package formatters
 
 import (
 	"encoding/json"
-	"io"
 
 	"github.com/aquasecurity/defsec/rules"
 )
 
-type JSONOutput struct {
-	Results []rules.FlatResult `json:"results"`
-}
-
-func FormatJSON(w io.Writer, results []rules.Result, _ string, options ...FormatterOption) error {
-	jsonWriter := json.NewEncoder(w)
+func outputJSON(b configurableFormatter, results []rules.Result) error {
+	jsonWriter := json.NewEncoder(b.Writer())
 	jsonWriter.SetIndent("", "\t")
 	var flatResults []rules.FlatResult
 	for _, result := range results {
-		flatResults = append(flatResults, result.Flatten())
+		flat := result.Flatten()
+		flat.Links = b.GetLinks(result)
+		flatResults = append(flatResults, flat)
 	}
-	return jsonWriter.Encode(JSONOutput{flatResults})
+	return jsonWriter.Encode(struct {
+		Results []rules.FlatResult `json:"results"`
+	}{flatResults})
 }
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/junit.go b/vendor/github.com/aquasecurity/defsec/formatters/junit.go
index 8d6f59f6d..4c5e39631 100644
--- a/vendor/github.com/aquasecurity/defsec/formatters/junit.go
+++ b/vendor/github.com/aquasecurity/defsec/formatters/junit.go
@@ -3,7 +3,6 @@ package formatters
 import (
 	"encoding/xml"
 	"fmt"
-	"io"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -15,35 +14,35 @@ import (
 // see https://github.com/windyroad/JUnit-Schema/blob/master/JUnit.xsd
 // tested with CircleCI
 
-// JUnitTestSuite is a single JUnit test suite which may contain many
+// jUnitTestSuite is a single JUnit test suite which may contain many
 // testcases.
-type JUnitTestSuite struct {
+type jUnitTestSuite struct {
 	XMLName   xml.Name        `xml:"testsuite"`
 	Name      string          `xml:"name,attr"`
 	Failures  string          `xml:"failures,attr"`
 	Tests     string          `xml:"tests,attr"`
-	TestCases []JUnitTestCase `xml:"testcase"`
+	TestCases []jUnitTestCase `xml:"testcase"`
 }
 
-// JUnitTestCase is a single test case with its result.
-type JUnitTestCase struct {
+// jUnitTestCase is a single test case with its result.
+type jUnitTestCase struct {
 	XMLName   xml.Name      `xml:"testcase"`
 	Classname string        `xml:"classname,attr"`
 	Name      string        `xml:"name,attr"`
 	Time      string        `xml:"time,attr"`
-	Failure   *JUnitFailure `xml:"failure,omitempty"`
+	Failure   *jUnitFailure `xml:"failure,omitempty"`
 }
 
-// JUnitFailure contains data related to a failed test.
-type JUnitFailure struct {
+// jUnitFailure contains data related to a failed test.
+type jUnitFailure struct {
 	Message  string `xml:"message,attr"`
 	Type     string `xml:"type,attr"`
 	Contents string `xml:",chardata"`
 }
 
-func FormatJUnit(w io.Writer, results []rules.Result, _ string, options ...FormatterOption) error {
+func outputJUnit(b configurableFormatter, results []rules.Result) error {
 
-	output := JUnitTestSuite{
+	output := jUnitTestSuite{
 		Name:     filepath.Base(os.Args[0]),
 		Failures: fmt.Sprintf("%d", len(results)-countPassedResults(results)),
 		Tests:    fmt.Sprintf("%d", len(results)),
@@ -52,20 +51,20 @@ func FormatJUnit(w io.Writer, results []rules.Result, _ string, options ...Forma
 	for _, res := range results {
 		rng := res.NarrowestRange()
 		output.TestCases = append(output.TestCases,
-			JUnitTestCase{
+			jUnitTestCase{
 				Classname: rng.GetFilename(),
 				Name:      fmt.Sprintf("[%s][%s] - %s", res.Rule().LongID(), res.Severity(), res.Description()),
 				Time:      "0",
-				Failure:   buildFailure(res),
+				Failure:   buildFailure(b, res),
 			},
 		)
 	}
 
-	if _, err := w.Write([]byte(xml.Header)); err != nil {
+	if _, err := b.Writer().Write([]byte(xml.Header)); err != nil {
 		return err
 	}
 
-	xmlEncoder := xml.NewEncoder(w)
+	xmlEncoder := xml.NewEncoder(b.Writer())
 	xmlEncoder.Indent("", "\t")
 
 	return xmlEncoder.Encode(output)
@@ -110,17 +109,18 @@ func highlightCodeJunit(res rules.Result) string {
 	return output
 }
 
-func buildFailure(res rules.Result) *JUnitFailure {
+func buildFailure(b configurableFormatter, res rules.Result) *jUnitFailure {
 	if res.Status() == rules.StatusPassed {
 		return nil
 	}
 
 	var link string
-	if len(res.Rule().Links) > 0 {
-		link = res.Rule().Links[0]
+	links := b.GetLinks(res)
+	if len(links) > 0 {
+		link = links[0]
 	}
 
-	return &JUnitFailure{
+	return &jUnitFailure{
 		Message: res.Description(),
 		Contents: fmt.Sprintf("%s\n%s\n%s",
 			res.NarrowestRange().String(),
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/sarif.go b/vendor/github.com/aquasecurity/defsec/formatters/sarif.go
index 8577e2adb..cd69c2b24 100644
--- a/vendor/github.com/aquasecurity/defsec/formatters/sarif.go
+++ b/vendor/github.com/aquasecurity/defsec/formatters/sarif.go
@@ -1,7 +1,6 @@
 package formatters
 
 import (
-	"io"
 	"path/filepath"
 
 	"github.com/aquasecurity/defsec/rules"
@@ -10,7 +9,7 @@ import (
 	"github.com/owenrumney/go-sarif/v2/sarif"
 )
 
-func FormatSarif(w io.Writer, results []rules.Result, baseDir string, _ ...FormatterOption) error {
+func outputSARIF(b configurableFormatter, results []rules.Result) error {
 	report, err := sarif.New(sarif.Version210)
 	if err != nil {
 		return err
@@ -19,19 +18,21 @@ func FormatSarif(w io.Writer, results []rules.Result, baseDir string, _ ...Forma
 	run := sarif.NewRunWithInformationURI("tfsec", "https://tfsec.dev")
 	report.AddRun(run)
 
+	baseDir := b.BaseDir()
+
 	for _, res := range results {
 
 		if res.Status() == rules.StatusPassed {
 			continue
 		}
 
-		var link string
-		if len(res.Rule().Links) > 0 {
-			link = res.Rule().Links[0]
-		}
 		rule := run.AddRule(res.Rule().LongID()).
-			WithDescription(res.Rule().Summary).
-			WithHelpURI(link)
+			WithDescription(res.Rule().Summary)
+
+		links := b.GetLinks(res)
+		if len(links) > 0 {
+			rule.WithHelpURI(links[0])
+		}
 
 		rng := res.NarrowestRange()
 
@@ -68,5 +69,5 @@ func FormatSarif(w io.Writer, results []rules.Result, baseDir string, _ ...Forma
 			AddLocation(sarif.NewLocation().WithPhysicalLocation(location))
 	}
 
-	return report.PrettyWrite(w)
+	return report.PrettyWrite(b.Writer())
 }
diff --git a/vendor/github.com/aquasecurity/defsec/formatters/text.go b/vendor/github.com/aquasecurity/defsec/formatters/text.go
deleted file mode 100644
index 556c02b16..000000000
--- a/vendor/github.com/aquasecurity/defsec/formatters/text.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package formatters
-
-import (
-	"io"
-
-	"github.com/aquasecurity/defsec/rules"
-)
-
-func FormatText(writer io.Writer, results []rules.Result, baseDir string, options ...FormatterOption) error {
-	return FormatDefault(writer, results, baseDir, append(options, NoColour, ConciseOutput)...)
-}
diff --git a/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/add_description_to_security_group_rule.go b/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/add_description_to_security_group_rule.go
index e26a6f93e..39a3427e9 100644
--- a/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/add_description_to_security_group_rule.go
+++ b/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/add_description_to_security_group_rule.go
@@ -22,19 +22,19 @@ Simplifies auditing, debugging, and managing security groups.`,
 		Links: []string{
 			"https://www.cloudconformity.com/knowledge-base/aws/EC2/security-group-rules-description.html",
 		},
-		Terraform:   &rules.EngineMetadata{
-            GoodExamples:        terraformAddDescriptionToSecurityGroupRuleGoodExamples,
-            BadExamples:         terraformAddDescriptionToSecurityGroupRuleBadExamples,
-            Links:               terraformAddDescriptionToSecurityGroupRuleLinks,
-            RemediationMarkdown: terraformAddDescriptionToSecurityGroupRuleRemediationMarkdown,
-        },
-        CloudFormation:   &rules.EngineMetadata{
-            GoodExamples:        cloudFormationAddDescriptionToSecurityGroupRuleGoodExamples,
-            BadExamples:         cloudFormationAddDescriptionToSecurityGroupRuleBadExamples,
-            Links:               cloudFormationAddDescriptionToSecurityGroupRuleLinks,
-            RemediationMarkdown: cloudFormationAddDescriptionToSecurityGroupRuleRemediationMarkdown,
-        },
-        Severity: severity.Low,
+		Terraform: &rules.EngineMetadata{
+			GoodExamples:        terraformAddDescriptionToSecurityGroupRuleGoodExamples,
+			BadExamples:         terraformAddDescriptionToSecurityGroupRuleBadExamples,
+			Links:               terraformAddDescriptionToSecurityGroupRuleLinks,
+			RemediationMarkdown: terraformAddDescriptionToSecurityGroupRuleRemediationMarkdown,
+		},
+		CloudFormation: &rules.EngineMetadata{
+			GoodExamples:        cloudFormationAddDescriptionToSecurityGroupRuleGoodExamples,
+			BadExamples:         cloudFormationAddDescriptionToSecurityGroupRuleBadExamples,
+			Links:               cloudFormationAddDescriptionToSecurityGroupRuleLinks,
+			RemediationMarkdown: cloudFormationAddDescriptionToSecurityGroupRuleRemediationMarkdown,
+		},
+		Severity: severity.Low,
 	},
 	func(s *state.State) (results rules.Results) {
 		for _, group := range s.AWS.VPC.SecurityGroups {
@@ -42,8 +42,8 @@ Simplifies auditing, debugging, and managing security groups.`,
 				if rule.Description.IsEmpty() {
 					results.Add(
 						"Security group rule does not have a description.",
-						&group,
 						&rule,
+						rule.Description,
 					)
 				} else {
 					results.AddPassed(&rule)
diff --git a/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/no_public_egress_sgr.go b/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/no_public_egress_sgr.go
index d2a20f711..c80ef2dc3 100644
--- a/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/no_public_egress_sgr.go
+++ b/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/no_public_egress_sgr.go
@@ -44,7 +44,7 @@ var CheckNoPublicEgressSgr = rules.Register(
 						fail = true
 						results.Add(
 							"Security group rule allows egress to multiple public internet addresses.",
-							&group,
+							&rule,
 							block,
 						)
 					}
diff --git a/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/no_public_ingress_sgr.go b/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/no_public_ingress_sgr.go
index 3a7f16a72..a3e8dbe90 100644
--- a/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/no_public_ingress_sgr.go
+++ b/vendor/github.com/aquasecurity/defsec/rules/aws/vpc/no_public_ingress_sgr.go
@@ -21,19 +21,19 @@ var CheckNoPublicIngressSgr = rules.Register(
 		Links: []string{
 			"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html",
 		},
-		Terraform:   &rules.EngineMetadata{
-            GoodExamples:        terraformNoPublicIngressSgrGoodExamples,
-            BadExamples:         terraformNoPublicIngressSgrBadExamples,
-            Links:               terraformNoPublicIngressSgrLinks,
-            RemediationMarkdown: terraformNoPublicIngressSgrRemediationMarkdown,
-        },
-        CloudFormation:   &rules.EngineMetadata{
-            GoodExamples:        cloudFormationNoPublicIngressSgrGoodExamples,
-            BadExamples:         cloudFormationNoPublicIngressSgrBadExamples,
-            Links:               cloudFormationNoPublicIngressSgrLinks,
-            RemediationMarkdown: cloudFormationNoPublicIngressSgrRemediationMarkdown,
-        },
-        Severity: severity.Critical,
+		Terraform: &rules.EngineMetadata{
+			GoodExamples:        terraformNoPublicIngressSgrGoodExamples,
+			BadExamples:         terraformNoPublicIngressSgrBadExamples,
+			Links:               terraformNoPublicIngressSgrLinks,
+			RemediationMarkdown: terraformNoPublicIngressSgrRemediationMarkdown,
+		},
+		CloudFormation: &rules.EngineMetadata{
+			GoodExamples:        cloudFormationNoPublicIngressSgrGoodExamples,
+			BadExamples:         cloudFormationNoPublicIngressSgrBadExamples,
+			Links:               cloudFormationNoPublicIngressSgrLinks,
+			RemediationMarkdown: cloudFormationNoPublicIngressSgrRemediationMarkdown,
+		},
+		Severity: severity.Critical,
 	},
 	func(s *state.State) (results rules.Results) {
 		for _, group := range s.AWS.VPC.SecurityGroups {
@@ -44,7 +44,7 @@ var CheckNoPublicIngressSgr = rules.Register(
 						failed = true
 						results.Add(
 							"Security group rule allows ingress from public internet.",
-							&group,
+							&rule,
 							block,
 						)
 					}
diff --git a/vendor/github.com/aquasecurity/defsec/rules/azure/database/enable_audit.go b/vendor/github.com/aquasecurity/defsec/rules/azure/database/enable_audit.go
index 499f97cf2..47c7dfc77 100644
--- a/vendor/github.com/aquasecurity/defsec/rules/azure/database/enable_audit.go
+++ b/vendor/github.com/aquasecurity/defsec/rules/azure/database/enable_audit.go
@@ -30,7 +30,7 @@ var CheckEnableAudit = rules.Register(
 	},
 	func(s *state.State) (results rules.Results) {
 		for _, server := range s.Azure.Database.MSSQLServers {
-			if len(server.ExtendedAuditingPolicies) == 0 {
+			if len(server.ExtendedAuditingPolicies) == 0 && server.IsManaged() {
 				results.Add(
 					"Server does not have an extended audit policy configured.",
 					&server,
diff --git a/vendor/github.com/liamg/tml/README.md b/vendor/github.com/liamg/tml/README.md
index 135b6aa18..353c8c262 100644
--- a/vendor/github.com/liamg/tml/README.md
+++ b/vendor/github.com/liamg/tml/README.md
@@ -91,6 +91,7 @@ It's not required to close tags you've opened, though it can make for easier rea
 
 - `<bold>`
 - `<dim>`
+- `<italic>`
 - `<underline>`
 - `<blink>`
 - `<reverse>`
diff --git a/vendor/github.com/liamg/tml/parser.go b/vendor/github.com/liamg/tml/parser.go
index 684e10463..cded7b80b 100644
--- a/vendor/github.com/liamg/tml/parser.go
+++ b/vendor/github.com/liamg/tml/parser.go
@@ -23,12 +23,13 @@ type parserState struct {
 type attrs uint8
 
 const (
-	bold      uint8 = 1
-	dim             = 2
-	underline       = 4
-	blink           = 8
-	reverse         = 16
-	hidden          = 32
+	bold uint8 = 1 << iota
+	dim
+	underline
+	blink
+	reverse
+	hidden
+	italic
 )
 
 var resetAll = "\x1b[0m"
@@ -38,6 +39,7 @@ var resetBg = "\x1b[49m"
 var attrMap = map[uint8]string{
 	bold:      "\x1b[1m",
 	dim:       "\x1b[2m",
+	italic:    "\x1b[3m",
 	underline: "\x1b[4m",
 	blink:     "\x1b[5m",
 	reverse:   "\x1b[7m",
@@ -160,7 +162,7 @@ func (p *Parser) Parse(reader io.Reader) error {
 			}
 			return err
 		}
-		for _, r := range []rune(string(buffer[:n])) {
+		for _, r := range string(buffer[:n]) {
 
 			if inTag {
 				if r == '>' {
diff --git a/vendor/github.com/liamg/tml/printf.go b/vendor/github.com/liamg/tml/printf.go
index e259435e8..92dc6a3e5 100644
--- a/vendor/github.com/liamg/tml/printf.go
+++ b/vendor/github.com/liamg/tml/printf.go
@@ -2,16 +2,21 @@ package tml
 
 import (
 	"fmt"
+	"io"
+	"os"
 )
 
 // Printf works like fmt.Printf, but adds the option of using tags to apply colour or text formatting to the written text. For example "<red>some red text</red>".
 // A full list of tags is available here: https://github.com/liamg/tml
 func Printf(input string, a ...interface{}) error {
+	return Fprintf(os.Stdout, input, a...)
+}
+
+func Fprintf(w io.Writer, input string, a ...interface{}) error {
 	format, err := Parse(input)
 	if err != nil {
 		return err
 	}
-	_, err = fmt.Printf(format, a...)
+	_, err = fmt.Fprintf(w, format, a...)
 	return err
 }
-
diff --git a/vendor/github.com/liamg/tml/println.go b/vendor/github.com/liamg/tml/println.go
index e91de1d5a..62ff8c3e0 100644
--- a/vendor/github.com/liamg/tml/println.go
+++ b/vendor/github.com/liamg/tml/println.go
@@ -1,7 +1,16 @@
 package tml
 
+import (
+	"io"
+	"os"
+)
+
 // Println works like fmt.Println, but adds the option of using tags to apply colour or text formatting to the written text. For example "<red>some red text</red>".
 // A full list of tags is available here: https://github.com/liamg/tml
 func Println(input string) {
-	Printf(input + "\n")
+	Fprintln(os.Stdout, input)
+}
+
+func Fprintln(w io.Writer, input string) {
+	Fprintf(w, "%s\n", input)
 }
diff --git a/vendor/github.com/liamg/tml/tags.go b/vendor/github.com/liamg/tml/tags.go
index 81722d177..77ff84a2b 100644
--- a/vendor/github.com/liamg/tml/tags.go
+++ b/vendor/github.com/liamg/tml/tags.go
@@ -41,6 +41,7 @@ var bgTags = map[string]string{
 var attrTags = map[string]uint8{
 	"bold":      bold,
 	"dim":       dim,
+	"italic":    italic,
 	"underline": underline,
 	"blink":     blink,
 	"reverse":   reverse,
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 4b12c4d5e..e0224c4e7 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -28,7 +28,7 @@ github.com/apparentlymart/go-cidr/cidr
 # github.com/apparentlymart/go-textseg/v13 v13.0.0
 ## explicit; go 1.16
 github.com/apparentlymart/go-textseg/v13/textseg
-# github.com/aquasecurity/defsec v0.4.1
+# github.com/aquasecurity/defsec v0.5.2
 ## explicit; go 1.17
 github.com/aquasecurity/defsec/cidr
 github.com/aquasecurity/defsec/formatters
@@ -309,7 +309,7 @@ github.com/liamg/gifwrap/pkg/ascii
 # github.com/liamg/iamgo v0.0.2
 ## explicit; go 1.17
 github.com/liamg/iamgo
-# github.com/liamg/tml v0.4.0
+# github.com/liamg/tml v0.6.0
 ## explicit; go 1.12
 github.com/liamg/tml
 # github.com/lucasb-eyer/go-colorful v1.0.3


Test patch:
diff --git a/internal/app/tfsec/adapter/aws/s3/adapt_test.go b/internal/pkg/adapter/aws/s3/adapt_test.go
similarity index 97%
rename from internal/app/tfsec/adapter/aws/s3/adapt_test.go
rename to internal/pkg/adapter/aws/s3/adapt_test.go
index a61c44bf9..0baba2386 100644
--- a/internal/app/tfsec/adapter/aws/s3/adapt_test.go
+++ b/internal/pkg/adapter/aws/s3/adapt_test.go
@@ -3,7 +3,7 @@ package s3
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/testutils"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/testutils"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
diff --git a/internal/app/tfsec/adapter/aws/s3/bucket_test.go b/internal/pkg/adapter/aws/s3/bucket_test.go
similarity index 80%
rename from internal/app/tfsec/adapter/aws/s3/bucket_test.go
rename to internal/pkg/adapter/aws/s3/bucket_test.go
index 8e0abefd6..240a5b376 100644
--- a/internal/app/tfsec/adapter/aws/s3/bucket_test.go
+++ b/internal/pkg/adapter/aws/s3/bucket_test.go
@@ -3,7 +3,7 @@ package s3
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/adapter/testutils"
+	"github.com/aquasecurity/tfsec/internal/pkg/adapter/testutils"
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/internal/app/tfsec/adapter/testutils/loader.go b/internal/pkg/adapter/testutils/loader.go
similarity index 84%
rename from internal/app/tfsec/adapter/testutils/loader.go
rename to internal/pkg/adapter/testutils/loader.go
index 75b3cfcc3..33f1421ed 100644
--- a/internal/app/tfsec/adapter/testutils/loader.go
+++ b/internal/pkg/adapter/testutils/loader.go
@@ -6,8 +6,8 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
 )
 
 func CreateModulesFromSource(source string, ext string, t *testing.T) block.Modules {
diff --git a/internal/app/tfsec/config/config.go b/internal/pkg/config/config.go
similarity index 100%
rename from internal/app/tfsec/config/config.go
rename to internal/pkg/config/config.go
diff --git a/internal/app/tfsec/config/config_test.go b/internal/pkg/config/config_test.go
similarity index 96%
rename from internal/app/tfsec/config/config_test.go
rename to internal/pkg/config/config_test.go
index 8351011ff..132e87833 100644
--- a/internal/app/tfsec/config/config_test.go
+++ b/internal/pkg/config/config_test.go
@@ -6,7 +6,7 @@ import (
 	"os"
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/config"
+	"github.com/aquasecurity/tfsec/internal/pkg/config"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
diff --git a/internal/app/tfsec/custom/processing_test.go b/internal/pkg/custom/processing_test.go
similarity index 98%
rename from internal/app/tfsec/custom/processing_test.go
rename to internal/pkg/custom/processing_test.go
index c01e776ad..155b954c5 100644
--- a/internal/app/tfsec/custom/processing_test.go
+++ b/internal/pkg/custom/processing_test.go
@@ -11,9 +11,9 @@ import (
 
 	"github.com/aquasecurity/defsec/rules"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/internal/app/tfsec/parser/parser_test.go b/internal/pkg/parser/parser_test.go
similarity index 99%
rename from internal/app/tfsec/parser/parser_test.go
rename to internal/pkg/parser/parser_test.go
index 17b981269..63c925132 100644
--- a/internal/app/tfsec/parser/parser_test.go
+++ b/internal/pkg/parser/parser_test.go
@@ -7,7 +7,7 @@ import (
 	"sort"
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/debug"
+	"github.com/aquasecurity/tfsec/internal/pkg/debug"
 
 	"github.com/zclconf/go-cty/cty"
 
diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule_test.go b/internal/pkg/rules/general/secrets/sensitive_in_attribute_rule_test.go
similarity index 98%
rename from internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule_test.go
rename to internal/pkg/rules/general/secrets/sensitive_in_attribute_rule_test.go
index 62704d51b..dbee63a58 100644
--- a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_rule_test.go
+++ b/internal/pkg/rules/general/secrets/sensitive_in_attribute_rule_test.go
@@ -3,7 +3,7 @@ package secrets
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 )
 
 func Test_AWSSensitiveAttributes(t *testing.T) {
diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule_test.go b/internal/pkg/rules/general/secrets/sensitive_in_attribute_value_rule_test.go
similarity index 97%
rename from internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule_test.go
rename to internal/pkg/rules/general/secrets/sensitive_in_attribute_value_rule_test.go
index f942b8151..c77700ea0 100644
--- a/internal/app/tfsec/rules/general/secrets/sensitive_in_attribute_value_rule_test.go
+++ b/internal/pkg/rules/general/secrets/sensitive_in_attribute_value_rule_test.go
@@ -3,7 +3,7 @@ package secrets
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 )
 
 func Test_GENAttributeHasSensitiveData(t *testing.T) {
diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule_test.go b/internal/pkg/rules/general/secrets/sensitive_in_local_rule_test.go
similarity index 94%
rename from internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule_test.go
rename to internal/pkg/rules/general/secrets/sensitive_in_local_rule_test.go
index b9d7367aa..7cacc7631 100644
--- a/internal/app/tfsec/rules/general/secrets/sensitive_in_local_rule_test.go
+++ b/internal/pkg/rules/general/secrets/sensitive_in_local_rule_test.go
@@ -3,7 +3,7 @@ package secrets
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 )
 
 func Test_AWSSensitiveLocals(t *testing.T) {
diff --git a/internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule_test.go b/internal/pkg/rules/general/secrets/sensitive_in_variable_rule_test.go
similarity index 94%
rename from internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule_test.go
rename to internal/pkg/rules/general/secrets/sensitive_in_variable_rule_test.go
index 9f51860e0..3c965d39b 100644
--- a/internal/app/tfsec/rules/general/secrets/sensitive_in_variable_rule_test.go
+++ b/internal/pkg/rules/general/secrets/sensitive_in_variable_rule_test.go
@@ -3,7 +3,7 @@ package secrets
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 )
 
 func Test_AWSSensitiveVariables(t *testing.T) {
diff --git a/internal/app/tfsec/scanner/statistics.go b/internal/pkg/scanner/statistics.go
similarity index 100%
rename from internal/app/tfsec/scanner/statistics.go
rename to internal/pkg/scanner/statistics.go
diff --git a/internal/app/tfsec/schema/schema.go b/internal/pkg/schema/schema.go
similarity index 100%
rename from internal/app/tfsec/schema/schema.go
rename to internal/pkg/schema/schema.go
diff --git a/internal/app/tfsec/security/sensitive.go b/internal/pkg/security/sensitive.go
similarity index 100%
rename from internal/app/tfsec/security/sensitive.go
rename to internal/pkg/security/sensitive.go
diff --git a/internal/app/tfsec/testutil/filesystem/fs.go b/internal/pkg/testutil/filesystem/fs.go
similarity index 100%
rename from internal/app/tfsec/testutil/filesystem/fs.go
rename to internal/pkg/testutil/filesystem/fs.go
diff --git a/internal/app/tfsec/testutil/util.go b/internal/pkg/testutil/util.go
similarity index 84%
rename from internal/app/tfsec/testutil/util.go
rename to internal/pkg/testutil/util.go
index fd13bc52b..7f960866e 100644
--- a/internal/app/tfsec/testutil/util.go
+++ b/internal/pkg/testutil/util.go
@@ -5,14 +5,14 @@ import (
 	"testing"
 
 	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil/filesystem"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil/filesystem"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 )
 
 func ScanHCL(source string, t *testing.T, additionalOptions ...scanner.Option) rules.Results {
@@ -58,6 +58,11 @@ func CreateModulesFromSource(source string, ext string, t *testing.T) block.Modu
 func AssertRuleFound(t *testing.T, ruleID string, results []rules.Result, message string, args ...interface{}) {
 	found := ruleIDInResults(ruleID, results)
 	assert.True(t, found, append([]interface{}{message}, args...)...)
+	for _, result := range results {
+		if result.Rule().LongID() == ruleID {
+			assert.NotEmpty(t, result.NarrowestRange().GetFilename())
+		}
+	}
 }
 
 func AssertRuleNotFound(t *testing.T, ruleID string, results []rules.Result, message string, args ...interface{}) {
diff --git a/pkg/rule/check_test.go b/pkg/rule/check_test.go
index c87555b5f..382123f8e 100644
--- a/pkg/rule/check_test.go
+++ b/pkg/rule/check_test.go
@@ -6,9 +6,9 @@ import (
 	"testing"
 
 	"github.com/aquasecurity/defsec/rules"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil/filesystem"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil/filesystem"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
diff --git a/internal/app/tfsec/test/attribute_test.go b/test/attribute_test.go
similarity index 99%
rename from internal/app/tfsec/test/attribute_test.go
rename to test/attribute_test.go
index 210bc5cdd..6d343050d 100644
--- a/internal/app/tfsec/test/attribute_test.go
+++ b/test/attribute_test.go
@@ -3,8 +3,8 @@ package test
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 
 	"github.com/stretchr/testify/assert"
 )
diff --git a/internal/app/tfsec/test/bench_blocks_test.go b/test/bench_blocks_test.go
similarity index 71%
rename from internal/app/tfsec/test/bench_blocks_test.go
rename to test/bench_blocks_test.go
index a6a6a2635..016cbbac0 100644
--- a/internal/app/tfsec/test/bench_blocks_test.go
+++ b/test/bench_blocks_test.go
@@ -3,9 +3,9 @@ package test
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil/filesystem"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil/filesystem"
 )
 
 func BenchmarkBlockParsing(b *testing.B) {
diff --git a/internal/app/tfsec/test/block_test.go b/test/block_test.go
similarity index 98%
rename from internal/app/tfsec/test/block_test.go
rename to test/block_test.go
index 703386de8..5a862d7fc 100644
--- a/internal/app/tfsec/test/block_test.go
+++ b/test/block_test.go
@@ -3,7 +3,7 @@ package test
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/internal/app/tfsec/test/count_test.go b/test/count_test.go
similarity index 95%
rename from internal/app/tfsec/test/count_test.go
rename to test/count_test.go
index 98145175e..7cbbc3d9f 100644
--- a/internal/app/tfsec/test/count_test.go
+++ b/test/count_test.go
@@ -6,9 +6,9 @@ import (
 	"github.com/aquasecurity/defsec/provider"
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/severity"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 	"github.com/stretchr/testify/assert"
 )
diff --git a/internal/app/tfsec/test/ignore_test.go b/test/ignore_test.go
similarity index 96%
rename from internal/app/tfsec/test/ignore_test.go
rename to test/ignore_test.go
index b263186fa..8ed614b2c 100644
--- a/internal/app/tfsec/test/ignore_test.go
+++ b/test/ignore_test.go
@@ -5,20 +5,20 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/legacy"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/legacy"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 
 	"github.com/aquasecurity/defsec/provider"
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/severity"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 
 	"github.com/aquasecurity/tfsec/pkg/rule"
 
 	"github.com/stretchr/testify/require"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 
 	"github.com/stretchr/testify/assert"
 )
diff --git a/internal/app/tfsec/test/init_test.go b/test/init_test.go
similarity index 86%
rename from internal/app/tfsec/test/init_test.go
rename to test/init_test.go
index ee0d56fa2..417c3e3c8 100644
--- a/internal/app/tfsec/test/init_test.go
+++ b/test/init_test.go
@@ -8,11 +8,11 @@ import (
 	"strings"
 	"testing"
 
-	_ "github.com/aquasecurity/tfsec/internal/app/tfsec/rules"
+	_ "github.com/aquasecurity/tfsec/internal/pkg/rules"
 )
 
 func Test_AllRulesWereInitialised(t *testing.T) {
-	rulesDir, err := filepath.Abs(strings.ReplaceAll("../rules", "/", string(os.PathSeparator)))
+	rulesDir, err := filepath.Abs(strings.ReplaceAll("../internal/pkg/rules", "/", string(os.PathSeparator)))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -26,7 +26,7 @@ func Test_AllRulesWereInitialised(t *testing.T) {
 		t.Fatal(err)
 	}
 	for _, pkg := range packages {
-		fullPath := fmt.Sprintf("github.com/aquasecurity/tfsec/internal/app/tfsec/rules/%s", pkg)
+		fullPath := fmt.Sprintf("github.com/aquasecurity/tfsec/internal/pkg/rules/%s", pkg)
 		if !strings.Contains(string(initData), `"`+fullPath+`"`) {
 			t.Errorf("init.go does not contain the rule package '%s'", fullPath)
 		}
diff --git a/internal/app/tfsec/test/json_test.go b/test/json_test.go
similarity index 91%
rename from internal/app/tfsec/test/json_test.go
rename to test/json_test.go
index d7bbabe8a..c536ac1d1 100644
--- a/internal/app/tfsec/test/json_test.go
+++ b/test/json_test.go
@@ -6,9 +6,9 @@ import (
 	"github.com/aquasecurity/defsec/provider"
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/severity"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
 
diff --git a/internal/app/tfsec/test/module_test.go b/test/module_test.go
similarity index 97%
rename from internal/app/tfsec/test/module_test.go
rename to test/module_test.go
index a2667630a..544148bee 100644
--- a/internal/app/tfsec/test/module_test.go
+++ b/test/module_test.go
@@ -3,17 +3,17 @@ package test
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil/filesystem"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil/filesystem"
 	"github.com/stretchr/testify/require"
 
 	"github.com/aquasecurity/defsec/provider"
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/rules/aws/iam"
 	"github.com/aquasecurity/defsec/severity"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
 
diff --git a/internal/app/tfsec/test/performance_test.go b/test/performance_test.go
similarity index 80%
rename from internal/app/tfsec/test/performance_test.go
rename to test/performance_test.go
index ce8e5f445..7d6ca44ed 100644
--- a/internal/app/tfsec/test/performance_test.go
+++ b/test/performance_test.go
@@ -4,9 +4,9 @@ import (
 	"fmt"
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil/filesystem"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil/filesystem"
 )
 
 func BenchmarkCalculate(b *testing.B) {
diff --git a/internal/app/tfsec/test/rules_test.go b/test/rules_test.go
similarity index 94%
rename from internal/app/tfsec/test/rules_test.go
rename to test/rules_test.go
index 1b11abb76..6551ea810 100644
--- a/internal/app/tfsec/test/rules_test.go
+++ b/test/rules_test.go
@@ -5,8 +5,8 @@ import (
 	"regexp"
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 )
 
 func TestBlockTypes(t *testing.T) {
@@ -58,6 +58,7 @@ func TestRulesAgainstExampleCode(t *testing.T) {
 					t.Run(fmt.Sprintf("example %d", i), func(t *testing.T) {
 						results := testutil.ScanHCL(example, t)
 						testutil.AssertRuleFound(t, rule.ID(), results, "Rule %s was not detected in bad example #%d:\n%s", rule.ID(), i, example)
+
 					})
 				}
 			})
diff --git a/internal/app/tfsec/test/scanner_test.go b/test/scanner_test.go
similarity index 90%
rename from internal/app/tfsec/test/scanner_test.go
rename to test/scanner_test.go
index 7e2af24fd..01e8d8b46 100644
--- a/internal/app/tfsec/test/scanner_test.go
+++ b/test/scanner_test.go
@@ -3,19 +3,19 @@ package test
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil/filesystem"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil/filesystem"
 
 	"github.com/aquasecurity/defsec/provider"
 	"github.com/aquasecurity/defsec/rules"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
 	"github.com/aquasecurity/defsec/severity"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/parser"
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/parser"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 	"github.com/aquasecurity/tfsec/pkg/rule"
 )
 
diff --git a/internal/app/tfsec/test/sensitive_test.go b/test/sensitive_test.go
similarity index 91%
rename from internal/app/tfsec/test/sensitive_test.go
rename to test/sensitive_test.go
index a36fed26b..0f0ce41f8 100644
--- a/internal/app/tfsec/test/sensitive_test.go
+++ b/test/sensitive_test.go
@@ -3,7 +3,7 @@ package test
 import (
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/security"
+	"github.com/aquasecurity/tfsec/internal/pkg/security"
 )
 
 func TestIsSensitiveAttribute(t *testing.T) {
diff --git a/internal/app/tfsec/test/wildcard_test.go b/test/wildcard_test.go
similarity index 91%
rename from internal/app/tfsec/test/wildcard_test.go
rename to test/wildcard_test.go
index 78cb07303..3bfcd67af 100644
--- a/internal/app/tfsec/test/wildcard_test.go
+++ b/test/wildcard_test.go
@@ -4,16 +4,16 @@ import (
 	"fmt"
 	"testing"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/testutil"
+	"github.com/aquasecurity/tfsec/internal/pkg/testutil"
 
 	"github.com/aquasecurity/defsec/rules"
 	"github.com/aquasecurity/defsec/severity"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/block"
+	"github.com/aquasecurity/tfsec/internal/pkg/block"
 
 	"github.com/aquasecurity/tfsec/pkg/rule"
 
-	"github.com/aquasecurity/tfsec/internal/app/tfsec/scanner"
+	"github.com/aquasecurity/tfsec/internal/pkg/scanner"
 )
 
 func Test_WildcardMatchingOnRequiredLabels(t *testing.T) {