Skip to content

Commit 29672af

Browse files
Merge master into feature/amazonqLSP
2 parents 006093b + 43b0bd1 commit 29672af

File tree

10 files changed

+72
-12
lines changed

10 files changed

+72
-12
lines changed

packages/amazonq/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -387,12 +387,12 @@
387387
},
388388
{
389389
"command": "aws.amazonq.openSecurityIssuePanel",
390-
"when": "view == aws.amazonq.SecurityIssuesTree && (viewItem == issueWithoutFix || viewItem == issueWithFix)",
390+
"when": "view == aws.amazonq.SecurityIssuesTree && (viewItem == issueWithoutFix || viewItem == issueWithFix || viewItem == issueWithFixDisabled)",
391391
"group": "inline@4"
392392
},
393393
{
394394
"command": "aws.amazonq.security.ignore",
395-
"when": "view == aws.amazonq.SecurityIssuesTree && (viewItem == issueWithoutFix || viewItem == issueWithFix)",
395+
"when": "view == aws.amazonq.SecurityIssuesTree && (viewItem == issueWithoutFix || viewItem == issueWithFix || viewItem == issueWithFixDisabled)",
396396
"group": "inline@5"
397397
},
398398
{
@@ -402,7 +402,7 @@
402402
},
403403
{
404404
"submenu": "aws.amazonq.submenu.securityIssueMoreActions",
405-
"when": "view == aws.amazonq.SecurityIssuesTree && (viewItem == issueWithoutFix || viewItem == issueWithFix)",
405+
"when": "view == aws.amazonq.SecurityIssuesTree && (viewItem == issueWithoutFix || viewItem == issueWithFix || viewItem == issueWithFixDisabled)",
406406
"group": "inline@7"
407407
}
408408
],

packages/amazonq/test/unit/codewhisperer/service/securityIssueTreeViewProvider.test.ts

+21
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
SeverityItem,
1313
CodeIssueGroupingStrategyState,
1414
CodeIssueGroupingStrategy,
15+
sasRuleId,
1516
} from 'aws-core-vscode/codewhisperer'
1617
import { createCodeScanIssue } from 'aws-core-vscode/test'
1718
import assert from 'assert'
@@ -154,3 +155,23 @@ describe('SecurityIssueTreeViewProvider', function () {
154155
})
155156
})
156157
})
158+
159+
describe('IssueItem', function () {
160+
it('has issueWithFix context value for issues with suggested fix', function () {
161+
const issueItem = new IssueItem(
162+
'file/path',
163+
createCodeScanIssue({ suggestedFixes: [{ code: 'fixCode', description: 'fixDescription' }] })
164+
)
165+
assert.strictEqual(issueItem.contextValue, 'issueWithFix')
166+
})
167+
168+
it('has issueWithoutFix context value for issues without suggested fix', function () {
169+
const issueItem = new IssueItem('file/path', createCodeScanIssue({ suggestedFixes: [] }))
170+
assert.strictEqual(issueItem.contextValue, 'issueWithoutFix')
171+
})
172+
173+
it('has issueWithFixDisabled context value for SAS findings', function () {
174+
const issueItem = new IssueItem('file/path', createCodeScanIssue({ ruleId: sasRuleId }))
175+
assert.strictEqual(issueItem.contextValue, 'issueWithFixDisabled')
176+
})
177+
})

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

+4
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,10 @@ export const generateFix = Commands.declare(
673673
if (!targetIssue) {
674674
return
675675
}
676+
if (targetIssue.ruleId === CodeWhispererConstants.sasRuleId) {
677+
getLogger().warn('GenerateFix is not available for SAS findings.')
678+
return
679+
}
676680
await telemetry.codewhisperer_codeScanIssueGenerateFix.run(async () => {
677681
try {
678682
await vscode.commands

packages/core/src/codewhisperer/models/constants.ts

+3
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,13 @@ export const securityScanLanguageIds = [
334334
'sh',
335335
'shell',
336336
'shellscript',
337+
'brazilPackageConfig',
337338
] as const
338339

339340
export type SecurityScanLanguageId = (typeof securityScanLanguageIds)[number]
340341

342+
export const sasRuleId = 'sbom-software-assurance-services'
343+
341344
// wait time for editor to update editor.selection.active (in milliseconds)
342345
export const vsCodeCursorUpdateDelay = 10
343346

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

+7-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import globals from '../../shared/extensionGlobals'
1616
import { getLogger } from '../../shared/logger/logger'
1717
import { SecurityIssueProvider } from './securityIssueProvider'
18+
import { sasRuleId } from '../models/constants'
1819

1920
export type SecurityViewTreeItem = FileItem | IssueItem | SeverityItem
2021
type CodeScanIssueWithFilePath = CodeScanIssue & { filePath: string }
@@ -118,6 +119,7 @@ enum ContextValue {
118119
FILE = 'file',
119120
ISSUE_WITH_FIX = 'issueWithFix',
120121
ISSUE_WITHOUT_FIX = 'issueWithoutFix',
122+
ISSUE_WITH_FIX_DISABLED = 'issueWithFixDisabled',
121123
SEVERITY = 'severity',
122124
}
123125

@@ -195,9 +197,11 @@ export class IssueItem extends vscode.TreeItem {
195197
}
196198

197199
private getContextValue() {
198-
return this.issue.suggestedFixes.length === 0 || !this.issue.suggestedFixes[0].code
199-
? ContextValue.ISSUE_WITHOUT_FIX
200-
: ContextValue.ISSUE_WITH_FIX
200+
return this.issue.ruleId === sasRuleId
201+
? ContextValue.ISSUE_WITH_FIX_DISABLED
202+
: this.issue.suggestedFixes.length === 0 || !this.issue.suggestedFixes[0].code
203+
? ContextValue.ISSUE_WITHOUT_FIX
204+
: ContextValue.ISSUE_WITH_FIX
201205
}
202206

203207
private getTooltipMarkdown() {

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ export async function listScanResults(
7676
// Key example: project/src/main/java/com/example/App.java
7777
const mappedProjectPaths: Set<string> = new Set()
7878
for (const projectPath of projectPaths) {
79-
// We need to remove the project path from the key to get the absolute path to the file
80-
// Do not use .. in between because there could be multiple project paths in the same parent dir.
81-
const filePath = path.join(projectPath, key.split('/').slice(1).join('/'))
79+
// There could be multiple projectPaths with the same parent dir
80+
// In that case, make sure to break out of this loop after a filePath is found
81+
// or else it might result in duplicate findings.
82+
const filePath = path.join(projectPath, '..', key)
8283
if (existsSync(filePath) && statSync(filePath).isFile()) {
8384
mappedProjectPaths.add(filePath)
8485
const document = await vscode.workspace.openTextDocument(filePath)
@@ -87,6 +88,7 @@ export async function listScanResults(
8788
issues: issues.map((issue) => mapRawToCodeScanIssue(issue, document, jobId, scope)),
8889
}
8990
aggregatedCodeScanIssueList.push(aggregatedCodeScanIssue)
91+
break
9092
}
9193
}
9294
const maybeAbsolutePath = `/${key}`

packages/core/src/codewhisperer/util/securityScanLanguageContext.ts

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export class SecurityScanLanguageContext {
4747
sh: 'shell',
4848
shell: 'shell',
4949
shellscript: 'shell',
50+
brazilPackageConfig: 'plaintext',
5051
})
5152
}
5253

packages/core/src/codewhisperer/views/securityIssue/vue/root.vue

+12-2
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,19 @@
8080
v-if="!isFixAvailable"
8181
@click="generateFix"
8282
class="mr-8 button-theme-primary"
83-
:disabled="isGenerateFixLoading"
83+
:disabled="isGenerateFixLoading || isGenerateFixDisabled"
8484
>
8585
Generate Fix
8686
</button>
8787
<button v-if="isFixAvailable" @click="applyFix" class="mr-8 button-theme-primary">Accept Fix</button>
88-
<button v-if="isFixAvailable" @click="regenerateFix" class="mr-8 button-theme-secondary">Regenerate Fix</button>
88+
<button
89+
v-if="isFixAvailable"
90+
@click="regenerateFix"
91+
class="mr-8 button-theme-secondary"
92+
:disabled="isGenerateFixDisabled"
93+
>
94+
Regenerate Fix
95+
</button>
8996
<button @click="explainWithQ" class="mr-8 button-theme-secondary">Explain</button>
9097
<button @click="ignoreIssue" class="mr-8 button-theme-secondary">Ignore</button>
9198
<button @click="ignoreAllIssues" class="mr-8 button-theme-secondary">Ignore All</button>
@@ -104,6 +111,7 @@ import criticalSeverity from '../../../../../resources/images/severity-critical.
104111
import markdownIt from 'markdown-it'
105112
import hljs from 'highlight.js'
106113
import { CodeScanIssue } from '../../../models/model'
114+
import { sasRuleId } from '../../../models/constants'
107115
108116
const client = WebviewClientFactory.create<SecurityIssueWebview>()
109117
const severityImages: Record<string, string> = {
@@ -197,6 +205,7 @@ export default defineComponent({
197205
fixedCode: '',
198206
referenceText: '',
199207
referenceSpan: [0, 0],
208+
isGenerateFixDisabled: false,
200209
}
201210
},
202211
created() {
@@ -277,6 +286,7 @@ export default defineComponent({
277286
this.endLine = issue.endLine
278287
this.isFixAvailable = false
279288
this.isFixDescriptionAvailable = false
289+
this.isGenerateFixDisabled = issue.ruleId === sasRuleId
280290
if (suggestedFix) {
281291
this.isFixAvailable = !!suggestedFix.code && suggestedFix.code?.trim() !== ''
282292
this.suggestedFix = suggestedFix.code ?? ''

packages/core/src/shared/utilities/commentUtils.ts

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const languageCommentConfig: Record<SecurityScanLanguageId, CommentConfig | unde
4747
sh: { lineComment: '#', blockComment: [": '", "'"] },
4848
shell: { lineComment: '#', blockComment: [": '", "'"] },
4949
shellscript: { lineComment: '#', blockComment: [": '", "'"] },
50+
brazilPackageConfig: { lineComment: '#' },
5051
}
5152

5253
export function getLanguageCommentConfig(languageId: string): CommentConfig {

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

+15-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import assert from 'assert'
88
import * as sinon from 'sinon'
99
import * as CodeWhispererConstants from '../../../codewhisperer/models/constants'
1010
import { createCodeScanIssue, createMockDocument, resetCodeWhispererGlobalVariables } from '../testUtil'
11-
import { assertTelemetry, assertTelemetryCurried, tryRegister } from '../../testUtil'
11+
import { assertNoTelemetryMatch, assertTelemetry, assertTelemetryCurried, tryRegister } from '../../testUtil'
1212
import {
1313
toggleCodeSuggestions,
1414
showSecurityScan,
@@ -902,6 +902,20 @@ def execute_input_compliant():
902902
reasonDesc: 'Unexpected error',
903903
})
904904
})
905+
906+
it('exits early for SAS findings', async function () {
907+
targetCommand = testCommand(generateFix, mockClient, mockExtContext)
908+
codeScanIssue = createCodeScanIssue({
909+
ruleId: CodeWhispererConstants.sasRuleId,
910+
})
911+
issueItem = new IssueItem(filePath, codeScanIssue)
912+
await targetCommand.execute(codeScanIssue, filePath, 'webview')
913+
assert.ok(updateSecurityIssueWebviewMock.notCalled)
914+
assert.ok(startCodeFixGenerationStub.notCalled)
915+
assert.ok(updateIssueMock.notCalled)
916+
assert.ok(refreshTreeViewMock.notCalled)
917+
assertNoTelemetryMatch('codewhisperer_codeScanIssueGenerateFix')
918+
})
905919
})
906920

907921
describe('rejectFix', function () {

0 commit comments

Comments
 (0)