@maverick006/ai-engine 1.0.2 → 1.0.4
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/explainer.d.ts +5 -0
- package/dist/explainer.d.ts.map +1 -1
- package/dist/explainer.js +85 -51
- package/dist/explainer.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/verifier.d.ts +24 -0
- package/dist/verifier.d.ts.map +1 -0
- package/dist/verifier.js +109 -0
- package/dist/verifier.js.map +1 -0
- package/package.json +24 -23
- package/src/explainer.ts +171 -127
- package/src/index.ts +1 -0
- package/src/verifier.ts +91 -0
- package/tests/eval/evaluation-harness.test.ts +2 -0
- package/tests/eval/evaluation-harness.ts +190 -0
- package/tests/explainer.test.ts +47 -26
- package/tests/verifier.test.ts +89 -0
- package/tsconfig.tsbuildinfo +0 -1
package/dist/explainer.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface ExplanationOptions {
|
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Generates contextual explanations for deterministic security findings using NVIDIA NIM.
|
|
9
|
+
* Operates as an optional advisory module; returns deterministic scanner guidance if API key is missing.
|
|
9
10
|
*/
|
|
10
11
|
export declare class ContextualExplainer {
|
|
11
12
|
private ai;
|
|
@@ -15,6 +16,10 @@ export declare class ContextualExplainer {
|
|
|
15
16
|
* Generates a contextual explanation and remediation strategy for a given finding.
|
|
16
17
|
*/
|
|
17
18
|
explainFinding(finding: NormalizedFinding, options?: ExplanationOptions): Promise<AIExplanation>;
|
|
19
|
+
/**
|
|
20
|
+
* Complete pre-AI secret redaction to ensure credentials never leak into prompt context.
|
|
21
|
+
*/
|
|
22
|
+
maskSecrets(text: string): string;
|
|
18
23
|
private buildPrompt;
|
|
19
24
|
private parseAIResponse;
|
|
20
25
|
private generateFallbackExplanation;
|
package/dist/explainer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explainer.d.ts","sourceRoot":"","sources":["../src/explainer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGtE,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED
|
|
1
|
+
{"version":3,"file":"explainer.d.ts","sourceRoot":"","sources":["../src/explainer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGtE,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,EAAE,CAAuB;IACjC,OAAO,CAAC,YAAY,CAAwC;gBAEhD,MAAM,CAAC,EAAE,MAAM;IAU3B;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,aAAa,CAAC;IAkC1G;;OAEG;IACI,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAyBxC,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,2BAA2B;CAgBpC"}
|
package/dist/explainer.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.ContextualExplainer = void 0;
|
|
|
7
7
|
const openai_1 = __importDefault(require("openai"));
|
|
8
8
|
/**
|
|
9
9
|
* Generates contextual explanations for deterministic security findings using NVIDIA NIM.
|
|
10
|
+
* Operates as an optional advisory module; returns deterministic scanner guidance if API key is missing.
|
|
10
11
|
*/
|
|
11
12
|
class ContextualExplainer {
|
|
12
13
|
ai = null;
|
|
@@ -24,94 +25,127 @@ class ContextualExplainer {
|
|
|
24
25
|
* Generates a contextual explanation and remediation strategy for a given finding.
|
|
25
26
|
*/
|
|
26
27
|
async explainFinding(finding, options = {}) {
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
const client = options.apiKey
|
|
29
|
+
? new openai_1.default({ apiKey: options.apiKey, baseURL: 'https://integrate.api.nvidia.com/v1' })
|
|
30
|
+
: this.ai;
|
|
31
|
+
if (!client) {
|
|
32
|
+
// Deterministic fallback when no AI API key is configured
|
|
29
33
|
return this.generateFallbackExplanation(finding);
|
|
30
34
|
}
|
|
31
35
|
try {
|
|
32
36
|
const modelName = options.model || this.defaultModel;
|
|
33
|
-
|
|
34
|
-
const
|
|
37
|
+
// MASK ALL SECRETS BEFORE SENDING TO MODEL
|
|
38
|
+
const safeContext = this.maskSecrets(options.codeContext || '').slice(0, 2000); // 2000 chars max context
|
|
39
|
+
const safeFinding = { ...finding, codeSnippet: this.maskSecrets(finding.codeSnippet || '') };
|
|
40
|
+
const prompt = this.buildPrompt(safeFinding, safeContext);
|
|
41
|
+
const completion = await client.chat.completions.create({
|
|
35
42
|
model: modelName,
|
|
36
43
|
messages: [{ role: "user", content: prompt }],
|
|
37
|
-
temperature: 0.2,
|
|
44
|
+
temperature: 0.2,
|
|
38
45
|
max_tokens: 1024,
|
|
39
46
|
});
|
|
40
47
|
const text = completion.choices[0]?.message?.content || "";
|
|
41
48
|
return this.parseAIResponse(finding.scanId || 'unknown', text);
|
|
42
49
|
}
|
|
43
50
|
catch (error) {
|
|
44
|
-
console.
|
|
45
|
-
return this.generateFallbackExplanation(finding);
|
|
51
|
+
console.warn('AI explanation failed, reverting to deterministic guidance:', error.message);
|
|
52
|
+
return this.generateFallbackExplanation(finding, 'FAILED');
|
|
46
53
|
}
|
|
47
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Complete pre-AI secret redaction to ensure credentials never leak into prompt context.
|
|
57
|
+
*/
|
|
58
|
+
maskSecrets(text) {
|
|
59
|
+
if (!text)
|
|
60
|
+
return text;
|
|
61
|
+
let masked = text;
|
|
62
|
+
// Mask Private Keys
|
|
63
|
+
masked = masked.replace(/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g, '[MASKED_PRIVATE_KEY]');
|
|
64
|
+
// Mask AWS Access Keys
|
|
65
|
+
masked = masked.replace(/\b(AKIA|ASIA|AROA)[0-9A-Z]{16}\b/g, '$1[MASKED_AWS_KEY]');
|
|
66
|
+
// Mask Database Connection Strings (Postgres, MySQL, Mongo, Redis)
|
|
67
|
+
masked = masked.replace(/(?:postgres|postgresql|mysql|mongodb|mongodb\+srv|redis):\/\/[^\s"']+/gi, '[MASKED_DATABASE_URL]');
|
|
68
|
+
// Mask Bearer Tokens
|
|
69
|
+
masked = masked.replace(/Bearer\s+[a-zA-Z0-9_\-\.]+/gi, 'Bearer [MASKED_BEARER_TOKEN]');
|
|
70
|
+
// Mask JWTs
|
|
71
|
+
masked = masked.replace(/eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/g, '[MASKED_JWT]');
|
|
72
|
+
// Mask Generic Secrets in code (password = "...", secret: '...', token = "...")
|
|
73
|
+
masked = masked.replace(/(password|secret|token|api[_-]?key|client_secret)["'\s:=]+(["'])(?:(?!\2).)+(\2)/gi, '$1="[MASKED_SECRET]"');
|
|
74
|
+
return masked;
|
|
75
|
+
}
|
|
48
76
|
buildPrompt(finding, codeContext) {
|
|
49
|
-
return `
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"summary": "A 1-2 sentence summary of what the issue is.",
|
|
72
|
-
"details": "A detailed explanation of how this vulnerability works and why it's dangerous.",
|
|
73
|
-
"remediation": "A step-by-step guide to fixing the issue.",
|
|
74
|
-
"codeFix": "The exact code snippet to replace the vulnerable code. (Optional, if applicable)"
|
|
75
|
-
}
|
|
76
|
-
`;
|
|
77
|
+
return `You are VibeGuard, a strict DevSecOps assistant.
|
|
78
|
+
A deterministic security scanner detected this vulnerability:
|
|
79
|
+
Title: ${finding.title}
|
|
80
|
+
Severity: ${finding.severity}
|
|
81
|
+
Scanner: ${finding.scanner}
|
|
82
|
+
File: ${finding.file || 'N/A'}
|
|
83
|
+
Line: ${finding.line || 'N/A'}
|
|
84
|
+
Rule: ${finding.ruleId || 'N/A'}
|
|
85
|
+
Description: ${finding.description || 'N/A'}
|
|
86
|
+
CWE: ${finding.cwe || 'Unknown'}
|
|
87
|
+
OWASP: ${finding.owasp || 'Unknown'}
|
|
88
|
+
|
|
89
|
+
${codeContext ? `CODE CONTEXT:\n${codeContext}` : ''}
|
|
90
|
+
${finding.codeSnippet ? `SNIPPET:\n${finding.codeSnippet}` : ''}
|
|
91
|
+
|
|
92
|
+
Provide an actionable remediation in pure JSON with no markdown wrapping:
|
|
93
|
+
{
|
|
94
|
+
"summary": "1-2 sentence overview of the vulnerability.",
|
|
95
|
+
"details": "Technical explanation of the security risk.",
|
|
96
|
+
"remediation": "Step-by-step guidance to fix the vulnerability.",
|
|
97
|
+
"codeFix": "The patched code snippet to replace the vulnerable lines."
|
|
98
|
+
}`;
|
|
77
99
|
}
|
|
78
100
|
parseAIResponse(findingId, text) {
|
|
79
101
|
try {
|
|
80
|
-
|
|
81
|
-
const
|
|
102
|
+
let cleanText = text.trim();
|
|
103
|
+
const jsonMatch = cleanText.match(/\{[\s\S]*\}/);
|
|
104
|
+
if (jsonMatch) {
|
|
105
|
+
cleanText = jsonMatch[0];
|
|
106
|
+
}
|
|
82
107
|
const parsed = JSON.parse(cleanText);
|
|
83
108
|
return {
|
|
84
109
|
id: `explain-${Date.now()}`,
|
|
85
110
|
findingId,
|
|
86
|
-
summary: parsed.summary || '
|
|
111
|
+
summary: parsed.summary || 'Security advisory generated.',
|
|
87
112
|
details: parsed.details || '',
|
|
88
113
|
remediation: parsed.remediation || '',
|
|
89
|
-
codeFix: parsed.codeFix,
|
|
114
|
+
codeFix: parsed.codeFix || undefined,
|
|
90
115
|
modelUsed: this.defaultModel,
|
|
91
|
-
createdAt: new Date()
|
|
116
|
+
createdAt: new Date(),
|
|
117
|
+
isAiAssisted: true,
|
|
118
|
+
verificationStatus: 'SUGGESTED'
|
|
92
119
|
};
|
|
93
120
|
}
|
|
94
|
-
catch
|
|
121
|
+
catch {
|
|
95
122
|
return {
|
|
96
123
|
id: `explain-${Date.now()}`,
|
|
97
124
|
findingId,
|
|
98
|
-
summary: '
|
|
99
|
-
details:
|
|
100
|
-
remediation:
|
|
125
|
+
summary: 'Advisory Guidance',
|
|
126
|
+
details: text.slice(0, 500),
|
|
127
|
+
remediation: 'Inspect the flagged file and apply standard security remediations.',
|
|
101
128
|
modelUsed: this.defaultModel,
|
|
102
|
-
createdAt: new Date()
|
|
129
|
+
createdAt: new Date(),
|
|
130
|
+
isAiAssisted: true,
|
|
131
|
+
verificationStatus: 'SUGGESTED'
|
|
103
132
|
};
|
|
104
133
|
}
|
|
105
134
|
}
|
|
106
|
-
generateFallbackExplanation(finding) {
|
|
135
|
+
generateFallbackExplanation(finding, state = 'NOT_CONFIGURED') {
|
|
136
|
+
const isFailed = state === 'FAILED';
|
|
107
137
|
return {
|
|
108
138
|
id: `fallback-${Date.now()}`,
|
|
109
139
|
findingId: finding.scanId,
|
|
110
|
-
summary:
|
|
111
|
-
details: finding.description,
|
|
112
|
-
remediation:
|
|
113
|
-
|
|
114
|
-
|
|
140
|
+
summary: finding.title || 'Deterministic Security Guidance',
|
|
141
|
+
details: finding.description || 'Vulnerability detected by deterministic security scanner.',
|
|
142
|
+
remediation: finding.remediation || (isFailed
|
|
143
|
+
? 'AI service was temporarily unreachable. Refer to rule guidance or vendor advisory to resolve.'
|
|
144
|
+
: 'Configure NVIDIA_API_KEY in environment to enable optional AI remediation assistance.'),
|
|
145
|
+
modelUsed: 'deterministic-rules',
|
|
146
|
+
createdAt: new Date(),
|
|
147
|
+
isAiAssisted: false,
|
|
148
|
+
verificationStatus: 'NOT_APPLIED'
|
|
115
149
|
};
|
|
116
150
|
}
|
|
117
151
|
}
|
package/dist/explainer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explainer.js","sourceRoot":"","sources":["../src/explainer.ts"],"names":[],"mappings":";;;;;;AACA,oDAA4B;AAQ5B
|
|
1
|
+
{"version":3,"file":"explainer.js","sourceRoot":"","sources":["../src/explainer.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,4 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./explainer"), exports);
|
|
18
|
+
__exportStar(require("./verifier"), exports);
|
|
18
19
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,6CAA2B"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { NormalizedFinding, FindingStatus, ScannerResult } from '@maverick006/types';
|
|
2
|
+
import { SecurityScanner } from '@maverick006/security-engine';
|
|
3
|
+
export interface VerificationRequest {
|
|
4
|
+
finding: NormalizedFinding;
|
|
5
|
+
codeFix: string;
|
|
6
|
+
originalFileContent?: string;
|
|
7
|
+
scanner: SecurityScanner;
|
|
8
|
+
filePath: string;
|
|
9
|
+
}
|
|
10
|
+
export interface VerificationResult {
|
|
11
|
+
originalFinding: NormalizedFinding;
|
|
12
|
+
status: FindingStatus.VERIFIED | FindingStatus.FAILED_VERIFICATION | FindingStatus.NOT_VERIFIED;
|
|
13
|
+
message: string;
|
|
14
|
+
reScanResult?: ScannerResult;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Rescan Verification Engine:
|
|
18
|
+
* Validates AI-suggested code fixes by applying them in an isolated workspace
|
|
19
|
+
* and executing the deterministic scanner to verify the vulnerability is actually gone.
|
|
20
|
+
*/
|
|
21
|
+
export declare class RescanVerifier {
|
|
22
|
+
verifyPatch(request: VerificationRequest): Promise<VerificationResult>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAK/D,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,eAAe,EAAE,iBAAiB,CAAC;IACnC,MAAM,EAAE,aAAa,CAAC,QAAQ,GAAG,aAAa,CAAC,mBAAmB,GAAG,aAAa,CAAC,YAAY,CAAC;IAChG,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACnB,WAAW,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CA+D7E"}
|
package/dist/verifier.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.RescanVerifier = void 0;
|
|
37
|
+
const types_1 = require("@maverick006/types");
|
|
38
|
+
const fs = __importStar(require("fs/promises"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
/**
|
|
42
|
+
* Rescan Verification Engine:
|
|
43
|
+
* Validates AI-suggested code fixes by applying them in an isolated workspace
|
|
44
|
+
* and executing the deterministic scanner to verify the vulnerability is actually gone.
|
|
45
|
+
*/
|
|
46
|
+
class RescanVerifier {
|
|
47
|
+
async verifyPatch(request) {
|
|
48
|
+
const { finding, codeFix, scanner, filePath } = request;
|
|
49
|
+
if (!codeFix || !codeFix.trim()) {
|
|
50
|
+
return {
|
|
51
|
+
originalFinding: finding,
|
|
52
|
+
status: types_1.FindingStatus.NOT_VERIFIED,
|
|
53
|
+
message: 'No executable code fix provided to verify'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vibeguard-verify-'));
|
|
57
|
+
try {
|
|
58
|
+
const relativeTarget = path.isAbsolute(filePath)
|
|
59
|
+
? path.basename(filePath)
|
|
60
|
+
: filePath;
|
|
61
|
+
const isolatedFilePath = path.join(tempDir, relativeTarget);
|
|
62
|
+
await fs.mkdir(path.dirname(isolatedFilePath), { recursive: true });
|
|
63
|
+
// Write the patched file
|
|
64
|
+
await fs.writeFile(isolatedFilePath, codeFix, 'utf8');
|
|
65
|
+
// Re-run scanner against the isolated workspace
|
|
66
|
+
const rescanResult = await scanner.scan({
|
|
67
|
+
scanId: `verify-${Date.now()}`,
|
|
68
|
+
repositoryPath: tempDir
|
|
69
|
+
});
|
|
70
|
+
// Check if the original finding still exists
|
|
71
|
+
const targetRule = (finding.ruleId || finding.title || '').toLowerCase();
|
|
72
|
+
const stillFails = rescanResult.findings.some(f => {
|
|
73
|
+
const rescanRule = (f.ruleId || f.title || '').toLowerCase();
|
|
74
|
+
return rescanRule === targetRule;
|
|
75
|
+
});
|
|
76
|
+
if (!stillFails) {
|
|
77
|
+
return {
|
|
78
|
+
originalFinding: finding,
|
|
79
|
+
status: types_1.FindingStatus.VERIFIED,
|
|
80
|
+
message: `Verification succeeded: ${scanner.name} confirmed the vulnerability is resolved with no new regressions.`,
|
|
81
|
+
reScanResult: rescanResult
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
return {
|
|
86
|
+
originalFinding: finding,
|
|
87
|
+
status: types_1.FindingStatus.FAILED_VERIFICATION,
|
|
88
|
+
message: `Verification failed: ${scanner.name} still flagged the vulnerability after applying the proposed fix.`,
|
|
89
|
+
reScanResult: rescanResult
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
return {
|
|
95
|
+
originalFinding: finding,
|
|
96
|
+
status: types_1.FindingStatus.NOT_VERIFIED,
|
|
97
|
+
message: `Verification could not be performed: ${err.message}`
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
try {
|
|
102
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
103
|
+
}
|
|
104
|
+
catch { }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.RescanVerifier = RescanVerifier;
|
|
109
|
+
//# sourceMappingURL=verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier.js","sourceRoot":"","sources":["../src/verifier.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@maverick006/ai-engine",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"@types/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@maverick006/ai-engine",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "VibeGuard AI Engine for intelligent remediation",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"clean": "rm -rf dist",
|
|
10
|
+
"test": "jest",
|
|
11
|
+
"typecheck": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@maverick006/types": "*",
|
|
15
|
+
"openai": "^7.8.0",
|
|
16
|
+
"typescript": "^5.0.0",
|
|
17
|
+
"@types/node": "^20.0.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/jest": "^29.5.0",
|
|
21
|
+
"jest": "^29.5.0",
|
|
22
|
+
"ts-jest": "^29.1.0"
|
|
23
|
+
}
|
|
24
|
+
}
|