Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ jobs:
if: ${{ github.event_name == 'workflow_dispatch' }}
env:
PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: ./gradlew publishPlugin

# test:
Expand Down
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

## [Unreleased]

## [1.9.2] - 2024-07-15

- Integrate Sentry

## [1.9.1] - 2024-06-25

- Remove forgotten "coming soon" from SAST
Expand Down Expand Up @@ -93,6 +97,8 @@

The first public release of the plugin.

[1.9.2]: https://github.com/cycodehq/intellij-platform-plugin/releases/tag/v1.9.2

[1.9.1]: https://github.com/cycodehq/intellij-platform-plugin/releases/tag/v1.9.1

[1.9.0]: https://github.com/cycodehq/intellij-platform-plugin/releases/tag/v1.9.0
Expand Down Expand Up @@ -129,4 +135,4 @@ The first public release of the plugin.

[1.0.0]: https://github.com/cycodehq/intellij-platform-plugin/releases/tag/v1.0.0

[Unreleased]: https://github.com/cycodehq/intellij-platform-plugin/compare/v1.4.0...HEAD
[Unreleased]: https://github.com/cycodehq/intellij-platform-plugin/compare/v1.9.2...HEAD
16 changes: 16 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ plugins {
alias(libs.plugins.gradleIntelliJPlugin) // Gradle IntelliJ Plugin
alias(libs.plugins.changelog) // Gradle Changelog Plugin
alias(libs.plugins.kover) // Gradle Kover Plugin
alias(libs.plugins.sentry)
}

group = properties("pluginGroup").get()
Expand Down Expand Up @@ -66,6 +67,20 @@ koverReport {
}
}

// Configure Sentry
sentry {
includeDependenciesReport = false

// Generates a JVM (Java, Kotlin, etc.) source bundle and uploads your source code to Sentry.
// This enables source context, allowing you to see your source
// code as part of your stack traces in Sentry.
includeSourceContext = true

org = "cycode"
projectName = "intellij-platform-plugin"
authToken = environment("SENTRY_AUTH_TOKEN")
}

tasks {
wrapper {
gradleVersion = properties("gradleVersion").get()
Expand Down Expand Up @@ -124,6 +139,7 @@ tasks {

publishPlugin {
dependsOn("patchChangelog")
dependsOn("sentryUploadSourceBundleJava")
token = environment("PUBLISH_TOKEN")
// The pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3
// Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more:
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pluginGroup = com.cycode.plugin
pluginName = Cycode
pluginRepositoryUrl = https://github.com/cycodehq/intellij-platform-plugin
# SemVer format -> https://semver.org
pluginVersion = 1.9.1
pluginVersion = 1.9.2

# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild = 211.1
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ kotlin = "1.9.20"
changelog = "2.2.0"
gradleIntelliJPlugin = "1.17.1"
kover = "0.7.3"
sentry = "4.9.0"

[libraries]
annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" }
Expand All @@ -22,3 +23,4 @@ dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
gradleIntelliJPlugin = { id = "org.jetbrains.intellij", version.ref = "gradleIntelliJPlugin" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentry" }
14 changes: 13 additions & 1 deletion src/main/kotlin/com/cycode/plugin/Consts.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.cycode.plugin

import com.cycode.plugin.utils.getPluginVersion
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.util.SystemInfo

Expand All @@ -16,12 +17,17 @@ private fun getDefaultCliPath(): String {
return "${Consts.PLUGIN_PATH}/cycode"
}

private fun getSentryReleaseVersion(): String {
val appName = CycodeBundle.message("appName")
val version = getPluginVersion()
return "$appName@${version}"
}

class Consts {
companion object {
val PLUGIN_PATH = PathManager.getPluginsPath() + "/cycode-intellij-platform-plugin"
val DEFAULT_CLI_PATH = getDefaultCliPath()
const val REQUIRED_CLI_VERSION = "1.10.1"
const val REQUIRED_CLI_VERSION = "1.10.3"

const val CLI_GITHUB_ORG = "cycodehq"
const val CLI_GITHUB_REPO = "cycode-cli"
Expand All @@ -30,5 +36,11 @@ class Consts {

const val PLUGIN_AUTO_SAVE_FLUSH_INITIAL_DELAY_SEC = 0L
const val PLUGIN_AUTO_SAVE_FLUSH_DELAY_SEC = 5L

const val SENTRY_DSN = "https://0f0524e8d03a4283702a10ed4b6e03d0@o1026942.ingest.us.sentry.io/4507543885774848"
const val SENTRY_DEBUG = false
val SENTRY_RELEASE = getSentryReleaseVersion()
const val SENTRY_SAMPLE_RATE = 1.0
const val SENTRY_SEND_DEFAULT_PII = false
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.cycode.plugin.activities

import com.cycode.plugin.annotators.CycodeAnnotator
import com.cycode.plugin.sentry.SentryInit
import com.cycode.plugin.services.cycode
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.StartupActivity

class PostStartupActivity : StartupActivity.DumbAware {
override fun runActivity(project: Project) {
SentryInit.init()

// we are using singleton here because runActivity is called for each project
CycodeAnnotator.INSTANCE.registerForAllLangs()

Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/com/cycode/plugin/cli/CliWrapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.intellij.execution.process.ProcessOutputTypes
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.util.Key
import com.intellij.util.io.BaseOutputReader
import io.sentry.Sentry
import java.io.File
import java.nio.charset.Charset

Expand Down Expand Up @@ -104,6 +105,7 @@ class CliWrapper(val executablePath: String, val workDirectory: String? = null)
val result: CliError = mapper.readValue(stdout)
return CliResult.Error(result)
} catch (e: Exception) {
Sentry.captureException(e)
thisLogger().error("Failed to parse ANY CLI output: $stdout", e)
}

Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/com/cycode/plugin/cli/UserAgent.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package com.cycode.plugin.cli

import com.cycode.plugin.CycodeBundle
import com.cycode.plugin.cli.models.IDEUserAgent
import com.cycode.plugin.utils.getPluginVersion
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.extensions.PluginId

private fun retrieveIDEInfo(): IDEUserAgent {
val appInfo = ApplicationInfo.getInstance()

val appName = "jetbrains_plugin"
val appVersion = PluginManagerCore.getPlugin(PluginId.getId("com.cycode.plugin"))?.version ?: "unknown"
val appName = CycodeBundle.message("appName")
val appVersion = getPluginVersion()
val envName = appInfo.versionName
val envVersion = appInfo.fullVersion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@ package com.cycode.plugin.cli.models
data class AuthCheckResult(
val result: Boolean,
val message: String,
val data: AuthCheckResultData,
)

data class AuthCheckResultData(
val userId: String,
val tenantId: String,
)
72 changes: 72 additions & 0 deletions src/main/kotlin/com/cycode/plugin/sentry/SentryErrorReporter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.cycode.plugin.sentry

import com.cycode.plugin.Consts
import com.cycode.plugin.CycodeBundle
import com.intellij.diagnostic.IdeaReportingEvent
import com.intellij.ide.DataManager
import com.intellij.idea.IdeaLogger
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.ErrorReportSubmitter
import com.intellij.openapi.diagnostic.IdeaLoggingEvent
import com.intellij.openapi.diagnostic.SubmittedReportInfo
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project
import com.intellij.util.Consumer
import io.sentry.Sentry
import io.sentry.SentryEvent
import io.sentry.SentryLevel
import java.awt.Component


class SentryErrorReporter : ErrorReportSubmitter() {
override fun getReportActionText(): String {
return CycodeBundle.message("reportActionButton")
}

override fun submit(
events: Array<out IdeaLoggingEvent>,
additionalInfo: String?,
parentComponent: Component,
consumer: Consumer<in SubmittedReportInfo>
): Boolean {
val mgr = DataManager.getInstance()
val context = mgr.getDataContext(parentComponent)
val project: Project? = CommonDataKeys.PROJECT.getData(context)

object : Task.Backgroundable(project, CycodeBundle.message("sentryReporting"), false) {
override fun run(indicator: ProgressIndicator) {
for (ideaEvent in events) {
if (ideaEvent !is IdeaReportingEvent) {
continue
}

val event = SentryEvent()
event.level = SentryLevel.ERROR
event.release = Consts.SENTRY_RELEASE
event.throwable = ideaEvent.data.throwable
event.serverName = ""

event.extras = mapOf(
"message" to ideaEvent.data.message,
"additional_info" to additionalInfo,
"last_action" to IdeaLogger.ourLastActionId,
)

Sentry.captureEvent(event)
}

ApplicationManager.getApplication().invokeLater {
consumer.consume(
SubmittedReportInfo(
SubmittedReportInfo.SubmissionStatus.NEW_ISSUE
)
)
}
}
}.queue()

return true
}
}
28 changes: 28 additions & 0 deletions src/main/kotlin/com/cycode/plugin/sentry/SentryInit.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.cycode.plugin.sentry

import com.cycode.plugin.Consts
import io.sentry.Sentry
import io.sentry.protocol.User

object SentryInit {
fun init() {
Sentry.init { options ->
options.dsn = Consts.SENTRY_DSN
options.isDebug = Consts.SENTRY_DEBUG
options.sampleRate = Consts.SENTRY_SAMPLE_RATE
options.release = Consts.SENTRY_RELEASE
options.isSendDefaultPii = Consts.SENTRY_SEND_DEFAULT_PII
options.serverName = ""
}
}

fun setupScope(userId: String, tenantId: String) {
Sentry.configureScope { scope ->
scope.setTag("tenant_id", tenantId)
scope.user = User().apply {
id = userId
data = mapOf("tenant_id" to tenantId)
}
}
}
}
6 changes: 6 additions & 0 deletions src/main/kotlin/com/cycode/plugin/services/CliService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.cycode.plugin.cli.models.scanResult.sast.SastScanResult
import com.cycode.plugin.cli.models.scanResult.sca.ScaScanResult
import com.cycode.plugin.cli.models.scanResult.secret.SecretScanResult
import com.cycode.plugin.components.toolWindow.updateToolWindowState
import com.cycode.plugin.sentry.SentryInit
import com.cycode.plugin.utils.CycodeNotifier
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.openapi.components.Service
Expand Down Expand Up @@ -124,6 +125,11 @@ class CliService(private val project: Project) {
showErrorNotification(CycodeBundle.message("checkAuthErrorNotification"))
}

SentryInit.setupScope(
processedResult.result.data.userId,
processedResult.result.data.tenantId,
)

return pluginState.cliAuthed
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.cycode.plugin.services
import com.cycode.plugin.utils.verifyFileChecksum
import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.thisLogger
import io.sentry.Sentry
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream
Expand Down Expand Up @@ -31,6 +32,7 @@ class DownloadService {

return content
} catch (e: Exception) {
Sentry.captureException(e)
thisLogger().error("Failed to download file $e", e)
}

Expand Down Expand Up @@ -88,6 +90,7 @@ class DownloadService {
return file
}
} catch (e: Exception) {
Sentry.captureException(e)
thisLogger().error("Failed to download file $e", e)
} finally {
tempFile.delete()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.intellij.openapi.components.Service
import io.sentry.Sentry
import java.net.URL


Expand Down Expand Up @@ -75,6 +76,7 @@ class GithubReleaseService {

null
} catch (e: Exception) {
Sentry.captureException(e)
e.printStackTrace()
null
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/com/cycode/plugin/utils/FileChecksum.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.cycode.plugin.utils

import io.sentry.Sentry
import java.io.File
import java.io.FileInputStream
import java.security.MessageDigest
Expand Down Expand Up @@ -38,6 +39,7 @@ fun verifyFileChecksum(file: File, sha256Checksum: String): Boolean {
try {
return sha256Checksum.equals(getFileShaHash(file), ignoreCase = true)
} catch (e: Exception) {
Sentry.captureException(e)
e.printStackTrace()
}

Expand Down
8 changes: 8 additions & 0 deletions src/main/kotlin/com/cycode/plugin/utils/Plugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.cycode.plugin.utils

import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.extensions.PluginId

fun getPluginVersion(): String {
return PluginManagerCore.getPlugin(PluginId.getId("com.cycode.plugin"))?.version ?: "unknown"
}
1 change: 1 addition & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<projectConfigurable instance="com.cycode.plugin.settings.ApplicationSettingsConfigurable" groupId="tools"
displayName="Cycode"/>
<notificationGroup id="Cycode" displayType="BALLOON"/>
<errorHandler implementation="com.cycode.plugin.sentry.SentryErrorReporter"/>
</extensions>

<applicationListeners>
Expand Down
Loading