Skip to content

Commit 5218bdd

Browse files
committed
POC: Finding Suppression Working POC
1 parent c8ca4ae commit 5218bdd

File tree

5 files changed

+76
-9
lines changed

5 files changed

+76
-9
lines changed

packages/core/src/codewhisperer/commands/basicCommands.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55

66
import * as vscode from 'vscode'
7+
import * as fs from 'fs'
8+
import * as path from 'path'
79
import { CodewhispererCodeScanIssueApplyFix, Component, telemetry } from '../../shared/telemetry/telemetry'
810
import { ExtContext, VSCODE_EXTENSION_ID } from '../../shared/extensions'
911
import { Commands, VsCodeCommandArg, placeholder } from '../../shared/vscode/commands2'
@@ -284,12 +286,51 @@ export const openSecurityIssuePanel = Commands.declare(
284286
)
285287
}
286288
)
287-
289+
/* Working
288290
export const suppressIssue = Commands.declare(
289291
'aws.amazonq.suppressIssue',
290292
(context: ExtContext) => async (issue: CodeScanIssue, filePath: string) => {
291293
// let issueData=issue
292-
void vscode.window.setStatusBarMessage(`Issue ${issue.findingId} is Suppressed`)
294+
void vscode.window.setStatusBarMessage(`Issue ${issue.title} is Suppressed`)
295+
}
296+
)
297+
*/
298+
299+
//TODO: Remove the yellow line on all the findings with the same title as finding title of user suppressed.
300+
export const suppressIssue = Commands.declare(
301+
'aws.amazonq.suppressIssue',
302+
(context: ExtContext) => async (issue: CodeScanIssue, filePath: string) => {
303+
const workspaceFolder = vscode.workspace.workspaceFolders?.[0]
304+
if (!workspaceFolder) {
305+
void vscode.window.showErrorMessage('No workspace folder found.')
306+
return
307+
}
308+
const hiddenFileName = '.suppressed_issues'
309+
const hiddenFilePath = path.join(workspaceFolder.uri.fsPath, hiddenFileName)
310+
const document = await vscode.workspace.openTextDocument(filePath)
311+
try {
312+
// Read existing content or create an empty array if file doesn't exist
313+
let suppressedIssues: string[] = []
314+
if (fs.existsSync(hiddenFilePath)) {
315+
const fileContent = await fs.promises.readFile(hiddenFilePath, 'utf-8')
316+
suppressedIssues = JSON.parse(fileContent)
317+
}
318+
// Add the new issue title if it's not already in the list
319+
if (!suppressedIssues.includes(issue.title)) {
320+
suppressedIssues.push(issue.title)
321+
// Write the updated list back to the file
322+
await fs.promises.writeFile(hiddenFilePath, JSON.stringify(suppressedIssues, undefined, 2))
323+
void vscode.window.setStatusBarMessage(`Issue "${issue.title}" is suppressed`)
324+
//Drop the finding from current file
325+
removeDiagnostic(document.uri, issue)
326+
SecurityIssueHoverProvider.instance.removeIssue(document.uri, issue)
327+
SecurityIssueCodeActionProvider.instance.removeIssue(document.uri, issue)
328+
} else {
329+
void vscode.window.setStatusBarMessage(`Issue "${issue.title}" was already suppressed`)
330+
}
331+
} catch (error) {
332+
void vscode.window.showErrorMessage(`Failed to suppress issue: ${error}`)
333+
}
293334
}
294335
)
295336

packages/core/src/codewhisperer/service/securityIssueCodeActionProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export class SecurityIssueCodeActionProvider extends SecurityIssueProvider imple
7373
`Amazon Q: Suppress Issue "${issue.title}"`,
7474
vscode.CodeActionKind.QuickFix
7575
)
76-
const suppressIssueWithQArgs = [issue]
76+
const suppressIssueWithQArgs = [issue, group.filePath]
7777
suppressIssueWithQ.command = {
7878
title: 'Suppress Issue with Amazon Q',
7979
command: 'aws.amazonq.suppressIssue',

packages/core/src/codewhisperer/service/securityIssueHoverProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export class SecurityIssueHoverProvider extends SecurityIssueProvider implements
9191
//TODO
9292
const suppressIssueCommand = this._getCommandMarkdown(
9393
'aws.amazonq.suppressIssue',
94-
[issue],
94+
[issue, filePath],
9595
'comment',
9696
'Suppress Issue',
9797
'Suppress Issue with Amazon Q'

packages/core/src/codewhisperer/service/securityScanHandler.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import { DefaultCodeWhispererClient } from '../client/codewhisperer'
77
import { getLogger } from '../../shared/logger'
88
import * as vscode from 'vscode'
9+
import * as fs from 'fs'
910
import {
1011
AggregatedCodeScanIssue,
1112
CodeScanIssue,
@@ -39,6 +40,22 @@ import {
3940
UploadArtifactToS3Error,
4041
} from '../models/errors'
4142
import { getTelemetryReasonDesc } from '../../shared/errors'
43+
async function getSuppressedIssues(projectPath: string): Promise<string[]> {
44+
const hiddenFileName = '.suppressed_issues'
45+
const hiddenFilePath = path.join(projectPath, hiddenFileName)
46+
47+
try {
48+
if (fs.existsSync(hiddenFilePath)) {
49+
const fileContent = await fs.promises.readFile(hiddenFilePath, 'utf-8')
50+
return JSON.parse(fileContent)
51+
}
52+
} catch (error) {
53+
// console.error('Error reading suppressed issues:', error)
54+
void vscode.window.showErrorMessage(`Error reading suppressed issues: ${error}`)
55+
}
56+
57+
return []
58+
}
4259

4360
export async function listScanResults(
4461
client: DefaultCodeWhispererClient,
@@ -53,6 +70,9 @@ export async function listScanResults(
5370
const aggregatedCodeScanIssueList: AggregatedCodeScanIssue[] = []
5471
const requester = (request: codewhispererClient.ListCodeScanFindingsRequest) => client.listCodeScanFindings(request)
5572
const collection = pageableToCollection(requester, { jobId, codeScanFindingsSchema }, 'nextToken')
73+
74+
const suppressedIssues = await getSuppressedIssues(projectPaths[0])
75+
5676
const issues = await collection
5777
.flatten()
5878
.map((resp) => {
@@ -74,11 +94,17 @@ export async function listScanResults(
7494
// Do not use .. in between because there could be multiple project paths in the same parent dir.
7595
const filePath = path.join(projectPath, key.split('/').slice(1).join('/'))
7696
if (existsSync(filePath) && statSync(filePath).isFile()) {
77-
const aggregatedCodeScanIssue: AggregatedCodeScanIssue = {
78-
filePath: filePath,
79-
issues: issues.map(mapRawToCodeScanIssue),
97+
const filteredIssues = issues
98+
.map(mapRawToCodeScanIssue)
99+
.filter((i) => !suppressedIssues.includes(i.title))
100+
101+
if (filteredIssues.length > 0) {
102+
const aggregatedCodeScanIssue: AggregatedCodeScanIssue = {
103+
filePath: filePath,
104+
issues: filteredIssues,
105+
}
106+
aggregatedCodeScanIssueList.push(aggregatedCodeScanIssue)
80107
}
81-
aggregatedCodeScanIssueList.push(aggregatedCodeScanIssue)
82108
}
83109
})
84110
const maybeAbsolutePath = `/${key}`

packages/core/src/codewhisperer/views/securityIssue/securityIssueWebview.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class SecurityIssueWebview extends VueWebview {
4343
})
4444
}
4545
public suppressIssueWithQ() {
46-
const args = [this.issue]
46+
const args = [this.issue, this.filePath]
4747
void this.navigateToFile()?.then(() => {
4848
void vscode.commands.executeCommand('aws.amazonq.suppressIssue', ...args)
4949
})

0 commit comments

Comments
 (0)