Skip to content

Commit fa3d2d5

Browse files
Merge main into feature/bid-paid
2 parents 07b9187 + a0196f5 commit fa3d2d5

File tree

1 file changed

+62
-14
lines changed
  • plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp

1 file changed

+62
-14
lines changed

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ import com.intellij.openapi.project.Project
2222
import com.intellij.openapi.util.Disposer
2323
import com.intellij.openapi.util.Key
2424
import com.intellij.openapi.util.SystemInfo
25+
import com.intellij.util.EnvironmentUtil
26+
import com.intellij.util.io.DigestUtil
2527
import com.intellij.util.io.await
2628
import com.intellij.util.net.HttpConfigurable
2729
import com.intellij.util.net.JdkProxyProvider
30+
import com.intellij.util.net.ssl.CertificateManager
2831
import kotlinx.coroutines.CoroutineScope
2932
import kotlinx.coroutines.Deferred
3033
import kotlinx.coroutines.Job
@@ -77,6 +80,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.textdocument.TextDoc
7780
import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.WorkspaceFolderUtil.createWorkspaceFolders
7881
import software.aws.toolkits.jetbrains.services.amazonq.lsp.workspace.WorkspaceServiceHandler
7982
import software.aws.toolkits.jetbrains.services.amazonq.profile.QDefaultServiceConfig
83+
import software.aws.toolkits.jetbrains.services.amazonq.profile.QEndpoints
8084
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
8185
import software.aws.toolkits.jetbrains.services.telemetry.ClientMetadata
8286
import software.aws.toolkits.jetbrains.settings.LspSettings
@@ -369,21 +373,60 @@ private class AmazonQServerInstance(private val project: Project, private val cs
369373
// will cause slow service init, but maybe fine for now. will not block UI since fetch/extract will be under background progress
370374
val artifact = runBlocking { service<ArtifactManager>().fetchArtifact(project) }.toAbsolutePath()
371375

372-
// more network calls
373-
// make assumption that all requests will resolve to the same CA
374-
// also terrible assumption that default endpoint is reachable
375-
val qUri = URI(QDefaultServiceConfig.ENDPOINT)
376-
val extraCaCerts = try {
377-
val rtsTrustChain = TrustChainUtil.getTrustChain(qUri)
378-
379-
Files.createTempFile("q-extra-ca", ".pem").apply {
380-
writeText(
381-
TrustChainUtil.certsToPem(rtsTrustChain)
382-
)
376+
// make some network calls for troubleshooting
377+
listOf(*QEndpoints.listRegionEndpoints().map { it.endpoint }.toTypedArray(), QDefaultServiceConfig.ENDPOINT).forEach { endpoint ->
378+
try {
379+
val qUri = URI(endpoint)
380+
val rtsTrustChain = TrustChainUtil.getTrustChain(qUri)
381+
val trustRoot = rtsTrustChain.last()
382+
// ATS is cross-signed against starfield certs: https://www.amazontrust.com/repository/
383+
if (listOf("Amazon Root CA", "Starfield Technologies").any { trustRoot.subjectX500Principal.name.contains(it) }) {
384+
LOG.info { "Trust chain for $endpoint ends with public-like CA with sha256 fingerprint: ${DigestUtil.sha256Hex(trustRoot.encoded)}" }
385+
} else {
386+
LOG.info {
387+
"""
388+
|Trust chain for $endpoint transits private CA:
389+
|${buildString {
390+
rtsTrustChain.forEach { cert ->
391+
append("Issuer: ${cert.issuerX500Principal}, ")
392+
append("Subject: ${cert.subjectX500Principal}, ")
393+
append("Fingerprint: ${DigestUtil.sha256Hex(cert.encoded)}\n\t")
394+
}
395+
}}
396+
""".trimMargin("|")
397+
}
398+
LOG.debug { "Full trust chain info for $endpoint: $rtsTrustChain" }
399+
}
400+
} catch (e: Exception) {
401+
LOG.info { "${e.message}: Could not resolve trust chain for $endpoint" }
383402
}
384-
} catch (e: Exception) {
385-
LOG.info(e) { "Could not resolve trust chain for $qUri, skipping NODE_EXTRA_CA_CERTS" }
403+
}
404+
405+
val userEnvNodeCaCerts = EnvironmentUtil.getValue("NODE_EXTRA_CA_CERTS")
406+
// if user has NODE_EXTRA_CA_CERTS in their environment, assume they know what they're doing
407+
val extraCaCerts = if (!userEnvNodeCaCerts.isNullOrEmpty()) {
408+
LOG.info { "Skipping injection of IDE trust store, user already defines NODE_EXTRA_CA_CERTS: $userEnvNodeCaCerts" }
409+
386410
null
411+
} else {
412+
try {
413+
// otherwise include everything the IDE knows about
414+
val allAcceptedIssuers = CertificateManager.getInstance().trustManager.acceptedIssuers
415+
val customIssuers = CertificateManager.getInstance().customTrustManager.acceptedIssuers
416+
LOG.info {
417+
"Injecting ${allAcceptedIssuers.size} IDE trusted certificates (${customIssuers.size} from IDE custom manager) into NODE_EXTRA_CA_CERTS"
418+
}
419+
420+
Files.createTempFile("q-extra-ca", ".pem").apply {
421+
writeText(
422+
TrustChainUtil.certsToPem(allAcceptedIssuers.toList())
423+
)
424+
}.toAbsolutePath().toString()
425+
} catch (e: Exception) {
426+
LOG.warn(e) { "Could not inject IDE trust store into NODE_EXTRA_CA_CERTS" }
427+
428+
null
429+
}
387430
}
388431

389432
val node = if (SystemInfo.isWindows) "node.exe" else "node"
@@ -396,8 +439,13 @@ private class AmazonQServerInstance(private val project: Project, private val cs
396439
"--set-credentials-encryption-key",
397440
).withEnvironment(
398441
buildMap {
399-
extraCaCerts?.let { put("NODE_EXTRA_CA_CERTS", it.toAbsolutePath().toString()) }
442+
extraCaCerts?.let {
443+
LOG.info { "Starting Flare with NODE_EXTRA_CA_CERTS: $it" }
444+
put("NODE_EXTRA_CA_CERTS", it)
445+
}
400446

447+
// assume default endpoint will pick correct proxy if needed
448+
val qUri = URI(QDefaultServiceConfig.ENDPOINT)
401449
val proxy = JdkProxyProvider.getInstance().proxySelector.select(qUri)
402450
// log if only socks proxy available
403451
.firstOrNull { it.type() == Proxy.Type.HTTP }

0 commit comments

Comments
 (0)