Skip to content
Closed
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 go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ require (
github.com/charmbracelet/x/term v0.2.2 // indirect
github.com/cloudflare/circl v1.6.5 // indirect
github.com/containerd/cgroups/v3 v3.1.3 // indirect
github.com/containerd/containerd v1.7.35 // indirect
github.com/containerd/containerd v1.7.36 // indirect
github.com/containerd/containerd/api v1.10.0 // indirect
github.com/containerd/continuity v0.5.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/containerd/cgroups/v3 v3.1.3 h1:eUNflyMddm18+yrDmZPn3jI7C5hJ9ahABE5q6dyLYXQ=
github.com/containerd/cgroups/v3 v3.1.3/go.mod h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw=
github.com/containerd/containerd v1.7.35 h1:7AU2T1qI2OdNBmKkreWZ7kASHUNFItN5Hgejd9sY938=
github.com/containerd/containerd v1.7.35/go.mod h1:ozI//0TomTCLPhQREnx0IXDIQMg+Fk7yTtg9fNvU8EQ=
github.com/containerd/containerd v1.7.36 h1:HyMsOG5kmp1LQsGzqwI6Ts06T4VpYZbszfDZYB0bW5w=
github.com/containerd/containerd v1.7.36/go.mod h1:ozI//0TomTCLPhQREnx0IXDIQMg+Fk7yTtg9fNvU8EQ=
github.com/containerd/containerd/api v1.10.0 h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o=
github.com/containerd/containerd/api v1.10.0/go.mod h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM=
github.com/containerd/continuity v0.5.0 h1:7a85HZpCSs+1Zps0Ee3DPSuAWY+0SJM1JNM51nlEVDg=
Expand Down
6 changes: 6 additions & 0 deletions internal/commands/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ var (
commonParams.StatusQueryParam,
commonParams.SeverityQueryParam,
commonParams.StateQueryParam,
commonParams.AIClassificationQueryParam,
}, ",",
),
)
Expand Down Expand Up @@ -2420,6 +2421,7 @@ func initSonarIssue(result *wrappers.ScanResult) wrappers.SonarIssues {
engineType := strings.TrimSpace(result.Type)
if engineType == commonParams.SastType {
sonarIssue.RuleID = result.ScanResultData.LanguageName + " - " + result.ScanResultData.QueryName
sonarIssue.AiClassification = result.ScanResultData.AIClassification
} else if engineType == commonParams.KicsType {
sonarIssue.RuleID = result.ScanResultData.QueryName
} else if engineType == commonParams.ScaType {
Expand Down Expand Up @@ -2961,6 +2963,10 @@ func parseSarifResultSast(result *wrappers.ScanResult, scanResults []wrappers.Sa
},
}

if result.ScanResultData.AIClassification != nil {
scanResult.Properties = &wrappers.SarifResultProperties{AIClassification: result.ScanResultData.AIClassification}
}

scanResults = append(scanResults, scanResult)
return scanResults
}
Expand Down
72 changes: 72 additions & 0 deletions internal/commands/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,46 @@ func TestRunWithoutScsResults_Other_AgentsShouldNotShowScsResults(t *testing.T)
mock.SetScsMockVarsToDefault()
}

func TestRunGetResultsByScanIdJSONFormat_AIClassificationPresentWhenSetByServer(t *testing.T) {
clearFlags()

execCmdNilAssertion(t, "results", "show", "--scan-id", "SAST_ONLY", "--report-format", "json")

reportBytes, err := os.ReadFile(fileName + "." + printer.FormatJSON)
assert.NilError(t, err, "Error reading file")

var scanResultsCollection *wrappers.ScanResultsCollection
err = json.Unmarshal(reportBytes, &scanResultsCollection)
assert.NilError(t, err, "Error unmarshalling JSON data")
assert.Assert(t, len(scanResultsCollection.Results) == 1)
assert.Assert(t, scanResultsCollection.Results[0].ScanResultData.AIClassification != nil)
assert.Equal(t, "TP", *scanResultsCollection.Results[0].ScanResultData.AIClassification)

// The raw JSON must carry the key, not just the unmarshalled struct
assert.Assert(t, strings.Contains(string(reportBytes), `"aiClassification":"TP"`))

removeFileBySuffix(t, printer.FormatJSON)
}

func TestRunGetResultsByScanIdJSONFormat_AIClassificationOmittedWhenAbsent(t *testing.T) {
clearFlags()

execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "json")

reportBytes, err := os.ReadFile(fileName + "." + printer.FormatJSON)
assert.NilError(t, err, "Error reading file")

var scanResultsCollection *wrappers.ScanResultsCollection
err = json.Unmarshal(reportBytes, &scanResultsCollection)
assert.NilError(t, err, "Error unmarshalling JSON data")
for i := range scanResultsCollection.Results {
assert.Assert(t, scanResultsCollection.Results[i].ScanResultData.AIClassification == nil)
}
assert.Assert(t, !strings.Contains(string(reportBytes), "aiClassification"))

removeFileBySuffix(t, printer.FormatJSON)
}

func TestRunNilResults_Other_AgentsShouldNotShowAnyResults(t *testing.T) {
clearFlags()

Expand Down Expand Up @@ -395,6 +435,38 @@ func TestParseSarifResultSastClampsZeroColumns(t *testing.T) {
assert.Equal(t, uint(6), threadLocations[1].Location.PhysicalLocation.Region.EndColumn)
}

func TestParseSarifResultSastSetsAIClassificationWhenPresent(t *testing.T) {
aiClassification := "TP"
result := &wrappers.ScanResult{
ScanResultData: wrappers.ScanResultData{
AIClassification: &aiClassification,
Nodes: []*wrappers.ScanResultNode{
{FileName: "/src/app.go", Line: 10, Column: 1, Length: 5},
},
},
}

sarifResults := parseSarifResultSast(result, nil)
assert.Assert(t, len(sarifResults) == 1)
assert.Assert(t, sarifResults[0].Properties != nil)
assert.Assert(t, sarifResults[0].Properties.AIClassification != nil)
assert.Equal(t, "TP", *sarifResults[0].Properties.AIClassification)
}

func TestParseSarifResultSastOmitsPropertiesWhenAIClassificationAbsent(t *testing.T) {
result := &wrappers.ScanResult{
ScanResultData: wrappers.ScanResultData{
Nodes: []*wrappers.ScanResultNode{
{FileName: "/src/app.go", Line: 10, Column: 1, Length: 5},
},
},
}

sarifResults := parseSarifResultSast(result, nil)
assert.Assert(t, len(sarifResults) == 1)
assert.Assert(t, sarifResults[0].Properties == nil)
}

func TestParseSarifResultKicsClampsZeroStartLine(t *testing.T) {
result := &wrappers.ScanResult{
ScanResultData: wrappers.ScanResultData{
Expand Down
1 change: 1 addition & 0 deletions internal/params/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ const (
IncludeNodesQueryParam = "include-nodes"
SortQueryParam = "sort"
SearchQueryParam = "search"
AIClassificationQueryParam = "ai-classification"
Profile = "default"
BaseURI = ""
BaseIAMURI = ""
Expand Down
6 changes: 4 additions & 2 deletions internal/wrappers/mock/results-mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ func (r ResultsMockWrapper) GetAllResultsByScanID(params map[string]string) (
}, nil, nil
}
if params["scan-id"] == "SAST_ONLY" {
aiClassification := "TP"
return &wrappers.ScanResultsCollection{
TotalCount: 1,
Results: []*wrappers.ScanResult{
Expand All @@ -113,8 +114,9 @@ func (r ResultsMockWrapper) GetAllResultsByScanID(params map[string]string) (
ID: "1",
Severity: "high",
ScanResultData: wrappers.ScanResultData{
LanguageName: "JavaScript",
QueryName: "mock-query-name-1",
LanguageName: "JavaScript",
QueryName: "mock-query-name-1",
AIClassification: &aiClassification,
Nodes: []*wrappers.ScanResultNode{
{
FileName: "dummy-file-name-1",
Expand Down
2 changes: 2 additions & 0 deletions internal/wrappers/results-json.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,6 @@ type ScanResultData struct {
Validity string `json:"validity,omitempty"`
IsInSource bool `json:"isInSource,omitempty"`
CommitURL string `json:"commitUrl,omitempty"`
// Added to support FAE Phase 2 AI classification
AIClassification *string `json:"aiClassification,omitempty"`
}
9 changes: 5 additions & 4 deletions internal/wrappers/results-sarif.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,9 @@ type SarifResultFingerprint struct {
}

type SarifResultProperties struct {
Severity string `json:"severity,omitempty"`
Validity string `json:"validity,omitempty"`
IsInSource bool `json:"isInSource,omitempty"`
CommitURL string `json:"commitUrl,omitempty"`
Severity string `json:"severity,omitempty"`
Validity string `json:"validity,omitempty"`
IsInSource bool `json:"isInSource,omitempty"`
CommitURL string `json:"commitUrl,omitempty"`
AIClassification *string `json:"aiClassification,omitempty"`
}
1 change: 1 addition & 0 deletions internal/wrappers/results-sonar.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type SonarIssues struct {
PrimaryLocation SonarLocation `json:"primaryLocation"`
EffortMinutes uint `json:"effortMinutes,omitempty"`
SecondaryLocations []SonarLocation `json:"secondaryLocations"`
AiClassification *string `json:"aiClassification,omitempty"` // SAST-only
}

type SonarLocation struct {
Expand Down
6 changes: 3 additions & 3 deletions test/integration/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func TestCodeBashingList(t *testing.T) {
"results",
"codebashing",
flag(params.LanguageFlag), "PHP",
flag(params.VulnerabilityTypeFlag), "Reflected XSS All Clients",
flag(params.VulnerabilityTypeFlag), "Reflected_XSS",
flag(params.CweIDFlag), "79")

codebashing := []wrappers.CodeBashingCollection{}
Expand All @@ -221,7 +221,7 @@ func TestCodeBashingListJson(t *testing.T) {
"results",
"codebashing",
flag(params.LanguageFlag), "PHP",
flag(params.VulnerabilityTypeFlag), "Reflected XSS All Clients",
flag(params.VulnerabilityTypeFlag), "Reflected_XSS",
flag(params.CweIDFlag), "79",
flag(params.FormatFlag), "json")

Expand All @@ -239,7 +239,7 @@ func TestCodeBashingListTable(t *testing.T) {
"results",
"codebashing",
flag(params.LanguageFlag), "PHP",
flag(params.VulnerabilityTypeFlag), "Reflected XSS All Clients",
flag(params.VulnerabilityTypeFlag), "Reflected_XSS",
flag(params.CweIDFlag), "79",
flag(params.FormatFlag), "table")

Expand Down
Loading