Skip to content

Commit d26035b

Browse files
leigaolmanodnyab
andauthored
feat(cwspr): Send CodeRemediationEvent to CWSPR Server (#4221)
* Add CodeRemediationEvent for SecurityScan * use null * fix thread bug * code format --------- Co-authored-by: manodnyab <[email protected]>
1 parent f0b1042 commit d26035b

File tree

3 files changed

+170
-8
lines changed

3 files changed

+170
-8
lines changed

plugins/core/sdk-codegen/codegen-resources/codewhispererruntime/service-2.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,46 @@
522522
"max":128,
523523
"min":1
524524
},
525+
"CodeScanRemediationsEvent": {
526+
"type": "structure",
527+
"members": {
528+
"programmingLanguage": {
529+
"shape": "ProgrammingLanguage"
530+
},
531+
"CodeScanRemediationsEventType": {
532+
"shape": "CodeScanRemediationsEventType"
533+
},
534+
"timestamp": {
535+
"shape": "Timestamp"
536+
},
537+
"detectorId": {
538+
"shape": "String"
539+
},
540+
"findingId": {
541+
"shape": "String"
542+
},
543+
"ruleId": {
544+
"shape": "String"
545+
},
546+
"component": {
547+
"shape": "String"
548+
},
549+
"reason": {
550+
"shape": "String"
551+
},
552+
"result": {
553+
"shape": "String"
554+
},
555+
"includesFix": {
556+
"shape": "Boolean"
557+
}
558+
}
559+
},
560+
"CodeScanRemediationsEventType": {
561+
"type": "string",
562+
"documentation": "<p>Code Scan Remediations Interaction Type</p>",
563+
"enum": ["CODESCAN_ISSUE_HOVER", "CODESCAN_ISSUE_APPLY_FIX", "CODESCAN_ISSUE_VIEW_DETAILS"]
564+
},
525565
"Completion":{
526566
"type":"structure",
527567
"required":["content"],
@@ -1458,6 +1498,7 @@
14581498
"codeCoverageEvent":{"shape":"CodeCoverageEvent"},
14591499
"userModificationEvent":{"shape":"UserModificationEvent"},
14601500
"codeScanEvent":{"shape":"CodeScanEvent"},
1501+
"codeScanRemediationsEvent": { "shape": "CodeScanRemediationsEvent" },
14611502
"metricData":{"shape":"MetricData"},
14621503
"chatAddMessageEvent": { "shape": "ChatAddMessageEvent" },
14631504
"chatInteractWithMessageEvent": { "shape": "ChatInteractWithMessageEvent" },

plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/listeners/CodeWhispererCodeScanEditorMouseMotionListener.kt

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package software.aws.toolkits.jetbrains.services.codewhisperer.codescan.listener
66
import com.intellij.icons.AllIcons
77
import com.intellij.ide.BrowserUtil
88
import com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI
9+
import com.intellij.openapi.application.ApplicationManager
910
import com.intellij.openapi.command.WriteCommandAction
1011
import com.intellij.openapi.editor.event.EditorMouseEvent
1112
import com.intellij.openapi.editor.event.EditorMouseEventArea
@@ -19,13 +20,18 @@ import com.intellij.ui.JBColor
1920
import com.intellij.ui.awt.RelativePoint
2021
import com.intellij.ui.components.JBScrollPane
2122
import icons.AwsIcons
23+
import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeException
2224
import software.aws.toolkits.core.utils.debug
2325
import software.aws.toolkits.core.utils.error
2426
import software.aws.toolkits.core.utils.getLogger
2527
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanIssue
2628
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanManager
29+
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor
30+
import software.aws.toolkits.jetbrains.services.codewhisperer.language.CodeWhispererProgrammingLanguage
31+
import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmingLanguage
2732
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
2833
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererColorUtil.getHexString
34+
import software.aws.toolkits.jetbrains.services.codewhisperer.util.runIfIdcConnectionOrTelemetryEnabled
2935
import software.aws.toolkits.jetbrains.utils.applyPatch
3036
import software.aws.toolkits.jetbrains.utils.convertMarkdownToHTML
3137
import software.aws.toolkits.jetbrains.utils.notifyError
@@ -95,7 +101,7 @@ class CodeWhispererCodeScanEditorMouseMotionListener(private val project: Projec
95101
<tbody>
96102
<tr>
97103
<td>$cweLinks</td>
98-
<td>${if (isFixAvailable) "<span style=\"color:${additionForegroundColor.getHexString()};\">Yes</span>" else "<span style=\"color:${deletionForegroundColor.getHexString()};\">No</span>" }</td>
104+
<td>${if (isFixAvailable) "<span style=\"color:${additionForegroundColor.getHexString()};\">Yes</span>" else "<span style=\"color:${deletionForegroundColor.getHexString()};\">No</span>"}</td>
99105
<td>$detectorLibraryLink</td>
100106
</tr>
101107
</tbody>
@@ -115,13 +121,17 @@ class CodeWhispererCodeScanEditorMouseMotionListener(private val project: Projec
115121
|${issue.suggestedFixes[0].code}
116122
|```
117123
|
118-
|${if (isFixDescriptionAvailable) {
119-
"|### ${message(
120-
"codewhisperer.codescan.suggested_fix_description"
121-
)}\n${issue.suggestedFixes[0].description}"
122-
} else {
123-
""
124-
}}
124+
|${
125+
if (isFixDescriptionAvailable) {
126+
"|### ${
127+
message(
128+
"codewhisperer.codescan.suggested_fix_description"
129+
)
130+
}\n${issue.suggestedFixes[0].description}"
131+
} else {
132+
""
133+
}
134+
}
125135
""".trimMargin()
126136
} else {
127137
""
@@ -253,6 +263,54 @@ class CodeWhispererCodeScanEditorMouseMotionListener(private val project: Projec
253263
popup.show(RelativePoint(e.mouseEvent))
254264

255265
CodeWhispererTelemetryService.getInstance().sendCodeScanIssueHoverEvent(issue)
266+
sendCodeRemediationTelemetryToServiceApi(
267+
issue.file.programmingLanguage(),
268+
"CODESCAN_ISSUE_HOVER",
269+
issue.detectorId,
270+
issue.findingId,
271+
issue.ruleId,
272+
null,
273+
null,
274+
null,
275+
issue.suggestedFixes.isNotEmpty()
276+
)
277+
}
278+
279+
private fun sendCodeRemediationTelemetryToServiceApi(
280+
language: CodeWhispererProgrammingLanguage?,
281+
codeScanRemediationEventType: String?,
282+
detectorId: String?,
283+
findingId: String?,
284+
ruleId: String?,
285+
component: String?,
286+
reason: String?,
287+
result: String?,
288+
includesFix: Boolean?
289+
) {
290+
runIfIdcConnectionOrTelemetryEnabled(project) {
291+
ApplicationManager.getApplication().executeOnPooledThread {
292+
try {
293+
val response = CodeWhispererClientAdaptor.getInstance(project)
294+
.sendCodeScanRemediationTelemetry(
295+
language,
296+
codeScanRemediationEventType,
297+
detectorId,
298+
findingId,
299+
ruleId,
300+
component,
301+
reason,
302+
result,
303+
includesFix
304+
)
305+
LOG.debug { "Successfully sent code scan remediation telemetry. RequestId: ${response.responseMetadata().requestId()}" }
306+
} catch (e: Exception) {
307+
val requestId = if (e is CodeWhispererRuntimeException) e.requestId() else null
308+
LOG.debug {
309+
"Failed to send code scan remediation telemetry. RequestId: $requestId, ErrorMessage: ${e.message}"
310+
}
311+
}
312+
}
313+
}
256314
}
257315

258316
override fun mouseMoved(e: EditorMouseEvent) {
@@ -305,10 +363,32 @@ class CodeWhispererCodeScanEditorMouseMotionListener(private val project: Projec
305363
CodeWhispererTelemetryService.getInstance().sendCodeScanIssueApplyFixEvent(issue, Result.Succeeded)
306364
hidePopup()
307365
}
366+
sendCodeRemediationTelemetryToServiceApi(
367+
issue.file.programmingLanguage(),
368+
"CODESCAN_ISSUE_APPLY_FIX",
369+
issue.detectorId,
370+
issue.findingId,
371+
issue.ruleId,
372+
null,
373+
null,
374+
Result.Succeeded.toString(),
375+
issue.suggestedFixes.isNotEmpty()
376+
)
308377
} catch (err: Error) {
309378
notifyError(message("codewhisperer.codescan.fix_applied_fail", err))
310379
LOG.error { "Apply fix command failed. $err" }
311380
CodeWhispererTelemetryService.getInstance().sendCodeScanIssueApplyFixEvent(issue, Result.Failed, err.message)
381+
sendCodeRemediationTelemetryToServiceApi(
382+
issue.file.programmingLanguage(),
383+
"CODESCAN_ISSUE_APPLY_FIX",
384+
issue.detectorId,
385+
issue.findingId,
386+
issue.ruleId,
387+
null,
388+
err.message,
389+
Result.Failed.toString(),
390+
issue.suggestedFixes.isNotEmpty()
391+
)
312392
}
313393
}
314394
}

plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/codewhisperer/credentials/CodeWhispererClientAdaptor.kt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,17 @@ interface CodeWhispererClientAdaptor : Disposable {
122122
codeScanJobId: String?
123123
): SendTelemetryEventResponse
124124

125+
fun sendCodeScanRemediationTelemetry(
126+
language: CodeWhispererProgrammingLanguage?,
127+
codeScanRemediationEventType: String?,
128+
detectorId: String?,
129+
findingId: String?,
130+
ruleId: String?,
131+
component: String?,
132+
reason: String?,
133+
result: String?,
134+
includesFix: Boolean?
135+
): SendTelemetryEventResponse
125136
fun listFeatureEvaluations(): ListFeatureEvaluationsResponse
126137

127138
fun sendMetricDataTelemetry(eventName: String, metadata: Map<String, Any?>): SendTelemetryEventResponse
@@ -376,6 +387,36 @@ open class CodeWhispererClientAdaptorImpl(override val project: Project) : CodeW
376387
requestBuilder.optOutPreference(getTelemetryOptOutPreference())
377388
requestBuilder.userContext(codeWhispererUserContext)
378389
}
390+
override fun sendCodeScanRemediationTelemetry(
391+
language: CodeWhispererProgrammingLanguage?,
392+
codeScanRemediationEventType: String?,
393+
detectorId: String?,
394+
findingId: String?,
395+
ruleId: String?,
396+
component: String?,
397+
reason: String?,
398+
result: String?,
399+
includesFix: Boolean?
400+
): SendTelemetryEventResponse = bearerClient().sendTelemetryEvent { requestBuilder ->
401+
requestBuilder.telemetryEvent { telemetryEventBuilder ->
402+
telemetryEventBuilder.codeScanRemediationsEvent {
403+
it.programmingLanguage { languageBuilder ->
404+
languageBuilder.languageName(language?.toCodeWhispererRuntimeLanguage()?.languageId)
405+
}
406+
it.codeScanRemediationsEventType(codeScanRemediationEventType)
407+
it.detectorId(detectorId)
408+
it.findingId(findingId)
409+
it.ruleId(ruleId)
410+
it.component(component)
411+
it.reason(reason)
412+
it.result(result)
413+
it.includesFix(includesFix)
414+
it.timestamp(Instant.now())
415+
}
416+
}
417+
requestBuilder.optOutPreference(getTelemetryOptOutPreference())
418+
requestBuilder.userContext(codeWhispererUserContext)
419+
}
379420

380421
override fun listFeatureEvaluations(): ListFeatureEvaluationsResponse = bearerClient().listFeatureEvaluations {
381422
it.userContext(codeWhispererUserContext)

0 commit comments

Comments
 (0)