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: ast-70404 include rules in sarif #252

Merged
merged 6 commits into from
Oct 23, 2024
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 Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ RUN go build -o /app/2ms .
# Runtime image
FROM cgr.dev/chainguard/git@sha256:02660563e96b553d6aeb4093e3fcc3e91b2ad3a86e05c65b233f37f035e5044e

RUN apk add --no-cache bash=5.2.21-r1 git=2.45.1-r0 git-lfs=3.5.1-r8 libcurl-openssl4=8.10.0-r0 glibc=2.39-r5 glibc-locale-posix=2.39-r5 ld-linux==2.39-r5 libcrypt1=2.39-r5 && git config --global --add safe.directory /repo
RUN apk add --no-cache bash=5.2.21-r1 git=2.45.1-r0 git-lfs=3.5.1-r8 libcurl-openssl4=8.10.0-r0 glibc=2.39-r5 glibc-locale-posix=2.39-r5 ld-linux==2.39-r5 libcrypt1=2.39-r5 libcrypto3=3.3.2-r2 libssl3=3.3.2-r2 && git config --global --add safe.directory /repo

COPY --from=builder /app/2ms .

Expand Down
19 changes: 10 additions & 9 deletions engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,16 @@ func (e *Engine) Detect(item plugins.ISourceItem, secretsChannel chan *secrets.S
endLine = value.EndLine
}
secret := &secrets.Secret{
ID: itemId,
Source: item.GetSource(),
RuleID: value.RuleID,
StartLine: startLine,
StartColumn: value.StartColumn,
EndLine: endLine,
EndColumn: value.EndColumn,
Value: value.Secret,
LineContent: value.Line,
ID: itemId,
Source: item.GetSource(),
RuleID: value.RuleID,
StartLine: startLine,
StartColumn: value.StartColumn,
EndLine: endLine,
EndColumn: value.EndColumn,
Value: value.Secret,
LineContent: value.Line,
RuleDescription: value.Description,
}
if !isSecretIgnored(secret, &e.ignoredIds, &e.allowedValues) {
secretsChannel <- secret
Expand Down
271 changes: 271 additions & 0 deletions lib/reporting/report_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,172 @@
package reporting

import (
"encoding/json"
"os"
"path/filepath"
"reflect"
"sort"
"strings"
"testing"

"github.com/checkmarx/2ms/lib/config"
"github.com/checkmarx/2ms/lib/secrets"
"github.com/stretchr/testify/assert"
)

// test input results
var (
ruleID1 = "ruleID1"
ruleID2 = "ruleID2"
result1 = &secrets.Secret{
ID: "ID1",
Source: "file1",
RuleID: ruleID1,
StartLine: 150,
EndLine: 150,
LineContent: "line content",
StartColumn: 31,
EndColumn: 150,
Value: "value",
ValidationStatus: secrets.ValidResult,
RuleDescription: "Rule Description",
}
// this result has a different rule than result1
result2 = &secrets.Secret{
ID: "ID2",
Source: "file2",
RuleID: ruleID2,
StartLine: 10,
EndLine: 10,
LineContent: "line content2",
StartColumn: 41,
EndColumn: 160,
Value: "value 2",
ValidationStatus: secrets.InvalidResult,
RuleDescription: "Rule Description2",
}
// this result has the same rule as result1
result3 = &secrets.Secret{
ID: "ID3",
Source: "file3",
RuleID: ruleID1,
StartLine: 16,
EndLine: 16,
LineContent: "line content3",
StartColumn: 11,
EndColumn: 130,
Value: "value 3",
ValidationStatus: secrets.UnknownResult,
RuleDescription: "Rule Description",
}
)

// test expected outputs
var (
// sarif rules
rule1Sarif = &SarifRule{
ID: ruleID1,
FullDescription: &Message{
Text: result1.RuleDescription,
},
}
rule2Sarif = &SarifRule{
ID: ruleID2,
FullDescription: &Message{
Text: result2.RuleDescription,
},
}
// sarif results
result1Sarif = Results{
Message: Message{
Text: messageText(result1.RuleID, result1.Source),
},
RuleId: ruleID1,
Locations: []Locations{
{
PhysicalLocation: PhysicalLocation{
ArtifactLocation: ArtifactLocation{
URI: result1.Source,
},
Region: Region{
StartLine: result1.StartLine,
StartColumn: result1.StartColumn,
EndLine: result1.EndLine,
EndColumn: result1.EndColumn,
Snippet: Snippet{
Text: result1.Value,
Properties: Properties{
"lineContent": strings.TrimSpace(result1.LineContent),
},
},
},
},
},
},
Properties: Properties{
"validationStatus": string(result1.ValidationStatus),
},
}
result2Sarif = Results{
Message: Message{
Text: messageText(result2.RuleID, result2.Source),
},
RuleId: ruleID2,
Locations: []Locations{
{
PhysicalLocation: PhysicalLocation{
ArtifactLocation: ArtifactLocation{
URI: result2.Source,
},
Region: Region{
StartLine: result2.StartLine,
StartColumn: result2.StartColumn,
EndLine: result2.EndLine,
EndColumn: result2.EndColumn,
Snippet: Snippet{
Text: result2.Value,
Properties: Properties{
"lineContent": strings.TrimSpace(result2.LineContent),
},
},
},
},
},
},
Properties: Properties{
"validationStatus": string(result2.ValidationStatus),
},
}
result3Sarif = Results{
Message: Message{
Text: messageText(result3.RuleID, result3.Source),
},
RuleId: ruleID1,
Locations: []Locations{
{
PhysicalLocation: PhysicalLocation{
ArtifactLocation: ArtifactLocation{
URI: result3.Source,
},
Region: Region{
StartLine: result3.StartLine,
StartColumn: result3.StartColumn,
EndLine: result3.EndLine,
EndColumn: result3.EndColumn,
Snippet: Snippet{
Text: result3.Value,
Properties: Properties{
"lineContent": strings.TrimSpace(result3.LineContent),
},
},
},
},
},
},
Properties: Properties{
"validationStatus": string(result3.ValidationStatus),
},
}
)

func TestAddSecretToFile(t *testing.T) {
Expand Down Expand Up @@ -57,3 +216,115 @@ func TestWriteReportInNonExistingDir(t *testing.T) {

os.RemoveAll(filepath.Join(tempDir, "test_temp_dir"))
}

func TestGetOutputSarif(t *testing.T) {
tests := []struct {
name string
arg Report
want []Runs
wantErr bool
}{
{
name: "two_results_same_rule_want_one_rule_in_report",
arg: Report{
TotalItemsScanned: 2,
TotalSecretsFound: 2,
Results: map[string][]*secrets.Secret{
"secret1": {result1},
"secret3": {result3},
},
},
wantErr: false,
want: []Runs{
{
Tool: Tool{
Driver: Driver{
Name: "report",
SemanticVersion: "1",
Rules: []*SarifRule{
rule1Sarif,
},
},
},
Results: []Results{
result1Sarif,
result3Sarif,
},
},
},
},
{
name: "two_results_two_rules_want_two_rules_in_report",
arg: Report{
TotalItemsScanned: 2,
TotalSecretsFound: 2,
Results: map[string][]*secrets.Secret{
"secret1": {result1},
"secret2": {result2},
},
},
wantErr: false,
want: []Runs{
{
Tool: Tool{
Driver: Driver{
Name: "report",
SemanticVersion: "1",
Rules: []*SarifRule{
rule1Sarif,
rule2Sarif,
},
},
},
Results: []Results{
result1Sarif,
result2Sarif,
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.arg.getOutput(sarifFormat, &config.Config{Name: "report", Version: "1"})
if tt.wantErr {
assert.NotNil(t, err)
return
}
var gotReport Sarif
err = json.Unmarshal([]byte(got), &gotReport)
assert.Nil(t, err)
SortSarifReports(&gotReport, &Sarif{Runs: tt.want})
assert.Equal(t, tt.want, gotReport.Runs)
})
}
}

// SortProject Sorts two sarif reports
func SortSarifReports(run1, run2 *Sarif) {
// Sort Rules
SortRules(run1.Runs[0].Tool.Driver.Rules, run2.Runs[0].Tool.Driver.Rules)
SortResults(run1.Runs[0].Results, run2.Runs[0].Results)

}

func SortRules(rules1, rules2 []*SarifRule) {
// Sort both slices
sort.Slice(rules1, func(i, j int) bool {
return rules1[i].ID < rules1[j].ID
})
sort.Slice(rules2, func(i, j int) bool {
return rules2[i].ID < rules2[j].ID
})
}

func SortResults(results1, results2 []Results) {
// Sort both slices
sort.Slice(results1, func(i, j int) bool {
return results1[i].Message.Text < results1[j].Message.Text
})
sort.Slice(results2, func(i, j int) bool {
return results2[i].Message.Text < results2[j].Message.Text
})
}
Loading