Skip to content

Commit

Permalink
BCE-38714 - [Configurations] Configuration screen overhaul
Browse files Browse the repository at this point in the history
  • Loading branch information
ChananM committed Sep 15, 2024
1 parent b0c6d7e commit d5d042f
Show file tree
Hide file tree
Showing 26 changed files with 365 additions and 292 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

# checkov-jetbrains-idea Changelog

## [1.0.22] - 2024-09-10
## [1.0.22] - 2024-09-15

### Added

- Added a new 'show logs' button in the plugin panel that opens the plugin log file
- Added validations to user input in the configuration screen
- Added a `test connection` button in the configuration screen

### Misc

- Upgraded gradle version to 8.10.1
- Migrated the IntelliJ platform plugin to version 2.0.1
- Refactored `ApiClient` (now `PrismaApiClient`) and `AnalyticsService` (*Work in progress*)

## [1.0.21] - 2024-08-29

Expand Down
15 changes: 12 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

fun properties(key: String): String = project.findProperty(key).toString()

plugins {
id("java") // Java support
alias(libs.plugins.kotlin) // Kotlin support
// alias(libs.plugins.kotlinSerialization) // Kotlin serialization support
alias(libs.plugins.intelliJPlatform) // IntelliJ Platform Gradle Plugin
alias(libs.plugins.changelog) // Gradle Changelog Plugin
alias(libs.plugins.qodana) // Gradle Qodana Plugin
alias(libs.plugins.kover) // Gradle Kover Plugin
kotlin("plugin.serialization") version "1.9.25"
}

group = properties("pluginGroup")
Expand All @@ -38,9 +40,13 @@ dependencies {
implementation("org.json:json:20231013")
implementation("commons-io:commons-io:2.11.0")
implementation("io.github.java-diff-utils:java-diff-utils:4.12")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("org.slf4j:slf4j-api:2.0.16")
implementation("ch.qos.logback:logback-classic:1.5.6")
implementation(libs.springWeb)
// implementation(libs.kotlinxSerializationJson)
implementation(libs.jackson)
compileOnly(libs.lombok)
annotationProcessor(libs.lombok)
testImplementation(libs.junit)
testImplementation(libs.jupiterApi)
testRuntimeOnly("org.junit.jupiter:junit-jupiter:5.8.1")
Expand Down Expand Up @@ -118,7 +124,10 @@ tasks {
targetCompatibility = it
}
withType<KotlinCompile> {
kotlinOptions.jvmTarget = it
compilerOptions {
jvmTarget = JvmTarget.fromTarget(it)
apiVersion = KotlinVersion.KOTLIN_2_0
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ pluginVerifierIdeVersions=2020.3.4, 2021.1.3, 2021.2.4, 2024.1.6
platformType = IC
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild=203
pluginUntilBuild=242
platformVersion=2024.1.6
pluginUntilBuild=242.*
platformVersion=2024.2.1
platformDownloadSources = true
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
Expand Down
14 changes: 12 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
[versions]

# libraries
lombok = "1.18.34"
junit = "4.13.2"
jupiterApi = "5.8.1"
springWeb = "6.1.12"
jackson = "2.17.2"
# kotlinxSerializationJson = "1.7.2"

# plugins
changelog = "2.2.1"
intelliJPlatform = "2.0.1"
kotlin = "1.9.25"
kotlin = "2.0.20"
kover = "0.8.3"
qodana = "0.1.13"

[libraries]
jackson = { group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version.ref = "jackson"}
# kotlinxSerializationJson = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson"}
lombok = { group = "org.projectlombok", name = "lombok", version.ref = "lombok" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
jupiterApi = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "jupiterApi" }
springWeb = { group = "org.springframework", name = "spring-web", version.ref = "springWeb" }

[plugins]
changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" }
intelliJPlatform = { id = "org.jetbrains.intellij.platform", version.ref = "intelliJPlatform" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
# kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" }
qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" }
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.bridgecrew.util;

import com.intellij.openapi.application.ApplicationManager;
import lombok.experimental.UtilityClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@UtilityClass
public class ApplicationServiceUtil {

private final static Logger logger = LoggerFactory.getLogger(ApplicationServiceUtil.class);
private static final Logger logger = LoggerFactory.getLogger(ApplicationServiceUtil.class);

public static <T> T getService(Class<T> clazz) {
T service = ApplicationManager.getApplication().getService(clazz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class PostStartupActivity : ProjectActivity {
override suspend fun execute(project: Project) {
val version = PluginManagerCore.getPlugin(PluginId.getId("com.github.bridgecrewio.prismacloud"))?.version
logger.info("Starting Prisma Cloud JetBrains plugin version $version")
project.messageBus.connect(project).subscribe(INITIALIZATION_TOPIC, object : InitializationListener {
project.messageBus.connect().subscribe(INITIALIZATION_TOPIC, object : InitializationListener {
override fun initializationCompleted() {
project.service<CheckovToolWindowManagerPanel>().subscribeToInternalEvents(project)
project.service<CheckovToolWindowManagerPanel>().subscribeToProjectEventChange()
Expand Down
74 changes: 28 additions & 46 deletions src/main/kotlin/com/bridgecrew/analytics/AnalyticsDataEvents.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,85 +3,67 @@ package com.bridgecrew.analytics
import com.bridgecrew.cache.InMemCache
import com.bridgecrew.settings.PLUGIN_NAME
import com.bridgecrew.settings.PrismaSettingsState
import com.google.gson.annotations.Expose
import com.fasterxml.jackson.annotation.JsonFormat
import com.fasterxml.jackson.annotation.JsonIgnore
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.extensions.PluginId
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.JsonObject
import java.util.*

open class AnalyticsData {

val pluginName: String = PLUGIN_NAME

@OptIn(ExperimentalSerializationApi::class)
@Serializable
sealed class AnalyticsData(@EncodeDefault val pluginName: String = PLUGIN_NAME) {

@EncodeDefault
val installationId: String = PrismaSettingsState().getInstance()!!.installationId

@EncodeDefault
var pluginVersion: String? =
PluginManagerCore.getPlugin(PluginId.getId("com.github.bridgecrewio.prismacloud"))?.version
val pluginVersion: String? = PluginManagerCore.getPlugin(PluginId.getId("com.github.bridgecrewio.prismacloud"))?.version

@EncodeDefault
var ideVersion: String? =
ApplicationInfo.getInstance().fullApplicationName + " / " + ApplicationInfo.getInstance().build
val ideVersion: String = ApplicationInfo.getInstance().fullApplicationName + " / " + ApplicationInfo.getInstance().build

@EncodeDefault
var operatingSystem: String? = System.getProperty("os.name") + " " + System.getProperty("os.version")
val operatingSystem: String = System.getProperty("os.name") + " " + System.getProperty("os.version")

@EncodeDefault
var checkovVersion: String? = InMemCache.get("checkovVersion")
val checkovVersion: String? = InMemCache.get("checkovVersion")

@Serializable
lateinit var eventType: String

@Serializable(with = DateSerializer::class)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSSZ", locale = "en")
lateinit var eventTime: Date

abstract val eventData: Any
open var eventData: MutableMap<String, *> = mutableMapOf<String, Any>()

}

@Serializable
data class FullScanAnalyticsData(@Transient val scanNumber: Int = 0): AnalyticsData() {
@Transient
data class FullScanAnalyticsData(@JsonIgnore val scanNumber: Int = 0): AnalyticsData() {

@JsonIgnore
lateinit var buttonPressedTime: Date

@Transient
@JsonIgnore
lateinit var scanStartedTime: Date

@Transient
@JsonIgnore
val frameworksScanTime: MutableMap<String, FullScanFrameworkScanTimeData> = mutableMapOf()

@Expose
override lateinit var eventData: MutableMap<String, FullScanFrameworkScanTimeData>

@Transient
@JsonIgnore
lateinit var scanFinishedTime: Date

@Transient
@JsonIgnore
lateinit var resultsWereFullyDisplayedTime: Date

@JsonIgnore
fun isFullScanFinished() = ::scanFinishedTime.isInitialized

@JsonIgnore
fun isFullScanStarted() = ::scanStartedTime.isInitialized
}

@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class PluginInstallAnalyticsData(
@EncodeDefault override val eventData: JsonObject = JsonObject(mapOf())
) : AnalyticsData()

@Serializable
data class FullScanFrameworkScanTimeData(
@Serializable(with = DateSerializer::class)
val startTime: Date
) {
@Serializable(with = DateSerializer::class)
class FullScanFrameworkScanTimeData {

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSSZ", locale = "en")
val startTime: Date = Date()

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSSZ", locale = "en")
var endTime: Date = Date()

var totalTimeSeconds = 0L
}
60 changes: 25 additions & 35 deletions src/main/kotlin/com/bridgecrew/analytics/AnalyticsService.kt
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
package com.bridgecrew.analytics

import com.bridgecrew.api.ApiClient
import com.bridgecrew.api.PrismaApiClient
import com.bridgecrew.cache.CacheDataAnalytics
import com.bridgecrew.scheduler.IntervalRunner
import com.bridgecrew.services.scan.FullScanStateService
import com.bridgecrew.services.scan.ScanTaskResult
import com.bridgecrew.settings.PrismaSettingsState
import com.bridgecrew.util.ApplicationServiceUtil
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.slf4j.LoggerFactory
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit

@Service
// TODO:
// This service should be an application level service, but it requires a major refactor with how it handles
// FullScanStateService and CacheDataAnalytics on a project level
@Service(Service.Level.PROJECT)
class AnalyticsService(val project: Project) {

private val logger = LoggerFactory.getLogger(javaClass)
private var apiClient: ApiClient? = null
private val analyticsReleaseTask = IntervalRunner("Analytics")

private var fullScanData: FullScanAnalyticsData? = null
private var fullScanNumber = 0

private var analyticsEventData: MutableList<String> = arrayListOf()
private var analyticsEventData: MutableList<AnalyticsData> = mutableListOf()

var wereFullScanResultsDisplayed = false
var wereSingleFileScanResultsDisplayed = false
Expand All @@ -47,7 +48,7 @@ class AnalyticsService(val project: Project) {

fun fullScanByFrameworkStarted(framework: String) {
logger.info("Prisma Cloud Plugin Analytics - scan #${fullScanNumber} - full scan started for framework $framework")
fullScanData!!.frameworksScanTime[framework] = FullScanFrameworkScanTimeData(Date())
fullScanData!!.frameworksScanTime[framework] = FullScanFrameworkScanTimeData()
}

fun fullScanByFrameworkFinished(framework: String) {
Expand Down Expand Up @@ -153,14 +154,18 @@ class AnalyticsService(val project: Project) {
return "${minutes}:${secondsString}"
}

fun releaseAnalytics() {
val apiClient = getApiClient() ?: return
fun stopAnalyticsService() {
logger.info("Analytics service for project ${project.name} is stopping, releasing all analytics")
analyticsReleaseTask.stop()
releaseAnalytics()
}

private fun releaseAnalytics() {
val apiClient = ApplicationServiceUtil.getService(PrismaApiClient::class.java) ?: return
if (analyticsEventData.isEmpty()) {
return
}

val data = analyticsEventData.joinToString(prefix = "[", postfix = "]")
val isReleased = apiClient.putDataAnalytics(data)
val isReleased = apiClient.putDataAnalytics(analyticsEventData)
if (isReleased) {
analyticsEventData.clear()
}
Expand All @@ -169,45 +174,30 @@ class AnalyticsService(val project: Project) {
}

fun startSchedulerReleasingAnalytics(){
val apiClient = getApiClient() ?: return
val apiClient = ApplicationServiceUtil.getService(PrismaApiClient::class.java) ?: return
val config = apiClient.getConfig()
CacheDataAnalytics(project).load(analyticsEventData)
project.service<IntervalRunner>()
.scheduleWithTimer({ releaseAnalytics() }, config.reportingInterval)
}

private fun getApiClient(): ApiClient? {
if (this.apiClient != null) {
return this.apiClient
}

val settings = PrismaSettingsState().getInstance()
if (settings != null && settings.isConfigured()) {
this.apiClient = ApiClient(settings.accessKey, settings.secretKey, settings.prismaURL)
return this.apiClient
}

return null
analyticsReleaseTask.scheduleWithTimer({ releaseAnalytics() }, config?.reportingInterval ?: 300)
}

private fun buildFullScanAnalyticsData(){
fullScanData!!.eventData = fullScanData!!.frameworksScanTime
fullScanData!!.eventTime = fullScanData!!.buttonPressedTime
fullScanData!!.eventType = EventTypeEnum.ON_FULL_SCAN
analyticsEventData.add(Json.encodeToString(fullScanData))
analyticsEventData.add(fullScanData!!)
}

private fun buildPluginInstalledAnalyticsData(){
val analyticsData = PluginInstallAnalyticsData()
val analyticsData = AnalyticsData()
analyticsData.eventTime = Date()
analyticsData.eventType = EventTypeEnum.ON_PLUGIN_INSTALL
analyticsEventData.add(Json.encodeToString(analyticsData))
analyticsEventData.add(analyticsData)
}

private fun buildPluginUninstalledAnalyticsData(){
val analyticsData = PluginInstallAnalyticsData()
val analyticsData = AnalyticsData()
analyticsData.eventTime = Date()
analyticsData.eventType = EventTypeEnum.ON_PLUGIN_UNINSTALL
analyticsEventData.add(Json.encodeToString(analyticsData))
analyticsEventData.add(analyticsData)
}
}
Loading

0 comments on commit d5d042f

Please sign in to comment.