secure-review-extension 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ - Initial production-ready v1 packaging of the Secure Review extension
6
+ - Deep static secure review workflows inside VS Code
7
+ - Findings tree, diagnostics, quick fixes, and report webview
8
+ - DOCX report export with structured security report formatting
9
+ - Marketplace-ready metadata, packaging scripts, and release docs
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Your Organization
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,304 @@
1
+ # Secure Review VS Code Extension
2
+
3
+ Secure Review is a VS Code extension for internal engineering teams that runs deep static secure code reviews and Docker-based dynamic web security scans directly from VS Code.
4
+
5
+ It can also run as a local terminal agent through the `secure-review` CLI.
6
+
7
+ ## Features
8
+
9
+ - Static workspace scan with built-in review packs
10
+ - Current-file scan command
11
+ - Docker-based OWASP ZAP dynamic scan for local/test applications
12
+ - Optional local external tool enrichment when available
13
+ - Findings tree view in the VS Code activity bar
14
+ - Inline diagnostics in the editor
15
+ - Report webview with summary, findings, and evidence
16
+ - DOCX security report export with project metadata prompts
17
+ - Ignore findings for the current workspace session
18
+ - Optional scan-on-save behavior
19
+
20
+ ## Installation
21
+
22
+ ### Visual Studio Marketplace
23
+
24
+ 1. Publish the extension with your real publisher identity.
25
+ 2. Search for `Secure Review` in VS Code Extensions.
26
+ 3. Click `Install`.
27
+
28
+ ### VSIX
29
+
30
+ 1. Package the extension:
31
+
32
+ ```bash
33
+ npm run package
34
+ ```
35
+
36
+ 2. In VS Code, run `Extensions: Install from VSIX...`
37
+ 3. Select the generated `.vsix` file.
38
+
39
+ ### CLI Agent
40
+
41
+ To use Secure Review as a terminal agent from this repo:
42
+
43
+ ```bash
44
+ npm link
45
+ ```
46
+
47
+ Then the `secure-review` command will be available on your machine:
48
+
49
+ ```bash
50
+ secure-review help
51
+ ```
52
+
53
+ To prepare the CLI package for distribution:
54
+
55
+ ```bash
56
+ npm run verify
57
+ npm run pack:cli:dry-run
58
+ ```
59
+
60
+ To build the tarball you would share or publish:
61
+
62
+ ```bash
63
+ npm run pack:cli
64
+ ```
65
+
66
+ To publish to npm after setting the final package name and metadata:
67
+
68
+ ```bash
69
+ npm run publish:npm
70
+ ```
71
+
72
+ ## Commands
73
+
74
+ - `Secure Review: Scan Workspace`
75
+ - `Secure Review: Scan Current File`
76
+ - `Secure Review: Dynamic Scan Local App`
77
+ - `Secure Review: Open Review Report`
78
+ - `Secure Review: Export Findings Report`
79
+ - `Secure Review: Clear Findings`
80
+ - `Secure Review: Ignore Finding`
81
+
82
+ ## CLI Usage
83
+
84
+ The terminal agent supports:
85
+
86
+ ```bash
87
+ secure-review inspect /path/to/repo
88
+ secure-review bootstrap /path/to/repo
89
+ secure-review bootstrap /path/to/repo --run
90
+ secure-review scan /path/to/repo --severity medium
91
+ secure-review scan /path/to/repo --format html --out report.html
92
+ secure-review scan /path/to/repo --format docx --out report.docx
93
+ secure-review scan /path/to/repo --dynamic-url http://127.0.0.1:3001 --dynamic-mode baseline
94
+ ```
95
+
96
+ Command summary:
97
+ - `inspect`
98
+ Shows detected languages, frameworks, and recommended scanner tools for a workspace.
99
+ - `bootstrap`
100
+ Prints the install plan for the workspace, or runs the supported install commands with `--run`.
101
+ - `scan`
102
+ Runs static review, optionally adds a Docker-based ZAP dynamic scan, and can export text, JSON, HTML, Markdown, or DOCX output.
103
+
104
+ ## npm Publishing Notes
105
+
106
+ Before publishing the CLI package for other users:
107
+ - replace the placeholder npm package name in [package.json](/home/ankit.singh/CODE_REVIEW_TOOL/package.json) if needed
108
+ - replace placeholder homepage, repository, and bugs URLs
109
+ - make sure the package name is actually available on npm
110
+ - run `npm run verify`
111
+ - run `npm run pack:cli:dry-run`
112
+ - run `npm run pack:cli`
113
+ - test the generated tarball locally with `npm install -g ./<tarball>.tgz`
114
+ - publish with `npm run publish:npm`
115
+
116
+ ## What The Extension Checks
117
+
118
+ ### Static checks
119
+
120
+ - hard-coded secrets and credentials
121
+ - weak crypto algorithms like `md5` and `sha1`
122
+ - SQL injection style string concatenation
123
+ - command execution sinks
124
+ - dangerous HTML injection patterns
125
+ - debug and verbose logging smells
126
+ - unsafe eval-like execution
127
+
128
+ ### Review domains
129
+
130
+ - security and vulnerability checks
131
+ - dependency and supply-chain checks
132
+ - code quality and maintainability
133
+ - reliability and error handling
134
+ - performance smells
135
+ - outdated practices
136
+ - testing gaps
137
+
138
+ ### Dynamic checks
139
+
140
+ - ZAP baseline scan for passive web checks
141
+ - ZAP full scan for active testing against local/test apps
142
+ - missing headers
143
+ - cookie issues
144
+ - information disclosure
145
+ - XSS and injection candidates surfaced by ZAP
146
+
147
+ Dynamic scans are intended only for developer-controlled local or test URLs. Full scan mode is intrusive and requires explicit confirmation.
148
+
149
+ ## Report Export
150
+
151
+ - Exported reports are generated as `.docx`
152
+ - The export flow prompts for:
153
+ - project name
154
+ - report date
155
+ - scan type
156
+ - optional notes
157
+ - Reports include:
158
+ - executive summary
159
+ - severity summary
160
+ - findings by category
161
+ - findings by review domain
162
+ - overview grouped by severity
163
+ - detailed findings with evidence, why-it-matters, remediation, and suggestions
164
+ - recommendations summary
165
+ - methodology, limitations, and scan configuration
166
+
167
+ ## Test In This Workspace
168
+
169
+ 1. Open this folder in VS Code.
170
+ 2. Press `Fn + F5` or use `Run and Debug` to launch the Extension Development Host.
171
+ 3. In the new VS Code window, open any code project.
172
+ 4. Run `Secure Review: Scan Workspace` from the Command Palette.
173
+ 5. Open the `Secure Review` activity bar icon to inspect findings.
174
+ 6. Run `Secure Review: Open Review Report` to see the webview report.
175
+ 7. Run `Secure Review: Export Findings Report` to create the Word report.
176
+
177
+ This repo already includes a vulnerable sample in [sample-workspace/demo-app.js](/home/ankit.singh/CODE_REVIEW_TOOL/sample-workspace/demo-app.js), so scanning this workspace should immediately produce findings.
178
+
179
+ ## Test The CLI Agent
180
+
181
+ 1. From this repo, run:
182
+
183
+ ```bash
184
+ npm link
185
+ ```
186
+
187
+ 2. Inspect a target workspace:
188
+
189
+ ```bash
190
+ secure-review inspect /home/ankit.singh/netbox-history-platform
191
+ ```
192
+
193
+ 3. See which scanners should be installed:
194
+
195
+ ```bash
196
+ secure-review bootstrap /home/ankit.singh/netbox-history-platform
197
+ ```
198
+
199
+ 4. Run the code review:
200
+
201
+ ```bash
202
+ secure-review scan /home/ankit.singh/netbox-history-platform --severity low
203
+ ```
204
+
205
+ 5. Export a report if needed:
206
+
207
+ ```bash
208
+ secure-review scan /home/ankit.singh/netbox-history-platform --format docx --out /home/ankit.singh/netbox-history-platform/review.docx
209
+ ```
210
+
211
+ ## Dynamic Scan Setup
212
+
213
+ 1. Install Docker and ensure it is running.
214
+ 2. Start a local test app or the included sample:
215
+
216
+ ```bash
217
+ PORT=3001 node sample-workspace/dev-server.js
218
+ ```
219
+
220
+ 3. Set `Secure Review > Dynamic Base Url` to match the port you used, for example `http://127.0.0.1:3001`.
221
+ 4. Run `Secure Review: Dynamic Scan Local App`.
222
+ 5. Use `baseline` mode first; switch to `full` mode only for applications you control.
223
+
224
+ ## Bootstrap Scanner Tools
225
+
226
+ If you want the workspace to prepare the matching external static-analysis tools before scanning, run:
227
+
228
+ ```bash
229
+ npm run bootstrap:tools
230
+ ```
231
+
232
+ That command inspects the current workspace and prints the install plan for tools such as:
233
+ - `semgrep`
234
+ - `eslint`
235
+ - `bandit`
236
+ - `pip-audit`
237
+ - `spotbugs`
238
+ - `gosec`
239
+ - `govulncheck`
240
+ - `cargo-audit`
241
+ - `clippy`
242
+ - `cppcheck`
243
+
244
+ To actually execute the supported install commands:
245
+
246
+ ```bash
247
+ npm run bootstrap:tools:run
248
+ ```
249
+
250
+ The bootstrap is best-effort:
251
+ - it detects the languages and frameworks present in the workspace
252
+ - it chooses the matching scanner tools
253
+ - it only auto-runs commands when there is a reasonable local install path
254
+ - some tools, such as `SpotBugs`, may still need a manual install depending on your OS and package manager setup
255
+
256
+ ## Packaging And Release
257
+
258
+ ### Precheck
259
+
260
+ ```bash
261
+ npm run verify
262
+ ```
263
+
264
+ ### Package
265
+
266
+ ```bash
267
+ npm run package
268
+ ```
269
+
270
+ ### Marketplace publish
271
+
272
+ ```bash
273
+ npm run publish:marketplace
274
+ ```
275
+
276
+ Before publishing:
277
+ - replace `your-publisher-id` in [package.json](/home/ankit.singh/CODE_REVIEW_TOOL/package.json)
278
+ - replace placeholder repository, homepage, and bugs URLs
279
+ - sign in to `vsce` with the publisher PAT for your Azure DevOps publisher
280
+
281
+ ## Security And Privacy Notes
282
+
283
+ - This extension is self-contained and does not require external scanner binaries.
284
+ - If local tools like `semgrep`, `npm audit`, or `pip-audit` are available, the extension can enrich static review results with them.
285
+ - Static scans operate only on files in the open workspace.
286
+ - Dynamic scans use OWASP ZAP via Docker and should only target developer-controlled local or test applications.
287
+ - The extension does not send findings to remote services.
288
+ - The rule engine is intentionally local and portable so it can be tested immediately in this workspace.
289
+
290
+ ## Troubleshooting
291
+
292
+ - `F5 changes brightness`
293
+ - Use `Fn + F5` or `Run and Debug`.
294
+ - `No findings appear`
295
+ - Lower `Secure Review > Minimum Severity` and confirm excluded globs are not hiding your files.
296
+ - Check whether built-in rules or external-tool integrations are disabled in settings.
297
+ - `Dynamic scan failed`
298
+ - Confirm Docker is installed and running.
299
+ - Confirm the target host is listed in `Secure Review > Dynamic Allow Hosts`.
300
+ - For localhost targets, confirm the app is reachable from Docker.
301
+ - `DOCX export opens incorrectly`
302
+ - Re-export after a fresh scan and test in Word or LibreOffice.
303
+ - `Marketplace package fails`
304
+ - Confirm your publisher ID, PAT, and repository metadata are set correctly.
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require("node:path");
4
+ const { spawnSync } = require("node:child_process");
5
+ const { detectWorkspace, buildInstallPlan, formatInstallPlan } = require("../src/scanners/bootstrap-tools");
6
+ const { scanWorkspaceAtPath } = require("../src/scanners/static-scan");
7
+ const { runDockerZapScanWithOptions } = require("../src/scanners/dynamic-scan");
8
+ const { buildReportModel, renderReportHtml, renderMarkdown, exportDocx } = require("../src/report");
9
+
10
+ const severityRank = {
11
+ low: 0,
12
+ medium: 1,
13
+ high: 2,
14
+ critical: 3
15
+ };
16
+
17
+ main().catch((error) => {
18
+ console.error(`secure-review failed: ${error.message}`);
19
+ process.exitCode = 1;
20
+ });
21
+
22
+ async function main() {
23
+ const { command, workspaceArg, flags } = parseArguments(process.argv.slice(2));
24
+ const workspaceRoot = path.resolve(workspaceArg || process.cwd());
25
+
26
+ switch (command) {
27
+ case "inspect":
28
+ inspectWorkspace(workspaceRoot);
29
+ return;
30
+ case "bootstrap":
31
+ bootstrapWorkspace(workspaceRoot, flags.run);
32
+ return;
33
+ case "scan":
34
+ await scanWorkspace(workspaceRoot, flags);
35
+ return;
36
+ case "help":
37
+ default:
38
+ printHelp();
39
+ }
40
+ }
41
+
42
+ function parseArguments(argv) {
43
+ const command = argv[0] || "help";
44
+ const flags = {};
45
+ let workspaceArg;
46
+
47
+ for (let index = 1; index < argv.length; index += 1) {
48
+ const token = argv[index];
49
+ if (!token.startsWith("--")) {
50
+ workspaceArg = workspaceArg || token;
51
+ continue;
52
+ }
53
+
54
+ const key = token.slice(2);
55
+ const next = argv[index + 1];
56
+ if (!next || next.startsWith("--")) {
57
+ flags[key] = true;
58
+ continue;
59
+ }
60
+
61
+ flags[key] = next;
62
+ index += 1;
63
+ }
64
+
65
+ return { command, workspaceArg, flags };
66
+ }
67
+
68
+ function inspectWorkspace(workspaceRoot) {
69
+ const profile = detectWorkspace(workspaceRoot);
70
+ const plan = buildInstallPlan(profile);
71
+ console.log(formatInstallPlan(profile, plan));
72
+ }
73
+
74
+ function bootstrapWorkspace(workspaceRoot, shouldRun) {
75
+ const profile = detectWorkspace(workspaceRoot);
76
+ const plan = buildInstallPlan(profile);
77
+ console.log(formatInstallPlan(profile, plan));
78
+
79
+ if (!shouldRun) {
80
+ console.log("");
81
+ console.log("Dry run only. Re-run with `--run` to execute supported install commands.");
82
+ return;
83
+ }
84
+
85
+ console.log("");
86
+ for (const item of plan) {
87
+ if (item.install.kind === "already-installed") {
88
+ console.log(`Skipping ${item.tool}: already available.`);
89
+ continue;
90
+ }
91
+ if (item.install.kind !== "command") {
92
+ console.log(`Skipping ${item.tool}: ${item.install.note}`);
93
+ continue;
94
+ }
95
+
96
+ console.log(`Running ${item.install.command.join(" ")}`);
97
+ const result = spawnSync(item.install.command[0], item.install.command.slice(1), {
98
+ cwd: workspaceRoot,
99
+ stdio: "inherit"
100
+ });
101
+
102
+ if (result.status !== 0) {
103
+ console.log(`Install failed for ${item.tool}.`);
104
+ }
105
+ }
106
+ }
107
+
108
+ async function scanWorkspace(workspaceRoot, flags) {
109
+ const findings = await scanWorkspaceAtPath(workspaceRoot, buildStaticConfig(flags));
110
+
111
+ if (flags["dynamic-url"]) {
112
+ const dynamicFindings = await runDockerZapScanWithOptions({
113
+ workspaceRoot,
114
+ target: flags["dynamic-url"],
115
+ scanMode: flags["dynamic-mode"] || "baseline",
116
+ allowHosts: splitCsv(flags["dynamic-allow-hosts"]) || ["127.0.0.1", "localhost"],
117
+ spiderMinutes: Number(flags["dynamic-spider-minutes"] || 1),
118
+ useAjaxSpider: Boolean(flags["dynamic-ajax"]),
119
+ dockerImage: flags["zap-image"] || "ghcr.io/zaproxy/zaproxy:stable"
120
+ });
121
+ findings.push(...dynamicFindings);
122
+ }
123
+
124
+ const filtered = filterBySeverity(findings, flags.severity || "low");
125
+
126
+ if (flags.format === "json" && !flags.out) {
127
+ console.log(JSON.stringify(filtered, null, 2));
128
+ return;
129
+ }
130
+
131
+ if (flags.format && flags.format !== "text") {
132
+ await writeReport(filtered, workspaceRoot, flags);
133
+ return;
134
+ }
135
+
136
+ printScanSummary(filtered, workspaceRoot);
137
+ }
138
+
139
+ function buildStaticConfig(flags) {
140
+ return {
141
+ excludeGlobs: [],
142
+ maxFiles: Number(flags["max-files"] || 400),
143
+ enableBuiltInRules: !isFalse(flags["built-in-rules"]),
144
+ enableSemgrep: !isFalse(flags.semgrep),
145
+ enableEslint: !isFalse(flags.eslint),
146
+ enableNpmAudit: !isFalse(flags["npm-audit"]),
147
+ enableBandit: !isFalse(flags.bandit),
148
+ enablePipAudit: !isFalse(flags["pip-audit"]),
149
+ enableSpotBugs: !isFalse(flags.spotbugs),
150
+ enableGosec: !isFalse(flags.gosec),
151
+ enableGovulncheck: !isFalse(flags.govulncheck),
152
+ enableCargoAudit: !isFalse(flags["cargo-audit"]),
153
+ enableClippy: !isFalse(flags.clippy),
154
+ enableCppcheck: !isFalse(flags.cppcheck)
155
+ };
156
+ }
157
+
158
+ function filterBySeverity(findings, minimumSeverity) {
159
+ const threshold = severityRank[minimumSeverity] ?? severityRank.low;
160
+ return findings.filter((finding) => (severityRank[finding.severity] ?? 0) >= threshold);
161
+ }
162
+
163
+ async function writeReport(findings, workspaceRoot, flags) {
164
+ const format = flags.format || "html";
165
+ const projectName = flags.project || path.basename(workspaceRoot);
166
+ const scanType = flags["dynamic-url"] ? "Static + Dynamic Analysis" : "Static Analysis";
167
+ const reportModel = buildReportModel(findings, {
168
+ projectName,
169
+ reportDate: flags.date || new Date(),
170
+ scanType,
171
+ notes: flags.notes || "",
172
+ scanConfiguration: buildScanConfiguration(flags)
173
+ });
174
+
175
+ const extension = format === "docx" ? "docx" : format === "md" ? "md" : format === "json" ? "json" : "html";
176
+ const outPath = path.resolve(flags.out || path.join(workspaceRoot, `${slugify(projectName)}-secure-review-report.${extension}`));
177
+
178
+ if (format === "docx") {
179
+ await exportDocx(reportModel, outPath);
180
+ } else if (format === "md") {
181
+ await require("node:fs/promises").writeFile(outPath, renderMarkdown(reportModel), "utf8");
182
+ } else if (format === "json") {
183
+ await require("node:fs/promises").writeFile(outPath, JSON.stringify({ findings, report: reportModel }, null, 2), "utf8");
184
+ } else {
185
+ await require("node:fs/promises").writeFile(outPath, renderReportHtml(reportModel), "utf8");
186
+ }
187
+
188
+ console.log(`Report written to ${outPath}`);
189
+ }
190
+
191
+ function buildScanConfiguration(flags) {
192
+ return [
193
+ `Minimum Severity: ${flags.severity || "low"}`,
194
+ `Built-In Rules: ${isFalse(flags["built-in-rules"]) ? "Disabled" : "Enabled"}`,
195
+ `Semgrep: ${isFalse(flags.semgrep) ? "Disabled" : "Enabled"}`,
196
+ `ESLint: ${isFalse(flags.eslint) ? "Disabled" : "Enabled"}`,
197
+ `Bandit: ${isFalse(flags.bandit) ? "Disabled" : "Enabled"}`,
198
+ `npm audit: ${isFalse(flags["npm-audit"]) ? "Disabled" : "Enabled"}`,
199
+ `pip-audit: ${isFalse(flags["pip-audit"]) ? "Disabled" : "Enabled"}`,
200
+ `SpotBugs: ${isFalse(flags.spotbugs) ? "Disabled" : "Enabled"}`,
201
+ `gosec: ${isFalse(flags.gosec) ? "Disabled" : "Enabled"}`,
202
+ `govulncheck: ${isFalse(flags.govulncheck) ? "Disabled" : "Enabled"}`,
203
+ `cargo-audit: ${isFalse(flags["cargo-audit"]) ? "Disabled" : "Enabled"}`,
204
+ `Clippy: ${isFalse(flags.clippy) ? "Disabled" : "Enabled"}`,
205
+ `cppcheck: ${isFalse(flags.cppcheck) ? "Disabled" : "Enabled"}`,
206
+ flags["dynamic-url"] ? `Dynamic URL: ${flags["dynamic-url"]}` : null,
207
+ flags["dynamic-mode"] ? `Dynamic Mode: ${flags["dynamic-mode"]}` : null
208
+ ].filter(Boolean).join("; ");
209
+ }
210
+
211
+ function printScanSummary(findings, workspaceRoot) {
212
+ console.log(`Secure Review scan completed for ${workspaceRoot}`);
213
+ console.log(`Total findings: ${findings.length}`);
214
+
215
+ const counts = ["critical", "high", "medium", "low"]
216
+ .map((severity) => `${severity}: ${findings.filter((item) => item.severity === severity).length}`)
217
+ .join(" | ");
218
+ console.log(`Severity summary: ${counts}`);
219
+ console.log("");
220
+
221
+ for (const finding of findings.slice(0, 25)) {
222
+ const location = finding.relativePath
223
+ ? `${finding.relativePath}:${finding.line || 1}`
224
+ : finding.targetUrl || "unknown-location";
225
+ console.log(`[${String(finding.severity || "low").toUpperCase()}] ${finding.title} :: ${location}`);
226
+ }
227
+
228
+ if (findings.length > 25) {
229
+ console.log("");
230
+ console.log(`Showing first 25 findings. Re-run with --format json or --format html --out <path> for full output.`);
231
+ }
232
+ }
233
+
234
+ function splitCsv(value) {
235
+ if (!value) {
236
+ return null;
237
+ }
238
+ return String(value).split(",").map((item) => item.trim()).filter(Boolean);
239
+ }
240
+
241
+ function isFalse(value) {
242
+ return value === "false" || value === false;
243
+ }
244
+
245
+ function slugify(value) {
246
+ return String(value || "secure-review")
247
+ .toLowerCase()
248
+ .replace(/[^a-z0-9]+/g, "-")
249
+ .replace(/^-+|-+$/g, "")
250
+ || "secure-review";
251
+ }
252
+
253
+ function printHelp() {
254
+ console.log(`secure-review
255
+
256
+ Commands:
257
+ secure-review inspect [workspace]
258
+ secure-review bootstrap [workspace] [--run]
259
+ secure-review scan [workspace] [--severity low|medium|high|critical] [--format text|json|html|md|docx] [--out <path>]
260
+ secure-review scan [workspace] --dynamic-url <url> [--dynamic-mode baseline|full]
261
+
262
+ Examples:
263
+ secure-review inspect /path/to/repo
264
+ secure-review bootstrap /path/to/repo --run
265
+ secure-review scan /path/to/repo --severity medium
266
+ secure-review scan /path/to/repo --format docx --out review.docx
267
+ secure-review scan /path/to/repo --dynamic-url http://127.0.0.1:3001 --format html --out report.html
268
+ `);
269
+ }