fivosense 0.1.2 → 0.1.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/.kilo/skill/fivosense/skill.json +20 -0
- package/.kilo/skill/fivosense/skill.md +260 -0
- package/DEPLOYMENT_GUIDE.md +311 -0
- package/bin/fivosense.cjs +2 -0
- package/bin/fivosense.mjs +2 -0
- package/dist/engine/graph.js +2 -2
- package/dist/engine/graph.js.map +1 -1
- package/mcp/README.md +158 -0
- package/mcp/index.js +252 -0
- package/mcp/package.json +23 -0
- package/package.json +3 -3
- package/src/engine/graph.ts +2 -2
- package/vscode-extension/.vscodeignore +11 -0
- package/vscode-extension/CHANGELOG.md +21 -0
- package/vscode-extension/LICENSE +21 -0
- package/vscode-extension/README.md +138 -0
- package/vscode-extension/fivosense-vscode-0.1.0.vsix +0 -0
- package/vscode-extension/package-lock.json +2665 -0
- package/vscode-extension/package.json +94 -0
- package/vscode-extension/src/extension.ts +289 -0
- package/vscode-extension/tsconfig.json +15 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fivosense-vscode",
|
|
3
|
+
"displayName": "FivoSense Security Scanner",
|
|
4
|
+
"description": "Real-time security vulnerability detection with AI-powered taint analysis",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"publisher": "fivosense",
|
|
7
|
+
"engines": {
|
|
8
|
+
"vscode": "^1.80.0"
|
|
9
|
+
},
|
|
10
|
+
"categories": [
|
|
11
|
+
"Linters",
|
|
12
|
+
"Programming Languages",
|
|
13
|
+
"Other"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"security",
|
|
17
|
+
"vulnerability",
|
|
18
|
+
"sql injection",
|
|
19
|
+
"xss",
|
|
20
|
+
"taint analysis",
|
|
21
|
+
"code scanner"
|
|
22
|
+
],
|
|
23
|
+
"activationEvents": [
|
|
24
|
+
"onLanguage:javascript",
|
|
25
|
+
"onLanguage:typescript",
|
|
26
|
+
"onLanguage:javascriptreact",
|
|
27
|
+
"onLanguage:typescriptreact"
|
|
28
|
+
],
|
|
29
|
+
"main": "./dist/extension.js",
|
|
30
|
+
"contributes": {
|
|
31
|
+
"commands": [
|
|
32
|
+
{
|
|
33
|
+
"command": "fivosense.scanFile",
|
|
34
|
+
"title": "FivoSense: Scan Current File"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"command": "fivosense.scanWorkspace",
|
|
38
|
+
"title": "FivoSense: Scan Workspace"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"command": "fivosense.roast",
|
|
42
|
+
"title": "FivoSense: Roast Mode 🔥"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"command": "fivosense.badge",
|
|
46
|
+
"title": "FivoSense: Get Security Badge"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"configuration": {
|
|
50
|
+
"title": "FivoSense",
|
|
51
|
+
"properties": {
|
|
52
|
+
"fivosense.enableRealTime": {
|
|
53
|
+
"type": "boolean",
|
|
54
|
+
"default": true,
|
|
55
|
+
"description": "Enable real-time security scanning as you type"
|
|
56
|
+
},
|
|
57
|
+
"fivosense.scanOnSave": {
|
|
58
|
+
"type": "boolean",
|
|
59
|
+
"default": true,
|
|
60
|
+
"description": "Automatically scan files on save"
|
|
61
|
+
},
|
|
62
|
+
"fivosense.severity": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"enum": ["all", "critical", "high", "medium"],
|
|
65
|
+
"default": "all",
|
|
66
|
+
"description": "Minimum severity level to report"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"vscode:prepublish": "npm run compile",
|
|
73
|
+
"compile": "tsc -p ./",
|
|
74
|
+
"watch": "tsc -watch -p ./",
|
|
75
|
+
"package": "vsce package"
|
|
76
|
+
},
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"@types/node": "^20.11.0",
|
|
79
|
+
"@types/vscode": "^1.80.0",
|
|
80
|
+
"@vscode/vsce": "^2.22.0",
|
|
81
|
+
"typescript": "^5.3.3"
|
|
82
|
+
},
|
|
83
|
+
"dependencies": {
|
|
84
|
+
"fivosense": "^0.1.3"
|
|
85
|
+
},
|
|
86
|
+
"repository": {
|
|
87
|
+
"type": "git",
|
|
88
|
+
"url": "https://github.com/itsvinsoni/sense.git"
|
|
89
|
+
},
|
|
90
|
+
"bugs": {
|
|
91
|
+
"url": "https://github.com/itsvinsoni/sense/issues"
|
|
92
|
+
},
|
|
93
|
+
"license": "MIT"
|
|
94
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import * as vscode from 'vscode';
|
|
2
|
+
import { auditFile } from 'fivosense';
|
|
3
|
+
|
|
4
|
+
let diagnosticCollection: vscode.DiagnosticCollection;
|
|
5
|
+
let statusBarItem: vscode.StatusBarItem;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extension activation
|
|
9
|
+
*/
|
|
10
|
+
export function activate(context: vscode.ExtensionContext) {
|
|
11
|
+
console.log('FivoSense extension activated');
|
|
12
|
+
|
|
13
|
+
// Create diagnostic collection
|
|
14
|
+
diagnosticCollection = vscode.languages.createDiagnosticCollection('fivosense');
|
|
15
|
+
context.subscriptions.push(diagnosticCollection);
|
|
16
|
+
|
|
17
|
+
// Create status bar item
|
|
18
|
+
statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
|
|
19
|
+
statusBarItem.text = '$(shield) FivoSense';
|
|
20
|
+
statusBarItem.tooltip = 'FivoSense Security Scanner';
|
|
21
|
+
statusBarItem.show();
|
|
22
|
+
context.subscriptions.push(statusBarItem);
|
|
23
|
+
|
|
24
|
+
// Register commands
|
|
25
|
+
context.subscriptions.push(
|
|
26
|
+
vscode.commands.registerCommand('fivosense.scanFile', scanCurrentFile),
|
|
27
|
+
vscode.commands.registerCommand('fivosense.scanWorkspace', scanWorkspace),
|
|
28
|
+
vscode.commands.registerCommand('fivosense.roast', roastMode),
|
|
29
|
+
vscode.commands.registerCommand('fivosense.badge', showBadge)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// Register event handlers
|
|
33
|
+
const config = vscode.workspace.getConfiguration('fivosense');
|
|
34
|
+
|
|
35
|
+
if (config.get('scanOnSave')) {
|
|
36
|
+
context.subscriptions.push(
|
|
37
|
+
vscode.workspace.onDidSaveTextDocument(document => {
|
|
38
|
+
if (shouldScanDocument(document)) {
|
|
39
|
+
scanDocument(document);
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (config.get('enableRealTime')) {
|
|
46
|
+
context.subscriptions.push(
|
|
47
|
+
vscode.workspace.onDidChangeTextDocument(event => {
|
|
48
|
+
if (shouldScanDocument(event.document)) {
|
|
49
|
+
// Debounce real-time scanning
|
|
50
|
+
debounce(() => scanDocument(event.document), 1000);
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Scan active editor on start
|
|
57
|
+
if (vscode.window.activeTextEditor) {
|
|
58
|
+
scanDocument(vscode.window.activeTextEditor.document);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Extension deactivation
|
|
64
|
+
*/
|
|
65
|
+
export function deactivate() {
|
|
66
|
+
if (diagnosticCollection) {
|
|
67
|
+
diagnosticCollection.dispose();
|
|
68
|
+
}
|
|
69
|
+
if (statusBarItem) {
|
|
70
|
+
statusBarItem.dispose();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check if document should be scanned
|
|
76
|
+
*/
|
|
77
|
+
function shouldScanDocument(document: vscode.TextDocument): boolean {
|
|
78
|
+
const supportedLanguages = ['javascript', 'typescript', 'javascriptreact', 'typescriptreact'];
|
|
79
|
+
return supportedLanguages.includes(document.languageId) &&
|
|
80
|
+
document.uri.scheme === 'file';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Scan a document
|
|
85
|
+
*/
|
|
86
|
+
async function scanDocument(document: vscode.TextDocument) {
|
|
87
|
+
try {
|
|
88
|
+
statusBarItem.text = '$(sync~spin) Scanning...';
|
|
89
|
+
|
|
90
|
+
const result = await auditFile(document.uri.fsPath);
|
|
91
|
+
const diagnostics: vscode.Diagnostic[] = [];
|
|
92
|
+
|
|
93
|
+
// Convert findings to VS Code diagnostics
|
|
94
|
+
const allFindings = [...result.vulnerabilities, ...result.secrets, ...result.destructive];
|
|
95
|
+
for (const finding of allFindings) {
|
|
96
|
+
const severity = getSeverity(finding.severity);
|
|
97
|
+
const range = new vscode.Range(
|
|
98
|
+
finding.line - 1, 0,
|
|
99
|
+
finding.line - 1, 1000
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const diagnostic = new vscode.Diagnostic(
|
|
103
|
+
range,
|
|
104
|
+
`[${finding.type}] ${finding.message}\n${finding.evidence}`,
|
|
105
|
+
severity
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
diagnostic.code = finding.cwe;
|
|
109
|
+
diagnostic.source = 'FivoSense';
|
|
110
|
+
|
|
111
|
+
// Add fix as code action
|
|
112
|
+
if (finding.fix) {
|
|
113
|
+
diagnostic.relatedInformation = [
|
|
114
|
+
new vscode.DiagnosticRelatedInformation(
|
|
115
|
+
new vscode.Location(document.uri, range),
|
|
116
|
+
`Fix: ${finding.fix}`
|
|
117
|
+
)
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
diagnostics.push(diagnostic);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
diagnosticCollection.set(document.uri, diagnostics);
|
|
125
|
+
|
|
126
|
+
// Update status bar
|
|
127
|
+
const { critical, high, medium } = result.summary;
|
|
128
|
+
if (result.summary.total === 0) {
|
|
129
|
+
statusBarItem.text = '$(shield-check) FivoSense: Clean';
|
|
130
|
+
statusBarItem.backgroundColor = undefined;
|
|
131
|
+
} else if (critical > 0) {
|
|
132
|
+
statusBarItem.text = `$(shield-x) FivoSense: ${critical} Critical`;
|
|
133
|
+
statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.errorBackground');
|
|
134
|
+
} else if (high > 0) {
|
|
135
|
+
statusBarItem.text = `$(warning) FivoSense: ${high} High`;
|
|
136
|
+
statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
|
|
137
|
+
} else {
|
|
138
|
+
statusBarItem.text = `$(info) FivoSense: ${medium} Issues`;
|
|
139
|
+
statusBarItem.backgroundColor = undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
} catch (error: any) {
|
|
143
|
+
statusBarItem.text = '$(shield-x) FivoSense: Error';
|
|
144
|
+
vscode.window.showErrorMessage(`FivoSense scan failed: ${error.message}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Convert severity to VS Code diagnostic severity
|
|
150
|
+
*/
|
|
151
|
+
function getSeverity(severity: string): vscode.DiagnosticSeverity {
|
|
152
|
+
switch (severity.toLowerCase()) {
|
|
153
|
+
case 'critical':
|
|
154
|
+
case 'high':
|
|
155
|
+
return vscode.DiagnosticSeverity.Error;
|
|
156
|
+
case 'medium':
|
|
157
|
+
return vscode.DiagnosticSeverity.Warning;
|
|
158
|
+
case 'low':
|
|
159
|
+
return vscode.DiagnosticSeverity.Information;
|
|
160
|
+
default:
|
|
161
|
+
return vscode.DiagnosticSeverity.Hint;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Scan current file command
|
|
167
|
+
*/
|
|
168
|
+
async function scanCurrentFile() {
|
|
169
|
+
const editor = vscode.window.activeTextEditor;
|
|
170
|
+
if (!editor) {
|
|
171
|
+
vscode.window.showWarningMessage('No active editor');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!shouldScanDocument(editor.document)) {
|
|
176
|
+
vscode.window.showWarningMessage('File type not supported');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
await scanDocument(editor.document);
|
|
181
|
+
vscode.window.showInformationMessage('FivoSense scan completed');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Scan workspace command
|
|
186
|
+
*/
|
|
187
|
+
async function scanWorkspace() {
|
|
188
|
+
const files = await vscode.workspace.findFiles('**/*.{js,ts,jsx,tsx}', '**/node_modules/**');
|
|
189
|
+
|
|
190
|
+
let totalFindings = 0;
|
|
191
|
+
let criticalCount = 0;
|
|
192
|
+
|
|
193
|
+
await vscode.window.withProgress({
|
|
194
|
+
location: vscode.ProgressLocation.Notification,
|
|
195
|
+
title: 'FivoSense: Scanning workspace...',
|
|
196
|
+
cancellable: false
|
|
197
|
+
}, async (progress) => {
|
|
198
|
+
for (let i = 0; i < files.length; i++) {
|
|
199
|
+
progress.report({
|
|
200
|
+
increment: (100 / files.length),
|
|
201
|
+
message: `${i + 1}/${files.length} files`
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const document = await vscode.workspace.openTextDocument(files[i]);
|
|
205
|
+
const result = await auditFile(document.uri.fsPath);
|
|
206
|
+
|
|
207
|
+
totalFindings += result.summary.total;
|
|
208
|
+
criticalCount += result.summary.critical;
|
|
209
|
+
|
|
210
|
+
if (result.summary.total > 0) {
|
|
211
|
+
await scanDocument(document);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
vscode.window.showInformationMessage(
|
|
217
|
+
`FivoSense: Scanned ${files.length} files. Found ${totalFindings} issues (${criticalCount} critical)`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Roast mode command
|
|
223
|
+
*/
|
|
224
|
+
async function roastMode() {
|
|
225
|
+
const editor = vscode.window.activeTextEditor;
|
|
226
|
+
if (!editor) {
|
|
227
|
+
vscode.window.showWarningMessage('No active editor');
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const result = await auditFile(editor.document.uri.fsPath);
|
|
232
|
+
|
|
233
|
+
let roast = '';
|
|
234
|
+
if (result.summary.total === 0) {
|
|
235
|
+
roast = '🎉 Your code is cleaner than your browser history!';
|
|
236
|
+
} else if (result.summary.critical > 0) {
|
|
237
|
+
roast = '🔥 Even script kiddies are embarrassed for you. This code has more holes than Swiss cheese!';
|
|
238
|
+
} else if (result.summary.high > 0) {
|
|
239
|
+
roast = '😬 Living dangerously, I see. Your security posture is... creative.';
|
|
240
|
+
} else {
|
|
241
|
+
roast = '🤔 Not terrible, but I\'ve seen better security at a lemonade stand.';
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
vscode.window.showInformationMessage(roast, { modal: true });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Show security badge command
|
|
249
|
+
*/
|
|
250
|
+
async function showBadge() {
|
|
251
|
+
const editor = vscode.window.activeTextEditor;
|
|
252
|
+
if (!editor) {
|
|
253
|
+
vscode.window.showWarningMessage('No active editor');
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const result = await auditFile(editor.document.uri.fsPath);
|
|
258
|
+
|
|
259
|
+
// Calculate grade
|
|
260
|
+
let grade = 'A+';
|
|
261
|
+
let score = 100;
|
|
262
|
+
|
|
263
|
+
if (result.summary.critical > 0) {
|
|
264
|
+
grade = 'F';
|
|
265
|
+
score = 40;
|
|
266
|
+
} else if (result.summary.high > 0) {
|
|
267
|
+
grade = 'D';
|
|
268
|
+
score = 60;
|
|
269
|
+
} else if (result.summary.medium > 0) {
|
|
270
|
+
grade = 'B';
|
|
271
|
+
score = 80;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const message = `🛡️ Security Grade: ${grade}\nScore: ${score}/100\n\nFindings:\n` +
|
|
275
|
+
`Critical: ${result.summary.critical}\n` +
|
|
276
|
+
`High: ${result.summary.high}\n` +
|
|
277
|
+
`Medium: ${result.summary.medium}`;
|
|
278
|
+
|
|
279
|
+
vscode.window.showInformationMessage(message, { modal: true });
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Debounce utility
|
|
284
|
+
*/
|
|
285
|
+
let debounceTimer: NodeJS.Timeout;
|
|
286
|
+
function debounce(func: Function, delay: number) {
|
|
287
|
+
clearTimeout(debounceTimer);
|
|
288
|
+
debounceTimer = setTimeout(() => func(), delay);
|
|
289
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"target": "ES2020",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"lib": ["ES2020"],
|
|
7
|
+
"sourceMap": true,
|
|
8
|
+
"rootDir": "src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true
|
|
13
|
+
},
|
|
14
|
+
"exclude": ["node_modules", ".vscode-test"]
|
|
15
|
+
}
|