vaspera 2.10.1 → 2.11.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/dist/action/pr-comment.test.js +8 -0
- package/dist/action/pr-comment.test.js.map +1 -1
- package/dist/action/sarif-upload.test.js +8 -0
- package/dist/action/sarif-upload.test.js.map +1 -1
- package/dist/scanners/cache.d.ts.map +1 -1
- package/dist/scanners/cache.js +8 -0
- package/dist/scanners/cache.js.map +1 -1
- package/dist/scanners/dast.d.ts +40 -0
- package/dist/scanners/dast.d.ts.map +1 -0
- package/dist/scanners/dast.js +228 -0
- package/dist/scanners/dast.js.map +1 -0
- package/dist/scanners/deploy/types.d.ts +6 -6
- package/dist/scanners/index.d.ts +4 -4
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +133 -15
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/index.test.js +6 -6
- package/dist/scanners/index.test.js.map +1 -1
- package/dist/scanners/openapi.d.ts +20 -0
- package/dist/scanners/openapi.d.ts.map +1 -0
- package/dist/scanners/openapi.js +226 -0
- package/dist/scanners/openapi.js.map +1 -0
- package/dist/scanners/runtime/types.d.ts +4 -4
- package/dist/scanners/rust.d.ts +22 -0
- package/dist/scanners/rust.d.ts.map +1 -0
- package/dist/scanners/rust.js +239 -0
- package/dist/scanners/rust.js.map +1 -0
- package/dist/scanners/scale/types.d.ts +16 -16
- package/dist/scanners/terraform.d.ts +23 -0
- package/dist/scanners/terraform.d.ts.map +1 -0
- package/dist/scanners/terraform.js +207 -0
- package/dist/scanners/terraform.js.map +1 -0
- package/dist/scanners/types.d.ts +1 -1
- package/dist/scanners/types.d.ts.map +1 -1
- package/dist/scanners/types.js +8 -0
- package/dist/scanners/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI Security Scanner
|
|
3
|
+
*
|
|
4
|
+
* Validates OpenAPI/Swagger specifications for security issues
|
|
5
|
+
* using Spectral with security-focused rules.
|
|
6
|
+
*
|
|
7
|
+
* @module scanners/openapi
|
|
8
|
+
*/
|
|
9
|
+
import { exec } from "child_process";
|
|
10
|
+
import { promisify } from "util";
|
|
11
|
+
import { readFile, readdir } from "fs/promises";
|
|
12
|
+
import { join, extname } from "path";
|
|
13
|
+
const execAsync = promisify(exec);
|
|
14
|
+
const SECURITY_RULES = `
|
|
15
|
+
extends: ["spectral:oas"]
|
|
16
|
+
rules:
|
|
17
|
+
# Authentication
|
|
18
|
+
operation-security-defined:
|
|
19
|
+
description: Operations must have security defined
|
|
20
|
+
given: "$.paths[*][get,post,put,patch,delete]"
|
|
21
|
+
then:
|
|
22
|
+
field: security
|
|
23
|
+
function: truthy
|
|
24
|
+
severity: error
|
|
25
|
+
|
|
26
|
+
# HTTPS only
|
|
27
|
+
servers-https:
|
|
28
|
+
description: Server URLs should use HTTPS
|
|
29
|
+
given: "$.servers[*].url"
|
|
30
|
+
then:
|
|
31
|
+
function: pattern
|
|
32
|
+
functionOptions:
|
|
33
|
+
match: "^https://"
|
|
34
|
+
severity: error
|
|
35
|
+
|
|
36
|
+
# No credentials in URLs
|
|
37
|
+
no-credentials-in-url:
|
|
38
|
+
description: URLs should not contain credentials
|
|
39
|
+
given: "$.servers[*].url"
|
|
40
|
+
then:
|
|
41
|
+
function: pattern
|
|
42
|
+
functionOptions:
|
|
43
|
+
notMatch: "://[^/]*:[^/]*@"
|
|
44
|
+
severity: error
|
|
45
|
+
|
|
46
|
+
# Rate limiting headers
|
|
47
|
+
rate-limit-headers:
|
|
48
|
+
description: Responses should include rate limiting headers
|
|
49
|
+
given: "$.paths[*][*].responses[*].headers"
|
|
50
|
+
then:
|
|
51
|
+
function: schema
|
|
52
|
+
functionOptions:
|
|
53
|
+
schema:
|
|
54
|
+
anyOf:
|
|
55
|
+
- required: ["X-RateLimit-Limit"]
|
|
56
|
+
- required: ["X-Rate-Limit-Limit"]
|
|
57
|
+
- required: ["RateLimit-Limit"]
|
|
58
|
+
severity: warn
|
|
59
|
+
|
|
60
|
+
# Sensitive data in query params
|
|
61
|
+
no-sensitive-query-params:
|
|
62
|
+
description: Sensitive data should not be in query parameters
|
|
63
|
+
given: "$.paths[*][*].parameters[?(@.in=='query')]"
|
|
64
|
+
then:
|
|
65
|
+
field: name
|
|
66
|
+
function: pattern
|
|
67
|
+
functionOptions:
|
|
68
|
+
notMatch: "(?i)(password|secret|token|api_key|apikey|auth|credential)"
|
|
69
|
+
severity: error
|
|
70
|
+
`;
|
|
71
|
+
export async function checkSpectralAvailable() {
|
|
72
|
+
try {
|
|
73
|
+
const { stdout } = await execAsync("npx spectral --version", { timeout: 10000 });
|
|
74
|
+
return {
|
|
75
|
+
scanner: "spectral",
|
|
76
|
+
available: true,
|
|
77
|
+
version: stdout.trim(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return {
|
|
82
|
+
scanner: "spectral",
|
|
83
|
+
available: false,
|
|
84
|
+
error: "Spectral not available. Install with: npm install -g @stoplight/spectral-cli",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function mapSeverity(severity) {
|
|
89
|
+
switch (severity) {
|
|
90
|
+
case 0:
|
|
91
|
+
return "high";
|
|
92
|
+
case 1:
|
|
93
|
+
return "medium";
|
|
94
|
+
case 2:
|
|
95
|
+
return "low";
|
|
96
|
+
default:
|
|
97
|
+
return "info";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export async function runSpectral(specPath, options) {
|
|
101
|
+
const startTime = Date.now();
|
|
102
|
+
try {
|
|
103
|
+
const availability = await checkSpectralAvailable();
|
|
104
|
+
if (!availability.available) {
|
|
105
|
+
return {
|
|
106
|
+
scanner: "spectral",
|
|
107
|
+
findings: [],
|
|
108
|
+
duration: Date.now() - startTime,
|
|
109
|
+
success: false,
|
|
110
|
+
error: availability.error,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
let command = `npx spectral lint "${specPath}" -f json`;
|
|
114
|
+
if (options?.rulesetPath) {
|
|
115
|
+
command += ` -r "${options.rulesetPath}"`;
|
|
116
|
+
}
|
|
117
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
118
|
+
timeout: options?.timeout || 60000,
|
|
119
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
120
|
+
}).catch((error) => {
|
|
121
|
+
if (error.stdout) {
|
|
122
|
+
return { stdout: error.stdout, stderr: error.stderr || "" };
|
|
123
|
+
}
|
|
124
|
+
throw error;
|
|
125
|
+
});
|
|
126
|
+
const results = JSON.parse(stdout || "[]");
|
|
127
|
+
const findings = results.map((result) => ({
|
|
128
|
+
scanner: "spectral",
|
|
129
|
+
ruleId: `spectral:${result.code}`,
|
|
130
|
+
file: result.source,
|
|
131
|
+
line: result.range.start.line + 1,
|
|
132
|
+
column: result.range.start.character + 1,
|
|
133
|
+
endLine: result.range.end.line + 1,
|
|
134
|
+
message: result.message,
|
|
135
|
+
severity: mapSeverity(result.severity),
|
|
136
|
+
confidence: 100,
|
|
137
|
+
metadata: {
|
|
138
|
+
path: result.path.join("."),
|
|
139
|
+
},
|
|
140
|
+
}));
|
|
141
|
+
return {
|
|
142
|
+
scanner: "spectral",
|
|
143
|
+
findings,
|
|
144
|
+
duration: Date.now() - startTime,
|
|
145
|
+
success: true,
|
|
146
|
+
version: availability.version,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
return {
|
|
151
|
+
scanner: "spectral",
|
|
152
|
+
findings: [],
|
|
153
|
+
duration: Date.now() - startTime,
|
|
154
|
+
success: false,
|
|
155
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export async function findOpenAPISpecs(projectPath) {
|
|
160
|
+
const specs = [];
|
|
161
|
+
const extensions = [".yaml", ".yml", ".json"];
|
|
162
|
+
const patterns = ["openapi", "swagger", "api-spec", "api"];
|
|
163
|
+
async function searchDir(dir, depth = 0) {
|
|
164
|
+
if (depth > 3)
|
|
165
|
+
return;
|
|
166
|
+
try {
|
|
167
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
168
|
+
for (const entry of entries) {
|
|
169
|
+
const fullPath = join(dir, entry.name);
|
|
170
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
171
|
+
await searchDir(fullPath, depth + 1);
|
|
172
|
+
}
|
|
173
|
+
else if (entry.isFile()) {
|
|
174
|
+
const ext = extname(entry.name).toLowerCase();
|
|
175
|
+
const nameWithoutExt = entry.name.slice(0, -ext.length).toLowerCase();
|
|
176
|
+
if (extensions.includes(ext) && patterns.some((p) => nameWithoutExt.includes(p))) {
|
|
177
|
+
try {
|
|
178
|
+
const content = await readFile(fullPath, "utf-8");
|
|
179
|
+
if (content.includes("openapi") || content.includes("swagger")) {
|
|
180
|
+
specs.push(fullPath);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Skip files that can't be read
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Skip directories that can't be read
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
await searchDir(projectPath);
|
|
195
|
+
return specs;
|
|
196
|
+
}
|
|
197
|
+
export async function runOpenAPIScan(projectPath, options) {
|
|
198
|
+
const startTime = Date.now();
|
|
199
|
+
const specs = await findOpenAPISpecs(projectPath);
|
|
200
|
+
if (specs.length === 0) {
|
|
201
|
+
return {
|
|
202
|
+
scanner: "openapi",
|
|
203
|
+
findings: [],
|
|
204
|
+
duration: Date.now() - startTime,
|
|
205
|
+
success: true,
|
|
206
|
+
filesScanned: 0,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const allFindings = [];
|
|
210
|
+
for (const spec of specs) {
|
|
211
|
+
const result = await runSpectral(spec, options);
|
|
212
|
+
allFindings.push(...result.findings);
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
scanner: "openapi",
|
|
216
|
+
findings: allFindings,
|
|
217
|
+
duration: Date.now() - startTime,
|
|
218
|
+
success: true,
|
|
219
|
+
filesScanned: specs.length,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
export async function detectOpenAPI(projectPath) {
|
|
223
|
+
const specs = await findOpenAPISpecs(projectPath);
|
|
224
|
+
return specs.length > 0;
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=openapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../src/scanners/openapi.ts"],"names":[],"mappings":"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"}
|
|
@@ -90,9 +90,9 @@ export declare const GoldenPathFlowSchema: z.ZodObject<{
|
|
|
90
90
|
description?: string | undefined;
|
|
91
91
|
timeout?: number | undefined;
|
|
92
92
|
url?: string | undefined;
|
|
93
|
+
headers?: Record<string, string> | undefined;
|
|
93
94
|
body?: Record<string, unknown> | undefined;
|
|
94
95
|
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | undefined;
|
|
95
|
-
headers?: Record<string, string> | undefined;
|
|
96
96
|
screenshot?: boolean | undefined;
|
|
97
97
|
selector?: string | undefined;
|
|
98
98
|
}, {
|
|
@@ -101,9 +101,9 @@ export declare const GoldenPathFlowSchema: z.ZodObject<{
|
|
|
101
101
|
description?: string | undefined;
|
|
102
102
|
timeout?: number | undefined;
|
|
103
103
|
url?: string | undefined;
|
|
104
|
+
headers?: Record<string, string> | undefined;
|
|
104
105
|
body?: Record<string, unknown> | undefined;
|
|
105
106
|
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | undefined;
|
|
106
|
-
headers?: Record<string, string> | undefined;
|
|
107
107
|
screenshot?: boolean | undefined;
|
|
108
108
|
selector?: string | undefined;
|
|
109
109
|
}>, "many">;
|
|
@@ -116,9 +116,9 @@ export declare const GoldenPathFlowSchema: z.ZodObject<{
|
|
|
116
116
|
description?: string | undefined;
|
|
117
117
|
timeout?: number | undefined;
|
|
118
118
|
url?: string | undefined;
|
|
119
|
+
headers?: Record<string, string> | undefined;
|
|
119
120
|
body?: Record<string, unknown> | undefined;
|
|
120
121
|
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | undefined;
|
|
121
|
-
headers?: Record<string, string> | undefined;
|
|
122
122
|
screenshot?: boolean | undefined;
|
|
123
123
|
selector?: string | undefined;
|
|
124
124
|
}[];
|
|
@@ -133,9 +133,9 @@ export declare const GoldenPathFlowSchema: z.ZodObject<{
|
|
|
133
133
|
description?: string | undefined;
|
|
134
134
|
timeout?: number | undefined;
|
|
135
135
|
url?: string | undefined;
|
|
136
|
+
headers?: Record<string, string> | undefined;
|
|
136
137
|
body?: Record<string, unknown> | undefined;
|
|
137
138
|
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | undefined;
|
|
138
|
-
headers?: Record<string, string> | undefined;
|
|
139
139
|
screenshot?: boolean | undefined;
|
|
140
140
|
selector?: string | undefined;
|
|
141
141
|
}[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rust Security Scanner
|
|
3
|
+
*
|
|
4
|
+
* Scans Rust projects for security vulnerabilities using
|
|
5
|
+
* cargo-audit and clippy.
|
|
6
|
+
*
|
|
7
|
+
* @module scanners/rust
|
|
8
|
+
*/
|
|
9
|
+
import type { ScannerResult, ScannerAvailability } from "./types.js";
|
|
10
|
+
export declare function checkCargoAuditAvailable(): Promise<ScannerAvailability>;
|
|
11
|
+
export declare function checkClippyAvailable(): Promise<ScannerAvailability>;
|
|
12
|
+
export declare function runCargoAudit(projectPath: string, options?: {
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}): Promise<ScannerResult>;
|
|
15
|
+
export declare function runClippy(projectPath: string, options?: {
|
|
16
|
+
timeout?: number;
|
|
17
|
+
}): Promise<ScannerResult>;
|
|
18
|
+
export declare function runRustScanners(projectPath: string, options?: {
|
|
19
|
+
timeout?: number;
|
|
20
|
+
}): Promise<ScannerResult>;
|
|
21
|
+
export declare function detectRust(projectPath: string): Promise<boolean>;
|
|
22
|
+
//# sourceMappingURL=rust.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rust.d.ts","sourceRoot":"","sources":["../../src/scanners/rust.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAwB,aAAa,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAmE3F,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAe7E;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAezE;AAgBD,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,OAAO,CAAC,aAAa,CAAC,CAqFxB;AAED,wBAAsB,SAAS,CAC7B,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,OAAO,CAAC,aAAa,CAAC,CAmFxB;AAED,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,OAAO,CAAC,aAAa,CAAC,CAkBxB;AAED,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOtE"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rust Security Scanner
|
|
3
|
+
*
|
|
4
|
+
* Scans Rust projects for security vulnerabilities using
|
|
5
|
+
* cargo-audit and clippy.
|
|
6
|
+
*
|
|
7
|
+
* @module scanners/rust
|
|
8
|
+
*/
|
|
9
|
+
import { exec } from "child_process";
|
|
10
|
+
import { promisify } from "util";
|
|
11
|
+
import { access } from "fs/promises";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
const execAsync = promisify(exec);
|
|
14
|
+
export async function checkCargoAuditAvailable() {
|
|
15
|
+
try {
|
|
16
|
+
const { stdout } = await execAsync("cargo audit --version", { timeout: 10000 });
|
|
17
|
+
return {
|
|
18
|
+
scanner: "cargo-audit",
|
|
19
|
+
available: true,
|
|
20
|
+
version: stdout.trim(),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return {
|
|
25
|
+
scanner: "cargo-audit",
|
|
26
|
+
available: false,
|
|
27
|
+
error: "cargo-audit not found. Install with: cargo install cargo-audit",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export async function checkClippyAvailable() {
|
|
32
|
+
try {
|
|
33
|
+
const { stdout } = await execAsync("cargo clippy --version", { timeout: 10000 });
|
|
34
|
+
return {
|
|
35
|
+
scanner: "clippy",
|
|
36
|
+
available: true,
|
|
37
|
+
version: stdout.trim(),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return {
|
|
42
|
+
scanner: "clippy",
|
|
43
|
+
available: false,
|
|
44
|
+
error: "clippy not found. Install with: rustup component add clippy",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function mapAuditSeverity(severity) {
|
|
49
|
+
switch (severity.toLowerCase()) {
|
|
50
|
+
case "critical":
|
|
51
|
+
return "critical";
|
|
52
|
+
case "high":
|
|
53
|
+
return "high";
|
|
54
|
+
case "medium":
|
|
55
|
+
case "moderate":
|
|
56
|
+
return "medium";
|
|
57
|
+
default:
|
|
58
|
+
return "low";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export async function runCargoAudit(projectPath, options) {
|
|
62
|
+
const startTime = Date.now();
|
|
63
|
+
try {
|
|
64
|
+
const availability = await checkCargoAuditAvailable();
|
|
65
|
+
if (!availability.available) {
|
|
66
|
+
return {
|
|
67
|
+
scanner: "cargo-audit",
|
|
68
|
+
findings: [],
|
|
69
|
+
duration: Date.now() - startTime,
|
|
70
|
+
success: false,
|
|
71
|
+
error: availability.error,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const { stdout } = await execAsync(`cd "${projectPath}" && cargo audit --json`, {
|
|
75
|
+
timeout: options?.timeout || 120000,
|
|
76
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
77
|
+
}).catch((error) => {
|
|
78
|
+
if (error.stdout) {
|
|
79
|
+
return { stdout: error.stdout, stderr: error.stderr || "" };
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
});
|
|
83
|
+
const output = JSON.parse(stdout);
|
|
84
|
+
const findings = [];
|
|
85
|
+
for (const vuln of output.vulnerabilities.list) {
|
|
86
|
+
findings.push({
|
|
87
|
+
scanner: "cargo-audit",
|
|
88
|
+
ruleId: `cargo-audit:${vuln.advisory.id}`,
|
|
89
|
+
file: "Cargo.lock",
|
|
90
|
+
line: 1,
|
|
91
|
+
message: `${vuln.advisory.title} in ${vuln.package.name}@${vuln.package.version}`,
|
|
92
|
+
severity: mapAuditSeverity(vuln.advisory.severity),
|
|
93
|
+
confidence: 100,
|
|
94
|
+
metadata: {
|
|
95
|
+
package: vuln.package.name,
|
|
96
|
+
version: vuln.package.version,
|
|
97
|
+
advisoryUrl: vuln.advisory.url,
|
|
98
|
+
patchedVersions: vuln.versions.patched,
|
|
99
|
+
cvss: vuln.advisory.cvss,
|
|
100
|
+
description: vuln.advisory.description,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// Add warnings for unmaintained packages
|
|
105
|
+
for (const warn of output.warnings.unmaintained || []) {
|
|
106
|
+
findings.push({
|
|
107
|
+
scanner: "cargo-audit",
|
|
108
|
+
ruleId: `cargo-audit:${warn.advisory.id}`,
|
|
109
|
+
file: "Cargo.lock",
|
|
110
|
+
line: 1,
|
|
111
|
+
message: `Unmaintained package: ${warn.package.name}@${warn.package.version} - ${warn.advisory.title}`,
|
|
112
|
+
severity: "low",
|
|
113
|
+
confidence: 100,
|
|
114
|
+
metadata: {
|
|
115
|
+
package: warn.package.name,
|
|
116
|
+
version: warn.package.version,
|
|
117
|
+
type: "unmaintained",
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
scanner: "cargo-audit",
|
|
123
|
+
findings,
|
|
124
|
+
duration: Date.now() - startTime,
|
|
125
|
+
success: true,
|
|
126
|
+
version: availability.version,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
return {
|
|
131
|
+
scanner: "cargo-audit",
|
|
132
|
+
findings: [],
|
|
133
|
+
duration: Date.now() - startTime,
|
|
134
|
+
success: false,
|
|
135
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export async function runClippy(projectPath, options) {
|
|
140
|
+
const startTime = Date.now();
|
|
141
|
+
try {
|
|
142
|
+
const availability = await checkClippyAvailable();
|
|
143
|
+
if (!availability.available) {
|
|
144
|
+
return {
|
|
145
|
+
scanner: "clippy",
|
|
146
|
+
findings: [],
|
|
147
|
+
duration: Date.now() - startTime,
|
|
148
|
+
success: false,
|
|
149
|
+
error: availability.error,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
const { stdout, stderr } = await execAsync(`cd "${projectPath}" && cargo clippy --message-format=json -- -W clippy::all -W clippy::pedantic -W clippy::nursery 2>&1`, {
|
|
153
|
+
timeout: options?.timeout || 300000,
|
|
154
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
155
|
+
}).catch((error) => {
|
|
156
|
+
if (error.stdout) {
|
|
157
|
+
return { stdout: error.stdout, stderr: error.stderr || "" };
|
|
158
|
+
}
|
|
159
|
+
throw error;
|
|
160
|
+
});
|
|
161
|
+
const findings = [];
|
|
162
|
+
const lines = stdout.split("\n").filter((l) => l.trim());
|
|
163
|
+
for (const line of lines) {
|
|
164
|
+
try {
|
|
165
|
+
const msg = JSON.parse(line);
|
|
166
|
+
if (msg.reason === "compiler-message" && msg.message && msg.message.spans?.length > 0) {
|
|
167
|
+
const primarySpan = msg.message.spans.find((s) => s.is_primary) || msg.message.spans[0];
|
|
168
|
+
// Only include security-relevant lints
|
|
169
|
+
const code = msg.message.code?.code || "";
|
|
170
|
+
const isSecurityRelevant = code.includes("unsafe") ||
|
|
171
|
+
code.includes("panic") ||
|
|
172
|
+
code.includes("unwrap") ||
|
|
173
|
+
code.includes("expect") ||
|
|
174
|
+
code.includes("transmute") ||
|
|
175
|
+
msg.message.level === "error";
|
|
176
|
+
if (isSecurityRelevant) {
|
|
177
|
+
findings.push({
|
|
178
|
+
scanner: "clippy",
|
|
179
|
+
ruleId: `clippy:${code}`,
|
|
180
|
+
file: primarySpan.file_name.replace(projectPath + "/", ""),
|
|
181
|
+
line: primarySpan.line_start,
|
|
182
|
+
endLine: primarySpan.line_end,
|
|
183
|
+
column: primarySpan.column_start,
|
|
184
|
+
message: msg.message.message,
|
|
185
|
+
severity: msg.message.level === "error" ? "high" : "medium",
|
|
186
|
+
confidence: 100,
|
|
187
|
+
evidence: primarySpan.text?.[0]?.text,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Skip non-JSON lines
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
scanner: "clippy",
|
|
198
|
+
findings,
|
|
199
|
+
duration: Date.now() - startTime,
|
|
200
|
+
success: true,
|
|
201
|
+
version: availability.version,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
return {
|
|
206
|
+
scanner: "clippy",
|
|
207
|
+
findings: [],
|
|
208
|
+
duration: Date.now() - startTime,
|
|
209
|
+
success: false,
|
|
210
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
export async function runRustScanners(projectPath, options) {
|
|
215
|
+
const startTime = Date.now();
|
|
216
|
+
const [auditResult, clippyResult] = await Promise.all([
|
|
217
|
+
runCargoAudit(projectPath, options),
|
|
218
|
+
runClippy(projectPath, options),
|
|
219
|
+
]);
|
|
220
|
+
const findings = [...auditResult.findings, ...clippyResult.findings];
|
|
221
|
+
const success = auditResult.success || clippyResult.success;
|
|
222
|
+
return {
|
|
223
|
+
scanner: "rust",
|
|
224
|
+
findings,
|
|
225
|
+
duration: Date.now() - startTime,
|
|
226
|
+
success,
|
|
227
|
+
error: !success ? "No Rust scanners available" : undefined,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
export async function detectRust(projectPath) {
|
|
231
|
+
try {
|
|
232
|
+
await access(join(projectPath, "Cargo.toml"));
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=rust.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rust.js","sourceRoot":"","sources":["../../src/scanners/rust.ts"],"names":[],"mappings":"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"}
|