Skip to content

Commit

Permalink
Terrascan init and config handling refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
devang-gaur committed Mar 17, 2021
1 parent b6732c7 commit eafa454
Show file tree
Hide file tree
Showing 39 changed files with 513 additions and 385 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ require (
github.com/spf13/cobra v1.1.1
github.com/zclconf/go-cty v1.7.1
go.uber.org/zap v1.16.0
golang.org/x/mod v0.4.1 // indirect
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b
golang.org/x/mod v0.4.2 // indirect
golang.org/x/sys v0.0.0-20210317091845-390168757d9c
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
helm.sh/helm/v3 v3.4.0
honnef.co/go/tools v0.1.2 // indirect
honnef.co/go/tools v0.1.3 // indirect
sigs.k8s.io/kustomize/api v0.7.2
)
14 changes: 12 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -1237,6 +1239,10 @@ golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b h1:lAZ0/chPUDWwjqosYR0X4M490zQhMsiJ4K3DbA7o+3g=
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210317091845-390168757d9c h1:WGyvPg8lhdtSkb8BiYWdtPlLSommHOmJHFvzWODI7BQ=
golang.org/x/sys v0.0.0-20210317091845-390168757d9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down Expand Up @@ -1476,8 +1482,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.1.2 h1:SMdYLJl312RXuxXziCCHhRsp/tvct9cGKey0yv95tZM=
honnef.co/go/tools v0.1.2/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
honnef.co/go/tools v0.1.0 h1:AWNL1W1i7f0wNZ8VwOKNJ0sliKvOF/adn0EHenfUh+c=
honnef.co/go/tools v0.1.0/go.mod h1:XtegFAyX/PfluP4921rXU5IkjkqBCDnUq4W8VCIoKvM=
honnef.co/go/tools v0.1.1 h1:EVDuO03OCZwpV2t/tLLxPmPiomagMoBOgfPt0FM+4IY=
honnef.co/go/tools v0.1.1/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
honnef.co/go/tools v0.1.3 h1:qTakTkI6ni6LFD5sBwwsdSO+AQqbSIxOauHTTQKZ/7o=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
k8s.io/api v0.19.0 h1:XyrFIJqTYZJ2DU7FBE/bSPz7b1HvbVBuBf07oeo6eTc=
k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw=
k8s.io/apiextensions-apiserver v0.19.2 h1:oG84UwiDsVDu7dlsGQs5GySmQHCzMhknfhFExJMz9tA=
Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/color-console_windows.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// +build windows

/*
Copyright (C) 2020 Accurics, Inc.
Expand All @@ -14,8 +16,6 @@
limitations under the License.
*/

// +build windows

package cli

import (
Expand Down
21 changes: 20 additions & 1 deletion pkg/cli/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ import (
"github.com/accurics/terrascan/pkg/config"
"github.com/accurics/terrascan/pkg/logging"
"github.com/spf13/cobra"
"go.uber.org/zap"
)

const configEnvvarName = "TERRASCAN_CONFIG"

// RegisterCommand Registers a new command under the base command
func RegisterCommand(baseCommand *cobra.Command, command *cobra.Command) {
baseCommand.AddCommand(command)
Expand All @@ -43,8 +46,24 @@ func Execute() {
cobra.OnInitialize(func() {
// Set up the logger
logging.Init(LogType, LogLevel)

var configfile string
if len(ConfigFile) > 0 {
configfile = ConfigFile
}

if len(configfile) == 0 {
configfile = os.Getenv(configEnvvarName)
}

zap.S().Debugf("%s=%s", configEnvvarName, os.Getenv(configEnvvarName))

// Make sure we load the global config from the specified config file
config.LoadGlobalConfig(ConfigFile)
if err := config.LoadGlobalConfig(configfile); err != nil {
zap.S().Error("error while loading global config", zap.Error(err))
os.Exit(1)
}

})

// parse the flags but hack around to avoid exiting with error code 2 on help
Expand Down
8 changes: 7 additions & 1 deletion pkg/cli/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"path/filepath"
"testing"

"github.com/accurics/terrascan/pkg/config"
"github.com/accurics/terrascan/pkg/iac-providers/output"
"github.com/accurics/terrascan/pkg/policy"
"github.com/accurics/terrascan/pkg/results"
Expand All @@ -38,14 +39,18 @@ func TestMain(m *testing.M) {
}

func setup() {
// set default config values before policy download
config.LoadGlobalConfig("")

// to download the policies for Run test
// downloads the policies at $HOME/.terrascan
initial(nil, nil, false)
}

func shutdown() {
// remove the downloaded policies
os.RemoveAll(filepath.Join(utils.GetHomeDir(), ".terrascan"))
os.RemoveAll(config.GetPolicyBasePath())
// cleanup the loaded config values
}

func TestRun(t *testing.T) {
Expand Down Expand Up @@ -222,6 +227,7 @@ func TestRun(t *testing.T) {

for _, tt := range table {
t.Run(tt.name, func(t *testing.T) {
config.LoadGlobalConfig(tt.scanOptions.configFile)
err := tt.scanOptions.Run()
if (err != nil) != tt.wantErr {
t.Errorf("ScanOptions.Run() error = %v, wantErr %v", err, tt.wantErr)
Expand Down
14 changes: 7 additions & 7 deletions pkg/config/config-reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

var (
// ErrTomlLoadConfig indicates error: Failed to load toml config
errTomlLoadConfig = fmt.Errorf("failed to load toml config")
ErrTomlLoadConfig = fmt.Errorf("failed to load toml config")
// ErrNotPresent indicates error: Config file not present
ErrNotPresent = fmt.Errorf("config file not present")
)
Expand Down Expand Up @@ -59,7 +59,7 @@ func NewTerrascanConfigReader(fileName string) (*TerrascanConfigReader, error) {
data, err := ioutil.ReadFile(fileName)
if err != nil {
zap.S().Error("error loading config file", zap.Error(err))
return configReader, errTomlLoadConfig
return configReader, ErrTomlLoadConfig
}

if err = toml.Unmarshal(data, &configReader.config); err != nil {
Expand All @@ -69,26 +69,26 @@ func NewTerrascanConfigReader(fileName string) (*TerrascanConfigReader, error) {
}

// GetPolicyConfig will return the policy config from the terrascan config file
func (r TerrascanConfigReader) GetPolicyConfig() Policy {
func (r TerrascanConfigReader) getPolicyConfig() Policy {
return r.config.Policy
}

// GetNotifications will return the notifiers specified in the terrascan config file
func (r TerrascanConfigReader) GetNotifications() map[string]Notifier {
func (r TerrascanConfigReader) getNotifications() map[string]Notifier {
return r.config.Notifications
}

// GetRules will return the rules specified in the terrascan config file
func (r TerrascanConfigReader) GetRules() Rules {
func (r TerrascanConfigReader) getRules() Rules {
return r.config.Rules
}

// GetCategory will return the category specified in the terrascan config file
func (r TerrascanConfigReader) GetCategory() Category {
func (r TerrascanConfigReader) getCategory() Category {
return r.config.Category
}

// GetSeverity will return the level of severity specified in the terrascan config file
func (r TerrascanConfigReader) GetSeverity() Severity {
func (r TerrascanConfigReader) getSeverity() Severity {
return r.config.Severity
}
6 changes: 3 additions & 3 deletions pkg/config/config-reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ func TestNewTerrascanConfigReader(t *testing.T) {
},
}
testPolicy := Policy{
BasePath: "custom-path",
RepoPath: "rego-subdir",
BasePath: "custom-path",
RepoURL: "https://repository/url",
Branch: "branch-name",
}
Expand Down Expand Up @@ -167,8 +167,8 @@ func TestNewTerrascanConfigReader(t *testing.T) {
t.Errorf("NewTerrascanConfigReader() = got %v, want %v", got, tt.want)
}
if tt.assertGetters {
if !reflect.DeepEqual(got.GetPolicyConfig(), tt.Policy) || !reflect.DeepEqual(got.GetNotifications(), tt.notifications) || !reflect.DeepEqual(got.GetRules(), tt.Rules) {
t.Errorf("NewTerrascanConfigReader() = got config: %v, notifications: %v, rules: %v want config: %v, notifications: %v, rules: %v", got.GetPolicyConfig(), got.GetNotifications(), got.GetRules(), tt.Policy, tt.notifications, tt.Rules)
if !reflect.DeepEqual(got.getPolicyConfig(), tt.Policy) || !reflect.DeepEqual(got.getNotifications(), tt.notifications) || !reflect.DeepEqual(got.getRules(), tt.Rules) {
t.Errorf("NewTerrascanConfigReader() = got config: %v, notifications: %v, rules: %v want config: %v, notifications: %v, rules: %v", got.getPolicyConfig(), got.getNotifications(), got.getRules(), tt.Policy, tt.notifications, tt.Rules)
}
}
})
Expand Down
138 changes: 97 additions & 41 deletions pkg/config/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,87 +17,143 @@
package config

import (
"os"
"path/filepath"

"github.com/accurics/terrascan/pkg/utils"
"go.uber.org/zap"
)

const (
policyRepoURL = "https://github.com/accurics/terrascan.git"
policyBranch = "master"
configEnvvarName = "TERRASCAN_CONFIG"
policyConfigKey = "policy"
defaultPolicyRepoURL = "https://github.com/accurics/terrascan.git"
defaultPolicyBranch = "master"
)

var (
policyBasePath = filepath.Join(utils.GetHomeDir(), ".terrascan")
policyRepoPath = filepath.Join(policyBasePath, "pkg", "policies", "opa", "rego")
defaultPolicyRepoPath = filepath.Join("pkg", "policies", "opa", "rego")
defaultBasePolicyPath = filepath.Join(utils.GetHomeDir(), ".terrascan")
)

func init() {
// If the user specifies a config file in TERRASCAN_CONFIG,
// overwrite the defaults with the values from that file.
// Retain the defaults for members not specified in the file.
if err := LoadGlobalConfig(os.Getenv(configEnvvarName)); err != nil {
zap.S().Error("error while loading global config", zap.Error(err))
}
}

// LoadGlobalConfig loads policy configuration from specified configFile
// into var Global.Policy. Members of Global.Policy that are not specified
// in configFile will get default values
func LoadGlobalConfig(configFile string) error {
// Start with the defaults
Global.Policy = Policy{
BasePath: policyBasePath,
RepoPath: policyRepoPath,
RepoURL: policyRepoURL,
Branch: policyBranch,
global.Policy = Policy{
BasePath: defaultBasePolicyPath,
RepoPath: defaultPolicyRepoPath,
RepoURL: defaultPolicyRepoURL,
Branch: defaultPolicyBranch,
}

var configReader *TerrascanConfigReader
var err error

if configReader, err = NewTerrascanConfigReader(configFile); err != nil {
return err
}

if configFile != "" {
zap.S().Debugf("loading global config from: %s", configFile)
}

if configFile == "" {
zap.S().Debug("global config env variable is not specified")
return nil
if len(configReader.getPolicyConfig().BasePath) > 0 && len(configReader.getPolicyConfig().RepoPath) == 0 {
zap.S().Warnf("policy base path specified in configfile %s, but rego_subdir path not specified.", configFile)
}

configReader, err := NewTerrascanConfigReader(configFile)
if len(configReader.getPolicyConfig().RepoPath) > 0 && len(configReader.getPolicyConfig().BasePath) == 0 {
zap.S().Warnf("policy rego_subdir specified in configfile %s, but base path not specified.", configFile)
}

if len(configReader.getPolicyConfig().BasePath) > 0 {
global.BasePath = configReader.getPolicyConfig().BasePath
}

if len(configReader.getPolicyConfig().RepoPath) > 0 {
global.RepoPath = configReader.getPolicyConfig().RepoPath
}

absolutePolicyBasePath, absolutePolicyRepoPath, err := utils.GetAbsPolicyConfigPaths(GetPolicyBasePath(), GetPolicyRepoPath())
if err != nil {
zap.S().Error("error processing provided policy paths", zap.Error(err))
return err
}

if len(configReader.GetPolicyConfig().BasePath) > 0 {
Global.Policy.BasePath = configReader.GetPolicyConfig().BasePath
global.Policy.BasePath = absolutePolicyBasePath
global.Policy.RepoPath = absolutePolicyRepoPath

if len(configReader.getPolicyConfig().RepoURL) > 0 {
global.Policy.RepoURL = configReader.getPolicyConfig().RepoURL
}
if len(configReader.getPolicyConfig().Branch) > 0 {
global.Policy.Branch = configReader.getPolicyConfig().Branch
}

if len(configReader.getRules().ScanRules) > 0 {
global.Rules.ScanRules = configReader.getRules().ScanRules
}
if len(configReader.GetPolicyConfig().RepoPath) > 0 {
Global.Policy.RepoPath = configReader.GetPolicyConfig().RepoPath

if len(configReader.getRules().SkipRules) > 0 {
global.Rules.SkipRules = configReader.getRules().SkipRules
}
if len(configReader.GetPolicyConfig().RepoURL) > 0 {
Global.Policy.RepoURL = configReader.GetPolicyConfig().RepoURL

if len(configReader.getSeverity().Level) > 0 {
global.Severity.Level = configReader.getSeverity().Level
}
if len(configReader.GetPolicyConfig().Branch) > 0 {
Global.Policy.Branch = configReader.GetPolicyConfig().Branch

if len(configReader.getNotifications()) > 0 {
global.Notifications = configReader.getNotifications()
}

if len(configReader.getCategory().List) > 0 {
global.Category.List = configReader.getCategory().List
}

zap.S().Debugf("global config loaded")

return nil
}

// GetPolicyBasePath returns policy base path as set in global config
// GetPolicyBasePath returns the configured policy base path
func GetPolicyBasePath() string {
return Global.Policy.BasePath
return global.Policy.BasePath
}

// GetPolicyRepoPath return path to the policies repo locally downloaded
// GetPolicyRepoPath return the configured path to the policies repo locally downloaded
func GetPolicyRepoPath() string {
return Global.Policy.RepoPath
return global.Policy.RepoPath
}

// GetPolicyRepoURL returns policy repo url
// GetPolicyRepoURL returns the configured policy repo url
func GetPolicyRepoURL() string {
return Global.Policy.RepoURL
return global.Policy.RepoURL
}

// GetPolicyBranch returns policy repo url
// GetPolicyBranch returns the configured policy repo url
func GetPolicyBranch() string {
return Global.Policy.Branch
return global.Policy.Branch
}

// GetScanRules returns the configured scan rules
func GetScanRules() []string {
return global.Rules.ScanRules
}

// GetSkipRules returns the configured skips rules
func GetSkipRules() []string {
return global.Rules.SkipRules
}

// GetSeverityLevel returns the configured severity level
func GetSeverityLevel() string {
return global.Severity.Level
}

// GetCategoryList returns the configured list of category of violations
func GetCategoryList() []string {
return global.Category.List
}

// GetNotifications returns the configured notifier map
func GetNotifications() map[string]Notifier {
return global.Notifications
}
Loading

0 comments on commit eafa454

Please sign in to comment.