Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Unit test coverage for Kustomize V3 Iac-provider #399

Merged
merged 1 commit into from
Dec 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ require (
github.com/zclconf/go-cty v1.2.1
go.uber.org/zap v1.13.0
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/tools v0.0.0-20201113202037-1643af1435f3 // indirect
golang.org/x/tools v0.0.0-20201201064407-fd09bd90d85c // indirect
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
helm.sh/helm/v3 v3.4.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,10 @@ golang.org/x/tools v0.0.0-20201113164040-559c4acc06b6 h1:LTVgvEdikVZCooj7814/UBp
golang.org/x/tools v0.0.0-20201113164040-559c4acc06b6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201113202037-1643af1435f3 h1:7R7+wzd5VuLvCNyHZ/MG511kkoP/DBEzkbh8qUsFbY8=
golang.org/x/tools v0.0.0-20201113202037-1643af1435f3/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb h1:z5+u0pkAUPUWd3taoTialQ2JAMo4Wo1Z3L25U4ZV9r0=
golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201064407-fd09bd90d85c h1:D/mVYXCk6gUcyr7WuGlAk/ShHqgARUXc2VQxo27Hmws=
golang.org/x/tools v0.0.0-20201201064407-fd09bd90d85c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
19 changes: 12 additions & 7 deletions pkg/iac-providers/kustomize/v3/load-dir.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package kustomizev3

import (
"errors"
"fmt"
"path/filepath"

Expand All @@ -17,6 +16,12 @@ const (
kustomizedirectory string = "kustomization"
)

var (
errorKustomizeNotFound = fmt.Errorf("kustomization.y(a)ml file not found in the directory")
errorMultipleKustomizeFile = fmt.Errorf("multiple kustomization.y(a)ml found in the directory")
errorFromKustomize = fmt.Errorf("error from kustomization")
)

// LoadIacDir loads the kustomize directory and returns the ResourceConfig mapping which is evaluated by the policy engine
func (k *KustomizeV3) LoadIacDir(absRootDir string) (output.AllResourceConfigs, error) {

Expand All @@ -29,23 +34,23 @@ func (k *KustomizeV3) LoadIacDir(absRootDir string) (output.AllResourceConfigs,
}

if len(files) == 0 {
err = errors.New("could not find a kustomization.yaml/yml file in the directory")
err = errorKustomizeNotFound
zap.S().Error("error while searching for iac files", zap.String("root dir", absRootDir), zap.Error(err))
return allResourcesConfig, err
}

if len(files) > 1 {
err = errors.New("a directory cannot have more than 1 kustomization.yaml/yml file")
err = errorMultipleKustomizeFile
zap.S().Error("error while searching for iac files", zap.String("root dir", absRootDir), zap.Error(err))
return allResourcesConfig, err
}

kustomizeFileName := *files[0]
yamlkustomizeobj, err := utils.ReadYamlFile(filepath.Join(absRootDir, kustomizeFileName))

if len(yamlkustomizeobj) == 0 {
err = fmt.Errorf("unable to read any kustomization file in the directory : %v", err)
zap.S().Error("error while searching for iac files", zap.String("root dir", absRootDir), zap.Error(err))
if err != nil {
err = fmt.Errorf("unable to read the kustomization file in the directory : %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend to move the error definitions into a variable that can be referenced easily by unit tests

zap.S().Error("error while reading the file", kustomizeFileName, zap.Error(err))
return allResourcesConfig, err
}

Expand Down Expand Up @@ -94,7 +99,7 @@ func LoadKustomize(basepath, filename string) ([]*utils.IacDocument, error) {

m, err := k.Run(basepath)
if err != nil {
return nil, err
return nil, errorFromKustomize
}

yaml, err := m.AsYaml()
Expand Down
183 changes: 183 additions & 0 deletions pkg/iac-providers/kustomize/v3/load-dir_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package kustomizev3

import (
"fmt"
"os"
"reflect"
"syscall"
"testing"

"github.com/accurics/terrascan/pkg/iac-providers/output"
"github.com/accurics/terrascan/pkg/utils"
)

var errorReadKustomize = fmt.Errorf("unable to read the kustomization file in the directory : %s", utils.ErrYamlFileEmpty.Error())

func TestLoadIacDir(t *testing.T) {

table := []struct {
name string
dirPath string
kustomize KustomizeV3
want output.AllResourceConfigs
wantErr error
resourceCount int
}{
{
name: "invalid dirPath",
dirPath: "not-there",
kustomize: KustomizeV3{},
wantErr: &os.PathError{Err: syscall.ENOENT, Op: "open", Path: "not-there"},
resourceCount: 0,
},
{
name: "simple-deployment",
dirPath: "./testdata/simple-deployment",
kustomize: KustomizeV3{},
wantErr: nil,
resourceCount: 4,
},
{
name: "multibases",
dirPath: "./testdata/multibases/base",
kustomize: KustomizeV3{},
wantErr: nil,
resourceCount: 2,
},
{
name: "multibases",
dirPath: "./testdata/multibases/dev",
kustomize: KustomizeV3{},
wantErr: nil,
resourceCount: 2,
},
{
name: "multibases",
dirPath: "./testdata/multibases/prod",
kustomize: KustomizeV3{},
wantErr: nil,
resourceCount: 2,
},

{
name: "multibases",
dirPath: "./testdata/multibases/stage",
kustomize: KustomizeV3{},
wantErr: nil,
resourceCount: 2,
},
{
name: "multibases",
dirPath: "./testdata/multibases",
kustomize: KustomizeV3{},
wantErr: nil,
resourceCount: 4,
},
{
name: "no-kustomize-directory",
dirPath: "./testdata/no-kustomizefile",
kustomize: KustomizeV3{},
wantErr: errorKustomizeNotFound,
resourceCount: 0,
},
{
name: "kustomize-file-empty",
dirPath: "./testdata/kustomize-file-empty",
kustomize: KustomizeV3{},
wantErr: errorReadKustomize,
resourceCount: 0,
},
}

for _, tt := range table {
t.Run(tt.name, func(t *testing.T) {
resourceMap, gotErr := tt.kustomize.LoadIacDir(tt.dirPath)
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
}

resCount := utils.GetResourceCount(resourceMap)
if resCount != tt.resourceCount {
t.Errorf("resource count (%d) does not match expected (%d)", resCount, tt.resourceCount)
}
})
}

}

func TestLoadKustomize(t *testing.T) {
kustomizeYaml := "kustomization.yaml"
kustomizeYml := "kustomization.yml"

table := []struct {
name string
basepath string
filename string
want output.AllResourceConfigs
wantErr error
}{
{
name: "simple-deployment",
basepath: "./testdata/simple-deployment",
filename: kustomizeYaml,
wantErr: nil,
},
{
name: "multibases",
basepath: "./testdata/multibases",
filename: kustomizeYaml,
wantErr: nil,
},
{
name: "multibases/base",
basepath: "./testdata/multibases/base",
filename: kustomizeYml,
wantErr: nil,
},
{
name: "multibases/dev",
basepath: "./testdata/multibases/dev",
filename: kustomizeYaml,
wantErr: nil,
},
{
name: "multibases/prod",
basepath: "./testdata/multibases/prod",
filename: kustomizeYaml,
wantErr: nil,
},
{
name: "multibases/stage",
basepath: "./testdata/multibases/stage",
filename: kustomizeYaml,
wantErr: nil,
},
{
name: "multibases/zero-violation-base",
basepath: "./testdata/multibases/zero-violation-base",
filename: kustomizeYaml,
wantErr: nil,
},
{
name: "erroneous-pod",
basepath: "./testdata/erroneous-pod",
filename: kustomizeYaml,
wantErr: errorFromKustomize,
},
{
name: "erroneous-deployment",
basepath: "./testdata/erroneous-deployment/",
filename: kustomizeYaml,
wantErr: errorFromKustomize,
},
}

for _, tt := range table {
t.Run(tt.name, func(t *testing.T) {
_, gotErr := LoadKustomize(tt.basepath, tt.filename)
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
}
})
}
}
38 changes: 38 additions & 0 deletions pkg/iac-providers/kustomize/v3/load-file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package kustomizev3

import (
"reflect"
"testing"

"github.com/accurics/terrascan/pkg/iac-providers/output"
)

func TestLoadIacFile(t *testing.T) {

table := []struct {
name string
filePath string
kustomize KustomizeV3
typeOnly bool
want output.AllResourceConfigs
wantErr error
}{
{
name: "load iac file is not supported for kustomize",
filePath: "/dummyfilepath.yaml",
kustomize: KustomizeV3{},
wantErr: errLoadIacFileNotSupported,
},
}

for _, tt := range table {
t.Run(tt.name, func(t *testing.T) {
_, gotErr := tt.kustomize.LoadIacFile(tt.filePath)
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
} else if tt.typeOnly && (reflect.TypeOf(gotErr)) != reflect.TypeOf(tt.wantErr) {
t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", reflect.TypeOf(gotErr), reflect.TypeOf(tt.wantErr))
}
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: apps/v1beta1
kind: Deployment
metadata:
labels:
app: myapp
test: someupdate
test2: someupdate3
spec:
template:
spec:
containers:
- name: myapp-container2
image: busybox
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
securityContext:
allowPrivilegeEscalation: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
commonLabels:
app: hello

resources:
- deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
commonLabels:
app: hello

resources:
- pod.yaml
14 changes: 14 additions & 0 deletions pkg/iac-providers/kustomize/v3/testdata/erroneous-pod/pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
metadata:
name: myapp-pod
labels:
app: myapp
test: someupdate
test2: someupdate3
spec:
containers:
- name: myapp-container
image: busybox
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
securityContext:
allowPrivilegeEscalation: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: the-map
data:
altGreeting: "Good Morning!"
enableRisky: "false"
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: the-deployment
spec:
replicas: 3
selector:
matchLabels:
deployment: hello
template:
metadata:
labels:
deployment: hello
spec:
containers:
- name: the-container
image: monopole/hello:1
command: ["/hello",
"--port=8080",
"--enableRiskyFeature=$(ENABLE_RISKY)"]
ports:
- containerPort: 8080
env:
- name: ALT_GREETING
valueFrom:
configMapKeyRef:
name: the-map
key: altGreeting
- name: ENABLE_RISKY
valueFrom:
configMapKeyRef:
name: the-map
key: enableRisky
Loading