diff --git a/package-lock.json b/package-lock.json index d3cda5c4334..f08d1d487c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "vscode-nls-dev": "^4.0.4" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.293", + "@aws-toolkits/telemetry": "^1.0.295", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", @@ -6047,10 +6047,11 @@ } }, "node_modules/@aws-toolkits/telemetry": { - "version": "1.0.294", - "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.294.tgz", - "integrity": "sha512-Hy/yj93pFuHhKCqAA9FgNjdJHRi4huUnyl13dZLzzICDlFVl/AHlm9iWmm9LR22KOuXUyu3uX40VtXLdExIHqw==", + "version": "1.0.295", + "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.295.tgz", + "integrity": "sha512-NGBM5vhNNHwEhok3asXpUW7oZv/z8mjZaf34LGflqEh/5+VraTd76T+QBz18sC+nE2sPvhTO+zjptR9zg5bBUA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "ajv": "^6.12.6", "cross-spawn": "^7.0.6", @@ -6061,19 +6062,6 @@ "yargs": "^17.0.1" } }, - "node_modules/@aws-toolkits/telemetry/node_modules/fs-extra": { - "version": "11.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/@aws/chat-client-ui-types": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@aws/chat-client-ui-types/-/chat-client-ui-types-0.0.8.tgz", @@ -8971,6 +8959,8 @@ }, "node_modules/@ts-morph/common": { "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.24.0.tgz", + "integrity": "sha512-c1xMmNHWpNselmpIqursHeOHHBTIsJLbB+NuovbTTRCNiTLEr/U9dbJ8qy0jd/O2x5pc3seWuOUN5R2IoOTp8A==", "dev": true, "license": "MIT", "dependencies": { @@ -8982,6 +8972,8 @@ }, "node_modules/@ts-morph/common/node_modules/brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", "dependencies": { @@ -8990,6 +8982,8 @@ }, "node_modules/@ts-morph/common/node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -9004,6 +8998,8 @@ }, "node_modules/@ts-morph/common/node_modules/mkdirp": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true, "license": "MIT", "bin": { @@ -11579,10 +11575,11 @@ } }, "node_modules/code-block-writer": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.2.tgz", - "integrity": "sha512-XfXzAGiStXSmCIwrkdfvc7FS5Dtj8yelCtyOf2p2skCAfvLd6zu0rGzuS9NSCO3bq1JKpFZ7tbKdKlcd5occQA==", - "dev": true + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "dev": true, + "license": "MIT" }, "node_modules/color": { "version": "3.2.1", @@ -13782,6 +13779,21 @@ "license": "MIT", "optional": true }, + "node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fs-monkey": { "version": "1.0.3", "dev": true, @@ -15366,6 +15378,8 @@ }, "node_modules/jsonfile": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "license": "MIT", "dependencies": { @@ -19546,6 +19560,8 @@ }, "node_modules/ts-morph": { "version": "23.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-23.0.0.tgz", + "integrity": "sha512-FcvFx7a9E8TUe6T3ShihXJLiJOiqyafzFKUO4aqIHDUCIvADdGNShcbc2W5PMr3LerXRv7mafvFZ9lRENxJmug==", "dev": true, "license": "MIT", "dependencies": { @@ -19809,7 +19825,9 @@ "license": "MIT" }, "node_modules/universalify": { - "version": "2.0.0", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index e14641a45c4..d6920d52ce1 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "mergeReports": "ts-node ./scripts/mergeReports.ts" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.293", + "@aws-toolkits/telemetry": "^1.0.295", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", diff --git a/packages/amazonq/test/unit/codewhisperer/service/securityScanHandler.test.ts b/packages/amazonq/test/unit/codewhisperer/service/securityScanHandler.test.ts index e297dfb82b3..b167721f334 100644 --- a/packages/amazonq/test/unit/codewhisperer/service/securityScanHandler.test.ts +++ b/packages/amazonq/test/unit/codewhisperer/service/securityScanHandler.test.ts @@ -131,6 +131,31 @@ describe('securityScanHandler', function () { assert.equal(aggregatedCodeScanIssueList.length, 2) assert.equal(aggregatedCodeScanIssueList[0].issues.length, 3) }) + + it('should set autoDetected based on scope', async function () { + mockClient.listCodeScanFindings.resolves( + buildMockListCodeScanFindingsResponse(JSON.stringify([buildRawCodeScanIssue()])) + ) + for (const [scope, expectedValue] of [ + [CodeAnalysisScope.FILE_AUTO, true], + [CodeAnalysisScope.FILE_ON_DEMAND, false], + [CodeAnalysisScope.PROJECT, false], + ] as [CodeAnalysisScope, boolean][]) { + const aggregatedCodeScanIssueList = await listScanResults( + mockClient, + 'jobId', + 'codeScanFindingsSchema', + ['projectPath'], + scope, + undefined + ) + assert.ok( + aggregatedCodeScanIssueList.every((item) => + item.issues.every((issue) => issue.autoDetected === expectedValue) + ) + ) + } + }) }) describe('mapToAggregatedList', () => { diff --git a/packages/core/src/codewhisperer/commands/basicCommands.ts b/packages/core/src/codewhisperer/commands/basicCommands.ts index 3a614b003f0..3693bbd4d6c 100644 --- a/packages/core/src/codewhisperer/commands/basicCommands.ts +++ b/packages/core/src/codewhisperer/commands/basicCommands.ts @@ -447,6 +447,8 @@ export const applySecurityFix = Commands.declare( result: 'Succeeded', credentialStartUrl: AuthUtil.instance.startUrl, codeFixAction: 'applyFix', + autoDetected: targetIssue.autoDetected, + codewhispererCodeScanJobId: targetIssue.scanJobId, } let languageId = undefined try { @@ -711,6 +713,7 @@ export const generateFix = Commands.declare( } else { hasSuggestedFix = suggestedFix !== undefined } + telemetry.record({ includesFix: hasSuggestedFix }) const updatedIssue: CodeScanIssue = { ...targetIssue, fixJobId: jobId, @@ -755,6 +758,8 @@ export const generateFix = Commands.declare( findingId: targetIssue.findingId, ruleId: targetIssue.ruleId, variant: refresh ? 'refresh' : undefined, + autoDetected: targetIssue.autoDetected, + codewhispererCodeScanJobId: targetIssue.scanJobId, }) } }) diff --git a/packages/core/src/codewhisperer/models/model.ts b/packages/core/src/codewhisperer/models/model.ts index d8eea5a018c..0f285f04ba8 100644 --- a/packages/core/src/codewhisperer/models/model.ts +++ b/packages/core/src/codewhisperer/models/model.ts @@ -487,6 +487,7 @@ export interface CodeScanIssue { scanJobId: string language: string fixJobId?: string + autoDetected?: boolean } export interface AggregatedCodeScanIssue { diff --git a/packages/core/src/codewhisperer/service/securityScanHandler.ts b/packages/core/src/codewhisperer/service/securityScanHandler.ts index 22f5fa30e60..a8db65603b3 100644 --- a/packages/core/src/codewhisperer/service/securityScanHandler.ts +++ b/packages/core/src/codewhisperer/service/securityScanHandler.ts @@ -83,7 +83,7 @@ export async function listScanResults( if (existsSync(filePath) && statSync(filePath).isFile()) { const aggregatedCodeScanIssue: AggregatedCodeScanIssue = { filePath: filePath, - issues: issues.map((issue) => mapRawToCodeScanIssue(issue, editor, jobId)), + issues: issues.map((issue) => mapRawToCodeScanIssue(issue, editor, jobId, scope)), } aggregatedCodeScanIssueList.push(aggregatedCodeScanIssue) } @@ -92,7 +92,7 @@ export async function listScanResults( if (existsSync(maybeAbsolutePath) && statSync(maybeAbsolutePath).isFile()) { const aggregatedCodeScanIssue: AggregatedCodeScanIssue = { filePath: maybeAbsolutePath, - issues: issues.map((issue) => mapRawToCodeScanIssue(issue, editor, jobId)), + issues: issues.map((issue) => mapRawToCodeScanIssue(issue, editor, jobId, scope)), } aggregatedCodeScanIssueList.push(aggregatedCodeScanIssue) } @@ -103,7 +103,8 @@ export async function listScanResults( function mapRawToCodeScanIssue( issue: RawCodeScanIssue, editor: vscode.TextEditor | undefined, - jobId: string + jobId: string, + scope: CodeWhispererConstants.CodeAnalysisScope ): CodeScanIssue { const isIssueTitleIgnored = CodeWhispererSettings.instance.getIgnoredSecurityIssues().includes(issue.title) const isSingleIssueIgnored = @@ -130,6 +131,7 @@ function mapRawToCodeScanIssue( visible: !isIssueTitleIgnored && !isSingleIssueIgnored, scanJobId: jobId, language, + autoDetected: scope === CodeWhispererConstants.CodeAnalysisScope.FILE_AUTO, } }