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

Feature 3390 enable project data in client #3409

Merged
merged 20 commits into from
Sep 6, 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
215 changes: 162 additions & 53 deletions sechub-cli/src/mercedes-benz.com/sechub/cli/false-positives.go

Large diffs are not rendered by default.

235 changes: 223 additions & 12 deletions sechub-cli/src/mercedes-benz.com/sechub/cli/false-positives_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package cli

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -44,7 +45,7 @@ func TestFalsePositivesSaveWritesAFile(t *testing.T) {
sechubTestUtil.AssertFileExists(expected, t)
}

func Example_defineFalsePositives() {
func Example_defineFalsePositivesJobData() {
/* prepare */
definedFalsePositives := []FalsePositivesJobData{
{JobUUID: "11111111-1111-1111-1111-111111111111", FindingID: 1, Comment: "test1"},
Expand All @@ -68,11 +69,11 @@ func Example_defineFalsePositives() {
fmt.Printf("Remove: %+v\n", falsePositivesToRemove)

// Output:
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:33333333-3333-3333-3333-333333333333 FindingID:3 Comment:test3} {JobUUID:55555555-5555-5555-5555-555555555555 FindingID:5 Comment:test5}]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:44444444-4444-4444-4444-444444444444 FindingID:4 Comment:}]}
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:33333333-3333-3333-3333-333333333333 FindingID:3 Comment:test3} {JobUUID:55555555-5555-5555-5555-555555555555 FindingID:5 Comment:test5}] ProjectData:[]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:44444444-4444-4444-4444-444444444444 FindingID:4 Comment:}] ProjectData:[]}
}

func Example_defineFalsePositivesEmptyInputList() {
func Example_defineFalsePositivesJobDataEmptyInputList() {
// An empty input list will remove all defined false-positives

/* prepare */
Expand All @@ -92,11 +93,11 @@ func Example_defineFalsePositivesEmptyInputList() {
fmt.Printf("Remove: %+v\n", falsePositivesToRemove)

// Output:
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:11111111-1111-1111-1111-111111111111 FindingID:1 Comment:} {JobUUID:22222222-2222-2222-2222-222222222222 FindingID:2 Comment:}]}
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:11111111-1111-1111-1111-111111111111 FindingID:1 Comment:} {JobUUID:22222222-2222-2222-2222-222222222222 FindingID:2 Comment:}] ProjectData:[]}
}

func Example_defineFalsePositivesEmptyServerList() {
func Example_defineFalsePositivesJobDataEmptyServerList() {
// An empty server list will simply add all defined false-positives

/* prepare */
Expand All @@ -116,8 +117,122 @@ func Example_defineFalsePositivesEmptyServerList() {
fmt.Printf("Remove: %+v\n", falsePositivesToRemove)

// Output:
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:11111111-1111-1111-1111-111111111111 FindingID:1 Comment:test1} {JobUUID:22222222-2222-2222-2222-222222222222 FindingID:2 Comment:test2}]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[]}
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:11111111-1111-1111-1111-111111111111 FindingID:1 Comment:test1} {JobUUID:22222222-2222-2222-2222-222222222222 FindingID:2 Comment:test2}] ProjectData:[]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[]}
}

func Example_defineFalsePositivesProjectData() {
/* prepare */
definedFalsePositives := []FalsePositivesProjectData{
{ID: "test1", Comment: "test1", WebScan: FalsePositivesProjectDataForWebScan{CweID: 1, UrlPattern: "https://example1/*", Methods: []string{"GET", "PUT"}}},
{ID: "test2", Comment: "test2", WebScan: FalsePositivesProjectDataForWebScan{CweID: 2, UrlPattern: "https://example2/*"}},
{ID: "test3", Comment: "test3", WebScan: FalsePositivesProjectDataForWebScan{CweID: 3, UrlPattern: "https://example3/*"}},
{ID: "test5", Comment: "test5", WebScan: FalsePositivesProjectDataForWebScan{CweID: 5, UrlPattern: "https://example5/*"}},
}
falsePositivesDefinitionList := FalsePositivesConfig{APIVersion: CurrentAPIVersion, Type: falsePositivesListType, ProjectData: definedFalsePositives}

falsePositivesServerList := []FalsePositiveDefinition{
{ProjectData: FalsePositivesProjectData{ID: "test1", Comment: "test1", WebScan: FalsePositivesProjectDataForWebScan{CweID: 1, UrlPattern: "https://example1/*", Methods: []string{"GET", "POST"}}}},
{ProjectData: FalsePositivesProjectData{ID: "test2", Comment: "test2 old", WebScan: FalsePositivesProjectDataForWebScan{CweID: 2, UrlPattern: "https://example2/*"}}},
{ProjectData: FalsePositivesProjectData{ID: "test4", Comment: "test4", WebScan: FalsePositivesProjectDataForWebScan{CweID: 4, UrlPattern: "https://example4/*"}}},
}

/* execute */
falsePositivesToAdd, falsePositivesToRemove := defineFalsePositives(falsePositivesDefinitionList, falsePositivesServerList)

/* test */
fmt.Printf("Add: %+v\n", falsePositivesToAdd)
fmt.Printf("Remove: %+v\n", falsePositivesToRemove)

// Output:
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[{ID:test1 Comment:test1 WebScan:{CweID:1 UrlPattern:https://example1/* Methods:[GET PUT]}} {ID:test2 Comment:test2 WebScan:{CweID:2 UrlPattern:https://example2/* Methods:[]}} {ID:test3 Comment:test3 WebScan:{CweID:3 UrlPattern:https://example3/* Methods:[]}} {ID:test5 Comment:test5 WebScan:{CweID:5 UrlPattern:https://example5/* Methods:[]}}]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[{ID:test4 Comment:test4 WebScan:{CweID:4 UrlPattern:https://example4/* Methods:[]}}]}
}

func Example_defineFalsePositivesProjectDataEmptyInputList() {
// An empty input list will remove all defined false-positives

/* prepare */
definedFalsePositives := []FalsePositivesProjectData{}
falsePositivesDefinitionList := FalsePositivesConfig{APIVersion: CurrentAPIVersion, Type: falsePositivesListType, ProjectData: definedFalsePositives}

falsePositivesServerList := []FalsePositiveDefinition{
{ProjectData: FalsePositivesProjectData{ID: "test1"}},
{ProjectData: FalsePositivesProjectData{ID: "test2"}},
}

/* execute */
falsePositivesToAdd, falsePositivesToRemove := defineFalsePositives(falsePositivesDefinitionList, falsePositivesServerList)

/* test */
fmt.Printf("Add: %+v\n", falsePositivesToAdd)
fmt.Printf("Remove: %+v\n", falsePositivesToRemove)

// Output:
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[{ID:test1 Comment: WebScan:{CweID:0 UrlPattern: Methods:[]}} {ID:test2 Comment: WebScan:{CweID:0 UrlPattern: Methods:[]}}]}
}

func Example_defineFalsePositivesProjectDataEmptyServerList() {
// An empty server list will simply add all defined false-positives

/* prepare */
definedFalsePositives := []FalsePositivesProjectData{
{ID: "test1", Comment: "test1", WebScan: FalsePositivesProjectDataForWebScan{CweID: 1, UrlPattern: "https://example1/*", Methods: []string{"GET", "PUT"}}},
{ID: "test2", Comment: "test2", WebScan: FalsePositivesProjectDataForWebScan{CweID: 2, UrlPattern: "https://example2/*"}},
}
falsePositivesDefinitionList := FalsePositivesConfig{APIVersion: CurrentAPIVersion, Type: falsePositivesListType, ProjectData: definedFalsePositives}

falsePositivesServerList := []FalsePositiveDefinition{}

/* execute */
falsePositivesToAdd, falsePositivesToRemove := defineFalsePositives(falsePositivesDefinitionList, falsePositivesServerList)

/* test */
fmt.Printf("Add: %+v\n", falsePositivesToAdd)
fmt.Printf("Remove: %+v\n", falsePositivesToRemove)

// Output:
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[{ID:test1 Comment:test1 WebScan:{CweID:1 UrlPattern:https://example1/* Methods:[GET PUT]}} {ID:test2 Comment:test2 WebScan:{CweID:2 UrlPattern:https://example2/* Methods:[]}}]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[]}
}

func Example_defineFalsePositivesWhenIdenticalToServerList() {
// When both lists are identical then no changes shall be made

/* prepare */
definedFalsePositivesJobData := []FalsePositivesJobData{
{JobUUID: "11111111-1111-1111-1111-111111111111", FindingID: 1},
{JobUUID: "22222222-2222-2222-2222-222222222222", FindingID: 2},
}
definedFalsePositivesProjectData := []FalsePositivesProjectData{
{ID: "test1", Comment: "test1", WebScan: FalsePositivesProjectDataForWebScan{CweID: 1, UrlPattern: "https://example1/*", Methods: []string{"GET", "PUT"}}},
{ID: "test2", Comment: "test2", WebScan: FalsePositivesProjectDataForWebScan{CweID: 2, UrlPattern: "https://example2/*"}},
}
falsePositivesDefinitionList := FalsePositivesConfig{
APIVersion: CurrentAPIVersion,
Type: falsePositivesListType,
JobData: definedFalsePositivesJobData,
ProjectData: definedFalsePositivesProjectData,
}

falsePositivesServerList := []FalsePositiveDefinition{
{JobData: FalsePositivesJobData{JobUUID: "11111111-1111-1111-1111-111111111111", FindingID: 1}},
{JobData: FalsePositivesJobData{JobUUID: "22222222-2222-2222-2222-222222222222", FindingID: 2}},
{ProjectData: FalsePositivesProjectData{ID: "test1", Comment: "test1", WebScan: FalsePositivesProjectDataForWebScan{CweID: 1, UrlPattern: "https://example1/*", Methods: []string{"GET", "PUT"}}}},
{ProjectData: FalsePositivesProjectData{ID: "test2", Comment: "test2", WebScan: FalsePositivesProjectDataForWebScan{CweID: 2, UrlPattern: "https://example2/*"}}},
}

/* execute */
falsePositivesToAdd, falsePositivesToRemove := defineFalsePositives(falsePositivesDefinitionList, falsePositivesServerList)

/* test */
fmt.Printf("Add: %+v\n", falsePositivesToAdd)
fmt.Printf("Remove: %+v\n", falsePositivesToRemove)

// Output:
// Add: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[]}
// Remove: {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[]}
}

func Example_getFalsePositivesUploadChunk1() {
Expand All @@ -141,7 +256,103 @@ func Example_getFalsePositivesUploadChunk1() {
/* test */

// Output:
// {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:11111111-1111-1111-1111-111111111111 FindingID:1 Comment:test1} {JobUUID:22222222-2222-2222-2222-222222222222 FindingID:2 Comment:test2}]}
// {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:33333333-3333-3333-3333-333333333333 FindingID:3 Comment:test3}]}
// {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[]}
// {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:11111111-1111-1111-1111-111111111111 FindingID:1 Comment:test1} {JobUUID:22222222-2222-2222-2222-222222222222 FindingID:2 Comment:test2}] ProjectData:[]}
// {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[{JobUUID:33333333-3333-3333-3333-333333333333 FindingID:3 Comment:test3}] ProjectData:[]}
// {APIVersion:1.0 Type:falsePositiveJobDataList JobData:[] ProjectData:[]}
}

func Example_newFalsePositivesListFromBytes_jobData() {
/* prepare */
fpJSON := `
{
"apiVersion": "1.0",
"type": "falsePositiveDataList",
"jobData": [
{
"jobUUID": "6cfa2ccf-da13-4dee-b529-0225ed9661bd",
"findingId": 1,
"comment": "Meaningful comment"
},
{
"jobUUID": "6cfa2ccf-da13-4dee-b529-0225ed9661bd",
"findingId": 2
}
]
}
`

inputfile := []byte(fpJSON)

/* execute */
fpList := newFalsePositivesListFromBytes(inputfile)

/* test */
jsonBlob, _ := json.Marshal(fpList)
fmt.Println(string(jsonBlob))

// Output:
// {"apiVersion":"1.0","type":"falsePositiveDataList","jobData":[{"jobUUID":"6cfa2ccf-da13-4dee-b529-0225ed9661bd","findingId":1,"comment":"Meaningful comment"},{"jobUUID":"6cfa2ccf-da13-4dee-b529-0225ed9661bd","findingId":2,"comment":""}],"projectData":null}
}

func Example_newFalsePositivesListFromBytes_projectData() {
/* prepare */
fpJSON := `
{
"apiVersion": "1.0",
"type": "falsePositiveDataList",
"projectData": [
{
"id": "my-id",
"comment": "text1",
"webScan": {
"cweId": 89,
"urlPattern": "https://myapp-*.example.com:80*/rest/*/search?*",
"methods": [ "GET", "DELETE" ]
}
}
]
}
`

inputfile := []byte(fpJSON)

/* execute */
fpList := newFalsePositivesListFromBytes(inputfile)

/* test */
jsonBlob, _ := json.Marshal(fpList)
fmt.Println(string(jsonBlob))

// Output:
// {"apiVersion":"1.0","type":"falsePositiveDataList","jobData":null,"projectData":[{"id":"my-id","comment":"text1","webScan":{"cweId":89,"urlPattern":"https://myapp-*.example.com:80*/rest/*/search?*","methods":["GET","DELETE"]}}]}
}

func Example_newFalsePositivesListFromBytes_projectDataWithoutCWE() {
/* prepare */
fpJSON := `
{
"apiVersion": "1.0",
"type": "falsePositiveDataList",
"projectData": [
{
"id": "my-id",
"webScan": {
"urlPattern": "https://myapp-*.example.com/rest/login?*"
}
}
]
}
`

inputfile := []byte(fpJSON)

/* execute */
fpList := newFalsePositivesListFromBytes(inputfile)

/* test */
jsonBlob, _ := json.Marshal(fpList)
fmt.Println(string(jsonBlob))

// Output:
// {"apiVersion":"1.0","type":"falsePositiveDataList","jobData":null,"projectData":[{"id":"my-id","comment":"","webScan":{"cweId":0,"urlPattern":"https://myapp-*.example.com/rest/login?*","methods":null}}]}
}
5 changes: 5 additions & 0 deletions sechub-cli/src/mercedes-benz.com/sechub/cli/urlbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ func buildFalsePositiveAPICall(context *Context) string {
return buildAPIUrl(&context.config.server, &apiPart)
}

func buildFalsePositiveProjectDataAPICall(context *Context) string {
apiPart := fmt.Sprintf("project/%s/false-positive/project-data", context.config.projectID)
return buildAPIUrl(&context.config.server, &apiPart)
}

func buildAPIUrl(server *string, apiPart *string) string {
return fmt.Sprintf("%s/api/%s", *server, *apiPart)
}
26 changes: 16 additions & 10 deletions sechub-doc/src/docs/asciidoc/documents/client/02_sechub_client.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ See also <<section-client-interactiveMarkFalsePositives-mark,example for interac
Instead of creating a json file to unmark false positives, you can also do this interactively:
Go to the project directory containing `sechub.json` and run `sechub interactiveUnmarkFalsePositives`

{sechub} client will download the current false posisitves list and interactively ask each entry: `"Do you want to remove this false positive?"`
{sechub} client will download the current false positives list and interactively ask each entry: `"Do you want to remove this false positive?"`
Your choices are:

- `y` Yes - Unmark this false positive.
Expand All @@ -250,10 +250,9 @@ See also <<section-client-interactiveMarkFalsePositives-mark,example for interac

[[section-client-false-positives-mark]]
===== markFalsePositives
Read your report carefully and figure out which of the findings are "false positives" (FP).
After this, create a json file containing jobUUID and ID of the findings you decided to be a FP.
You should add an optional comment, describing your decision to mark this as FP.
Select this file by the `-file` argument and start action `markFalsePositives`.
Read your report carefully and decide which of the findings you consider as "false positives" (FP).

Create a json file as described below and start action `markFalsePositives`.

**Minimum call syntax**
----
Expand All @@ -271,23 +270,30 @@ TIP: See also <<interactiveMarkFalsePositives,interactiveMarkFalsePositives>> fo

[[section-client-false-positives-unmark]]
===== unmarkFalsePositives
Remove formerly defined false positives. +
Remove formerly defined false positives.

It works similar to `markFalsePositives`: Just define a JSON file, select the file by the `-file` argument and start
action `unmarkFalsePositives`
action `unmarkFalsePositives`.

**Minimum call syntax**
----
sechub -file ${json-file} unmarkFalsePositives
----

*Example JSON:*
The JSON scheme is identical to `markFalsePositives`

Mandatory fields for unmarkFalsePositives: +
- for jobData: `jobUUID` and `findingId` +
- for projectData: `id`

*Example JSON with both: jobData and projectData*

[source, json]
----
include::sechub_client_falsepositive_list_example_unmark.json[]
include::sechub_client_falsepositive_list_example_unmark_jobData+projectData.json[]
----

TIP: <<interactiveUnmarkFalsePositives,interactiveMarkFalsePositives>> might be much easier to use
TIP: <<interactiveUnmarkFalsePositives,interactiveMarkFalsePositives>> might be easier to use


==== Configuration overview
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"apiVersion": "1.0",
"type": "falsePositiveDataList",
"jobData": [
{
"jobUUID": "6cfa2ccf-da13-4dee-b529-0225ed9661bd",
"findingId": 1
}
],
"projectData": [
{
"id": "unique-id"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,11 @@
{
"jobUUID": "6cfa2ccf-da13-4dee-b529-0225ed9661bd", //<4>
"findingId": 1, //<5>
"comment": "Absolute Path Traversal, can be ignored because not in deployment" //<6>
"comment": "Can be ignored because not in deployment" //<6>
},
{
"jobUUID": "6cfa2ccf-da13-4dee-b529-0225ed9661bd",
"findingId": 15
}
],
"projectData": [ //<7>
{
"id": "unique-id", //<8>
"comment": "It was verified that there is no SQL-injection vulnerability at this location",
"webScan": { //<9>
"cweId": 89, //<10>
"urlPattern": "https://*.example.com/rest/products/search*", //<11>
"methods": [ "GET", "DELETE" ] //<12>
}
}
]
}
}
Loading
Loading