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

feat(terraform): Added Ignore lines by comments to terraform #4480

Merged
merged 1 commit into from
Nov 5, 2021
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
19 changes: 17 additions & 2 deletions pkg/engine/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,14 @@ func (c *Inspector) decodeQueryResults(ctx *QueryContext, results rego.ResultSet
if _, ok := c.excludeResults[vulnerability.SimilarityID]; ok {
log.Debug().
Msgf("Excluding result SimilarityID: %s", vulnerability.SimilarityID)
} else {
vulnerabilities = append(vulnerabilities, vulnerability)
continue
} else if checkComment(vulnerability.Line, file.LinesIgnore) {
log.Debug().
Msgf("Excluding result Comment: %s", vulnerability.SimilarityID)
continue
}

vulnerabilities = append(vulnerabilities, vulnerability)
}

if failedDetectLine {
Expand All @@ -360,6 +365,16 @@ func (c *Inspector) decodeQueryResults(ctx *QueryContext, results rego.ResultSet
return vulnerabilities, nil
}

// checkComment checks if the vulnerability should be skipped from comment
func checkComment(line int, ignoreLines []int) bool {
for _, ignoreLine := range ignoreLines {
if line == ignoreLine {
return true
}
}
return false
}

// contains is a simple method to check if a slice
// contains an entry
func contains(s []string, e string) bool {
Expand Down
50 changes: 36 additions & 14 deletions pkg/engine/inspector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,15 +363,15 @@ func TestNewInspector(t *testing.T) { // nolint
Query: "all_auth_users_get_read_access",
Content: string(contentByte),
InputData: "{}",
Platform: "cloudFormation",
Platform: "terraform",
Metadata: map[string]interface{}{
"id": "57b9893d-33b1-4419-bcea-b828fb87e318",
"queryName": "All Auth Users Get Read Access",
"severity": model.SeverityHigh,
"category": "Access Control",
"descriptionText": "Misconfigured S3 buckets can leak private information to the entire internet or allow unauthorized data tampering / deletion", // nolint
"descriptionUrl": "https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket#acl",
"platform": "CloudFormation",
"platform": "Terraform",
},
Aggregation: 1,
},
Expand Down Expand Up @@ -521,26 +521,18 @@ func TestEngine_LenQueriesByPlat(t *testing.T) {
{
name: "test_len_queries_plat",
args: args{
queriesPath: filepath.FromSlash("./assets/queries"),
queriesPath: filepath.FromSlash("./test/fixtures"),
platform: []string{"terraform"},
},
min: 100,
},
{
name: "test_len_queries_plat_dockerfile",
args: args{
queriesPath: filepath.FromSlash("./assets/queries"),
platform: []string{"dockerfile"},
},
min: 50,
min: 1,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ins := newInspectorInstance(t, tt.args.queriesPath)
got := ins.LenQueriesByPlat(tt.args.platform)
require.True(t, got > tt.min)
require.True(t, got >= tt.min)
})
}
}
Expand All @@ -560,7 +552,7 @@ func TestEngine_GetFailedQueries(t *testing.T) {
{
name: "test_get_failed_queries",
args: args{
queriesPath: filepath.FromSlash("./assets/queries"),
queriesPath: filepath.FromSlash("./test/fixtures"),
nrFailedQueries: 5,
},
},
Expand Down Expand Up @@ -696,3 +688,33 @@ func (m *mockSource) GetQueryLibrary(platform string) (source.RegoLibraries, err
LibraryInputData: "{}",
}, errGettingEmbeddedLibrary
}

func TestInspector_checkComment(t *testing.T) {
tests := []struct {
name string
lines []int
line int
want bool
}{
{
name: "test_checkComment_true",
lines: []int{1, 2, 3, 4, 5, 6},
line: 3,
want: true,
},
{
name: "test_checkComment_false",
lines: []int{1, 2, 3, 4, 5, 6},
line: 7,
want: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := checkComment(tt.line, tt.lines); got != tt.want {
t.Errorf("checkComment() = %v, want %v", got, tt.want)
}
})
}
}
14 changes: 7 additions & 7 deletions pkg/engine/source/filesystem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ func TestFilesystemSource_GetQueriesWithExclude(t *testing.T) { //nolint
"id": "57b9893d-33b1-4419-bcea-b828fb87e318",
"queryName": "All Auth Users Get Read Access",
"severity": model.SeverityHigh,
"platform": "CloudFormation",
"platform": "Terraform",
},
Platform: "cloudFormation",
Platform: "terraform",
Aggregation: 1,
},
},
Expand Down Expand Up @@ -219,9 +219,9 @@ func TestFilesystemSource_GetQueriesWithInclude(t *testing.T) {
"id": "57b9893d-33b1-4419-bcea-b828fb87e318",
"queryName": "All Auth Users Get Read Access",
"severity": model.SeverityHigh,
"platform": "CloudFormation",
"platform": "Terraform",
},
Platform: "cloudFormation",
Platform: "terraform",
Aggregation: 1,
},
},
Expand Down Expand Up @@ -433,9 +433,9 @@ func TestFilesystemSource_GetQueries(t *testing.T) {
"id": "57b9893d-33b1-4419-bcea-b828fb87e318",
"queryName": "All Auth Users Get Read Access",
"severity": model.SeverityHigh,
"platform": "CloudFormation",
"platform": "Terraform",
},
Platform: "cloudFormation",
Platform: "terraform",
Aggregation: 1,
},
},
Expand Down Expand Up @@ -511,7 +511,7 @@ func Test_ReadMetadata(t *testing.T) {
"id": "<ID>",
"queryName": "<QUERY_NAME>",
"severity": model.SeverityHigh,
"platform": "<PLATFORM>",
"platform": "Dockerfile",
"aggregation": float64(1),
},
wantErr: false,
Expand Down
1 change: 1 addition & 0 deletions pkg/kics/sink.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ func (s *Service) sink(ctx context.Context, filename, scanID string, rc io.Reade
Kind: documents.Kind,
FilePath: filename,
Commands: fileCommands,
LinesIgnore: documents.IgnoreLines,
}
s.saveToFile(ctx, &file)
}
Expand Down
17 changes: 17 additions & 0 deletions pkg/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package model

import (
"regexp"
"sort"
"strings"

Expand All @@ -19,6 +20,13 @@ const (
KindHELM FileKind = "HELM"
)

// Constants to describe commands given from comments
const (
IgnoreLine CommentCommand = "ignore-line"
IgnoreBlock CommentCommand = "ignore-block"
IgnoreComment CommentCommand = "ignore-comment"
)

// Constants to describe vulnerability's severity
const (
SeverityHigh = "HIGH"
Expand Down Expand Up @@ -52,6 +60,11 @@ var (
}
)

var (
// KICSCommentRgxp is the regexp to identify if a comment is a KICS comment
KICSCommentRgxp = regexp.MustCompile(`^((/{2})|#)\s*kics\s*`)
)

// Version - is the model for the version response
type Version struct {
Latest bool `json:"is_latest"`
Expand All @@ -65,6 +78,9 @@ type VulnerabilityLines struct {
LineWithVulnerabilty string
}

// CommentCommand represents a command given from a comment
type CommentCommand string

// FileKind is the extension of a file
type FileKind string

Expand Down Expand Up @@ -103,6 +119,7 @@ type FileMetadata struct {
HelmID string
IDInfo map[int]interface{}
Commands CommentsCommands
LinesIgnore []int
}

// QueryMetadata is a representation of general information about a query
Expand Down
10 changes: 5 additions & 5 deletions pkg/parser/docker/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ func (p *Parser) Resolve(fileContent []byte, filename string) (*[]byte, error) {
}

// Parse - parses dockerfile to Json
func (p *Parser) Parse(_ string, fileContent []byte) ([]model.Document, error) {
func (p *Parser) Parse(_ string, fileContent []byte) ([]model.Document, []int, error) {
var documents []model.Document
reader := bytes.NewReader(fileContent)

parsed, err := parser.Parse(reader)
if err != nil {
return nil, errors.Wrap(err, "failed to parse Dockerfile")
return nil, []int{}, errors.Wrap(err, "failed to parse Dockerfile")
}

fromValue := "args"
Expand Down Expand Up @@ -82,16 +82,16 @@ func (p *Parser) Parse(_ string, fileContent []byte) ([]model.Document, error) {

j, err := json.Marshal(resource)
if err != nil {
return nil, errors.Wrap(err, "failed to Marshal Dockerfile")
return nil, []int{}, errors.Wrap(err, "failed to Marshal Dockerfile")
}

if err := json.Unmarshal(j, &doc); err != nil {
return nil, errors.Wrap(err, "failed to Unmarshal Dockerfile")
return nil, []int{}, errors.Wrap(err, "failed to Unmarshal Dockerfile")
}

documents = append(documents, *doc)

return documents, nil
return documents, []int{}, nil
}

// GetKind returns the kind of the parser
Expand Down
2 changes: 1 addition & 1 deletion pkg/parser/docker/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func TestParser_Parse(t *testing.T) {
}

for idx, sampleFile := range sample {
doc, err := p.Parse("Dockerfile", []byte(sampleFile))
doc, _, err := p.Parse("Dockerfile", []byte(sampleFile))
switch idx {
case 0:
require.NoError(t, err)
Expand Down
8 changes: 4 additions & 4 deletions pkg/parser/json/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ func (p *Parser) Resolve(fileContent []byte, filename string) (*[]byte, error) {
}

// Parse parses json file and returns it as a Document
func (p *Parser) Parse(_ string, fileContent []byte) ([]model.Document, error) {
func (p *Parser) Parse(_ string, fileContent []byte) ([]model.Document, []int, error) {
r := model.Document{}
err := json.Unmarshal(fileContent, &r)
if err != nil {
r := []model.Document{}
err = json.Unmarshal(fileContent, &r)
return r, err
return r, []int{}, err
}

jLine := initializeJSONLine(fileContent)
Expand All @@ -34,12 +34,12 @@ func (p *Parser) Parse(_ string, fileContent []byte) ([]model.Document, error) {
kicsPlan, err := parseTFPlan(kicsJSON)
if err != nil {
// JSON is not a tf plan
return []model.Document{kicsJSON}, nil
return []model.Document{kicsJSON}, []int{}, nil
}

p.shouldIdent = true

return []model.Document{kicsPlan}, nil
return []model.Document{kicsPlan}, []int{}, nil
}

// SupportedExtensions returns extensions supported by this parser, which is json extension
Expand Down
2 changes: 1 addition & 1 deletion pkg/parser/json/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestParser_SupportedTypes(t *testing.T) {
func TestParser_Parse(t *testing.T) {
p := &Parser{}

doc, err := p.Parse("test.json", []byte(have))
doc, _, err := p.Parse("test.json", []byte(have))
require.NoError(t, err)
require.Len(t, doc, 1)
require.Contains(t, doc[0], "martin")
Expand Down
25 changes: 14 additions & 11 deletions pkg/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type kindParser interface {
GetCommentToken() string
SupportedExtensions() []string
SupportedTypes() []string
Parse(filePath string, fileContent []byte) ([]model.Document, error)
Parse(filePath string, fileContent []byte) ([]model.Document, []int, error)
Resolve(fileContent []byte, filename string) (*[]byte, error)
StringifyContent(content []byte) (string, error)
}
Expand Down Expand Up @@ -71,9 +71,10 @@ type Parser struct {

// ParsedDocument is a struct containing data retrieved from parsing
type ParsedDocument struct {
Docs []model.Document
Kind model.FileKind
Content string
Docs []model.Document
Kind model.FileKind
Content string
IgnoreLines []int
}

// CommentsCommands gets commands on comments in the file beginning, before the code starts
Expand Down Expand Up @@ -115,7 +116,7 @@ func (c *Parser) Parse(filePath string, fileContent []byte) (ParsedDocument, err
if err != nil {
return ParsedDocument{}, err
}
obj, err := c.parsers.Parse(filePath, *resolved)
obj, igLines, err := c.parsers.Parse(filePath, *resolved)
if err != nil {
return ParsedDocument{}, err
}
Expand All @@ -127,15 +128,17 @@ func (c *Parser) Parse(filePath string, fileContent []byte) (ParsedDocument, err
}

return ParsedDocument{
Docs: obj,
Kind: c.parsers.GetKind(),
Content: cont,
Docs: obj,
Kind: c.parsers.GetKind(),
Content: cont,
IgnoreLines: igLines,
}, nil
}
return ParsedDocument{
Docs: nil,
Kind: "break",
Content: "",
Docs: nil,
Kind: "break",
Content: "",
IgnoreLines: []int{},
}, ErrNotSupportedFile
}

Expand Down
Loading