Skip to content

Commit

Permalink
add --github flag for github suited sarif output
Browse files Browse the repository at this point in the history
  • Loading branch information
devang-gaur committed Jul 1, 2021
1 parent bedfaa1 commit 520f4ea
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 17 deletions.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/VerbalExpressions/GoVerbalExpressions v0.0.0-20200410162751-4d76a1099a6e
github.com/awslabs/goformation/v4 v4.19.1
github.com/ghodss/yaml v1.0.0
github.com/go-errors/errors v1.0.1
github.com/google/uuid v1.2.0
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
Expand Down Expand Up @@ -39,7 +40,7 @@ require (
github.com/stretchr/testify v1.7.0
github.com/zclconf/go-cty v1.8.2
go.uber.org/zap v1.16.0
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
golang.org/x/tools v0.1.4 // indirect
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1188,6 +1188,8 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
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
2 changes: 1 addition & 1 deletion pkg/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ var (
// LogType Logging output type (console, json)
LogType string

// OutputType Violation output type (human, json, yaml, xml)
// OutputType Violation output type (human, json, yaml, xml, sarif)
OutputType string

// ConfigFile Config file path
Expand Down
15 changes: 15 additions & 0 deletions pkg/cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (

const (
humanOutputFormat = "human"
sarifOutputFormat = "sarif"
)

// ScanOptions represents scan command and its optional flags
Expand Down Expand Up @@ -95,6 +96,9 @@ type ScanOptions struct {

// nonRecursive enables recursive scan for the terraform iac provider
nonRecursive bool

// sarifForGithub enables sarif output suited for github code scanning alert format
sarifForGithub bool
}

// NewScanOptions returns a new pointer to ScanOptions
Expand Down Expand Up @@ -135,6 +139,14 @@ func (s ScanOptions) validate() error {
if s.configOnly && strings.EqualFold(s.outputType, humanOutputFormat) {
return errors.New("please use yaml or json output format when using --config-only flag")
}

// only sarif output supports --github flag
// if --github flag is set, then exit with an error
// asking the user to use sarif output format
if s.sarifForGithub && !strings.EqualFold(s.outputType, sarifOutputFormat) {
return errors.New("please use sarif output format when using --github flag")
}

return nil
}

Expand Down Expand Up @@ -235,6 +247,9 @@ func (s ScanOptions) writeResults(results runtime.Output) error {

outputWriter := NewOutputWriter(s.UseColors)

if s.sarifForGithub {
writer.SarifForGithub = true
}
if s.configOnly {
return writer.Write(s.outputType, results.ResourceConfig, outputWriter)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/cli/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,6 @@ func init() {
scanCmd.Flags().StringSliceVarP(&scanOptions.categories, "categories", "", []string{}, "list of categories of violations to be reported by terrascan (example: --categories=\"category1,category2\")")
scanCmd.Flags().BoolVarP(&scanOptions.showPassedRules, "show-passed", "", false, "display passed rules, along with violations")
scanCmd.Flags().BoolVarP(&scanOptions.nonRecursive, "non-recursive", "", false, "do not scan directories and modules recursively")
scanCmd.Flags().BoolVarP(&scanOptions.sarifForGithub, "github", "", false, "arrange sarif output to suit github codescanning alert format")
RegisterCommand(rootCmd, scanCmd)
}
30 changes: 19 additions & 11 deletions pkg/writer/sarif.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/accurics/terrascan/pkg/policy"
"github.com/accurics/terrascan/pkg/utils"
"github.com/accurics/terrascan/pkg/version"
"github.com/go-errors/errors"
"github.com/owenrumney/go-sarif/sarif"
"go.uber.org/zap"
"io"
Expand All @@ -32,6 +33,9 @@ const (
sarifFormat supportedFormat = "sarif"
)

// SarifForGithub is a flag to know Sarif has to be generated for Github usage format or the generic default format
var SarifForGithub = false

func init() {
RegisterWriter(sarifFormat, SarifWriter)
}
Expand All @@ -46,7 +50,6 @@ func SarifWriter(data interface{}, writer io.Writer) error {

run := sarif.NewRun("terrascan", "https://github.com/accurics/terrascan")
run.Tool.Driver.WithVersion(version.GetNumeric())

// add a run to the report
report.AddRun(run)

Expand All @@ -55,7 +58,7 @@ func SarifWriter(data interface{}, writer io.Writer) error {
m["category"] = passedRule.Category
m["severity"] = passedRule.Severity

run.AddRule(string(passedRule.RuleID)).
run.AddRule(passedRule.RuleID).
WithDescription(passedRule.Description).WithName(passedRule.RuleName).WithProperties(m)
}

Expand All @@ -65,19 +68,24 @@ func SarifWriter(data interface{}, writer io.Writer) error {
m["category"] = violation.Category
m["severity"] = violation.Severity

rule := run.AddRule(string(violation.RuleID)).
rule := run.AddRule(violation.RuleID).
WithDescription(violation.Description).WithName(violation.RuleName).WithProperties(m)

absFilePath, err := getAbsoluteFilePath(outputData.Summary.ResourcePath, violation.File)

if err != nil {
return err
var artifactLocation *sarif.ArtifactLocation

if SarifForGithub {
artifactLocation = sarif.NewSimpleArtifactLocation(violation.File).
WithUriBaseId(outputData.Summary.ResourcePath)
} else {
absFilePath, err := getAbsoluteFilePath(outputData.Summary.ResourcePath, violation.File)
if err != nil {
return errors.Errorf("unable to create absolute path, error: %v", err)
}
artifactLocation = sarif.NewSimpleArtifactLocation(fmt.Sprintf("file://%s", absFilePath))
}

location := sarif.NewLocation().
WithPhysicalLocation(sarif.NewPhysicalLocation().
WithArtifactLocation(sarif.NewSimpleArtifactLocation(fmt.Sprintf("file://%s", absFilePath))).
WithRegion(sarif.NewRegion().WithStartLine(violation.LineNumber)))
location := sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().
WithArtifactLocation(artifactLocation).WithRegion(sarif.NewRegion().WithStartLine(violation.LineNumber)))

if len(violation.ResourceType) > 0 && len(violation.ResourceName) > 0 {
location.LogicalLocations = append(location.LogicalLocations, sarif.NewLogicalLocation().
Expand Down
79 changes: 75 additions & 4 deletions pkg/writer/sarif_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import (
"github.com/accurics/terrascan/pkg/version"
)

var testpath, _ = getAbsoluteFilePath(violationsInput.Summary.ResourcePath, violationsInput.Violations[0].File)
var abstestpath, _ = getAbsoluteFilePath(violationsInput.Summary.ResourcePath, violationsInput.Violations[0].File)
var testpath = fmt.Sprintf("file://%s", abstestpath)
var testpathForGH = violationsInput.Violations[0].File

var expectedSarifOutput1 = fmt.Sprintf(`{
const violationTemplate = `{
"version": "2.1.0",
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"runs": [
Expand Down Expand Up @@ -68,7 +70,67 @@ var expectedSarifOutput1 = fmt.Sprintf(`{
]
}
]
}`, version.GetNumeric(), fmt.Sprintf("file://%s", testpath))
}`

const violationTemplateForGH = `{
"version": "2.1.0",
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"runs": [
{
"tool": {
"driver": {
"name": "terrascan",
"version": "%s",
"informationUri": "https://github.com/accurics/terrascan",
"rules": [
{
"id": "AWS.S3Bucket.DS.High.1043",
"name": "s3EnforceUserACL",
"shortDescription": {
"text": "S3 bucket Access is allowed to all AWS Account Users."
},
"properties": {
"category": "S3",
"severity": "HIGH"
}
}
]
}
},
"results": [
{
"ruleId": "AWS.S3Bucket.DS.High.1043",
"level": "error",
"message": {
"text": "S3 bucket Access is allowed to all AWS Account Users."
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "%s",
"uriBaseId": "test"
},
"region": {
"startLine": 20
}
},
"logicalLocations": [
{
"name": "bucket",
"kind": "aws_s3_bucket"
}
]
}
]
}
]
}
]
}`

var expectedSarifOutput1 = fmt.Sprintf(violationTemplate, version.GetNumeric(), testpath)
var expectedSarifOutput1GH = fmt.Sprintf(violationTemplateForGH, version.GetNumeric(), testpathForGH)

var expectedSarifOutput2 = fmt.Sprintf(`{
"version": "2.1.0",
Expand Down Expand Up @@ -125,12 +187,19 @@ func TestSarifWriter(t *testing.T) {
input funcInput
expectedError bool
expectedOutput string
forGithub bool
}{
{
name: "Human Readable Writer: Violations",
name: "Sarif Writer: Violations",
input: violationsInput,
expectedOutput: expectedSarifOutput1,
},
{
name: "Sarif Writer for Github: Violations",
input: violationsInput,
expectedOutput: expectedSarifOutput1GH,
forGithub: true,
},
{
name: "Human Readable Writer: No Violations",
input: policy.EngineOutput{
Expand All @@ -150,9 +219,11 @@ func TestSarifWriter(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
writer := &bytes.Buffer{}
SarifForGithub = tt.forGithub
if err := SarifWriter(tt.input, writer); (err != nil) != tt.expectedError {
t.Errorf("HumanReadbleWriter() error = gotErr: %v, wantErr: %v", err, tt.expectedError)
}
SarifForGithub = false
outputBytes := writer.Bytes()
gotOutput := string(bytes.TrimSpace(outputBytes))

Expand Down

0 comments on commit 520f4ea

Please sign in to comment.