Skip to content

Commit 83ead2f

Browse files
authored
Security scans: Improving telemetry error messages (#4600)
* Improving telemetry error messages * Adding reasonDesc param to telemetry error messages
1 parent e43fb5a commit 83ead2f

File tree

7 files changed

+84
-42
lines changed

7 files changed

+84
-42
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Security Scan: Improved telemetry error messages"
4+
}

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanException.kt

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,35 @@ package software.aws.toolkits.jetbrains.services.codewhisperer.codescan
55

66
import software.aws.toolkits.resources.message
77

8-
open class CodeWhispererCodeScanException(override val message: String?) : RuntimeException()
8+
open class CodeScanException(override val message: String, open val code: String?) : RuntimeException(message)
99

10-
open class CodeWhispererCodeScanServerException(override val message: String?) : RuntimeException()
10+
open class CodeWhispererCodeScanException(override val message: String, override val code: String?) : CodeScanException(message, code)
11+
12+
open class CodeWhispererCodeScanServerException(override val message: String, override val code: String?) : CodeScanException(message, code)
1113

1214
internal fun noFileOpenError(): Nothing =
13-
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.no_file_open"))
15+
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.no_file_open"), "NoSourceFilesError")
1416

15-
internal fun codeScanFailed(errorMessage: String): Nothing =
16-
throw Exception(errorMessage)
17+
internal fun codeScanFailed(errorMessage: String, code: String?): Nothing =
18+
throw CodeScanException(errorMessage, code)
1719

1820
internal fun cannotFindFile(errorMessage: String, filepath: String): Nothing =
1921
error(message("codewhisperer.codescan.file_not_found", filepath, errorMessage))
2022

2123
internal fun cannotFindBuildArtifacts(): Nothing =
22-
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.build_artifacts_not_found"))
24+
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.build_artifacts_not_found"), "NoSourceFilesError")
2325

2426
internal fun fileFormatNotSupported(format: String): Nothing =
25-
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.file_ext_not_supported", format))
27+
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.file_ext_not_supported", format), "FileFormatNotSupportedError")
2628

2729
internal fun fileTooLarge(): Nothing =
28-
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.file_too_large"))
30+
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.file_too_large"), "ProjectSizeExceeded")
2931

30-
internal fun codeScanServerException(errorMessage: String): Nothing =
31-
throw CodeWhispererCodeScanServerException(errorMessage)
32+
internal fun codeScanServerException(errorMessage: String, code: String?): Nothing =
33+
throw CodeWhispererCodeScanServerException(errorMessage, code)
3234

3335
internal fun invalidSourceZipError(): Nothing =
34-
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.invalid_source_zip_telemetry"))
36+
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.invalid_source_zip_telemetry"), "InvalidSourceZip")
3537

3638
internal fun noSupportedFilesError(): Nothing =
37-
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.unsupported_language_error"))
39+
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.unsupported_language_error"), "NoSourceFilesError")

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanManager.kt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,14 @@ class CodeWhispererCodeScanManager(val project: Project) {
282282
isProjectScanInProgress.set(false)
283283
}
284284
val errorMessage = handleError(coroutineContext, e, scope)
285-
codeScanResponseContext = codeScanResponseContext.copy(reason = errorMessage)
286-
} catch (e: Exception) {
285+
codeScanResponseContext = codeScanResponseContext.copy(reasonDesc = errorMessage)
286+
codeScanResponseContext = codeScanResponseContext.copy(reason = "DefaultError")
287+
} catch (e: CodeScanException) {
287288
if (scope == CodeWhispererConstants.CodeAnalysisScope.PROJECT) {
288289
isProjectScanInProgress.set(false)
289290
}
290-
val errorMessage = handleException(coroutineContext, e, scope)
291-
codeScanResponseContext = codeScanResponseContext.copy(reason = errorMessage)
291+
codeScanResponseContext = codeScanResponseContext.copy(reasonDesc = handleException(coroutineContext, e, scope))
292+
codeScanResponseContext = codeScanResponseContext.copy(reason = e.code ?: "DefaultError")
292293
} finally {
293294
// After code scan
294295
afterCodeScan(scope)
@@ -337,7 +338,7 @@ class CodeWhispererCodeScanManager(val project: Project) {
337338
private fun getCodeScanExceptionMessage(e: CodeWhispererCodeScanException): String? {
338339
val message = e.message
339340
return when {
340-
message.isNullOrBlank() -> null
341+
message.isBlank() -> null
341342
message == message("codewhisperer.codescan.invalid_source_zip_telemetry") -> {
342343
message("codewhisperer.codescan.run_scan_error")
343344
}
@@ -346,8 +347,12 @@ class CodeWhispererCodeScanManager(val project: Project) {
346347
}
347348

348349
private fun getCodeScanServerExceptionMessage(e: CodeWhispererCodeScanServerException): String? =
349-
e.message?.takeIf { it.startsWith("UploadArtifactToS3Exception:") }
350-
?.let { message("codewhisperer.codescan.upload_to_s3_failed") }
350+
e.code?.let {
351+
when (it) {
352+
"UploadArtifactToS3Error" -> message("codewhisperer.codescan.upload_to_s3_failed")
353+
else -> null
354+
}
355+
}
351356

352357
fun handleException(coroutineContext: CoroutineContext, e: Exception, scope: CodeWhispererConstants.CodeAnalysisScope): String {
353358
val errorMessage = when (e) {

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanSession.kt

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
154154
}
155155
}
156156
val errorMessage = createCodeScanResponse.errorMessage()?.let { it } ?: message("codewhisperer.codescan.run_scan_error_telemetry")
157-
codeScanFailed(errorMessage)
157+
codeScanFailed(errorMessage, "CreateCodeScanFailedError")
158158
}
159159
val jobId = createCodeScanResponse.jobId()
160160
codeScanResponseContext = codeScanResponseContext.copy(codeScanJobId = jobId)
@@ -191,7 +191,7 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
191191
}
192192
}
193193
val errorMessage = getCodeScanResponse.errorMessage()?.let { it } ?: message("codewhisperer.codescan.run_scan_error_telemetry")
194-
codeScanFailed(errorMessage)
194+
codeScanFailed(errorMessage, "DefaultError")
195195
}
196196
}
197197

@@ -286,13 +286,8 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
286286
)
287287
} catch (e: Exception) {
288288
LOG.debug { "Create Upload URL failed: ${e.message}" }
289-
290-
val errorMessage = when {
291-
e.message?.contains("Your account is not authorized to make this call.") == true -> "Your account is not authorized to make this call."
292-
e.message?.contains("Service returned HTTP status code 407") == true -> "Service returned HTTP status code 407"
293-
else -> e.message ?: message("codewhisperer.codescan.run_scan_error_telemetry")
294-
}
295-
throw codeScanServerException("CreateUploadUrlException: $errorMessage")
289+
val errorMessage = getTelemetryErrorMessage(e)
290+
throw codeScanServerException(errorMessage, "CreateUploadUrlError")
296291
}
297292

298293
private fun getUploadIntent(scope: CodeWhispererConstants.CodeAnalysisScope): UploadIntent = when (scope) {
@@ -325,7 +320,8 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
325320
}
326321
} catch (e: Exception) {
327322
LOG.debug { "Artifact failed to upload in the S3 bucket: ${e.message}" }
328-
throw codeScanServerException("UploadArtifactToS3Exception: " + e.message?.let { it } ?: message("codewhisperer.codescan.run_scan_error_telemetry"))
323+
val errorMessage = getTelemetryErrorMessage(e)
324+
throw codeScanServerException(errorMessage, "UploadArtifactToS3Error")
329325
}
330326
}
331327

@@ -347,15 +343,8 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
347343
)
348344
} catch (e: Exception) {
349345
LOG.debug { "Creating security scan failed: ${e.message}" }
350-
val errorMessage = when {
351-
e.message?.contains("Too many requests, please wait before trying again.") == true -> "Too many requests, please wait before trying again."
352-
e.message?.contains("Improperly formed request.") == true -> "Improperly formed request."
353-
e.message?.contains("Service returned HTTP status code 407") == true -> "Service returned HTTP status code 407"
354-
e.message?.contains("Encountered an unexpected error when processing the request, please try again.") == true ->
355-
"Encountered an unexpected error when processing the request, please try again."
356-
else -> e.message ?: message("codewhisperer.codescan.run_scan_error_telemetry")
357-
}
358-
throw codeScanServerException("CreateCodeScanException: $errorMessage")
346+
val errorMessage = getTelemetryErrorMessage(e)
347+
throw codeScanServerException(errorMessage, "CreateCodeScanError")
359348
}
360349
}
361350

@@ -367,7 +356,8 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
367356
)
368357
} catch (e: Exception) {
369358
LOG.debug { "Getting security scan failed: ${e.message}" }
370-
throw codeScanServerException("GetCodeScanException: " + e.message?.let { it } ?: message("codewhisperer.codescan.run_scan_error_telemetry"))
359+
val errorMessage = getTelemetryErrorMessage(e)
360+
throw codeScanServerException(errorMessage, "GetCodeScanError")
371361
}
372362

373363
fun listCodeScanFindings(jobId: String, nextToken: String?): ListCodeScanFindingsResponse = try {
@@ -380,7 +370,8 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
380370
)
381371
} catch (e: Exception) {
382372
LOG.debug { "Listing security scan failed: ${e.message}" }
383-
throw codeScanServerException("ListCodeScanFindingsException: " + e.message?.let { it } ?: message("codewhisperer.codescan.run_scan_error_telemetry"))
373+
val errorMessage = getTelemetryErrorMessage(e)
374+
throw codeScanServerException(errorMessage, "ListCodeScanFindingsError")
384375
}
385376

386377
fun mapToCodeScanIssues(recommendations: List<String>): List<CodeWhispererCodeScanIssue> {
@@ -441,6 +432,17 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
441432
sleep(CODE_SCAN_POLLING_INTERVAL_IN_SECONDS * TOTAL_MILLIS_IN_SECOND)
442433
}
443434

435+
fun getTelemetryErrorMessage(e: Exception): String = when {
436+
e.message?.contains("Resource not found.") == true -> "Resource not found."
437+
e.message?.contains("Service returned HTTP status code 407") == true -> "Service returned HTTP status code 407"
438+
e.message?.contains("Service returned HTTP status code 403") == true -> "Service returned HTTP status code 403"
439+
e.message?.contains("invalid_grant: Invalid token provided") == true -> "invalid_grant: Invalid token provided"
440+
e.message?.contains("Connect timed out") == true -> "Unable to execute HTTP request: Connect timed out" // Error: Connect to host failed
441+
e.message?.contains("Encountered an unexpected error when processing the request, please try again.") == true ->
442+
"Encountered an unexpected error when processing the request, please try again."
443+
else -> e.message ?: message("codewhisperer.codescan.run_scan_error_telemetry")
444+
}
445+
444446
private fun isProjectScope(): Boolean = sessionContext.codeAnalysisScope == CodeWhispererConstants.CodeAnalysisScope.PROJECT
445447

446448
companion object {

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/model/CodeWhispererModel.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ data class CodeScanResponseContext(
155155
val codeScanJobId: String? = null,
156156
val codeScanTotalIssues: Int = 0,
157157
val codeScanIssuesWithFixes: Int = 0,
158-
val reason: String? = null
158+
val reason: String? = null,
159+
val reasonDesc: String? = null
159160
)
160161

161162
data class LatencyContext(

plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanTest.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,34 @@ class CodeWhispererCodeScanTest : CodeWhispererCodeScanTestBase(PythonCodeInsigh
154154
assertThat(res).hasSize(1)
155155
}
156156

157+
@Test
158+
fun `test getTelemetryErrorMessage should return the correct error message`() {
159+
val exceptions = listOf(
160+
Exception("Resource not found."),
161+
Exception("Service returned HTTP status code 407"),
162+
Exception("Service returned HTTP status code 403"),
163+
Exception("invalid_grant: Invalid token provided"),
164+
Exception("Connect timed out"),
165+
Exception("Encountered an unexpected error when processing the request, please try again."),
166+
Exception("Some other error message")
167+
)
168+
169+
val expectedMessages = listOf(
170+
"Resource not found.",
171+
"Service returned HTTP status code 407",
172+
"Service returned HTTP status code 403",
173+
"invalid_grant: Invalid token provided",
174+
"Unable to execute HTTP request: Connect timed out",
175+
"Encountered an unexpected error when processing the request, please try again.",
176+
"Some other error message"
177+
)
178+
179+
exceptions.forEachIndexed { index, exception ->
180+
val actualMessage = codeScanSessionSpy.getTelemetryErrorMessage(exception)
181+
assertThat(expectedMessages[index]).isEqualTo(actualMessage)
182+
}
183+
}
184+
157185
@Test
158186
fun `test run() - happypath`() {
159187
assertNotNull(sessionConfigSpy)

plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ codewhisperer.codescan.file_ext_not_supported=File extension {0} is not supporte
763763
codewhisperer.codescan.file_name_issues_count=<html><body> {0} <font color="{3}"> {1} {2, choice, 1#1 issue|2#{2,number} issues}</font></body></html>
764764
codewhisperer.codescan.file_not_found=For file path {0} with error message: {0}
765765
codewhisperer.codescan.file_too_large=Amazon Q: The selected file exceeds the input artifact limit. Try again with a smaller file. For more information about scan limits, see the Amazon Q documentation.
766-
codewhisperer.codescan.file_too_large_telemetry=Payload size limit reached.
766+
codewhisperer.codescan.file_too_large_telemetry=Payload size limit reached
767767
codewhisperer.codescan.fix_applied_fail=Apply fix command failed. {0}
768768
codewhisperer.codescan.fix_available_label=Code fix available
769769
codewhisperer.codescan.fix_button_label=Fix with Q

0 commit comments

Comments
 (0)