From 017c2cc06837b6e852bff41cd1a135342e73c454 Mon Sep 17 00:00:00 2001 From: Guillermo Gabarrin Date: Sat, 1 Apr 2023 19:06:17 -0300 Subject: [PATCH 1/8] Parse bandit results --- README.md | 7 ++-- src/parsers/bandit.ts | 41 ++++++++++++++++++++++++ src/webviews/importToolResultsWebview.ts | 14 ++++---- 3 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 src/parsers/bandit.ts diff --git a/README.md b/README.md index a7d3cac..f3ce38e 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,10 @@ Security Notes allows the creation of notes within source files, which can be replied to, reacted to using emojis, and assigned statuses such as "TODO", "Vulnerable" and "Not Vulnerable". -Also, it allows importing the output from SAST tools (currently only [Semgrep](https://semgrep.dev/)) into notes, making the processing of the findings much easier. +Also, it allows importing the output from SAST tools into notes, making the processing of the findings much easier. Currently supported tools include: + +- semgrep (https://semgrep.dev/) +- bandit (https://bandit.readthedocs.io/en/latest/) Finally, collaborate with others by using a centralized database for notes that will be automatically synced in **real-time**! Create a note locally, and it will be automatically pushed to whoever is working with you on the project. @@ -70,7 +73,7 @@ The extension allows you to import the output from SAST tools (currently only [S ## Extension Settings -Various settings for the extension can be configured in VSCode's User Settings page (`CMD+Shift+P` / `Ctrl + Shift + P` -> *Preferences: Open Settings (UI)*): +Various settings for the extension can be configured in VSCode's User Settings page (`CMD+Shift+P` / `Ctrl + Shift + P` -> _Preferences: Open Settings (UI)_): ![Extension Settings](images/settings.png) diff --git a/src/parsers/bandit.ts b/src/parsers/bandit.ts new file mode 100644 index 0000000..b451e4d --- /dev/null +++ b/src/parsers/bandit.ts @@ -0,0 +1,41 @@ +'use strict'; + +import * as vscode from 'vscode'; +import { ToolFinding } from '../models/toolFinding'; + +class BanditParser { + static parse(fileContent: string) { + const toolFindings: ToolFinding[] = []; + + try { + const banditFindings = JSON.parse(fileContent).results; + banditFindings.map((banditFinding: any) => { + // uri + let fullPath = ''; + if (vscode.workspace.workspaceFolders) { + fullPath = vscode.workspace.workspaceFolders[0].uri.fsPath + '/'; + } + const uri = vscode.Uri.file(`${fullPath}${banditFinding.filename}`); + + // range + const lineRange = banditFinding.line_range; + const range = new vscode.Range( + lineRange[0] - 1, + 0, + (lineRange[1] ? lineRange[1] : lineRange[0]) - 1, + 0, + ); + + // instantiate tool finding and add to list + const toolFinding = new ToolFinding(uri, range, banditFinding.issue_text); + toolFindings.push(toolFinding); + }); + } catch { + /* empty */ + } + + return toolFindings; + } +} + +export { BanditParser }; diff --git a/src/webviews/importToolResultsWebview.ts b/src/webviews/importToolResultsWebview.ts index 883c166..35191bd 100644 --- a/src/webviews/importToolResultsWebview.ts +++ b/src/webviews/importToolResultsWebview.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import { commentController } from '../controllers/comments'; +import { BanditParser } from '../parsers/bandit'; import { SemgrepParser } from '../parsers/semgrep'; import { ToolFinding } from '../models/toolFinding'; import { saveNoteComment } from '../helpers'; @@ -42,12 +43,7 @@ export class ImportToolResultsWebview implements vscode.WebviewViewProvider { webviewView.webview.onDidReceiveMessage((data) => { switch (data.type) { case 'processToolFile': { - processToolFile( - data.toolName, - data.fileContent, - this.noteMap, - this.remoteDb, - ); + processToolFile(data.toolName, data.fileContent, this.noteMap, this.remoteDb); } } }); @@ -86,6 +82,7 @@ export class ImportToolResultsWebview implements vscode.WebviewViewProvider {

Select file:

@@ -113,6 +110,11 @@ function processToolFile( switch (toolName) { case 'semgrep': { toolFindings = SemgrepParser.parse(fileContent); + break; + } + case 'bandit': { + toolFindings = BanditParser.parse(fileContent); + break; } } From 4af7f32fdb9dfd2983e572dfe2bb479f34686e2c Mon Sep 17 00:00:00 2001 From: Guillermo Gabarrin Date: Sun, 2 Apr 2023 14:20:15 -0300 Subject: [PATCH 2/8] Parse brakeman results --- README.md | 13 ++++--- src/parsers/brakeman.ts | 44 ++++++++++++++++++++++++ src/webviews/importToolResultsWebview.ts | 6 ++++ 3 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 src/parsers/brakeman.ts diff --git a/README.md b/README.md index f3ce38e..53df0a7 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,7 @@ Security Notes allows the creation of notes within source files, which can be replied to, reacted to using emojis, and assigned statuses such as "TODO", "Vulnerable" and "Not Vulnerable". -Also, it allows importing the output from SAST tools into notes, making the processing of the findings much easier. Currently supported tools include: - -- semgrep (https://semgrep.dev/) -- bandit (https://bandit.readthedocs.io/en/latest/) +Also, it allows importing the output from SAST tools (such as semgrep, bandit and brakeman), into notes, making the processing of the findings much easier. Finally, collaborate with others by using a centralized database for notes that will be automatically synced in **real-time**! Create a note locally, and it will be automatically pushed to whoever is working with you on the project. @@ -67,10 +64,16 @@ Naturally, you will want to collaborate with remote peers. To do so in a secure ## Importing SAST results -The extension allows you to import the output from SAST tools (currently only [Semgrep](https://semgrep.dev/)) into notes, making the processing of the findings much easier: +The extension allows you to import the output from SAST tools into notes, making the processing of the findings much easier: ![Demo for semgrep import](images/demo-semgrep-import.gif) +Currently supported tools include: + +- semgrep (https://semgrep.dev/) +- bandit (https://bandit.readthedocs.io/en/latest/) +- brakeman (https://brakemanscanner.org/) + ## Extension Settings Various settings for the extension can be configured in VSCode's User Settings page (`CMD+Shift+P` / `Ctrl + Shift + P` -> _Preferences: Open Settings (UI)_): diff --git a/src/parsers/brakeman.ts b/src/parsers/brakeman.ts new file mode 100644 index 0000000..58f8b70 --- /dev/null +++ b/src/parsers/brakeman.ts @@ -0,0 +1,44 @@ +'use strict'; + +import * as vscode from 'vscode'; +import { ToolFinding } from '../models/toolFinding'; + +class BrakemanParser { + static parse(fileContent: string) { + const toolFindings: ToolFinding[] = []; + + try { + const brakemanFindings = JSON.parse(fileContent).warnings; + brakemanFindings.map((brakemanFinding: any) => { + // uri + let fullPath = ''; + if (vscode.workspace.workspaceFolders) { + fullPath = vscode.workspace.workspaceFolders[0].uri.fsPath + '/'; + } + const uri = vscode.Uri.file(`${fullPath}${brakemanFinding.file}`); + + // range + const range = new vscode.Range( + brakemanFinding.line - 1, + 0, + brakemanFinding.line - 1, + 0, + ); + + // instantiate tool finding and add to list + const toolFinding = new ToolFinding( + uri, + range, + `${brakemanFinding.warning_type}: ${brakemanFinding.message}`, + ); + toolFindings.push(toolFinding); + }); + } catch { + /* empty */ + } + + return toolFindings; + } +} + +export { BrakemanParser }; diff --git a/src/webviews/importToolResultsWebview.ts b/src/webviews/importToolResultsWebview.ts index 35191bd..a190767 100644 --- a/src/webviews/importToolResultsWebview.ts +++ b/src/webviews/importToolResultsWebview.ts @@ -4,6 +4,7 @@ import * as vscode from 'vscode'; import { commentController } from '../controllers/comments'; import { BanditParser } from '../parsers/bandit'; import { SemgrepParser } from '../parsers/semgrep'; +import { BrakemanParser } from '../parsers/brakeman'; import { ToolFinding } from '../models/toolFinding'; import { saveNoteComment } from '../helpers'; import { RemoteDb } from '../persistence/remote-db'; @@ -83,6 +84,7 @@ export class ImportToolResultsWebview implements vscode.WebviewViewProvider {

Select file:

@@ -116,6 +118,10 @@ function processToolFile( toolFindings = BanditParser.parse(fileContent); break; } + case 'brakeman': { + toolFindings = BrakemanParser.parse(fileContent); + break; + } } if (!toolFindings.length) { From 0f4825ec682f3ce2a9976bd98a3b02048be91de3 Mon Sep 17 00:00:00 2001 From: Guillermo Gabarrin Date: Sun, 2 Apr 2023 14:45:56 -0300 Subject: [PATCH 3/8] Parse checkov results --- README.md | 1 + src/parsers/checkov.ts | 43 ++++++++++++++++++++++++ src/webviews/importToolResultsWebview.ts | 18 ++++++---- 3 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 src/parsers/checkov.ts diff --git a/README.md b/README.md index 53df0a7..afba090 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ Currently supported tools include: - semgrep (https://semgrep.dev/) - bandit (https://bandit.readthedocs.io/en/latest/) - brakeman (https://brakemanscanner.org/) +- checkov (https://www.checkov.io/) ## Extension Settings diff --git a/src/parsers/checkov.ts b/src/parsers/checkov.ts new file mode 100644 index 0000000..7f65269 --- /dev/null +++ b/src/parsers/checkov.ts @@ -0,0 +1,43 @@ +'use strict'; + +import * as vscode from 'vscode'; +import { ToolFinding } from '../models/toolFinding'; + +class CheckovParser { + static parse(fileContent: string) { + const toolFindings: ToolFinding[] = []; + + try { + const checkovCheckTypes = JSON.parse(fileContent); + checkovCheckTypes.map((checkovCheckType: any) => { + const checkovFindings = checkovCheckType.results.failed_checks; + checkovFindings.map((checkovFinding: any) => { + // uri + let fullPath = ''; + if (vscode.workspace.workspaceFolders) { + fullPath = vscode.workspace.workspaceFolders[0].uri.fsPath + '/'; + } + const uri = vscode.Uri.file(`${fullPath}${checkovFinding.file_path}`); + + // range + const range = new vscode.Range( + checkovFinding.file_line_range[0] - 1, + 0, + checkovFinding.file_line_range[1] - 1, + 0, + ); + + // instantiate tool finding and add to list + const toolFinding = new ToolFinding(uri, range, checkovFinding.check_name); + toolFindings.push(toolFinding); + }); + }); + } catch { + /* empty */ + } + + return toolFindings; + } +} + +export { CheckovParser }; diff --git a/src/webviews/importToolResultsWebview.ts b/src/webviews/importToolResultsWebview.ts index a190767..ba4d8b7 100644 --- a/src/webviews/importToolResultsWebview.ts +++ b/src/webviews/importToolResultsWebview.ts @@ -3,8 +3,9 @@ import * as vscode from 'vscode'; import { commentController } from '../controllers/comments'; import { BanditParser } from '../parsers/bandit'; -import { SemgrepParser } from '../parsers/semgrep'; import { BrakemanParser } from '../parsers/brakeman'; +import { CheckovParser } from '../parsers/checkov'; +import { SemgrepParser } from '../parsers/semgrep'; import { ToolFinding } from '../models/toolFinding'; import { saveNoteComment } from '../helpers'; import { RemoteDb } from '../persistence/remote-db'; @@ -82,9 +83,10 @@ export class ImportToolResultsWebview implements vscode.WebviewViewProvider {

Select tool:

Select file:

@@ -110,10 +112,6 @@ function processToolFile( // parse tool findings switch (toolName) { - case 'semgrep': { - toolFindings = SemgrepParser.parse(fileContent); - break; - } case 'bandit': { toolFindings = BanditParser.parse(fileContent); break; @@ -122,6 +120,14 @@ function processToolFile( toolFindings = BrakemanParser.parse(fileContent); break; } + case 'checkov': { + toolFindings = CheckovParser.parse(fileContent); + break; + } + case 'semgrep': { + toolFindings = SemgrepParser.parse(fileContent); + break; + } } if (!toolFindings.length) { From 02540e90643bca263ef9c882046caa5db0f1b429 Mon Sep 17 00:00:00 2001 From: Guillermo Gabarrin Date: Sun, 2 Apr 2023 14:53:07 -0300 Subject: [PATCH 4/8] Specify expected format for tool results parsing --- src/webviews/assets/main.js | 2 +- src/webviews/importToolResultsWebview.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/webviews/assets/main.js b/src/webviews/assets/main.js index fd8e43d..85a572f 100644 --- a/src/webviews/assets/main.js +++ b/src/webviews/assets/main.js @@ -11,7 +11,7 @@ function onButtonClicked() { let toolSelect = document.getElementById('toolSelect'); - let toolName = toolSelect.options[toolSelect.selectedIndex].text; + let toolName = toolSelect.options[toolSelect.selectedIndex].value; let selectedFile = document.getElementById('fileInput').files[0]; readFile(selectedFile).then((fileContent) => { diff --git a/src/webviews/importToolResultsWebview.ts b/src/webviews/importToolResultsWebview.ts index ba4d8b7..7dad337 100644 --- a/src/webviews/importToolResultsWebview.ts +++ b/src/webviews/importToolResultsWebview.ts @@ -83,10 +83,10 @@ export class ImportToolResultsWebview implements vscode.WebviewViewProvider {

Select tool:

Select file:

From a36c29d811a61166f9a49692cd7059a833f60b5d Mon Sep 17 00:00:00 2001 From: Guillermo Gabarrin Date: Sun, 2 Apr 2023 15:14:46 -0300 Subject: [PATCH 5/8] Improve parsing of relative paths in tool results --- src/parsers/bandit.ts | 7 ++----- src/parsers/brakeman.ts | 7 ++----- src/parsers/checkov.ts | 7 ++----- src/parsers/semgrep.ts | 7 ++----- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/parsers/bandit.ts b/src/parsers/bandit.ts index b451e4d..c8e3d7f 100644 --- a/src/parsers/bandit.ts +++ b/src/parsers/bandit.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import { ToolFinding } from '../models/toolFinding'; +import { relativePathToFull } from '../utils'; class BanditParser { static parse(fileContent: string) { @@ -11,11 +12,7 @@ class BanditParser { const banditFindings = JSON.parse(fileContent).results; banditFindings.map((banditFinding: any) => { // uri - let fullPath = ''; - if (vscode.workspace.workspaceFolders) { - fullPath = vscode.workspace.workspaceFolders[0].uri.fsPath + '/'; - } - const uri = vscode.Uri.file(`${fullPath}${banditFinding.filename}`); + const uri = vscode.Uri.file(relativePathToFull(banditFinding.filename)); // range const lineRange = banditFinding.line_range; diff --git a/src/parsers/brakeman.ts b/src/parsers/brakeman.ts index 58f8b70..1899a97 100644 --- a/src/parsers/brakeman.ts +++ b/src/parsers/brakeman.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import { ToolFinding } from '../models/toolFinding'; +import { relativePathToFull } from '../utils'; class BrakemanParser { static parse(fileContent: string) { @@ -11,11 +12,7 @@ class BrakemanParser { const brakemanFindings = JSON.parse(fileContent).warnings; brakemanFindings.map((brakemanFinding: any) => { // uri - let fullPath = ''; - if (vscode.workspace.workspaceFolders) { - fullPath = vscode.workspace.workspaceFolders[0].uri.fsPath + '/'; - } - const uri = vscode.Uri.file(`${fullPath}${brakemanFinding.file}`); + const uri = vscode.Uri.file(relativePathToFull(brakemanFinding.file)); // range const range = new vscode.Range( diff --git a/src/parsers/checkov.ts b/src/parsers/checkov.ts index 7f65269..569450d 100644 --- a/src/parsers/checkov.ts +++ b/src/parsers/checkov.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import { ToolFinding } from '../models/toolFinding'; +import { relativePathToFull } from '../utils'; class CheckovParser { static parse(fileContent: string) { @@ -13,11 +14,7 @@ class CheckovParser { const checkovFindings = checkovCheckType.results.failed_checks; checkovFindings.map((checkovFinding: any) => { // uri - let fullPath = ''; - if (vscode.workspace.workspaceFolders) { - fullPath = vscode.workspace.workspaceFolders[0].uri.fsPath + '/'; - } - const uri = vscode.Uri.file(`${fullPath}${checkovFinding.file_path}`); + const uri = vscode.Uri.file(relativePathToFull(checkovFinding.file_path)); // range const range = new vscode.Range( diff --git a/src/parsers/semgrep.ts b/src/parsers/semgrep.ts index 3271694..295ff8d 100644 --- a/src/parsers/semgrep.ts +++ b/src/parsers/semgrep.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode'; import { ToolFinding } from '../models/toolFinding'; +import { relativePathToFull } from '../utils'; class SemgrepParser { static parse(fileContent: string) { @@ -11,11 +12,7 @@ class SemgrepParser { const semgrepFindings = JSON.parse(fileContent).results; semgrepFindings.map((semgrepFinding: any) => { // uri - let fullPath = ''; - if (vscode.workspace.workspaceFolders) { - fullPath = vscode.workspace.workspaceFolders[0].uri.fsPath + '/'; - } - const uri = vscode.Uri.file(`${fullPath}${semgrepFinding.path}`); + const uri = vscode.Uri.file(relativePathToFull(semgrepFinding.path)); // range const range = new vscode.Range( From c5099594bc3101e0ce666218a3a535af84b0046d Mon Sep 17 00:00:00 2001 From: Guillermo Gabarrin Date: Sun, 2 Apr 2023 15:54:20 -0300 Subject: [PATCH 6/8] Parse gosec results --- README.md | 3 ++- src/parsers/gosec.ts | 32 ++++++++++++++++++++++++ src/webviews/importToolResultsWebview.ts | 6 +++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/parsers/gosec.ts diff --git a/README.md b/README.md index afba090..ee524c7 100644 --- a/README.md +++ b/README.md @@ -70,10 +70,11 @@ The extension allows you to import the output from SAST tools into notes, making Currently supported tools include: -- semgrep (https://semgrep.dev/) - bandit (https://bandit.readthedocs.io/en/latest/) - brakeman (https://brakemanscanner.org/) - checkov (https://www.checkov.io/) +- gosec (https://github.com/securego/gosec) +- semgrep (https://semgrep.dev/) ## Extension Settings diff --git a/src/parsers/gosec.ts b/src/parsers/gosec.ts new file mode 100644 index 0000000..61d1972 --- /dev/null +++ b/src/parsers/gosec.ts @@ -0,0 +1,32 @@ +'use strict'; + +import * as vscode from 'vscode'; +import { ToolFinding } from '../models/toolFinding'; + +class GosecParser { + static parse(fileContent: string) { + const toolFindings: ToolFinding[] = []; + + try { + const gosecFindings = JSON.parse(fileContent).Issues; + gosecFindings.map((gosecFinding: any) => { + // uri + const uri = vscode.Uri.file(gosecFinding.file); + + // range + const line = gosecFinding.line; + const range = new vscode.Range(line - 1, 0, line - 1, 0); + + // instantiate tool finding and add to list + const toolFinding = new ToolFinding(uri, range, gosecFinding.details); + toolFindings.push(toolFinding); + }); + } catch { + /* empty */ + } + + return toolFindings; + } +} + +export { GosecParser }; diff --git a/src/webviews/importToolResultsWebview.ts b/src/webviews/importToolResultsWebview.ts index 7dad337..eabea5b 100644 --- a/src/webviews/importToolResultsWebview.ts +++ b/src/webviews/importToolResultsWebview.ts @@ -5,6 +5,7 @@ import { commentController } from '../controllers/comments'; import { BanditParser } from '../parsers/bandit'; import { BrakemanParser } from '../parsers/brakeman'; import { CheckovParser } from '../parsers/checkov'; +import { GosecParser } from '../parsers/gosec'; import { SemgrepParser } from '../parsers/semgrep'; import { ToolFinding } from '../models/toolFinding'; import { saveNoteComment } from '../helpers'; @@ -86,6 +87,7 @@ export class ImportToolResultsWebview implements vscode.WebviewViewProvider { +

@@ -124,6 +126,10 @@ function processToolFile( toolFindings = CheckovParser.parse(fileContent); break; } + case 'gosec': { + toolFindings = GosecParser.parse(fileContent); + break; + } case 'semgrep': { toolFindings = SemgrepParser.parse(fileContent); break; From 3a07b3b675f23c300102d5a9eefcf914ab3627ae Mon Sep 17 00:00:00 2001 From: Guillermo Gabarrin Date: Thu, 6 Apr 2023 12:10:47 -0300 Subject: [PATCH 7/8] Update README --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index ee524c7..85c79fc 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,21 @@ Currently supported tools include: - gosec (https://github.com/securego/gosec) - semgrep (https://semgrep.dev/) +For imports to be successful, we recommend running commands as follows (exporting results as JSON), and making sure to run these tools from the project's folder (so that all relative paths can be processed correctly): + +```bash +# bandit +bandit -f json -o bandit-results.json -r . +# brakeman +brakeman -f json -o brakeman-results.json . +# checkov +checkov -d . -o json --output-file-path checkov-results.json +# gosec +gosec -fmt=json -out=gosec-results.json ./... +# semgrep +semgrep scan --json -o semgrep-results.json --config=auto . +``` + ## Extension Settings Various settings for the extension can be configured in VSCode's User Settings page (`CMD+Shift+P` / `Ctrl + Shift + P` -> _Preferences: Open Settings (UI)_): From e19ea44200d937aaa7eead65d1797d00938fcee0 Mon Sep 17 00:00:00 2001 From: Guillermo Gabarrin Date: Thu, 6 Apr 2023 12:12:18 -0300 Subject: [PATCH 8/8] Bump version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index adb2394..14b82dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "security-notes", - "version": "1.1.1", + "version": "1.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "security-notes", - "version": "1.1.1", + "version": "1.2.0", "license": "MIT", "dependencies": { "@types/uuid": "^9.0.0", diff --git a/package.json b/package.json index 7455911..62e266b 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Security Notes", "description": "Create notes during a security code review. Import your favorite SAST tool results and collaborate with others.", "icon": "resources/security_notes_logo.png", - "version": "1.1.1", + "version": "1.2.0", "publisher": "refactor-security", "private": false, "license": "MIT",