Skip to content

Commit 11b3c5f

Browse files
author
cx-Margarita-LevitM
committed
Fix some issue
1 parent 89701f1 commit 11b3c5f

File tree

1 file changed

+93
-102
lines changed

1 file changed

+93
-102
lines changed

packages/core/src/aiTracking/AISuggestionTracker.ts

Lines changed: 93 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -180,37 +180,35 @@ export class AISuggestionTracker {
180180
}
181181
case 'Secrets': {
182182
const secretsItem = item as SecretsHoverData;
183-
const secretType = secretsItem.title || 'unknown';
184-
const secretValue = secretsItem.secretValue || 'unknown';
185-
return `secrets:${secretType}:${secretValue}:${filePath}`;
183+
const startIndex = secretsItem.location?.startIndex ?? 0;
184+
return `secrets:${line}:${startIndex}:${filePath}`;
186185
}
187186
case 'Asca': {
188187
const ascaItem = item as AscaHoverData;
189188
const ruleId = ascaItem.ruleId || ascaItem.ruleName;
190-
return `asca:${ruleId}:${filePath}`;
189+
return `asca:${ruleId}:${line}:${filePath}`;
191190
}
192191
case 'Containers': {
193192
const containersItem = item as ContainersHoverData;
194193
return `containers:${containersItem.imageName}:${containersItem.imageTag}:${filePath}`;
195194
}
196195
case 'IaC': {
197196
const iacItem = item as IacHoverData;
198-
return `iac:${iacItem.similarityId}:${iacItem}`;
197+
return `iac:${iacItem.similarityId}:${filePath}`;
199198
}
200199
default:
201200
return `unknown:${scannerType}:${line}:${filePath}`;
202201
}
203202
}
204203

205204
private getFilePath(item: AnyHoverData): string {
206-
207-
if (isIacHoverData(item) && item.originalFilePath) {
205+
if (this.getScannerType(item) === 'IaC' && 'originalFilePath' in item && item.originalFilePath) {
208206
return item.originalFilePath;
209207
}
210208
if ('filePath' in item && item.filePath) {
211209
return item.filePath;
212210
}
213-
return vscode.window.activeTextEditor?.document.uri.fsPath || '';
211+
214212
}
215213

216214
private getLine(item: AnyHoverData): number {
@@ -253,6 +251,11 @@ export class AISuggestionTracker {
253251

254252
this.logs.info(`User requested AI fix for ${scannerType} vulnerability`);
255253

254+
this.pendingConfirmation.set(vulnKey, {
255+
detectedAt: Date.now(),
256+
detectedValue: null
257+
});
258+
256259
// Check for duplicate request
257260
const existing = this.pendingFixes.get(vulnKey);
258261
if (existing) {
@@ -270,12 +273,7 @@ export class AISuggestionTracker {
270273
return existing.id;
271274
}
272275

273-
let validatorState: unknown;
274-
try {
275-
validatorState = await this.validator.captureInitialState(filePath);
276-
} catch (error) {
277-
throw error;
278-
}
276+
const validatorState = await this.validator.captureInitialState(filePath);
279277

280278
const fix: PendingAIFix = {
281279
id: randomUUID(),
@@ -308,6 +306,8 @@ export class AISuggestionTracker {
308306
}
309307

310308
private async checkFixOutcome(fix: PendingAIFix): Promise<void> {
309+
310+
await new Promise(resolve => setTimeout(resolve, 30000));
311311
const currentValue = await this.getCurrentValue(fix);
312312
const isFixed = currentValue === null;
313313

@@ -329,66 +329,45 @@ export class AISuggestionTracker {
329329
// Check if ghost text disappeared
330330
const fileNotActive = !activeEditor || activeEditor?.document.uri.fsPath !== fix.filePath;
331331
const vulnerabilityBack = vulnerabilityStatus !== null;
332-
const timeout = attempts >= 150;
332+
const timeout = attempts >= 300;
333333

334334
if (fileNotActive || vulnerabilityBack || timeout) {
335335
clearInterval(checkInterval);
336336
this.activeIntervals.delete(intervalKey);
337337

338-
if (timeout) {
339-
return;
340-
}
341-
342-
if (fix.scannerType === 'Secrets') {
343-
if (vulnerabilityBack && fileNotActive) {
344-
await this.finalizeFix(fix, 'changes_rejected');
345-
} if (!vulnerabilityBack && fileNotActive) {
346-
await this.finalizeFix(fix, 'changes_accepted');
347-
}
348-
} else {
349-
const fileChanged = await this.validator.validate(fix.filePath, fix.validatorState);
350-
const vulnerabilityGone = await this.getCurrentValue(fix) === null;
351-
const changesAccepted = fileChanged && vulnerabilityGone;
352-
const outcome = changesAccepted ? 'changes_accepted' : 'changes_rejected';
353-
await this.finalizeFix(fix, outcome);
354-
}
338+
const reason = fileNotActive ? 'file closed' :
339+
vulnerabilityBack ? 'changes rejected' :
340+
'timeout';
341+
this.logs.info(`[AITracker] Ghost text DISAPPEARED (${reason})`);
342+
343+
const changesAccepted = await this.validator.validate(fix.filePath, fix.validatorState);
344+
const outcome = changesAccepted ? 'changes_accepted' : 'changes_rejected';
345+
await this.finalizeFix(fix, outcome);
355346
}
356347
}, 2000);
357348

358349
this.activeIntervals.set(intervalKey, checkInterval);
359350
}
360351
}
361352

362-
363-
private isFileOpen(uri: vscode.Uri): boolean {
364-
return vscode.window.visibleTextEditors.some(e => e.document.uri.fsPath === uri.fsPath)
365-
|| vscode.window.activeTextEditor?.document.uri.fsPath === uri.fsPath;
366-
}
367-
368-
369353
private async hasActiveInlineSuggestion(uri: vscode.Uri, fix: PendingAIFix): Promise<boolean> {
370354
try {
371-
if (!this.isFileOpen(uri)) {
355+
const activeEditor = vscode.window.activeTextEditor;
356+
if (!activeEditor) {
372357
return false;
373358
}
374359

375-
const timeSinceRequest = Date.now() - fix.requestedAt;
376-
const gracePeriodMs = 5 * 1000; // 5 seconds (adjust as needed)
377-
378-
if (timeSinceRequest < gracePeriodMs) {
379-
return true;
380-
}
381-
382360
const pendingConf = this.pendingConfirmation.get(fix.vulnerabilityKey);
383361
if (pendingConf) {
384362
const timeSinceDetection = Date.now() - pendingConf.detectedAt;
385-
if (timeSinceDetection < 2000) {
363+
if (timeSinceDetection < 10000) {
386364
return true;
387365
}
388366
}
389367

390368
return false;
391369
} catch (error) {
370+
this.logs.warn(`[AITracker] Error checking for active suggestions: ${error}`);
392371
return false;
393372
}
394373
}
@@ -403,16 +382,13 @@ export class AISuggestionTracker {
403382
}
404383
const diagnostics = vscode.languages.getDiagnostics(uri);
405384

406-
let matchingDiagnosticCount = 0;
407-
408385
for (const diagnostic of diagnostics) {
409386
const data = (diagnostic as vscode.Diagnostic & { data?: CxDiagnosticData }).data;
410387
if (!data?.item) {
411388
continue;
412389
}
413390

414391
if (this.diagnosticMatchesFix(data, fix)) {
415-
matchingDiagnosticCount++;
416392
const currentValue = this.extractValueFromDiagnostic(data, fix.scannerType);
417393
return currentValue;
418394
}
@@ -435,31 +411,24 @@ export class AISuggestionTracker {
435411

436412
const packageManager = keyParts[1];
437413
const packageName = keyParts[2];
438-
const expectedVersion = keyParts[3];
439-
440-
const matches = ossItem.packageManager === packageManager &&
441-
ossItem.packageName === packageName &&
442-
ossItem.version === expectedVersion;
443-
414+
const matches = ossItem.packageName === packageName && ossItem.packageManager === packageManager;
415+
if (matches) {
416+
this.logs.info(`[AITracker] OSS Match: ${ossItem.packageName}@${ossItem.version}`);
417+
}
444418
return matches;
445419
}
446420
case 'Secrets': {
447421
if (!('secretValue' in item)) {
448422
return false;
449423
}
450424
const secretsItem = item as SecretsHoverData;
451-
452-
const expectedSecretType = keyParts[1];
453-
const expectedLine = parseInt(keyParts[2]);
454-
const expectedSecretValue = keyParts[3];
455-
456-
const actualSecretType = secretsItem.title || 'unknown';
457-
const actualLine = secretsItem.location?.line ?? 0;
458-
const actualSecretValue = secretsItem.secretValue || 'unknown';
459-
460-
const matches = actualSecretType === expectedSecretType &&
461-
actualLine === expectedLine &&
462-
actualSecretValue === expectedSecretValue;
425+
const line = parseInt(keyParts[1]);
426+
const startIndex = parseInt(keyParts[2]);
427+
const matches = secretsItem.location?.line === line &&
428+
secretsItem.location?.startIndex === startIndex;
429+
if (matches) {
430+
this.logs.info(`[AITracker] Secrets Match: line ${line}, index ${startIndex}`);
431+
}
463432
return matches;
464433
}
465434
case 'Asca': {
@@ -468,7 +437,12 @@ export class AISuggestionTracker {
468437
}
469438
const ascaItem = item as AscaHoverData;
470439
const ruleId = keyParts[1];
471-
const matches = String(ascaItem.ruleId) === ruleId || ascaItem.ruleName === ruleId;
440+
const line = parseInt(keyParts[2]);
441+
const matches = (String(ascaItem.ruleId) === ruleId || ascaItem.ruleName === ruleId) &&
442+
ascaItem.location?.line === line;
443+
if (matches) {
444+
this.logs.info(`[AITracker] ASCA Match: ${ascaItem.ruleName} at line ${line}`);
445+
}
472446
return matches;
473447
}
474448
case 'Containers': {
@@ -527,43 +501,60 @@ export class AISuggestionTracker {
527501
}
528502

529503
private async finalizeFix(fix: PendingAIFix, status: FixOutcome['status']): Promise<void> {
530-
// Checking no active inline suggestions
531-
const uri = vscode.Uri.file(fix.filePath);
532-
const hasActiveSuggestion = await this.hasActiveInlineSuggestion(uri, fix);
504+
const eventName = this.getEventNameFromStatus(status);
505+
let telemetryData: FixOutcomeTelemetry | null = null;
506+
try {
507+
// Checking no active inline suggestions
508+
const uri = vscode.Uri.file(fix.filePath);
509+
const hasActiveSuggestion = await this.hasActiveInlineSuggestion(uri, fix);
533510

534-
if (hasActiveSuggestion) {
535-
return;
536-
}
511+
if (hasActiveSuggestion) {
512+
return;
513+
}
537514

538-
const relativePath = this.getRelativePath(fix.filePath);
539-
const itemName = this.getItemName(fix);
515+
const relativePath = this.getRelativePath(fix.filePath);
516+
const itemName = this.getItemName(fix);
540517

541-
let finalState: unknown;
542-
let validatorMetadata: Record<string, unknown>;
543-
try {
544-
finalState = await this.validator.captureFinalState(fix.filePath);
545-
validatorMetadata = this.validator.getMetadata(fix.validatorState, finalState);
518+
let finalState: unknown;
519+
let validatorMetadata: Record<string, unknown>;
520+
try {
521+
finalState = await this.validator.captureFinalState(fix.filePath);
522+
validatorMetadata = this.validator.getMetadata(fix.validatorState, finalState);
523+
} catch (error) {
524+
return;
525+
}
526+
telemetryData = {
527+
status,
528+
scannerType: fix.scannerType,
529+
severity: fix.severity,
530+
filePath: relativePath,
531+
packageName: itemName,
532+
duplicateRequests: fix.requestCount - 1,
533+
initialFileHash: (validatorMetadata.initialFileHash as string) || '',
534+
finalFileHash: (validatorMetadata.finalFileHash as string) || '',
535+
hashesMatch: (validatorMetadata.hashesMatch as boolean) || false
536+
};
546537
} catch (error) {
547-
return;
538+
this.logs.warn(`[AITracker] Validation failed: ${error}`);
539+
} finally {
540+
if (!telemetryData) {
541+
// Create basic telemetry data as fallback
542+
telemetryData = {
543+
status,
544+
scannerType: fix.scannerType,
545+
severity: fix.severity,
546+
filePath: 'fallback',
547+
packageName: 'unknown',
548+
duplicateRequests: fix.requestCount - 1,
549+
initialFileHash: 'error',
550+
finalFileHash: 'error',
551+
hashesMatch: false
552+
};
553+
}
554+
await this.sendTelemetry(eventName, telemetryData);
555+
this.pendingFixes.delete(fix.vulnerabilityKey);
556+
this.logs.info(`[AITracker] Deferred telemetry sent: ${eventName}`);
548557
}
549-
const eventName = this.getEventNameFromStatus(status);
550-
551-
const telemetryData: FixOutcomeTelemetry = {
552-
status,
553-
scannerType: fix.scannerType,
554-
severity: fix.severity,
555-
filePath: relativePath,
556-
packageName: itemName,
557-
duplicateRequests: fix.requestCount - 1,
558-
initialFileHash: (validatorMetadata.initialFileHash as string) || '',
559-
finalFileHash: (validatorMetadata.finalFileHash as string) || '',
560-
hashesMatch: (validatorMetadata.hashesMatch as boolean) || false
561-
};
562-
563-
await this.sendTelemetry(eventName, telemetryData);
564-
this.pendingFixes.delete(fix.vulnerabilityKey);
565-
566-
this.logs.info(`User ${status === 'changes_accepted' ? 'accepted' : 'rejected'} AI suggestion for ${fix.scannerType} vulnerability`);
567558
}
568559

569560
// Get relative path from absolute path for Iac scans

0 commit comments

Comments
 (0)