Skip to content

Commit c122695

Browse files
committed
Merge branch 'feat/pre-release-changes' into dev
2 parents 69d7e2b + 776ab1b commit c122695

15 files changed

+327
-210
lines changed

README.md

Lines changed: 98 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,120 @@
1-
# README
2-
3-
## SAH - Static Analysis Hero
4-
5-
Finds vulnerabilities in source code using pattern matching, allows easy organization and export of findings.
6-
SAH is used while having the project to review open in VSCode.
7-
Open the command palette (`Ctrl + Shift + P`) and type "SAH" for all available commands.
8-
Additionally some commands are available from the context menu (right click), and from keyboard shortcut.
9-
Results in this plugin are organized as *Matches*.
10-
A match is a possible finding, based on a list of regular expressions or semgrep rules, that should hint at common vulnerabilities.
11-
12-
### Usage
13-
14-
- [README](#readme)
15-
- [SAH - Static Analysis Hero](#sah---static-analysis-hero)
16-
- [Usage](#usage)
17-
- [Install/ Dev Setup](#install-dev-setup)
18-
- [Review Projects](#review-projects)
19-
- [New Project](#new-project)
20-
- [Load Project](#load-project)
21-
- [Scan For Potential Findings](#scan-for-potential-findings)
22-
- [Scan Code](#scan-code)
23-
- [Import semgrep Scan](#import-semgrep-scan)
24-
- [Scanning Sandbox](#scanning-sandbox)
25-
- [Review Matches](#review-matches)
1+
# Static Analysis Hero (SAH)
2+
3+
## Introduction
4+
5+
SAH is a Visual Studio Code extension for efficient and effective security code reviews. It integrates external code scanning tools (e.g. semgrep / opengrep) and provides a toolbox for reviewing source code for security vulnerabilities.
6+
7+
SAH is used while having the project to review open in VSCode. Open the command palette (`Ctrl + Shift + P`) and type "SAH" for all available commands. Additionally, some commands are available from the context menu (right click), and from keyboard shortcut.
8+
9+
Results in this plugin are organized as *Matches*. A match is a possible security vulnerability, based on a list of regular expressions or semgrep / opengrep rule. Upon manual inspection, matches can be categorized as findings or false positives.
10+
11+
### Table of Contents
12+
- [Installation](#installation)
13+
- [Usage](#usage)
14+
- [Working with Projects](#working-with-projects)
15+
- [New Project](#new-project)
16+
- [Load Project](#load-project)
17+
- [Scan For Potential Findings](#scan-for-potential-findings)
18+
- [Scan Code](#scan-code)
19+
- [Import Semgrep / Opengrep Scan](#import-semgrep--opengrep-scan)
20+
- [Scanning Sandbox](#scanning-sandbox)
21+
- [Review Matches](#review-matches)
2622
- [Blacklist Files And Directories](#blacklist-files-and-directories)
27-
- [Command Palette](#command-palette)
23+
- [Command Palette](#command-palette)
24+
- [Contribution & Dev Setup](#contribution--dev-setup)
25+
- [Development Setup](#development-setup)
26+
- [Debugging in VSCode](#debugging-in-vscode)
2827

29-
#### Install/ Dev Setup
3028

31-
To build this plugin, you need a recent version of nodejs and npm on your machine.
29+
## Installation
3230

31+
1. Download the `.vsix`-file from the Releases section in GitHub.
32+
2. In VSCode, navigate to the Extensions menu and select `Install from VSIX...`.
33+
3. After installation, launch SAH from the command palette (`Ctrl + Shift + P`).
34+
35+
If you want to build SAH from source, see instructions in the section [Contribution & Dev Setup](#contribution--dev-setup) below.
3336

34-
```
35-
sudo apt install npm nodejs
36-
git clone git@github.com:usdAG/sah.git
37-
cd visual-source-code-plugin
38-
npm install --legacy-peer-deps
39-
npm install '@vscode/vsce' --legacy-peer-deps
40-
node_modules/@vscode/vsce/vsce package
41-
```
4237

43-
You can the install the resulting .vsix file in VSCode via the `Extensions: Install from VSIX...` command.
38+
## Usage
4439

45-
#### Review Projects
40+
### Working with Projects
4641

47-
##### New Project
42+
#### New Project
4843

49-
To start a review project open command palette and run `SAH: New Project`.
50-
Create a file that should be used as a project file.
44+
To start a review project, open the command palette and choose `SAH: New Project`.
45+
Select a file that will be used to preserve the project state (in JSON format).
5146
All actions will automatically be saved to this file.
5247

53-
##### Load Project
48+
#### Load Project
5449

55-
To resume a previous project, or import a project file, run `SAH: Load Project` from the command palette and select the respective project file.
50+
To resume a project, or import a project file, run `SAH: Load Project` from the command palette and select the respective project file.
5651
If there is no review project loaded, all actions are temporary only!
5752

58-
#### Scan For Potential Findings
5953

60-
To add a scan, you can either run a new *semgrep*/ *opengrep* scan or import an existing one into the TOL.
54+
### Scan For Potential Findings
6155

62-
##### Scan Code
56+
To add a scan, you can either run a new *semgrep*/ *opengrep* scan or import scan results into the tool.
6357

64-
Call the `SAH: Scan Code` dialog from the command palette.
65-
The SAH allows you to start scans from within the plugin.
58+
#### Scan Code
59+
60+
Call the `SAH: Scan Code` command from the command palette. SAH allows you to start semgrep scans from within the plugin.
6661

6762
This requires an install of semgrep/ opengrep on the local system.
68-
Installation is recommended by using `pipx` (e.g. for semgrep `pipx install semgrep`)
63+
Installation is recommended by using `pipx` (e.g. for semgrep `pipx install semgrep`).
64+
65+
The interface lets you define the following parameters:
66+
- The *config* to use for the scan: Either point to custom rules on disk or provide the name(s) of a standard ruleset, such as `p/owasp-top-ten` available in the [semgrep registry](https://semgrep.dev/r)
67+
- The *output destination* specifies a path to write the scan results on disk (in addition to storing the results in the project file)
68+
- Optional: *Include Patterns* / *Exclude Patterns* tune the scanning engine of semgrep to include or exclude resources for scanning
6969

70-
The dialog lets you define the following parameters:
71-
- The config to use for the scan: This can either be an OS path pointing to custom rules or a standard ruleset such as `p/owasp-top-ten` available in the [semgrep registry](https://semgrep.dev/r)
72-
- The outpath writes the scan to a chosen location on disk for archival
73-
- Include Patterns/ Exclude Patterns tune the scanning engine of semgrep to include/ exclude resources for scanning
70+
After configuration, start the scan. Progress will be transparent during the scan and the results are automatically imported into the matches view.
7471

75-
When finished configuring you can start the scan by clicking the "Start Scan" button.
76-
After the scan is finished results are automatically imported into the matches view.
72+
*Note that semgrep requires an active Internet connection to download / update rules from the registry.*
7773

7874

79-
#### Import semgrep Scan
75+
#### Import Semgrep / Opengrep Scan
8076

81-
If you already have a semgrep/opengrep scan you can import them also in `SAH: Scan Code`. An exemplary command to run a semgrep scan, importable by the SAH, is as follows: `semgrep scan -c "<ruleset>" --json -o <outputfile>`.
82-
Some important notices:
77+
It is possible to import existing semgrep/opengrep scan results into SAH. To do so, use the upper section in the `SAH: Scan Code` command. For example, run the following command in a terminal and select the resulting outputfile for import: `semgrep scan -c "<ruleset>" --json -o <outputfile>`.
78+
79+
Important notes:
8380
- `--json` is required as the plugin can only parse the JSON output of semgrep
84-
- The SAH creates links from the findings to the affected files. In order for this to work it currently requires your semgrep scans to *NOT* include the full paths, but scan from the project/worksapce root. This can be achieved by scanning a path like `.` or removing the path entirely. Tip: If you already performed a scan and the paths don't match just edit the json file.
81+
- SAH creates links from the findings to the affected files. In order for this to work, it currently requires your semgrep scans to *NOT* include the full paths, but scan from the project/workspace root. This can be achieved by scanning a path like `.` or removing the path entirely. Tip: If you already performed a scan and the paths don't match, manually edit the json file.
82+
8583

8684
#### Scanning Sandbox
8785

88-
With the `SAH: Scanning Sandbox` command you can open the scanning sandbox. It allows you to quickly develop new rules in a running project and test their detection capabilities in your currently opened codebase. It allows you to specify a ruleset or a single rule - that will conveniently be opened in a separate tab inside VSCode for quick edits - to run against the current workspace. It directly integrates a view of alle matches found with this rule.
86+
With the `SAH: Scanning Sandbox` command you can open the scanning sandbox. It allows you to quickly develop new rules in a running project and test their detection capabilities in the codebase - without importing the results into the project state. You can either specify a ruleset or a single rule - that will conveniently be opened in a separate tab inside VSCode for quick edits - to run against the current workspace. It directly integrates a view of all matches found with this rule.
8987

90-
This way you can develop new rules or enhance existing ones. Once your satisfied with the results of your scans you can directly import them into the *Matches View* from here and continue investigating.
88+
Using the scanning sandbox is useful for developing new or enhancing existing rules. Once your satisfied with the results of your scan, you can directly import the results into the project - and thus the *Matches View* - for further review.
9189

92-
#### Review Matches
9390

94-
You can get an overview of all matches by using the `SAH: Show Matches List` commmand.
91+
### Review Matches
9592

96-
It enables you to review and work through the list of issues.
97-
You can also categorize them with the buttons on every match. This enables priorization of certain matches.
93+
In order to list all matches, use the `SAH: Show Matches List` commmand. This provides an overview with various filter options.
9894

99-
To only get matches from a certain file right click the file in the workspace explorer.
95+
For each match, multiple utility functions are available:
10096

101-
You can filter the matches to only show matches from certain paths in the workspace or exclude other paths. This can be done by going to the "File Explorer" on the bottom left of the workspace panel.
102-
By right clicking on a folder you can either exclude it or show matches only from this path. Reset is possible in the top bar of this File Explorer.
97+
- *Jump to code*: Opens the corresponding file and selects the exact match in the correct line of the file
98+
- *Finding*: After review, set the status of this match to finding when it represents an actual vulnerability (true positive)
99+
- *False Positive*: After review, set the status of this match to false positive when there is no vulnerability
100+
- *Save for Later*: Use this status to mark this finding for follow-up review (e.g. when passing on the project to another person)
103101

104-
### Blacklist Files And Directories
102+
*Tip:* While performing the manual code review, filter for the status "Unprocessed" to hide matches which have already been classified.
103+
104+
To narrow down the manual analysis, use the context menu with a *right click* on a file in the workspace. This allows to
105+
106+
- *SAH: Only show Matches for this file*: Filter matches for a single file
107+
- *SAH: Exclude File/Folder*: Filter matches *not* in a single file or folder
108+
- *SAH: Reset the exclusion of all files/folders*
109+
110+
Finally, SAH provides an additional *File Explorer* in the bottom left panel that shows excluded files (toggle with button) as well as the number of findings per file.
111+
112+
#### Blacklist Files And Directories
105113

106114
You may not want to search every single file or directory in the project. In this case, create a file in your project folder called '`.semgrepignore`'. This file should contain names of all the files and directories that you want to be excluded from the code scan.
107-
In lieu of a `.semgrepignore` file, a default blacklist is used containing some commonly blacklisted files and directories (`node_modules`, `package-lock.json` etc.)
115+
In lieu of a `.semgrepignore` file, a default blacklist is used containing some commonly blacklisted files and directories (`node_modules`, `package-lock.json`, etc.)
108116

109-
### Command Palette
117+
## Command Palette
110118

111119
- `SAH: New Project`: Create a new project on disk to work with SAH and save your progress
112120
- `SAH: Load Project`: Open FS window to select and load a review project file.
@@ -116,3 +124,22 @@ In lieu of a `.semgrepignore` file, a default blacklist is used containing some
116124
- `SAH: Scanning Sandbox`: Allows you to easily test/ adjust rules on your current workspace and import resulting matches afterwards
117125
- `SAH: Show Help`: Renders this README inside VSCode for quick help
118126
- `SAH: Set Log Level to <LEVEL>`: Allows you to update the Loglevel for troubleshooting. Levels are: Off, Debug, Info, Warn, Error.
127+
128+
129+
## Contribution & Dev Setup
130+
131+
### Development Setup
132+
133+
To build this plugin, you need a recent version of nodejs and npm, as well as vsce to create the `vsix` package.
134+
135+
```
136+
sudo apt install npm nodejs
137+
git clone ssh://git@github.com:usdAG/sah
138+
cd sah
139+
npm install --legacy-peer-deps
140+
npm install '@vscode/vsce' --legacy-peer-deps
141+
node_modules/@vscode/vsce/vsce package
142+
```
143+
144+
### Debugging in VSCode
145+
In VS Code, open the code of SAH. Then use `F5` to launch a debugging session.

src/extension.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import {
1414
newProject, loadProject, saveProject, displayNoProjectWarning,
1515
} from './projects';
16-
import generateStartWebview from './startWebview';
16+
// import generateStartWebview from './startWebview';
1717
import generateSemgrepWebview from './semgrepWebview';
1818
import {
1919
isRelative, handlePathSelection, handleOutputPathSelection,
@@ -118,8 +118,8 @@ export const activate = (context: vscode.ExtensionContext) => {
118118
}),
119119
vscode.commands.registerCommand("extension.newProject", () => {
120120
const callback = () => {
121-
// set HTML content
122-
activePanel().webview.html = generateStartWebview(activePanel().webview, localPath);
121+
//activePanel().webview.html = generateStartWebview(activePanel().webview, localPath);
122+
activePanel().webview.html = generateSemgrepWebview(activePanel().webview, localPath);
123123
};
124124
newProject(callback);
125125
}),
@@ -146,9 +146,8 @@ export const activate = (context: vscode.ExtensionContext) => {
146146
updateAllMatches(newMatches)
147147
vscode.commands.executeCommand('extension.showMatchesList');
148148
}),
149-
// https://stackoverflow.com/questions/70074231/in-a-vs-code-extension-open-the-markdown-preview-of-the-readme-md-of-the-extens
150149
vscode.commands.registerCommand("extension.showHelp", () => {
151-
const readmePath = path.join(context.extensionPath, "readme.md"); //context.asAbsolutePath("README.md");
150+
const readmePath = path.join(context.extensionPath, "readme.md");
152151
logger.debug("Open readme from location: " + readmePath);
153152
vscode.commands.executeCommand("markdown.showPreview", vscode.Uri.file(readmePath));
154153
})
@@ -174,8 +173,8 @@ export const activate = (context: vscode.ExtensionContext) => {
174173

175174
// initialize webview panel
176175
panel = vscode.window.createWebviewPanel(
177-
'sah', // type of webview
178-
'SAH', // title of panel
176+
'sah',
177+
'Static Analysis Hero (SAH)',
179178
vscode.ViewColumn.Beside,
180179
{
181180
enableScripts: true,
@@ -223,9 +222,9 @@ export const activate = (context: vscode.ExtensionContext) => {
223222
importMatchesTestSection : hImportMatchesTestSection,
224223
};
225224

226-
const post = (msg: any) => panel.webview.postMessage(msg);
227-
const cmd = (c: string) => vscode.commands.executeCommand(c);
228-
const log = (...a: any[]) => logger.debug('[msg]', ...a);
225+
const post = (msg: any) => panel.webview.postMessage(msg);
226+
const cmd = (c: string) => vscode.commands.executeCommand(c);
227+
const log = (...a: any[]) => logger.debug('[msg]', ...a);
229228
const showMatchesList = () => cmd('extension.showMatchesList');
230229

231230
function hJump(message:any){
@@ -341,7 +340,7 @@ export const activate = (context: vscode.ExtensionContext) => {
341340
finalImportSemgrepJson(isTest);
342341
return;
343342
}
344-
vscode.window.showInformationMessage("There is currently now data to import!");
343+
vscode.window.showInformationMessage("There is currently no data to import!");
345344
}
346345
// listen for messages from the webview
347346
// this now calles the function based on the command set in the handlers

src/logging.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Logger {
1313
public setLogLevel(level: 'debug' | 'info' | 'warn' | 'error' | 'off') {
1414
this.logLevel = level;
1515
vscode.window.showInformationMessage(`SAH log level set to ${level}.`);
16+
this.log('INFO', `SAH log level set to ${level}.`, []);
1617
}
1718

1819
debug(msg: string, ...args: any[]) {

src/matches.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,24 @@ export interface Match {
1717
selected: boolean; // this is for the multiselect in the MatchesWebview
1818
}
1919

20+
export const criticalityOptions = [
21+
{ value: '0', label: 'All Criticalities', icon: '' },
22+
{ value: '1', label: 'INFO', icon: '&#x1F535;' },
23+
{ value: '2', label: 'LOW', icon: '&#x1F7E1;' },
24+
{ value: '3', label: 'MEDIUM', icon: '&#x1F7E0;' },
25+
{ value: '4', label: 'HIGH', icon: '&#x1F534;' },
26+
{ value: '5', label: 'CRITICAL', icon: '&#x1F534;' },
27+
];
28+
29+
export const statusOptions = [
30+
{ value: 'all', label: 'All Matches' },
31+
{ value: 'unprocessed', label: 'Unprocessed' },
32+
{ value: 'finding', label: 'Findings' },
33+
{ value: 'falsePositive', label: 'False Positive' },
34+
{ value: 'saveForLater', label: 'Saved for later' }
35+
];
36+
37+
2038
export let allMatches: Array<Match> = [];
2139
export const toggledMatchIds: Set<number> = new Set<number>();
2240
let matchIdCounter = 0;

0 commit comments

Comments
 (0)