Skip to content

Commit

Permalink
Skip Comment Feature (#530)
Browse files Browse the repository at this point in the history
* Added option to bypass automatic tagging by adding  comment above specific resources.

* Fix of UT

* Fix integration and go-lint tests

* Fix integration_test and go-lint tests 2

* fix integration test3

* Fix integration_test and lint4

* "Another way to implement skipping  resources tagging  by comments"

* Fix integration_test5

* Fix integration_test6

* Fix integration_test6

* Fix integration_test7

* Another way to solve the issue

* Fix UT

* readme file and fixing code review

* Feature skip resource by comment

* Fix the golint

* Fix golint

* Fix security

* Update src/terraform/structure/terraform_parser.go

---------

Co-authored-by: ChanochShayner <[email protected]>
  • Loading branch information
chanaMovshowich and ChanochShayner authored Jun 30, 2024
1 parent c6a0b50 commit 20ec9a6
Show file tree
Hide file tree
Showing 27 changed files with 479 additions and 76 deletions.
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,55 @@ yor list-tags
yor list-tags --tag-groups git
```

## Supporting comment format
To prevent resource from being tagged, apply the following comment pattern above the resource, currently supported only in Terraform and CloudFormation files.

## Example

# skip specific resource - #yor:skip
```sh
## for terraform files
#yor:Skip
resource "aws_instance" "example_instance" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
subnet_id = aws_subnet.example_subnet.id }
## for cloudformation files
#yor:skip
ExampleInt:
Type: AWS::Lambda::Function
Properties:
Description: An example template
```

# skip all rsources in the page - #yor:skipAll
```sh
## for terraform files
#yor:skipAll
resource "aws_vpc" "example_vpc" {
cidr_block = "10.0.0.0/16" }
resource "aws_subnet" "example_subnet" {
vpc_id = aws_vpc.example_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-west-1a" }
## for cloudformation files
#yor:skipAll
Resources:
NewVolume:
Type: AWS::EC2::Volume
Properties:
Size: 100
NewVolume2:
Type: AWS::EC2::Volume
Tags:
- Key: MyTag
Value: TagValue
- Key: Name
```
### What is Yor trace?
yor_trace is a magical tag creating a unique identifier for an IaC resource code block.

Expand Down
8 changes: 7 additions & 1 deletion src/cloudformation/structure/cloudformation_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
type CloudformationParser struct {
*types.YamlParser
*types.JSONParser
skippedByCommentList []string
}

const TagsAttributeName = "Tags"
Expand Down Expand Up @@ -113,6 +114,7 @@ func goformationParse(file string) (*cloudformation.Template, error) {
}

func (p *CloudformationParser) ParseFile(filePath string) ([]structure.IBlock, error) {
var skipResourcesByComment []string
goformationLock.Lock()
template, err := goformationParse(filePath)
goformationLock.Unlock()
Expand All @@ -138,7 +140,8 @@ func (p *CloudformationParser) ParseFile(filePath string) ([]structure.IBlock, e
var resourceNamesToLines map[string]*structure.Lines
switch utils.GetFileFormat(filePath) {
case common.YmlFileType.FileFormat, common.YamlFileType.FileFormat:
resourceNamesToLines = yaml.MapResourcesLineYAML(filePath, resourceNames, ResourcesStartToken)
resourceNamesToLines, skipResourcesByComment = yaml.MapResourcesLineYAML(filePath, resourceNames, ResourcesStartToken)
p.skippedByCommentList = append(p.skippedByCommentList, skipResourcesByComment...)
case common.JSONFileType.FileFormat:
var fileBracketsMapping map[int]json.BracketPair
resourceNamesToLines, fileBracketsMapping = json.MapResourcesLineJSON(filePath, resourceNames)
Expand Down Expand Up @@ -293,3 +296,6 @@ func (p *CloudformationParser) getTagsLines(filePath string, resourceLinesRange
return structure.Lines{Start: -1, End: -1}
}
}
func (p *CloudformationParser) GetSkipResourcesByComment() []string {
return p.skippedByCommentList
}
4 changes: 2 additions & 2 deletions src/cloudformation/structure/cloudformation_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func Test_mapResourcesLineYAML(t *testing.T) {
expected := map[string]*structure.Lines{
"NewVolume": {Start: 3, End: 15},
}
actual := yaml.MapResourcesLineYAML(filePath, resourcesNames, ResourcesStartToken)
actual, _ := yaml.MapResourcesLineYAML(filePath, resourcesNames, ResourcesStartToken)
compareLines(t, expected, actual)
})

Expand All @@ -136,7 +136,7 @@ func Test_mapResourcesLineYAML(t *testing.T) {
"EC2LaunchTemplateResource0": {Start: 18, End: 23},
"EC2LaunchTemplateResource1": {Start: 24, End: 34},
}
actual := yaml.MapResourcesLineYAML(filePath, resourcesNames, ResourcesStartToken)
actual, _ := yaml.MapResourcesLineYAML(filePath, resourcesNames, ResourcesStartToken)
compareLines(t, expected, actual)
})

Expand Down
55 changes: 27 additions & 28 deletions src/common/color_check.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
package common

type ColorStruct struct {
NoColor bool
Reset string
Green string
Yellow string
Blue string
Purple string
NoColor bool
Reset string
Green string
Yellow string
Blue string
Purple string
}

func NoColorCheck (NoColorBool bool) *ColorStruct {
var colors ColorStruct
colors = ColorStruct{
NoColor : true,
Reset : "",
Green : "",
Yellow : "",
Blue : "",
Purple : "",
}
if !NoColorBool {
colors = ColorStruct{
NoColor : false,
Reset : "\033[0m",
Green : "\033[32m",
Yellow : "\033[33m",
Blue : "\033[34m",
Purple : "\033[35m",
}
}
return &colors
func NoColorCheck(noColorBool bool) *ColorStruct {
var colors ColorStruct
colors = ColorStruct{
NoColor: true,
Reset: "",
Green: "",
Yellow: "",
Blue: "",
Purple: "",
}
if !noColorBool {
colors = ColorStruct{
NoColor: false,
Reset: "\033[0m",
Green: "\033[32m",
Yellow: "\033[33m",
Blue: "\033[34m",
Purple: "\033[35m",
}
}
return &colors
}

7 changes: 4 additions & 3 deletions src/common/json/json_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ func AddTagsToResourceStr(fullOriginStr string, resourceBlock structure.IBlock,
firstTagStr := tagsStr[firstTagIndex : firstTagIndex+strings.Index(tagsStr[firstTagIndex+1:], "\"")]
tagEntryIndent := findIndent(tagsStr, '"', strings.Index(tagsStr[1:], "{")) // find the indent of the key and value entry
compact := false
if strings.Contains(firstTagStr, "\n") {
switch {
case strings.Contains(firstTagStr, "\n"):
// If the tag string has a newline, it means the indent needs to be re-evaluated. Example for this use case:
// "Tags": [
// {
Expand All @@ -102,10 +103,10 @@ func AddTagsToResourceStr(fullOriginStr string, resourceBlock structure.IBlock,
indentDiff := len(tagEntryIndent) - len(tagBlockIndent)
tagBlockIndent = tagBlockIndent[0 : len(tagBlockIndent)-indentDiff]
tagEntryIndent = tagEntryIndent[0 : len(tagEntryIndent)-indentDiff]
} else if len(tagsLinesList) == 1 {
case len(tagsLinesList) == 1:
// multi tags in one line
compact = true
} else {
default:
// Otherwise, need to take the indent of the "{" character. This case handles:
// "Tags": [
// { "Key": "some-key", "Value": "some-val" }
Expand Down
1 change: 1 addition & 0 deletions src/common/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ type IParser interface {
WriteFile(readFilePath string, blocks []structure.IBlock, writeFilePath string) error
GetSkippedDirs() []string
GetSupportedFileExtensions() []string
GetSkipResourcesByComment() []string
Close()
}
38 changes: 19 additions & 19 deletions src/common/reports/report_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,16 @@ func (r *ReportService) printUpdatedResourcesToStdout(colors *common.ColorStruct
fmt.Print(colors.Green, fmt.Sprintf("Updated Resource Traces (%v):\n", r.report.Summary.UpdatedResources), colors.Reset)
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"File", "Resource", "Tag Key", "Old Value", "Updated Value", "Yor ID"})
if !colors.NoColor {
table.SetColumnColor(
tablewriter.Colors{},
tablewriter.Colors{},
tablewriter.Colors{tablewriter.Bold},
tablewriter.Colors{tablewriter.Normal, tablewriter.FgRedColor},
tablewriter.Colors{tablewriter.Normal, tablewriter.FgGreenColor},
tablewriter.Colors{},
)
}
if !colors.NoColor {
table.SetColumnColor(
tablewriter.Colors{},
tablewriter.Colors{},
tablewriter.Colors{tablewriter.Bold},
tablewriter.Colors{tablewriter.Normal, tablewriter.FgRedColor},
tablewriter.Colors{tablewriter.Normal, tablewriter.FgGreenColor},
tablewriter.Colors{},
)
}

table.SetRowLine(true)
table.SetRowSeparator("-")
Expand All @@ -176,15 +176,15 @@ func (r *ReportService) printNewResourcesToStdout(colors *common.ColorStruct) {
table.SetHeader([]string{"File", "Resource", "Tag Key", "Tag Value", "Yor ID"})
table.SetRowLine(true)
table.SetRowSeparator("-")
if !colors.NoColor {
table.SetColumnColor(
tablewriter.Colors{},
tablewriter.Colors{},
tablewriter.Colors{tablewriter.Bold},
tablewriter.Colors{tablewriter.Normal, tablewriter.FgGreenColor},
tablewriter.Colors{},
)
}
if !colors.NoColor {
table.SetColumnColor(
tablewriter.Colors{},
tablewriter.Colors{},
tablewriter.Colors{tablewriter.Bold},
tablewriter.Colors{tablewriter.Normal, tablewriter.FgGreenColor},
tablewriter.Colors{},
)
}
for _, tr := range r.report.NewResourceTags {
table.Append([]string{tr.File, tr.ResourceID, tr.TagKey, tr.UpdatedValue, tr.YorTraceID})
}
Expand Down
2 changes: 1 addition & 1 deletion src/common/reports/results_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func TestResultsGeneration(t *testing.T) {
t.Run("Test CLI output structure", func(t *testing.T) {
ReportServiceInst.CreateReport()

colors := common.NoColorCheck(false)
colors := common.NoColorCheck(false)
output := utils.CaptureOutputColors(ReportServiceInst.PrintToStdout)
lines := strings.Split(output, "\n")
// Verify banner
Expand Down
11 changes: 9 additions & 2 deletions src/common/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,18 @@ func (r *Runner) isSkippedResourceType(resourceType string) bool {
return false
}

func (r *Runner) isSkippedResource(resource string) bool {
func (r *Runner) isSkippedResource(resource string, skipResource []string) bool {
for _, skippedResource := range r.skippedResources {
if resource == skippedResource {
return true
}
}
for _, skippedResource := range skipResource {
if resource == skippedResource {
return true
}
}

return false
}

Expand All @@ -186,7 +192,8 @@ func (r *Runner) TagFile(file string) {
if r.isSkippedResourceType(block.GetResourceType()) {
continue
}
if r.isSkippedResource(block.GetResourceID()) {
skipResourcesByComment := parser.GetSkipResourcesByComment()
if r.isSkippedResource(block.GetResourceID(), skipResourcesByComment) {
continue
}
if block.IsBlockTaggable() {
Expand Down
7 changes: 5 additions & 2 deletions src/common/runner/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package runner

import (
"fmt"
"github.com/bridgecrewio/yor/src/common/tagging/tags"
"os"
"path/filepath"
"strings"
"testing"
"time"

"github.com/bridgecrewio/yor/src/common/tagging/tags"

cloudformationStructure "github.com/bridgecrewio/yor/src/cloudformation/structure"
"github.com/bridgecrewio/yor/src/common/clioptions"
"github.com/bridgecrewio/yor/src/common/gitservice"
Expand Down Expand Up @@ -220,7 +221,6 @@ func TestRunnerInternals(t *testing.T) {
})
assert.NotContains(t, output, "aws_s3_bucket.test-bucket")
})

t.Run("Test skip resource - cloudformation", func(t *testing.T) {
runner := Runner{}
rootDir := "../../../tests/cloudformation"
Expand Down Expand Up @@ -286,6 +286,9 @@ func Test_YorNameTag(t *testing.T) {

runner := Runner{}
err := runner.Init(&options)
if err != nil {
t.Error(err)
}
reportService, err := runner.TagDirectory()
if err != nil {
t.Error(err)
Expand Down
6 changes: 3 additions & 3 deletions src/common/tagging/external/tag_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ func (t Tag) SatisfyFilters(block structure.IBlock) bool {

case "directory":
prefixes := make([]string, 0)
switch filterValue.(type) {
switch filterValue := filterValue.(type) {
case []interface{}:
for _, e := range filterValue.([]interface{}) {
for _, e := range filterValue {
prefixes = append(prefixes, e.(string))
}
case interface{}:
Expand Down Expand Up @@ -244,7 +244,7 @@ func (t *TagGroup) CalculateTagValue(block structure.IBlock, tag Tag) (tags.ITag
}
}
if len(gitModifiersCounts) == 1 {
for k, _ := range gitModifiersCounts {
for k := range gitModifiersCounts {
retTag.Value = evaluateTemplateVariable(k)
break
}
Expand Down
4 changes: 2 additions & 2 deletions src/common/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ func TestInSlice(t *testing.T) {
args: args[int]{slice: []int{1, 2, 3, 4}, elem: 5},
want: false,
},
//{ // not supported for generics
// { // not supported for generics
// name: "different kinds",
// args: args[int]{slice: []int{1, 2, 3, 4}, elem: "bana"},
// want: false,
//},
// },

}
for _, tt := range testsStr {
Expand Down
Loading

0 comments on commit 20ec9a6

Please sign in to comment.