Skip to content

Commit

Permalink
code nits: added comments and renamed config struct name
Browse files Browse the repository at this point in the history
  • Loading branch information
Rchanger committed Jul 15, 2021
1 parent fb684e0 commit ac64ef9
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 18 deletions.
1 change: 1 addition & 0 deletions pkg/iac-providers/docker/v1/load-dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (dc *DockerV1) LoadIacDir(absRootDir string, nonRecursive bool) (output.All

allResourcesConfig := make(map[string][]output.ResourceConfig)

// find all the files in the folder with name `Dockerfile`
fileMap, err := utils.FindFilesBySuffix(absRootDir, []string{DockerFileName})
if err != nil {
zap.S().Errorf("error while searching for iac files", zap.String("root dir", absRootDir), zap.Error(err))
Expand Down
29 changes: 28 additions & 1 deletion pkg/iac-providers/docker/v1/load-dir_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"os"
"path/filepath"
"reflect"
"syscall"
"testing"

Expand Down Expand Up @@ -68,15 +69,41 @@ func TestLoadIacDir(t *testing.T) {
dockerV1: DockerV1{},
wantErr: multierror.Append(errors.New(errString)),
},
{
name: "valid dirPath having dockerfile with in-file instrumentation",
dirPath: filepath.Join(testDataDir, "valid-directory-with-in-file-instrumentation"),
dockerV1: DockerV1{},
want: output.AllResourceConfigs{
"cmd": []output.ResourceConfig{
{ID: "cmd.55ceacedc5f1c0df6951723a7401a74e",
Name: "Dockerfile",
ModuleName: "",
Source: "Dockerfile",
PlanRoot: "", Line: 5,
Type: "cmd",
Config: "server",
SkipRules: []output.SkipRule{{Rule: "AWS.S3Bucket.DS.High.1041",
Comment: "This rule does not belong to dockerfile will add correct once dockerfile policy added."}},
MaxSeverity: "None",
MinSeverity: "High"}},
"docker": []output.ResourceConfig{{ID: "docker.96052d48e5364a05995aaec1e5d53f2d", Name: "Dockerfile", ModuleName: "", Source: "Dockerfile", PlanRoot: "", Line: 1, Type: "dockerfile", Config: []string{"from", "cmd"}, SkipRules: []output.SkipRule{{Rule: "AWS.S3Bucket.DS.High.1041", Comment: "This rule does not belong to dockerfile will add correct once dockerfile policy added."}}, MaxSeverity: "None", MinSeverity: "High"}},
"from": []output.ResourceConfig{{ID: "from.68be487d8ad02b4e09b46d29c8dbef3b", Name: "Dockerfile", ModuleName: "", Source: "Dockerfile", PlanRoot: "", Line: 1, Type: "from", Config: "runatlantis/atlantis:v0.16.1", SkipRules: []output.SkipRule{{Rule: "AWS.S3Bucket.DS.High.1041", Comment: "This rule does not belong to dockerfile will add correct once dockerfile policy added."}}, MaxSeverity: "None", MinSeverity: "High"}}},
wantErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

_, gotErr := tt.dockerV1.LoadIacDir(tt.dirPath, false)
got, gotErr := tt.dockerV1.LoadIacDir(tt.dirPath, false)
me, ok := gotErr.(*multierror.Error)
if !ok {
t.Errorf("expected multierror.Error, got %T", gotErr)
}
if tt.want != nil {
if got == nil || !reflect.DeepEqual(got, tt.want) {
t.Errorf("unexpected result; got: '%#v', want: '%v'", got, tt.want)
}
}
if tt.wantErr == nil {
if err := me.ErrorOrNil(); err != nil {
t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr)
Expand Down
19 changes: 15 additions & 4 deletions pkg/iac-providers/docker/v1/load-file.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,33 @@ import (
const (
dockerDirectory string = "docker"
resourceTypeDockerfile string = "dockerfile"

// IDConnectorString is string connector used in id creation
IDConnectorString string = "."
)

// LoadIacFile loads the docker file specified
// LoadIacFile loads the docker file specified and create ResourceConfig for each dockerfile
func (dc *DockerV1) LoadIacFile(absFilePath string) (allResourcesConfig output.AllResourceConfigs, err error) {
allResourcesConfig = make(map[string][]output.ResourceConfig)

data, comments, err := dc.Parse(absFilePath)
if err != nil {
errMsg := fmt.Sprintf("error while parsing file %s, error: %v", absFilePath, err)
zap.S().Errorf("error while parsing file %s", absFilePath, err)
errMsg := fmt.Sprintf("error while parsing dockerfile %s, error: %v", absFilePath, err)
zap.S().Errorf("error while parsing dockerfile %s", absFilePath, err)
return allResourcesConfig, errors.New(errMsg)
}

minSeverity, maxSeverity := utils.GetMinMaxSeverity(comments)

skipRules := utils.GetSkipRules(comments)

// create an array of all the instructions present in the docker file
dockerCommand := []string{}

// create config for each instruction of dockerfile
for i := 0; i < len(data); i++ {
dockerCommand = append(dockerCommand, data[i].Cmd)

config := output.ResourceConfig{
Name: filepath.Base(absFilePath),
Type: data[i].Cmd,
Expand All @@ -67,7 +75,9 @@ func (dc *DockerV1) LoadIacFile(absFilePath string) (allResourcesConfig output.A

}

// creates config for entire dockerfile
// Creates config for entire dockerfile which has array of instructions against the Config field.
// Created to use against policies which checks for availablility of command/instruction in dockerfile
// if command is not present line no also doesnot have any importance thats why set to 1.
config := output.ResourceConfig{
Name: filepath.Base(absFilePath),
Type: resourceTypeDockerfile,
Expand Down Expand Up @@ -101,6 +111,7 @@ func (dc *DockerV1) getSourceRelativePath(sourceFile string) string {
}

// GetresourceIdforDockerfile Generates hash of the string to be used as the reference id for docker file
// added line no in creating hash because dockerfile may have same command multiple times with same value
func GetresourceIdforDockerfile(filepath string, value string, lineNumber int) (referenceID string) {
hasher := md5.New()
hasher.Write([]byte(filepath + value + strconv.Itoa(lineNumber)))
Expand Down
2 changes: 1 addition & 1 deletion pkg/iac-providers/docker/v1/load-file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestLoadIacFile(t *testing.T) {
name: "empty config file",
absFilePath: filepath.Join(fileTestDataDir, "Dockerfile"),
dockerV1: DockerV1{},
wantErr: fmt.Errorf("error while parsing file %s, error: file with no instructions", filepath.Join(fileTestDataDir, "Dockerfile")),
wantErr: fmt.Errorf("error while parsing dockerfile %s, error: file with no instructions", filepath.Join(fileTestDataDir, "Dockerfile")),
},
{
name: "valid docker file",
Expand Down
24 changes: 15 additions & 9 deletions pkg/iac-providers/docker/v1/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
"go.uber.org/zap"
)

// ResourceConfig holds information about individual docker instructions
type ResourceConfig struct {
// DockerConfig holds information about individual docker instructions
type DockerConfig struct {
Cmd string `json:"cmd"`
Value string `json:"value"`
Line int `json:"line"`
Expand All @@ -45,38 +45,44 @@ func (dc *DockerV1) ValidateInstruction(node *parser.Node) error {
return err
}

// Parse parses the given dockerfile and gives docker config.
func (dc *DockerV1) Parse(filepath string) ([]ResourceConfig, string, error) {
config := []ResourceConfig{}
// Parse parses the given dockerfile and gives docker config and string of comments present in dockerfile.
func (dc *DockerV1) Parse(filepath string) ([]DockerConfig, string, error) {
config := []DockerConfig{}
comments := ""

data, err := ioutil.ReadFile(filepath)
if err != nil {
zap.S().Error("error loading docker file", filepath, zap.Error(err))
return []ResourceConfig{}, "", err
return config, "", err
}
r := bytes.NewReader(data)
res, err := parser.Parse(r)
if err != nil {
zap.S().Errorf("error while parsing iac file", filepath, zap.Error(err))
return []ResourceConfig{}, "", err
return config, "", err
}

for _, child := range res.AST.Children {
values := []string{}
err = dc.ValidateInstruction(child)
if err != nil {
return []ResourceConfig{}, "", err
return config, "", err
}

// loop over all the comments before the instruction is found to create one single string of comments
// appending # prefix and new line since it is removed by the parser while creating the AST
// Purpose of adding them back is to use the comman function to find skiprules and min max severity.
for _, comment := range child.PrevComment {
comments = comments + commentPrefix + comment + newLine
}

for i := child.Next; i != nil; i = i.Next {
values = append(values, i.Value)
}

value := strings.Join(values, stringJoinCharacter)
tempConfig := ResourceConfig{

tempConfig := DockerConfig{
Cmd: child.Value,
Value: value,
Line: child.StartLine,
Expand Down
6 changes: 3 additions & 3 deletions pkg/iac-providers/docker/v1/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ func TestParse(t *testing.T) {
name string
filePath string
dockerv1 DockerV1
want []ResourceConfig
want []DockerConfig
wantErr error
}{
{
name: "valid docker file",
filePath: filepath.Join(fileTestDataDir, "dockerfile-testparse-function"),
dockerv1: DockerV1{},
wantErr: nil,
want: []ResourceConfig{{Cmd: "from", Value: "runatlantis/atlantis:v0.16.1", Line: 1}, {Cmd: "maintainer", Value: "accurics", Line: 2}, {Cmd: "label", Value: "key \"value\"", Line: 3}, {Cmd: "workdir", Value: "test", Line: 4}, {Cmd: "env", Value: "DEFAULT_TERRASCAN_VERSION 1.5.1", Line: 5}, {Cmd: "env", Value: "PLANFILE tfplan", Line: 6}, {Cmd: "add", Value: "setup.sh terrascan.sh launch-atlantis.sh entrypoint.sh /usr/local/bin/", Line: 7}, {Cmd: "run", Value: "mkdir -p /etc/atlantis/ && chmod +x /usr/local/bin/*.sh && /usr/local/bin/setup.sh", Line: 8}, {Cmd: "copy", Value: "terrascan-workflow.yaml /etc/atlantis/workflow.yaml", Line: 11}, {Cmd: "user", Value: "atlantis", Line: 13}, {Cmd: "arg", Value: "name=defaultValue", Line: 14}, {Cmd: "run", Value: "terrascan init", Line: 15}, {Cmd: "volume", Value: "/temp", Line: 16}, {Cmd: "healthcheck", Value: "CMD executable", Line: 17}, {Cmd: "entrypoint", Value: "/bin/bash entrypoint.sh", Line: 18}, {Cmd: "shell", Value: "cd", Line: 19}, {Cmd: "onbuild", Value: "", Line: 20}, {Cmd: "expose", Value: "9090", Line: 21}, {Cmd: "stopsignal", Value: "1", Line: 22}, {Cmd: "cmd", Value: "server", Line: 23}},
want: []DockerConfig{{Cmd: "from", Value: "runatlantis/atlantis:v0.16.1", Line: 1}, {Cmd: "maintainer", Value: "accurics", Line: 2}, {Cmd: "label", Value: "key \"value\"", Line: 3}, {Cmd: "workdir", Value: "test", Line: 4}, {Cmd: "env", Value: "DEFAULT_TERRASCAN_VERSION 1.5.1", Line: 5}, {Cmd: "env", Value: "PLANFILE tfplan", Line: 6}, {Cmd: "add", Value: "setup.sh terrascan.sh launch-atlantis.sh entrypoint.sh /usr/local/bin/", Line: 7}, {Cmd: "run", Value: "mkdir -p /etc/atlantis/ && chmod +x /usr/local/bin/*.sh && /usr/local/bin/setup.sh", Line: 8}, {Cmd: "copy", Value: "terrascan-workflow.yaml /etc/atlantis/workflow.yaml", Line: 11}, {Cmd: "user", Value: "atlantis", Line: 13}, {Cmd: "arg", Value: "name=defaultValue", Line: 14}, {Cmd: "run", Value: "terrascan init", Line: 15}, {Cmd: "volume", Value: "/temp", Line: 16}, {Cmd: "healthcheck", Value: "CMD executable", Line: 17}, {Cmd: "entrypoint", Value: "/bin/bash entrypoint.sh", Line: 18}, {Cmd: "shell", Value: "cd", Line: 19}, {Cmd: "onbuild", Value: "", Line: 20}, {Cmd: "expose", Value: "9090", Line: 21}, {Cmd: "stopsignal", Value: "1", Line: 22}, {Cmd: "cmd", Value: "server", Line: 23}},
},
{
name: "invalid docker file path",
filePath: filepath.Join(fileTestDataDir, "dockerfile-testparse-function1"),
dockerv1: DockerV1{},
want: []ResourceConfig{},
want: []DockerConfig{},
wantErr: fmt.Errorf("open %s: no such file or directory", filepath.Join(fileTestDataDir, "dockerfile-testparse-function1")),
},
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM runatlantis/atlantis:v0.16.1
#ts:minseverity=High
#ts:maxseverity=None
#ts:skip=AWS.S3Bucket.DS.High.1041 This rule does not belong to dockerfile will add correct once dockerfile policy added.
CMD ["server"]
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
FROM runatlantis/atlantis:v0.16.1
#ts:minseverity=High
#ts:maxseverity=None
#ts:skip=AWS.S3Bucket.DS.High.1041 This rule does not belong to dockerfile will add correct once dockerfile policy added.\n"
ENV DEFAULT_TERRASCAN_VERSION=1.5.1
ENV PLANFILE tfplan
ADD setup.sh terrascan.sh launch-atlantis.sh entrypoint.sh /usr/local/bin/
Expand Down

0 comments on commit ac64ef9

Please sign in to comment.