From f53a1315b1faf0f32309cf6d6b02b7472743857f Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Mon, 19 Feb 2024 19:13:15 +0100 Subject: [PATCH 1/8] CM-27504 - Add Tree View visualization --- .../plugin/annotators/CycodeAnnotator.kt | 12 +- .../cli/models/scanResult/DetectionBase.kt | 8 + .../cli/models/scanResult/ScanResultBase.kt | 5 + .../cli/models/scanResult/sca/ScaDetection.kt | 31 +++- .../models/scanResult/sca/ScaScanResult.kt | 5 +- .../scanResult/secret/SecretDetection.kt | 23 ++- .../scanResult/secret/SecretScanResult.kt | 5 +- .../scanContentTab/ScanContentTab.kt | 9 +- .../components/treeView/TreeCellRenderer.kt | 27 +++ .../components/treeView/TreeView.kt | 172 ++++++++++++++++++ .../components/treeView/nodes/AbstractNode.kt | 13 ++ .../treeView/nodes/DetectionNodes.kt | 17 ++ .../components/treeView/nodes/DummyNode.kt | 10 + .../components/treeView/nodes/FileNode.kt | 9 + .../components/treeView/nodes/RootNodes.kt | 50 +++++ .../components/treeView/nodes/ScanTypeNode.kt | 9 + .../components/treeView/nodes/utils.kt | 7 + .../components/treeView/utils.kt | 42 +++++ .../com/cycode/plugin/icons/PluginIcons.kt | 11 ++ .../CycodeIgnoreIntentionQuickFix.kt | 2 + .../plugin/services/CliDownloadService.kt | 4 +- .../com/cycode/plugin/services/CliService.kt | 3 + src/main/resources/icons/scan-type/IaC.png | Bin 0 -> 1127 bytes src/main/resources/icons/scan-type/SAST.png | Bin 0 -> 1068 bytes src/main/resources/icons/scan-type/SCA.png | Bin 0 -> 1220 bytes .../resources/icons/scan-type/Secrets.png | Bin 0 -> 1159 bytes src/main/resources/icons/severity/C.png | Bin 0 -> 1186 bytes src/main/resources/icons/severity/H.png | Bin 0 -> 1213 bytes src/main/resources/icons/severity/I.png | Bin 0 -> 1213 bytes src/main/resources/icons/severity/L.png | Bin 0 -> 1163 bytes src/main/resources/icons/severity/M.png | Bin 0 -> 1137 bytes .../messages/CycodeBundle.properties | 8 +- 32 files changed, 453 insertions(+), 29 deletions(-) create mode 100644 src/main/kotlin/com/cycode/plugin/cli/models/scanResult/DetectionBase.kt create mode 100644 src/main/kotlin/com/cycode/plugin/cli/models/scanResult/ScanResultBase.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/utils.kt create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/utils.kt create mode 100644 src/main/resources/icons/scan-type/IaC.png create mode 100644 src/main/resources/icons/scan-type/SAST.png create mode 100644 src/main/resources/icons/scan-type/SCA.png create mode 100644 src/main/resources/icons/scan-type/Secrets.png create mode 100644 src/main/resources/icons/severity/C.png create mode 100644 src/main/resources/icons/severity/H.png create mode 100644 src/main/resources/icons/severity/I.png create mode 100644 src/main/resources/icons/severity/L.png create mode 100644 src/main/resources/icons/severity/M.png diff --git a/src/main/kotlin/com/cycode/plugin/annotators/CycodeAnnotator.kt b/src/main/kotlin/com/cycode/plugin/annotators/CycodeAnnotator.kt index 48a4a2e..5f1e6c4 100644 --- a/src/main/kotlin/com/cycode/plugin/annotators/CycodeAnnotator.kt +++ b/src/main/kotlin/com/cycode/plugin/annotators/CycodeAnnotator.kt @@ -208,8 +208,8 @@ class CycodeAnnotator : DumbAware, ExternalAnnotator() { val detectedValue = psiFile.text.substring(textRange.startOffset, textRange.endOffset) detectionDetails.detectedValue = detectedValue - val message = detection.message.replace("within '' repository", "") // BE bug - val title = CycodeBundle.message("secretsAnnotationTitle", detection.type, message) + val message = detection.getFormattedMessage() + val title = CycodeBundle.message("annotationTitle", detection.getFormattedTitle()) var companyGuidelineMessage = "" if (detectionDetails.customRemediationGuidelines != null) { @@ -283,13 +283,7 @@ class CycodeAnnotator : DumbAware, ExternalAnnotator() { return@forEach } - val title = CycodeBundle.message( - "scaAnnotationTitle", - detectionDetails.packageName, - detectionDetails.packageVersion, - // using the message as fallback for non-premise license detections - detectionDetails.vulnerabilityDescription ?: detection.message - ) + val title = CycodeBundle.message("annotationTitle", detection.getFormattedTitle()) var firstPatchedVersionMessage = "" if (detectionDetails.alert?.firstPatchedVersion != null) { diff --git a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/DetectionBase.kt b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/DetectionBase.kt new file mode 100644 index 0000000..b270e3a --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/DetectionBase.kt @@ -0,0 +1,8 @@ +package com.cycode.plugin.cli.models.scanResult + +interface DetectionBase { + val severity: String + val detectionDetails: ScanDetectionDetailsBase + + fun getFormattedNodeTitle(): String +} diff --git a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/ScanResultBase.kt b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/ScanResultBase.kt new file mode 100644 index 0000000..48ebe28 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/ScanResultBase.kt @@ -0,0 +1,5 @@ +package com.cycode.plugin.cli.models.scanResult + +interface ScanResultBase { + val detections: List +} diff --git a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/sca/ScaDetection.kt b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/sca/ScaDetection.kt index b869303..776842b 100644 --- a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/sca/ScaDetection.kt +++ b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/sca/ScaDetection.kt @@ -1,10 +1,35 @@ package com.cycode.plugin.cli.models.scanResult.sca +import com.cycode.plugin.CycodeBundle +import com.cycode.plugin.cli.models.scanResult.DetectionBase + data class ScaDetection( val message: String, - val detectionDetails: ScaDetectionDetails, - val severity: String, + override val detectionDetails: ScaDetectionDetails, + override val severity: String, val type: String, val detectionRuleId: String, val detectionTypeId: String, -) +) : DetectionBase { + fun getFormattedMessage(): String { + return message + } + + fun getFormattedTitle(): String { + return CycodeBundle.message( + "scaTitle", + detectionDetails.packageName, + detectionDetails.packageVersion, + // using the message as fallback for non-premise license detections + detectionDetails.vulnerabilityDescription ?: getFormattedMessage() + ) + } + + override fun getFormattedNodeTitle(): String { + return CycodeBundle.message( + "scaNodeTitle", + detectionDetails.lineInFile, + getFormattedTitle(), + ) + } +} diff --git a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/sca/ScaScanResult.kt b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/sca/ScaScanResult.kt index b11ac84..0bce73a 100644 --- a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/sca/ScaScanResult.kt +++ b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/sca/ScaScanResult.kt @@ -1,8 +1,9 @@ package com.cycode.plugin.cli.models.scanResult.sca import com.cycode.plugin.cli.models.CliError +import com.cycode.plugin.cli.models.scanResult.ScanResultBase data class ScaScanResult( - val detections: List, + override val detections: List, val errors: List, -) +) : ScanResultBase diff --git a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/secret/SecretDetection.kt b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/secret/SecretDetection.kt index 29c3d95..567f82e 100644 --- a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/secret/SecretDetection.kt +++ b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/secret/SecretDetection.kt @@ -1,10 +1,27 @@ package com.cycode.plugin.cli.models.scanResult.secret +import com.cycode.plugin.CycodeBundle +import com.cycode.plugin.cli.models.scanResult.DetectionBase + +const val IDE_ENTRY_LINE_NUMBER = 1 + data class SecretDetection( val message: String, - val detectionDetails: SecretDetectionDetails, - val severity: String, + override val detectionDetails: SecretDetectionDetails, + override val severity: String, val type: String, val detectionRuleId: String, // UUID val detectionTypeId: String, // UUID -) +) : DetectionBase { + fun getFormattedMessage(): String { + return message.replace("within '' repository", "") // BE bug + } + + fun getFormattedTitle(): String { + return CycodeBundle.message("secretsTitle", type, getFormattedMessage()) + } + + override fun getFormattedNodeTitle(): String { + return CycodeBundle.message("secretsNodeTitle", detectionDetails.line + IDE_ENTRY_LINE_NUMBER, type) + } +} diff --git a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/secret/SecretScanResult.kt b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/secret/SecretScanResult.kt index 621b0e5..5784eb6 100644 --- a/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/secret/SecretScanResult.kt +++ b/src/main/kotlin/com/cycode/plugin/cli/models/scanResult/secret/SecretScanResult.kt @@ -1,8 +1,9 @@ package com.cycode.plugin.cli.models.scanResult.secret import com.cycode.plugin.cli.models.CliError +import com.cycode.plugin.cli.models.scanResult.ScanResultBase data class SecretScanResult( - val detections: List, + override val detections: List, val errors: List, -) +) : ScanResultBase diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/ScanContentTab.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/ScanContentTab.kt index f61cc2d..441bea1 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/ScanContentTab.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/ScanContentTab.kt @@ -2,11 +2,10 @@ package com.cycode.plugin.components.toolWindow.components.scanContentTab import com.cycode.plugin.CycodeBundle import com.cycode.plugin.components.Component -import com.cycode.plugin.components.common.BorderedPanel import com.cycode.plugin.components.common.createClickableLabel +import com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.TreeView import com.cycode.plugin.services.CycodeService import com.intellij.util.ui.JBUI -import java.awt.BorderLayout import java.awt.GridBagConstraints import java.awt.GridBagLayout import javax.swing.JButton @@ -14,7 +13,7 @@ import javax.swing.JPanel class ScanContentTab : Component() { override fun getContent(service: CycodeService): JPanel { - val panel = JPanel().apply { + val rightPanel = JPanel().apply { layout = GridBagLayout() add(add(JPanel().apply { add(createClickableLabel(CycodeBundle.message("scanTabTitleLabel"))) @@ -64,8 +63,6 @@ class ScanContentTab : Component() { }) } - return BorderedPanel().apply { - add(panel, BorderLayout.NORTH) - } + return TreeView(service.project, rightPanel) } } diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt new file mode 100644 index 0000000..01920a1 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt @@ -0,0 +1,27 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView + +import com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes.AbstractNode +import com.intellij.ui.ColoredTreeCellRenderer +import javax.swing.JTree +import javax.swing.tree.DefaultMutableTreeNode + +class TreeCellRenderer : ColoredTreeCellRenderer() { + override fun customizeCellRenderer( + tree: JTree, + value: Any?, + selected: Boolean, + expanded: Boolean, + leaf: Boolean, + row: Int, + hasFocus: Boolean + ) { + if (value !is DefaultMutableTreeNode) return + val nodeData = value.userObject as AbstractNode + icon = nodeData.icon + append(nodeData.name) + + isIconOpaque = false + isTransparentIconBackground = true + isOpaque = false + } +} diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt new file mode 100644 index 0000000..a5aedef --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt @@ -0,0 +1,172 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView + +import com.cycode.plugin.cli.CliResult +import com.cycode.plugin.cli.CliScanType +import com.cycode.plugin.cli.models.scanResult.DetectionBase +import com.cycode.plugin.cli.models.scanResult.ScanResultBase +import com.cycode.plugin.cli.models.scanResult.sca.ScaDetection +import com.cycode.plugin.cli.models.scanResult.secret.SecretDetection +import com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes.* +import com.cycode.plugin.icons.PluginIcons +import com.cycode.plugin.services.scanResults +import com.intellij.openapi.project.Project +import com.intellij.ui.components.JBScrollPane +import com.intellij.ui.treeStructure.Tree +import java.awt.Component +import java.awt.Dimension +import java.awt.GridLayout +import java.io.File +import javax.swing.Icon +import javax.swing.JPanel +import javax.swing.JSplitPane +import javax.swing.event.TreeSelectionEvent +import javax.swing.event.TreeSelectionListener +import javax.swing.tree.DefaultMutableTreeNode +import javax.swing.tree.TreeSelectionModel + + +class TreeView(val project: Project, defaultRightPane: Component) : JPanel(GridLayout(1, 0)), TreeSelectionListener { + private val tree: Tree + private val scanResults = scanResults(project) + + init { + val top = createNode(DummyNode()) + createNodes(top) + + tree = Tree(top) + tree.setRootVisible(false) + tree.setCellRenderer(TreeCellRenderer()) + + tree.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION + tree.addTreeSelectionListener(this) // we want to listen for when the user selects a node + + val treeView = JBScrollPane(tree) + + val splitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT) + flattenJSplitPane(splitPane) + + splitPane.leftComponent = treeView + splitPane.rightComponent = defaultRightPane + + val minimumSize = Dimension(400, 100) + defaultRightPane.minimumSize = minimumSize + treeView.minimumSize = minimumSize + + splitPane.resizeWeight = 0.5 + + add(splitPane) + } + + override fun valueChanged(e: TreeSelectionEvent) { + if (tree.getLastSelectedPathComponent() == null) return + + val node = tree.getLastSelectedPathComponent() as DefaultMutableTreeNode + + if (node.userObject is SecretDetectionNode) { + openSecretDetectionInFile(node.userObject as SecretDetectionNode) + } + + if (node.userObject is ScaDetectionNode) { + openScaDetectionInFile(node.userObject as ScaDetectionNode) + displayScaViolationCard(node.userObject as ScaDetectionNode) + } + } + + private fun openSecretDetectionInFile(node: SecretDetectionNode) { + val filePath = node.detection.detectionDetails.getFilepath() + val line = node.detection.detectionDetails.line + openFileInEditor(project, filePath, line) + } + + private fun openScaDetectionInFile(node: ScaDetectionNode) { + val filePath = node.detection.detectionDetails.getFilepath() + val line = node.detection.detectionDetails.lineInFile - 1 + openFileInEditor(project, filePath, line) + } + + private fun displayScaViolationCard(node: ScaDetectionNode) { + // not implemented yet + } + + private fun convertSeverityToIcon(severity: String): Icon { + return when (severity.toLowerCase()) { + "critical" -> PluginIcons.SEVERITY_CRITICAL + "high" -> PluginIcons.SEVERITY_HIGH + "medium" -> PluginIcons.SEVERITY_MEDIUM + "low" -> PluginIcons.SEVERITY_LOW + else -> PluginIcons.SEVERITY_INFO + } + } + + private fun getSeverityWeight(severity: String): Int { + return when (severity.toLowerCase()) { + "critical" -> 4 + "high" -> 3 + "medium" -> 2 + "low" -> 1 + else -> 0 + } + } + + private fun createDetectionNodes( + scanType: CliScanType, + scanResults: ScanResultBase, + createNodeCallback: (detection: DetectionBase) -> DefaultMutableTreeNode + ) { + val sortedDetections = scanResults.detections.sortedByDescending { getSeverityWeight(it.severity) } + val detectionsByFile = sortedDetections.groupBy { it.detectionDetails.getFilepath() } + + for ((filePath, detections) in detectionsByFile) { + val fileName = File(filePath).name + val fileNode = createNode(FileNode(fileName)) + for (detection in detections) { + fileNode.add(createNodeCallback(detection)) + } + RootNodes.getScanTypeNode(scanType).add(fileNode) + } + } + + private fun createSecretDetectionNodes() { + val secretDetections = scanResults.getSecretResults() + if (secretDetections !is CliResult.Success) { + return + } + + fun createSecretDetectionNode(detection: DetectionBase): DefaultMutableTreeNode { + return createNode( + SecretDetectionNode( + detection.getFormattedNodeTitle(), + convertSeverityToIcon(detection.severity), + detection as SecretDetection + ) + ) + } + + createDetectionNodes(CliScanType.Secret, secretDetections.result, ::createSecretDetectionNode) + } + + private fun createScaDetectionNodes() { + val scaDetections = scanResults.getScaResults() + if (scaDetections !is CliResult.Success) { + return + } + + fun createScaDetectionNode(detection: DetectionBase): DefaultMutableTreeNode { + return createNode( + ScaDetectionNode( + detection.getFormattedNodeTitle(), + convertSeverityToIcon(detection.severity), + detection as ScaDetection + ) + ) + } + + createDetectionNodes(CliScanType.Sca, scaDetections.result, ::createScaDetectionNode) + } + + private fun createNodes(top: DefaultMutableTreeNode) { + RootNodes.createNodes(top) + createSecretDetectionNodes() + createScaDetectionNodes() + } +} diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt new file mode 100644 index 0000000..33e20b8 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt @@ -0,0 +1,13 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes + +import javax.swing.Icon + + +abstract class AbstractNode { + abstract var name: String + abstract var icon: Icon? + + override fun toString(): String { + return name + } +} diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt new file mode 100644 index 0000000..41ee641 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt @@ -0,0 +1,17 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes + +import com.cycode.plugin.cli.models.scanResult.sca.ScaDetection +import com.cycode.plugin.cli.models.scanResult.secret.SecretDetection +import javax.swing.Icon + +data class SecretDetectionNode( + override var name: String, + override var icon: Icon?, + val detection: SecretDetection, +) : AbstractNode() + +data class ScaDetectionNode( + override var name: String, + override var icon: Icon?, + val detection: ScaDetection, +) : AbstractNode() diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt new file mode 100644 index 0000000..83e2b46 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt @@ -0,0 +1,10 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes + +import com.cycode.plugin.CycodeBundle +import javax.swing.Icon + +data class DummyNode( + override var name: String = CycodeBundle.message("name"), + override var icon: Icon? = null, + val summary: String? = null +) : AbstractNode() diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt new file mode 100644 index 0000000..4a99082 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt @@ -0,0 +1,9 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes + +import javax.swing.Icon + +data class FileNode( + override var name: String, + override var icon: Icon? = null, + val summary: String? = null +) : AbstractNode() diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt new file mode 100644 index 0000000..e738258 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt @@ -0,0 +1,50 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes + +import com.cycode.plugin.CycodeBundle +import com.cycode.plugin.cli.CliScanType +import com.cycode.plugin.icons.PluginIcons +import javax.swing.tree.DefaultMutableTreeNode + +class RootNodes { + companion object { + private val SecretsNode = createNode( + ScanTypeNode(CycodeBundle.message("secretDisplayName"), PluginIcons.SCAN_TYPE_SECRETS) + ) + + private val SastNode = createNode( + ScanTypeNode(CycodeBundle.message("sastDisplayName"), PluginIcons.SCAN_TYPE_SAST) + ) + + private val ScaNode = createNode( + ScanTypeNode(CycodeBundle.message("scaDisplayName"), PluginIcons.SCAN_TYPE_SCA) + ) + + private val IacNode = createNode( + ScanTypeNode(CycodeBundle.message("iacDisplayName"), PluginIcons.SCAN_TYPE_IAC) + ) + + private val scanTypeToNode = mapOf( + CliScanType.Secret to SecretsNode, + CliScanType.Sast to SastNode, + CliScanType.Sca to ScaNode, + CliScanType.Iac to IacNode + ) + + fun createNodes(top: DefaultMutableTreeNode) { + SecretsNode.removeAllChildren() + ScaNode.removeAllChildren() + SastNode.removeAllChildren() + IacNode.removeAllChildren() + + // the order of adding nodes is important + top.add(SecretsNode) + top.add(ScaNode) + top.add(SastNode) + top.add(IacNode) + } + + fun getScanTypeNode(scanType: CliScanType): DefaultMutableTreeNode { + return scanTypeToNode[scanType] ?: throw IllegalArgumentException("Unknown scan type: $scanType") + } + } +} diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt new file mode 100644 index 0000000..24a4699 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt @@ -0,0 +1,9 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes + +import javax.swing.Icon + +data class ScanTypeNode( + override var name: String, + override var icon: Icon?, + val summary: String? = null +) : AbstractNode() diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/utils.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/utils.kt new file mode 100644 index 0000000..0d39f4b --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/utils.kt @@ -0,0 +1,7 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes + +import javax.swing.tree.DefaultMutableTreeNode + +fun createNode(node: AbstractNode): DefaultMutableTreeNode { + return DefaultMutableTreeNode(node) +} diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/utils.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/utils.kt new file mode 100644 index 0000000..b64f861 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/utils.kt @@ -0,0 +1,42 @@ +package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView + +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.OpenFileDescriptor +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.LocalFileSystem +import java.io.File +import javax.swing.BorderFactory +import javax.swing.JSplitPane +import javax.swing.border.Border +import javax.swing.plaf.basic.BasicSplitPaneDivider +import javax.swing.plaf.basic.BasicSplitPaneUI + +/** + * Makes a split pane invisible. Only contained components are shown. + * + * Ref: https://stackoverflow.com/a/12799814/8032027 + * + * @param splitPane + */ +fun flattenJSplitPane(splitPane: JSplitPane) { + splitPane.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)) + val flatDividerSplitPaneUI: BasicSplitPaneUI = object : BasicSplitPaneUI() { + override fun createDefaultDivider(): BasicSplitPaneDivider { + return object : BasicSplitPaneDivider(this) { + override fun setBorder(b: Border?) {} + } + } + } + splitPane.setUI(flatDividerSplitPaneUI) + splitPane.setBorder(null) +} + +fun openFileInEditor(project: Project, filePath: String, lineNumber: Int) { + val file = File(filePath) + val virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file) ?: return + + val editorManager = FileEditorManager.getInstance(project) + editorManager.openTextEditor( + OpenFileDescriptor(project, virtualFile, lineNumber, 0), true + ) +} diff --git a/src/main/kotlin/com/cycode/plugin/icons/PluginIcons.kt b/src/main/kotlin/com/cycode/plugin/icons/PluginIcons.kt index cf83d9f..4062be7 100644 --- a/src/main/kotlin/com/cycode/plugin/icons/PluginIcons.kt +++ b/src/main/kotlin/com/cycode/plugin/icons/PluginIcons.kt @@ -8,6 +8,17 @@ import javax.swing.Icon object PluginIcons { val TOOL_WINDOW: Icon = load("/icons/toolWindowIcon.svg") + val SCAN_TYPE_IAC: Icon = load("/icons/scan-type/IaC.png") + val SCAN_TYPE_SAST: Icon = load("/icons/scan-type/SAST.png") + val SCAN_TYPE_SCA: Icon = load("/icons/scan-type/SCA.png") + val SCAN_TYPE_SECRETS: Icon = load("/icons/scan-type/Secrets.png") + + val SEVERITY_CRITICAL: Icon = load("/icons/severity/C.png") + val SEVERITY_HIGH: Icon = load("/icons/severity/H.png") + val SEVERITY_INFO: Icon = load("/icons/severity/I.png") + val SEVERITY_LOW: Icon = load("/icons/severity/L.png") + val SEVERITY_MEDIUM: Icon = load("/icons/severity/M.png") + private fun load(path: String): Icon { return IconLoader.getIcon(path, PluginIcons::class.java) } diff --git a/src/main/kotlin/com/cycode/plugin/intentions/CycodeIgnoreIntentionQuickFix.kt b/src/main/kotlin/com/cycode/plugin/intentions/CycodeIgnoreIntentionQuickFix.kt index 8e13a8f..c252066 100644 --- a/src/main/kotlin/com/cycode/plugin/intentions/CycodeIgnoreIntentionQuickFix.kt +++ b/src/main/kotlin/com/cycode/plugin/intentions/CycodeIgnoreIntentionQuickFix.kt @@ -1,6 +1,7 @@ package com.cycode.plugin.intentions import com.cycode.plugin.cli.CliScanType +import com.cycode.plugin.components.toolWindow.updateToolWindowState import com.cycode.plugin.services.cycode import com.cycode.plugin.services.scanResults import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer @@ -63,6 +64,7 @@ class CycodeIgnoreIntentionQuickFix( } DaemonCodeAnalyzer.getInstance(project).restart() + updateToolWindowState(project) } override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { diff --git a/src/main/kotlin/com/cycode/plugin/services/CliDownloadService.kt b/src/main/kotlin/com/cycode/plugin/services/CliDownloadService.kt index 1b3b7a3..bc4a167 100644 --- a/src/main/kotlin/com/cycode/plugin/services/CliDownloadService.kt +++ b/src/main/kotlin/com/cycode/plugin/services/CliDownloadService.kt @@ -153,7 +153,7 @@ class CliDownloadService { return true } - if (shouldDownloadNewRemoteCli(Consts.DEFAULT_CLI_PATH, isDir=false)) { + if (shouldDownloadNewRemoteCli(Consts.DEFAULT_CLI_PATH, isDir = false)) { return true } @@ -172,7 +172,7 @@ class CliDownloadService { return true } - if (shouldDownloadNewRemoteCli(Consts.PLUGIN_PATH, isDir=true)) { + if (shouldDownloadNewRemoteCli(Consts.PLUGIN_PATH, isDir = true)) { return true } diff --git a/src/main/kotlin/com/cycode/plugin/services/CliService.kt b/src/main/kotlin/com/cycode/plugin/services/CliService.kt index 66083ef..f1ea810 100644 --- a/src/main/kotlin/com/cycode/plugin/services/CliService.kt +++ b/src/main/kotlin/com/cycode/plugin/services/CliService.kt @@ -7,6 +7,7 @@ import com.cycode.plugin.cli.models.AuthResult import com.cycode.plugin.cli.models.VersionResult 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.utils.CycodeNotifier import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer import com.intellij.openapi.components.Service @@ -210,6 +211,7 @@ class CliService(private val project: Project) { // save results and rerun annotators scanResults.setSecretResults(results) DaemonCodeAnalyzer.getInstance(project).restart() + updateToolWindowState(project) } fun scanPathsSca(paths: List, onDemand: Boolean = true, cancelledCallback: TaskCancelledCallback = null) { @@ -228,5 +230,6 @@ class CliService(private val project: Project) { scanResults.setScaResults(results) DaemonCodeAnalyzer.getInstance(project).restart() + updateToolWindowState(project) } } diff --git a/src/main/resources/icons/scan-type/IaC.png b/src/main/resources/icons/scan-type/IaC.png new file mode 100644 index 0000000000000000000000000000000000000000..5855c1db5f1dfd2bec7fd9bc1ae69bda17edb5ed GIT binary patch literal 1127 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVkr05M1pgl1mAh%j*h z6I`{x0%imor0saV%ts)_S>O>_%)r1c48n{Iv*t(uO^eJ7i71Ki^|4CM&(%vz$xlkv ztH>0+>{umUo3Q%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)CuG zfu4bq9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)Btk zRH0j3nOBlnp_^B%3^4>|j!SBBa#3bMNoIbY0?6FNr2NtnTO}osMQ{LdXGvxn!lt}p zsJDO~)CbAv8|oS8!_5Y2wE>A*`4?rT0&NDFZ)a!&R*518wZ}#uWI2*!AU*|)0=;U- zWup%dHajlKxQFb(Kz`xr;uvBf*gEOFpNONtvHkBP72Y&;i&rw~x9rY%)Z2VffU9A)Y=J4D%WEyv^2WSR0>RUp2E-jI+$>a%}y+Rlio9%6!8z zJ+&x#m9^8fouB%$G};8@Si%%Oul~I(&45+?#_qd({*&&9T%6M7q1m5W#%0T&23!jnfBD5_R3{&fjTES_(8w25-xIez>K2oU zLrLd#n;r5E`<3T^+_rm0cIM@3-Otk!m05)gYI4ja?LO~c_NRQpFA1+wMjw{-`@G&d zzMQ(g=ImUfp76>Nk$Gp$zUV5Zc+Ow@MrC8i?wUxR3jE%<&mAqRV;?)z_8ouV;uncFwk7 ela7#7?WgkyhKbLh*2~7Z9YJE%q literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/scan-type/SAST.png b/src/main/resources/icons/scan-type/SAST.png new file mode 100644 index 0000000000000000000000000000000000000000..7592b4a4c58ab9565b46b31bf36f2f847fac7c74 GIT binary patch literal 1068 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVkr05M1pgl1mAh%j*h z6I`{x0%imor0saV%ts)_S>O>_%)r1c48n{Iv*t(uO^eJ7i71Ki^|4CM&(%vz$xlkv ztH>0+>{umUo3Q%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)CuG zfu4bq9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)Btk zRH0j3nOBlnp_^B%3^4>|j!SBBa#3bMNoIbY0?6FNr2NtnTO}osMQ{LdXGvxn!lt}p zsJDO~)CbAv8|oS8!_5Y2wE>A*`4?rT0&NDFZ)a!&R*518wZ}#uWI2*!AU*|)0=;U- zWup%dHajlKxQFb(Kwj(V;uvBfI5pVN@34cw9BXx@h)0|z9q|m0xF<|7vJD6fRQT86 z!uVy%gag7F55zm#)D>8Tj+dWV^Y(~gz=lhz+lzM_?=H`7SMAnw+p*hvhw6@!U$rjJ z1sIQC-5~LJy=SjM@#~G#R2tIOEDpTWXPjeX^nc=<2Wzhv>mOPzBjho2>f|Sh9jm8` z%535_o|c_vw=qmwqQCI6ZGrn!&eY^DA^aite61^z93Cu857PKG_kMeZE$bbX!+zUe z&zt&sHFq)N>&Ub{m;QPPO_1RH{>gUwH^-|5D_u3h+0zb+dIcq%N#?PLe0yUe#}Ym5 z*->}S&vBSg_3xLHhYg#`nPc-UR2Qm-eGmLAeQG|dW9yXvI?dtDIcCNQr#5xRD(7`N z{4KTmP$YJ7nEFL)CdfHy_=a)2efPcTvuk)s8|2yZWzZb~)QFKe6SN z>gn`W^WU~I;*(eVH!suFVMws(iLRN*`;gZ=WGS0Rh3)Z2EG9z#N?vd5UGl&F-2K*& VeP=tOT_1q*fTydU%Q~loCII+PWN82Z literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/scan-type/SCA.png b/src/main/resources/icons/scan-type/SCA.png new file mode 100644 index 0000000000000000000000000000000000000000..9c1536e8a311eec59b5c8d981f6555b7c58c0371 GIT binary patch literal 1220 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVkr05M1pgl1mAh%j*h z6I`{x0%imor0saV%ts)_S>O>_%)r1c48n{Iv*t(uO^eJ7i71Ki^|4CM&(%vz$xlkv ztH>0+>{umUo3Q%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)CuG zfu4bq9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)Btk zRH0j3nOBlnp_^B%3^4>|j!SBBa#3bMNoIbY0?6FNr2NtnTO}osMQ{LdXGvxn!lt}p zsJDO~)CbAv8|oS8!_5Y2wE>A*`4?rT0&NDFZ)a!&R*518wZ}#uWI2*!AU*|)0=;U- zWup%dHajlKxQFZv3{0+`E{-78O-W%DhEGKAq`t*jXIp>v4j-3!(xHpe=-Foju*SSk-lKy>_=Ms7R zd&8P5X#uCdAKfe_xo*SNLvCuxSzOERYly=}LTJ=!<>fU26q z-ac8g&ssBGGP6!yQBEmW-oP9eBl7)^w z;@L@4x2Z|{J^poqLu}1K4QA;ztJc1lc{yXjTD$8iMzt*8E<~nt{XuMj}rkqV#R!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVkr05M1pgl1mAh%j*h z6I`{x0%imor0saV%ts)_S>O>_%)r1c48n{Iv*t(uO^eJ7i71Ki^|4CM&(%vz$xlkv ztH>0+>{umUo3Q%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)CuG zfu4bq9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)Btk zRH0j3nOBlnp_^B%3^4>|j!SBBa#3bMNoIbY0?6FNr2NtnTO}osMQ{LdXGvxn!lt}p zsJDO~)CbAv8|oS8!_5Y2wE>A*`4?rT0&NDFZ)a!&R*518wZ}#uWI2*!AU*|)0=;U- zWup%dHajlKxQFZv3``uJE{-794_@rn||fradFwB_zh9X%gkm~7TcCjayJg@;&1zI_VRp;7o|17=#TF&g*$G-k9dUo6{kE`IK zR836&tk~p`DFsG0Y(+U$3nu+Eep|Za9n1MH*ELNGC$}7ATd&5)??~kQ(0$zK2jIV)TDKk zf&a$DAgvuspS~~`*Da<}s?PkZv^p~CoHhr5mt#ECe zd9tZd_Tw{^*YnaJl$)%!kx6nod9;=FZ0jnq>WYqdotG1vOciSju37tkkV?L1U?Ka@ zWqFiqbHm?{66;@{sk~+F(DeLa?B}ERg;TfPt6XAm55#M>AUX9!N@0KD_6u zgZ&@dkJYc|rtg&(smYV{zR&+*$3=sgm;ZXasa|!-MRE6%??;+T=iPPLd*97UcBcr( zy3M}3&o2A My85}Sb4q9e0LE67g8%>k literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/severity/C.png b/src/main/resources/icons/severity/C.png new file mode 100644 index 0000000000000000000000000000000000000000..9927bfa2a8a6eacc7250231b48d61b67d1609fd5 GIT binary patch literal 1186 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVl)0Ai3H2+h2J5n~a zDsl@zx)^LKtboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?}6yY17;GAESs$iyP zpl6_D$EBd4U{jQmW)z9|8>y;bpKhp88yV>W zRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74+Zoz`RicPN?Xl4ZS&rlwh)=T_j_cbz9yKH+o?CYg8qd@Mo zWvgGUUjMI(;h!Q~gJ`V(q7&M${@YrA$l6^SaxT8|!>?O!GPxY?>a%~^l(?c^B8~g7 zu=1h(%T3-ZW*R6jEqkK(PJnUhz256VOdoWFqrFs<6Dz(wdDh>a(jBE6ob%pce)f!| zqQ_UxnZNsVL$Bn6=8FfS@AzDOCwPCo%FKPHx1%e6)z!qr$nb~={!?7=Z^e)#7o9DVY}&H0A!MFCq0HsN_KiJ?E9`TkPrZ41@y4!%&NxBc1Qn*ujFOC?uW z%-uI_LBfUB;-4AShC2V<`ushU#0we@7*ssJn8SF=#jLW8Z;sP^hO%cW(bAQ<~xJS#wxStbn#niZ3oz*mce$XZ5D9lO`UCU6y`bUv~BKhqA|Rw9b({%6sDFQ}KQd r=Yw}Gw%zo!SE>K~SZ2i^<%xgIRe8?n+ea_`3Cek%u6{1-oD!M<9dfD| literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/severity/H.png b/src/main/resources/icons/severity/H.png new file mode 100644 index 0000000000000000000000000000000000000000..41e4fe89875d52e85d87cdc37431e375c3debe36 GIT binary patch literal 1213 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVl)0Ai3H2+h2J5n~a zDsl@zx)^LKtboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?}6yY17;GAESs$iyP zpl6_D$EBd4U{jQmW)z9|8>y;bpKhp88yV>W zRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74+Zoz`RicPN?Xl4ZS&rlwh)=_LTsUed;HDjY^|toosmEbnqw#-;NDUWz+vL zY}8XKVF`@hRq!ysSBx*~T52#BY>UhFNHrW~umb=fa>ftq>$Ys>3Cyq8}| zK6_@f@AKUE_huV>?M!ekNbH9bWspb;^4CpZhoiC-k3iuXX3}s50kaWi(;1J9FvAR_W({Qj@c%eBK=! zdH>!IJKqD(4jy`Bs}|{f`RTO7Z^N5SJeOH)e;jjW`}}qLf9%+EMt|*^6qgDQ1>5rt z8mIRE-0m0Mwy`(ZF1c|1$)7oM(%FOCECtga&E37TtX0aB_1e-~O_QEfs*3s?uCU0B zdQ!Gy+4*CUVM@C;>IZdxd^&fwcUQyDeXl~jI~Z9UckbR$;>fE`!6T6m`#ik1S0#C_BpB-Fkr8=kBqVpTSE4U*CM? zt@L5hiUrG+I6ko5dsO`(FXxT-g>`Q`zwFMwX(m+oXSVL?P385nd$t#qHP3o+c+uSn z>%UBLc2g<-VU+v5$}jj;{qNG;Gt=X&lITz159N@eBM~Ce9qrDEtYcK6*eBgBX VztllZV7bG<;OXk;vd$@?2>>D0v-$u4 literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/severity/I.png b/src/main/resources/icons/severity/I.png new file mode 100644 index 0000000000000000000000000000000000000000..a16cb973ea27c24f5a90b79eb5978e0f55cd19cf GIT binary patch literal 1213 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVl)0Ai3H2+h2J5n~a zDsl@zx)^LKtboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?}6yY17;GAESs$iyP zpl6_D$EBd4U{jQmW)z9|8>y;bpKhp88yV>W zRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74+Zoz`RicPN?Xl4ZS&rlwh)=$^fPd@<`f*_$kL*4lCrhszC@GcFvAa~&tWWA#2L*>aDY@2*xoW0nz{fTuw_ zOT=B#Prt(6GfpUtd3~{L!ve9(d6&xnJUZ*O_Ii)}xzR<6YV|kIILVVziy3v(DW7!zoSQ&u(c>QOsinr!|Ttg)2qGh zEk|VWtb_?_M}ButJ$r=1#n&L_v$*MjM@%nI9s6f_dfR&bNiJIwY)-jcVM?;x_NIc> zZ%z2qHCJW|YLsp(RyT|LI_3DchVG6_ot@4L9pX&O)Mii4b^B=0F!vklW<}q0&!SJa zJ5NniRCI}dr2Frr0n@_BQ<8mZ-t+ig&0f#xagTY+Kg}6apSm)i(2bio;mMKnCj{*h z7uxg9IPHEYRp62J!FOA}^C*b_m{9KE_#x|p_rBd;w-{>cmRy&#mR_OyG%fSis_^c7 z3%0cuGN*G`mM|CbZ(DUEb!GOQR{6TXpYwwF?De)^_22bUo%gY+;?wJuLBX6p?h^Z- zpWb4%>toLLC;WGJiyf+DvVCH*_SfOo=}p2##k{`XG~ZwNvt2)rYsUWxD*vRf2wxAm S=n|I$%9Nh2elF{r5}E*&52#cC literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/severity/L.png b/src/main/resources/icons/severity/L.png new file mode 100644 index 0000000000000000000000000000000000000000..4778b637300b1606a4a6351d84e18c7d8cc6ed04 GIT binary patch literal 1163 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVl)0Ai3H2+h2J5n~a zDsl@zx)^LKtboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?}6yY17;GAESs$iyP zpl6_D$EBd4U{jQmW)z9|8>y;bpKhp88yV>W zRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74+Zoz`RicPN?Xl4ZS&rlwh)=wuqy^zg^EaK2A38e5R(s;Z|_8S@6njJr9Gf z740A2U2Wct{|nhI1@Cwj$vtU!U!-#zV2GAKcFz!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVl)0Ai3H2+h2J5n~a zDsl@zx)^LKtboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?}6yY17;GAESs$iyP zpl6_D$EBd4U{jQmW)z9|8>y;bpKhp88yV>W zRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74+Zoz`RicPN?Xl4ZS&rlwh)=8uSy#Z(#7rZAmD5`!fI;*TyMl|O zlvWhibNv|i&fXOh7nEpmak)&M(h%fkVj}WvF_+f_!)^KP=DVN2s9_A-wR`5x%KUrh z-Z1`;;PR;SZudC#uReFL{N%4Ek6ym@p65&C?yJ*9C;!gs z#gW_fB%g7AVtpsksO7S0Z>GD5_bG-BtOaE7@v`3w5O7NV-7wP(K*_6K=e&-IH z){80#?`?fPY?xxF1+C=M$?rhV2Go6!*eNnl_)L#j{TRe|2u^ISIIrXCI!#=k4 z9vU*wV)zm{MV;?$oUWvM{FG?N^~%cPlVL%}r`7X+Ec>E#aIMnS)9p^dQ#G2_DmQIc ztbWO1-4R>-()-UBWxs_7mvG9@{yJsB{XIUVeksvai?25-BwO!nYBFHl&A!*4y06vaK`@U9A-Qz_G13Yy1IU;V%IOGR_)o=mG*DK#MJ>a4YOy9zi>Ta p_`z+BoWs@W6GM`@|L5=jB5x(Ma`S=ImS#{!@^tlcS?83{1ORYmfNuZ* literal 0 HcmV?d00001 diff --git a/src/main/resources/messages/CycodeBundle.properties b/src/main/resources/messages/CycodeBundle.properties index 678db0d..a88d9be 100755 --- a/src/main/resources/messages/CycodeBundle.properties +++ b/src/main/resources/messages/CycodeBundle.properties @@ -1,10 +1,14 @@ # general name=Cycode +# detection titles +secretsTitle={0}. {1} +secretsNodeTitle=line {0}: a hardcoded {1} is used +scaTitle={0}@{1} - {2} +scaNodeTitle=line {0}: {1} # code annotator -secretsAnnotationTitle=Cycode: {0}. {1} +annotationTitle=Cycode: {0} secretsAnnotationTooltip=Severity: {0}
{1}: {2}
Rule ID: {3}
In file: {4}
Secret SHA: {5}{6} secretsAnnotationTooltipCompanyGuideline=
Company Guideline: {0} -scaAnnotationTitle=Cycode: {0}@{1} - {2} scaAnnotationTooltip=Severity: {0}
{1}
{2}
Rule ID: {3}{4} scaAnnotationTooltipFirstPatchedVersion=First patched version: {0} scaAnnotationTooltipLockFileNote=

Avoid manual packages upgrades in lock files. Update the {0} file and re-generate the lock file. From f30140cc9bd2cbf2afd714db855b39567a5407c1 Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Tue, 20 Feb 2024 11:52:25 +0100 Subject: [PATCH 2/8] add summary support --- .../components/treeView/TreeCellRenderer.kt | 13 ++- .../components/treeView/TreeView.kt | 12 ++- .../components/treeView/nodes/AbstractNode.kt | 1 + .../treeView/nodes/DetectionNodes.kt | 2 + .../components/treeView/nodes/DummyNode.kt | 2 +- .../components/treeView/nodes/FileNode.kt | 2 +- .../components/treeView/nodes/RootNodes.kt | 81 ++++++++++++------- .../components/treeView/nodes/ScanTypeNode.kt | 2 +- .../messages/CycodeBundle.properties | 8 +- 9 files changed, 83 insertions(+), 40 deletions(-) diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt index 01920a1..ab463ae 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt @@ -2,9 +2,14 @@ package com.cycode.plugin.components.toolWindow.components.scanContentTab.compon import com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes.AbstractNode import com.intellij.ui.ColoredTreeCellRenderer +import com.intellij.ui.JBColor +import com.intellij.ui.SimpleTextAttributes import javax.swing.JTree import javax.swing.tree.DefaultMutableTreeNode +const val NODE_DELIMITER = " " +val SUMMARY_ATTRIBUTES = SimpleTextAttributes(null, JBColor.GRAY, null, SimpleTextAttributes.STYLE_PLAIN) + class TreeCellRenderer : ColoredTreeCellRenderer() { override fun customizeCellRenderer( tree: JTree, @@ -17,11 +22,17 @@ class TreeCellRenderer : ColoredTreeCellRenderer() { ) { if (value !is DefaultMutableTreeNode) return val nodeData = value.userObject as AbstractNode - icon = nodeData.icon + append(nodeData.name) + if (nodeData.summary != null) { + append(NODE_DELIMITER) + append(nodeData.summary!!, SUMMARY_ATTRIBUTES) + } + icon = nodeData.icon isIconOpaque = false isTransparentIconBackground = true + isOpaque = false } } diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt index a5aedef..17db849 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt @@ -1,5 +1,6 @@ package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView +import com.cycode.plugin.CycodeBundle import com.cycode.plugin.cli.CliResult import com.cycode.plugin.cli.CliScanType import com.cycode.plugin.cli.models.scanResult.DetectionBase @@ -24,9 +25,11 @@ import javax.swing.event.TreeSelectionListener import javax.swing.tree.DefaultMutableTreeNode import javax.swing.tree.TreeSelectionModel +const val DIFFERENCE_BETWEEN_SCA_LINE_NUMBERS = 1 class TreeView(val project: Project, defaultRightPane: Component) : JPanel(GridLayout(1, 0)), TreeSelectionListener { private val tree: Tree + private val rootNodes: RootNodes = RootNodes() private val scanResults = scanResults(project) init { @@ -80,7 +83,7 @@ class TreeView(val project: Project, defaultRightPane: Component) : JPanel(GridL private fun openScaDetectionInFile(node: ScaDetectionNode) { val filePath = node.detection.detectionDetails.getFilepath() - val line = node.detection.detectionDetails.lineInFile - 1 + val line = node.detection.detectionDetails.lineInFile - DIFFERENCE_BETWEEN_SCA_LINE_NUMBERS openFileInEditor(project, filePath, line) } @@ -118,11 +121,12 @@ class TreeView(val project: Project, defaultRightPane: Component) : JPanel(GridL for ((filePath, detections) in detectionsByFile) { val fileName = File(filePath).name - val fileNode = createNode(FileNode(fileName)) + val summary = CycodeBundle.message("fileNodeSummary", detections.size) + val fileNode = createNode(FileNode(fileName, summary)) for (detection in detections) { fileNode.add(createNodeCallback(detection)) } - RootNodes.getScanTypeNode(scanType).add(fileNode) + rootNodes.getScanTypeNode(scanType).add(fileNode) } } @@ -165,7 +169,7 @@ class TreeView(val project: Project, defaultRightPane: Component) : JPanel(GridL } private fun createNodes(top: DefaultMutableTreeNode) { - RootNodes.createNodes(top) + rootNodes.createNodes(top) createSecretDetectionNodes() createScaDetectionNodes() } diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt index 33e20b8..b78f153 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt @@ -5,6 +5,7 @@ import javax.swing.Icon abstract class AbstractNode { abstract var name: String + abstract var summary: String? abstract var icon: Icon? override fun toString(): String { diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt index 41ee641..405c5b1 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt @@ -8,10 +8,12 @@ data class SecretDetectionNode( override var name: String, override var icon: Icon?, val detection: SecretDetection, + override var summary: String? = null, ) : AbstractNode() data class ScaDetectionNode( override var name: String, override var icon: Icon?, val detection: ScaDetection, + override var summary: String? = null, ) : AbstractNode() diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt index 83e2b46..2636a02 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt @@ -5,6 +5,6 @@ import javax.swing.Icon data class DummyNode( override var name: String = CycodeBundle.message("name"), + override var summary: String? = null, override var icon: Icon? = null, - val summary: String? = null ) : AbstractNode() diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt index 4a99082..eb2c972 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt @@ -4,6 +4,6 @@ import javax.swing.Icon data class FileNode( override var name: String, + override var summary: String?, override var icon: Icon? = null, - val summary: String? = null ) : AbstractNode() diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt index e738258..46dfe75 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt @@ -6,45 +6,64 @@ import com.cycode.plugin.icons.PluginIcons import javax.swing.tree.DefaultMutableTreeNode class RootNodes { - companion object { - private val SecretsNode = createNode( - ScanTypeNode(CycodeBundle.message("secretDisplayName"), PluginIcons.SCAN_TYPE_SECRETS) + private val secretNode = createNode( + ScanTypeNode( + CycodeBundle.message("secretDisplayName"), + CycodeBundle.message("secretNodeSummary"), + PluginIcons.SCAN_TYPE_SECRETS ) + ) - private val SastNode = createNode( - ScanTypeNode(CycodeBundle.message("sastDisplayName"), PluginIcons.SCAN_TYPE_SAST) + private val scaNode = createNode( + ScanTypeNode( + CycodeBundle.message("scaDisplayName"), + CycodeBundle.message("scaNodeSummary"), + PluginIcons.SCAN_TYPE_SCA ) + ) - private val ScaNode = createNode( - ScanTypeNode(CycodeBundle.message("scaDisplayName"), PluginIcons.SCAN_TYPE_SCA) + private val sastNode = createNode( + ScanTypeNode( + CycodeBundle.message("sastDisplayName"), + CycodeBundle.message("sastNodeSummary"), + PluginIcons.SCAN_TYPE_SAST ) + ) - private val IacNode = createNode( - ScanTypeNode(CycodeBundle.message("iacDisplayName"), PluginIcons.SCAN_TYPE_IAC) + private val iacNode = createNode( + ScanTypeNode( + CycodeBundle.message("iacDisplayName"), + CycodeBundle.message("iacNodeSummary"), + PluginIcons.SCAN_TYPE_IAC ) + ) - private val scanTypeToNode = mapOf( - CliScanType.Secret to SecretsNode, - CliScanType.Sast to SastNode, - CliScanType.Sca to ScaNode, - CliScanType.Iac to IacNode - ) + private val scanTypeToNode = mapOf( + CliScanType.Secret to secretNode, + CliScanType.Sast to sastNode, + CliScanType.Sca to scaNode, + CliScanType.Iac to iacNode + ) + + fun setNodeSummary(scanType: CliScanType, summary: String) { + val node = getScanTypeNode(scanType) + (node.userObject as ScanTypeNode).summary = summary + } + + fun createNodes(top: DefaultMutableTreeNode) { + secretNode.removeAllChildren() + scaNode.removeAllChildren() + sastNode.removeAllChildren() + iacNode.removeAllChildren() + + // the order of adding nodes is important + top.add(secretNode) + top.add(scaNode) + top.add(sastNode) + top.add(iacNode) + } - fun createNodes(top: DefaultMutableTreeNode) { - SecretsNode.removeAllChildren() - ScaNode.removeAllChildren() - SastNode.removeAllChildren() - IacNode.removeAllChildren() - - // the order of adding nodes is important - top.add(SecretsNode) - top.add(ScaNode) - top.add(SastNode) - top.add(IacNode) - } - - fun getScanTypeNode(scanType: CliScanType): DefaultMutableTreeNode { - return scanTypeToNode[scanType] ?: throw IllegalArgumentException("Unknown scan type: $scanType") - } + fun getScanTypeNode(scanType: CliScanType): DefaultMutableTreeNode { + return scanTypeToNode[scanType] ?: throw IllegalArgumentException("Unknown scan type: $scanType") } } diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt index 24a4699..e7e5ca2 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt @@ -4,6 +4,6 @@ import javax.swing.Icon data class ScanTypeNode( override var name: String, + override var summary: String?, override var icon: Icon?, - val summary: String? = null ) : AbstractNode() diff --git a/src/main/resources/messages/CycodeBundle.properties b/src/main/resources/messages/CycodeBundle.properties index a88d9be..3bc047e 100755 --- a/src/main/resources/messages/CycodeBundle.properties +++ b/src/main/resources/messages/CycodeBundle.properties @@ -56,6 +56,12 @@ settingsCliAppUrlLabel=APP URL: settingsCliAdditionalParamsLabel=Additional parameters: # scan types display names secretDisplayName=Hardcoded Secrets -scaDisplayName=Open Source Threat (beta) +scaDisplayName=Open Source Threat sastDisplayName=Code Security iacDisplayName=Infrastructure As Code +# tree view nodes summaries +fileNodeSummary={0} vulnerabilities +secretNodeSummary= +scaNodeSummary=(beta) +sastNodeSummary=(coming soon) +iacNodeSummary=(coming soon) From 42b46646cfddafc0b63ac0a56a47df296f33368e Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Tue, 20 Feb 2024 13:47:01 +0100 Subject: [PATCH 3/8] fix tool window content management --- .../components/toolWindow/CycodeContentTab.kt | 14 +++++ .../toolWindow/CycodeToolWindowFactory.kt | 63 ++++++++++--------- .../scanContentTab/ScanContentTab.kt | 5 +- .../treeView/TreeCellRenderer.kt | 4 +- .../components => }/treeView/TreeView.kt | 41 ++++++++---- .../treeView/nodes/AbstractNode.kt | 2 +- .../treeView/nodes/DetectionNodes.kt | 2 +- .../treeView/nodes/DummyNode.kt | 2 +- .../treeView/nodes/FileNode.kt | 2 +- .../treeView/nodes/RootNodes.kt | 2 +- .../treeView/nodes/ScanTypeNode.kt | 2 +- .../components => }/treeView/nodes/utils.kt | 2 +- .../components => }/treeView/utils.kt | 2 +- .../cycode/plugin/services/CycodeService.kt | 8 ++- 14 files changed, 97 insertions(+), 54 deletions(-) create mode 100644 src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeContentTab.kt rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/TreeCellRenderer.kt (83%) rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/TreeView.kt (85%) rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/nodes/AbstractNode.kt (68%) rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/nodes/DetectionNodes.kt (84%) rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/nodes/DummyNode.kt (71%) rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/nodes/FileNode.kt (62%) rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/nodes/RootNodes.kt (95%) rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/nodes/ScanTypeNode.kt (62%) rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/nodes/utils.kt (60%) rename src/main/kotlin/com/cycode/plugin/components/toolWindow/components/{scanContentTab/components => }/treeView/utils.kt (93%) diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeContentTab.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeContentTab.kt new file mode 100644 index 0000000..5a28994 --- /dev/null +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeContentTab.kt @@ -0,0 +1,14 @@ +package com.cycode.plugin.components.toolWindow + +import com.cycode.plugin.components.toolWindow.components.treeView.TreeView +import com.intellij.openapi.project.Project +import javax.swing.JPanel + +class CycodeContentTab(project: Project) { + private val treeView = TreeView(project) + + fun updateContent(rightPanel: JPanel): JPanel { + treeView.refreshTree() + return treeView.replaceRightPanel(rightPanel) + } +} diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt index 218ea8b..74e360c 100755 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt @@ -1,24 +1,21 @@ package com.cycode.plugin.components.toolWindow -import com.cycode.plugin.CycodeBundle -import com.cycode.plugin.components.Component import com.cycode.plugin.components.toolWindow.components.authContentTab.AuthContentTab import com.cycode.plugin.components.toolWindow.components.loadingContentTab.LoadingContentTab import com.cycode.plugin.components.toolWindow.components.scanContentTab.ScanContentTab import com.cycode.plugin.icons.PluginIcons -import com.cycode.plugin.services.CycodeService import com.cycode.plugin.services.cycode import com.cycode.plugin.services.pluginState import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.WriteAction import com.intellij.openapi.project.DumbAware import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Disposer import com.intellij.openapi.wm.ToolWindow import com.intellij.openapi.wm.ToolWindowFactory -import com.intellij.openapi.wm.ToolWindowManager import com.intellij.ui.content.Content import com.intellij.ui.content.ContentFactory - +import javax.swing.JPanel class CycodeToolWindowFactory : DumbAware, ToolWindowFactory { @@ -27,48 +24,58 @@ class CycodeToolWindowFactory : DumbAware, ToolWindowFactory { } override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { - createLoadingTabOnly(project) + val service = cycode(project) + + val contentTab = CycodeContentTab(project) + TabManager.addTab(project, contentTab) + + val defaultRightPanel = LoadingContentTab().getContent(service) + val toolWindowContent = createToolWindowContent(contentTab.updateContent(defaultRightPanel)) + toolWindow.contentManager.addContent(toolWindowContent) + + Disposer.register(service, toolWindowContent) } override fun shouldBeAvailable(project: Project) = true -} -private fun getCycodeToolWindow(project: Project): ToolWindow? { - return ToolWindowManager.getInstance(project).getToolWindow(CycodeBundle.message("toolWindowId")) -} + object TabManager { + private val toolWindowsTabs = mutableMapOf() -private fun replaceToolWindowContent(project: Project, content: Content) { - val window = getCycodeToolWindow(project) ?: return - window.contentManager.removeAllContents(true) - window.contentManager.addContent(content) -} + fun addTab(project: Project, tab: CycodeContentTab) { + toolWindowsTabs[project] = tab + } -private fun createToolWindowContent(project: Project, component: Component): Content { - return ContentFactory.SERVICE.getInstance() - .createContent(component.getContent(cycode(project)), null, false) -} + fun getTab(project: Project): CycodeContentTab? { + return toolWindowsTabs[project] + } -private fun createLoadingTabOnly(project: Project) { - replaceToolWindowContent(project, createToolWindowContent(project, LoadingContentTab())) -} + fun removeTab(project: Project) { + toolWindowsTabs.remove(project) + } + } +} -private fun createAuthTabOnly(project: Project) { - replaceToolWindowContent(project, createToolWindowContent(project, AuthContentTab())) +private fun replaceToolWindowRightPanel(project: Project, panel: JPanel) { + val contentTab = CycodeToolWindowFactory.TabManager.getTab(project) ?: return + contentTab.updateContent(panel) } -private fun createScanTabOnly(project: Project) { - replaceToolWindowContent(project, createToolWindowContent(project, ScanContentTab())) +private fun createToolWindowContent(component: JPanel): Content { + return ContentFactory.SERVICE.getInstance().createContent(component, null, false) } + fun updateToolWindowState(project: Project) { val pluginState = pluginState() + val service = cycode(project) + ApplicationManager.getApplication().invokeLater { WriteAction.run { if (pluginState.cliAuthed) { - createScanTabOnly(project) + replaceToolWindowRightPanel(project, ScanContentTab().getContent(service)) } else { - createAuthTabOnly(project) + replaceToolWindowRightPanel(project, AuthContentTab().getContent(service)) } } } diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/ScanContentTab.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/ScanContentTab.kt index 441bea1..fba9b35 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/ScanContentTab.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/ScanContentTab.kt @@ -3,7 +3,6 @@ package com.cycode.plugin.components.toolWindow.components.scanContentTab import com.cycode.plugin.CycodeBundle import com.cycode.plugin.components.Component import com.cycode.plugin.components.common.createClickableLabel -import com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.TreeView import com.cycode.plugin.services.CycodeService import com.intellij.util.ui.JBUI import java.awt.GridBagConstraints @@ -13,7 +12,7 @@ import javax.swing.JPanel class ScanContentTab : Component() { override fun getContent(service: CycodeService): JPanel { - val rightPanel = JPanel().apply { + return JPanel().apply { layout = GridBagLayout() add(add(JPanel().apply { add(createClickableLabel(CycodeBundle.message("scanTabTitleLabel"))) @@ -62,7 +61,5 @@ class ScanContentTab : Component() { anchor = GridBagConstraints.NORTHWEST }) } - - return TreeView(service.project, rightPanel) } } diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeCellRenderer.kt similarity index 83% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeCellRenderer.kt index ab463ae..b9df885 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeCellRenderer.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeCellRenderer.kt @@ -1,6 +1,6 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView +package com.cycode.plugin.components.toolWindow.components.treeView -import com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes.AbstractNode +import com.cycode.plugin.components.toolWindow.components.treeView.nodes.AbstractNode import com.intellij.ui.ColoredTreeCellRenderer import com.intellij.ui.JBColor import com.intellij.ui.SimpleTextAttributes diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt similarity index 85% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt index 17db849..fb94787 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/TreeView.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt @@ -1,4 +1,4 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView +package com.cycode.plugin.components.toolWindow.components.treeView import com.cycode.plugin.CycodeBundle import com.cycode.plugin.cli.CliResult @@ -7,7 +7,7 @@ import com.cycode.plugin.cli.models.scanResult.DetectionBase import com.cycode.plugin.cli.models.scanResult.ScanResultBase import com.cycode.plugin.cli.models.scanResult.sca.ScaDetection import com.cycode.plugin.cli.models.scanResult.secret.SecretDetection -import com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes.* +import com.cycode.plugin.components.toolWindow.components.treeView.nodes.* import com.cycode.plugin.icons.PluginIcons import com.cycode.plugin.services.scanResults import com.intellij.openapi.project.Project @@ -27,16 +27,23 @@ import javax.swing.tree.TreeSelectionModel const val DIFFERENCE_BETWEEN_SCA_LINE_NUMBERS = 1 -class TreeView(val project: Project, defaultRightPane: Component) : JPanel(GridLayout(1, 0)), TreeSelectionListener { +class TreeView( + val project: Project, defaultRightPane: Component? = null +) : JPanel(GridLayout(1, 0)), TreeSelectionListener { private val tree: Tree + + // dummyRootNode is a workaround to allow us to hide the root node of the tree + private val dummyRootNode = createNode(DummyNode()) private val rootNodes: RootNodes = RootNodes() + + private val splitPane: JSplitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT) + private val scanResults = scanResults(project) init { - val top = createNode(DummyNode()) - createNodes(top) + createNodes(dummyRootNode) - tree = Tree(top) + tree = Tree(dummyRootNode) tree.setRootVisible(false) tree.setCellRenderer(TreeCellRenderer()) @@ -45,17 +52,17 @@ class TreeView(val project: Project, defaultRightPane: Component) : JPanel(GridL val treeView = JBScrollPane(tree) - val splitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT) flattenJSplitPane(splitPane) - splitPane.leftComponent = treeView - splitPane.rightComponent = defaultRightPane + splitPane.resizeWeight = 0.5 val minimumSize = Dimension(400, 100) - defaultRightPane.minimumSize = minimumSize treeView.minimumSize = minimumSize - splitPane.resizeWeight = 0.5 + if (defaultRightPane != null) { + splitPane.rightComponent = defaultRightPane + defaultRightPane.minimumSize = minimumSize + } add(splitPane) } @@ -168,6 +175,18 @@ class TreeView(val project: Project, defaultRightPane: Component) : JPanel(GridL createDetectionNodes(CliScanType.Sca, scaDetections.result, ::createScaDetectionNode) } + fun replaceRightPanel(newRightPanel: Component): TreeView { + splitPane.rightComponent = newRightPanel + return this + } + + fun refreshTree() { + // TODO(MarshalX): is possible to optimize this to only update the nodes that have changed + dummyRootNode.removeAllChildren() + createNodes(dummyRootNode) + tree.updateUI() + } + private fun createNodes(top: DefaultMutableTreeNode) { rootNodes.createNodes(top) createSecretDetectionNodes() diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/AbstractNode.kt similarity index 68% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/AbstractNode.kt index b78f153..79bbfdd 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/AbstractNode.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/AbstractNode.kt @@ -1,4 +1,4 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes +package com.cycode.plugin.components.toolWindow.components.treeView.nodes import javax.swing.Icon diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/DetectionNodes.kt similarity index 84% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/DetectionNodes.kt index 405c5b1..61d5707 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DetectionNodes.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/DetectionNodes.kt @@ -1,4 +1,4 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes +package com.cycode.plugin.components.toolWindow.components.treeView.nodes import com.cycode.plugin.cli.models.scanResult.sca.ScaDetection import com.cycode.plugin.cli.models.scanResult.secret.SecretDetection diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/DummyNode.kt similarity index 71% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/DummyNode.kt index 2636a02..b8be73c 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/DummyNode.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/DummyNode.kt @@ -1,4 +1,4 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes +package com.cycode.plugin.components.toolWindow.components.treeView.nodes import com.cycode.plugin.CycodeBundle import javax.swing.Icon diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/FileNode.kt similarity index 62% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/FileNode.kt index eb2c972..404b474 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/FileNode.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/FileNode.kt @@ -1,4 +1,4 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes +package com.cycode.plugin.components.toolWindow.components.treeView.nodes import javax.swing.Icon diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/RootNodes.kt similarity index 95% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/RootNodes.kt index 46dfe75..e94fa6f 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/RootNodes.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/RootNodes.kt @@ -1,4 +1,4 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes +package com.cycode.plugin.components.toolWindow.components.treeView.nodes import com.cycode.plugin.CycodeBundle import com.cycode.plugin.cli.CliScanType diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/ScanTypeNode.kt similarity index 62% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/ScanTypeNode.kt index e7e5ca2..7a6f84a 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/ScanTypeNode.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/ScanTypeNode.kt @@ -1,4 +1,4 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes +package com.cycode.plugin.components.toolWindow.components.treeView.nodes import javax.swing.Icon diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/utils.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/utils.kt similarity index 60% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/utils.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/utils.kt index 0d39f4b..8fc2b1c 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/nodes/utils.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/nodes/utils.kt @@ -1,4 +1,4 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView.nodes +package com.cycode.plugin.components.toolWindow.components.treeView.nodes import javax.swing.tree.DefaultMutableTreeNode diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/utils.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/utils.kt similarity index 93% rename from src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/utils.kt rename to src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/utils.kt index b64f861..6c8a336 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/scanContentTab/components/treeView/utils.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/utils.kt @@ -1,4 +1,4 @@ -package com.cycode.plugin.components.toolWindow.components.scanContentTab.components.treeView +package com.cycode.plugin.components.toolWindow.components.treeView import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.OpenFileDescriptor diff --git a/src/main/kotlin/com/cycode/plugin/services/CycodeService.kt b/src/main/kotlin/com/cycode/plugin/services/CycodeService.kt index bde8235..e63d6e9 100755 --- a/src/main/kotlin/com/cycode/plugin/services/CycodeService.kt +++ b/src/main/kotlin/com/cycode/plugin/services/CycodeService.kt @@ -1,8 +1,10 @@ package com.cycode.plugin.services import com.cycode.plugin.CycodeBundle +import com.cycode.plugin.components.toolWindow.CycodeToolWindowFactory import com.cycode.plugin.components.toolWindow.updateToolWindowState import com.cycode.plugin.utils.CycodeNotifier +import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.progress.ProgressIndicator @@ -12,7 +14,7 @@ import com.intellij.psi.PsiDocumentManager @Service(Service.Level.PROJECT) -class CycodeService(val project: Project) { +class CycodeService(val project: Project) : Disposable { private val cliService = cli(project) private val cliDownloadService = cliDownload() @@ -108,4 +110,8 @@ class CycodeService(val project: Project) { startPathScaScan(projectRoot) } + + override fun dispose() { + CycodeToolWindowFactory.TabManager.removeTab(project) + } } From f155c56190fa29948d61672a40b8d847e44f08f5 Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Tue, 20 Feb 2024 14:01:12 +0100 Subject: [PATCH 4/8] fix tool window sync after login --- .../components/toolWindow/CycodeToolWindowFactory.kt | 12 ++++++++++++ .../com/cycode/plugin/services/CycodeService.kt | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt index 74e360c..b6979cf 100755 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt @@ -10,6 +10,7 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.WriteAction import com.intellij.openapi.project.DumbAware import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.util.Disposer import com.intellij.openapi.wm.ToolWindow import com.intellij.openapi.wm.ToolWindowFactory @@ -65,6 +66,17 @@ private fun createToolWindowContent(component: JPanel): Content { return ContentFactory.SERVICE.getInstance().createContent(component, null, false) } +fun updateToolWindowStateForAllProjects() { + // we are using this method to sync the state of the tool window for all open projects + // for example, after changing the auth state + ApplicationManager.getApplication().runReadAction { + val projects = ProjectManager.getInstance().openProjects + projects.forEach { project -> + updateToolWindowState(project) + } + } +} + fun updateToolWindowState(project: Project) { val pluginState = pluginState() diff --git a/src/main/kotlin/com/cycode/plugin/services/CycodeService.kt b/src/main/kotlin/com/cycode/plugin/services/CycodeService.kt index e63d6e9..5da78c2 100755 --- a/src/main/kotlin/com/cycode/plugin/services/CycodeService.kt +++ b/src/main/kotlin/com/cycode/plugin/services/CycodeService.kt @@ -3,6 +3,7 @@ package com.cycode.plugin.services import com.cycode.plugin.CycodeBundle import com.cycode.plugin.components.toolWindow.CycodeToolWindowFactory import com.cycode.plugin.components.toolWindow.updateToolWindowState +import com.cycode.plugin.components.toolWindow.updateToolWindowStateForAllProjects import com.cycode.plugin.utils.CycodeNotifier import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service @@ -46,7 +47,7 @@ class CycodeService(val project: Project) : Disposable { val successLogin = cliService.doAuth { indicator.isCanceled } pluginState.cliAuthed = successLogin - updateToolWindowState(project) + updateToolWindowStateForAllProjects() } } }.queue() From 6c52afb99ab2f412b0f8ddc9cbcef3e7937b0524 Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Tue, 20 Feb 2024 15:26:01 +0100 Subject: [PATCH 5/8] fix ui glitch --- .../components/treeView/TreeView.kt | 29 ++++++++++--------- .../toolWindow/components/treeView/utils.kt | 24 --------------- 2 files changed, 16 insertions(+), 37 deletions(-) diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt index fb94787..658018a 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt @@ -11,15 +11,17 @@ import com.cycode.plugin.components.toolWindow.components.treeView.nodes.* import com.cycode.plugin.icons.PluginIcons import com.cycode.plugin.services.scanResults import com.intellij.openapi.project.Project +import com.intellij.ui.JBColor +import com.intellij.ui.JBSplitter +import com.intellij.ui.SideBorder import com.intellij.ui.components.JBScrollPane import com.intellij.ui.treeStructure.Tree -import java.awt.Component import java.awt.Dimension import java.awt.GridLayout import java.io.File import javax.swing.Icon +import javax.swing.JComponent import javax.swing.JPanel -import javax.swing.JSplitPane import javax.swing.event.TreeSelectionEvent import javax.swing.event.TreeSelectionListener import javax.swing.tree.DefaultMutableTreeNode @@ -28,7 +30,7 @@ import javax.swing.tree.TreeSelectionModel const val DIFFERENCE_BETWEEN_SCA_LINE_NUMBERS = 1 class TreeView( - val project: Project, defaultRightPane: Component? = null + val project: Project, defaultRightPane: JComponent? = null ) : JPanel(GridLayout(1, 0)), TreeSelectionListener { private val tree: Tree @@ -36,7 +38,7 @@ class TreeView( private val dummyRootNode = createNode(DummyNode()) private val rootNodes: RootNodes = RootNodes() - private val splitPane: JSplitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT) + private val splitPane: JBSplitter = JBSplitter() private val scanResults = scanResults(project) @@ -50,17 +52,18 @@ class TreeView( tree.selectionModel.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION tree.addTreeSelectionListener(this) // we want to listen for when the user selects a node - val treeView = JBScrollPane(tree) - - flattenJSplitPane(splitPane) - splitPane.leftComponent = treeView - splitPane.resizeWeight = 0.5 - val minimumSize = Dimension(400, 100) + + val treeView = JBScrollPane(tree) + treeView.border = SideBorder(JBColor.GRAY, SideBorder.RIGHT) treeView.minimumSize = minimumSize + splitPane.firstComponent = treeView + splitPane.isShowDividerControls = true + splitPane.isShowDividerIcon = true + if (defaultRightPane != null) { - splitPane.rightComponent = defaultRightPane + splitPane.secondComponent = defaultRightPane defaultRightPane.minimumSize = minimumSize } @@ -175,8 +178,8 @@ class TreeView( createDetectionNodes(CliScanType.Sca, scaDetections.result, ::createScaDetectionNode) } - fun replaceRightPanel(newRightPanel: Component): TreeView { - splitPane.rightComponent = newRightPanel + fun replaceRightPanel(newRightPanel: JComponent): TreeView { + splitPane.secondComponent = newRightPanel return this } diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/utils.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/utils.kt index 6c8a336..f334b4a 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/utils.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/utils.kt @@ -5,31 +5,7 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.LocalFileSystem import java.io.File -import javax.swing.BorderFactory -import javax.swing.JSplitPane -import javax.swing.border.Border -import javax.swing.plaf.basic.BasicSplitPaneDivider -import javax.swing.plaf.basic.BasicSplitPaneUI -/** - * Makes a split pane invisible. Only contained components are shown. - * - * Ref: https://stackoverflow.com/a/12799814/8032027 - * - * @param splitPane - */ -fun flattenJSplitPane(splitPane: JSplitPane) { - splitPane.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)) - val flatDividerSplitPaneUI: BasicSplitPaneUI = object : BasicSplitPaneUI() { - override fun createDefaultDivider(): BasicSplitPaneDivider { - return object : BasicSplitPaneDivider(this) { - override fun setBorder(b: Border?) {} - } - } - } - splitPane.setUI(flatDividerSplitPaneUI) - splitPane.setBorder(null) -} fun openFileInEditor(project: Project, filePath: String, lineNumber: Int) { val file = File(filePath) From 15d88a3d1f86ba0b9d8826209d790168b232ed3c Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Tue, 20 Feb 2024 15:31:49 +0100 Subject: [PATCH 6/8] use cycode tab instead of problems in notification about detections --- src/main/kotlin/com/cycode/plugin/utils/CycodeNotifier.kt | 6 +----- src/main/resources/messages/CycodeBundle.properties | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/com/cycode/plugin/utils/CycodeNotifier.kt b/src/main/kotlin/com/cycode/plugin/utils/CycodeNotifier.kt index fa3f1c5..34031bd 100644 --- a/src/main/kotlin/com/cycode/plugin/utils/CycodeNotifier.kt +++ b/src/main/kotlin/com/cycode/plugin/utils/CycodeNotifier.kt @@ -14,13 +14,9 @@ class OpenProblemsTabAction : AnAction(CycodeBundle.message("openProblemsTabActi override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return val toolWindowManager = ToolWindowManager.getInstance(project) - val toolWindow = toolWindowManager.getToolWindow(PROBLEMS_TOOL_WINDOW_ID) + val toolWindow = toolWindowManager.getToolWindow(CycodeBundle.message("toolWindowId")) toolWindow?.activate(null) } - - companion object { - const val PROBLEMS_TOOL_WINDOW_ID = "Problems View" - } } diff --git a/src/main/resources/messages/CycodeBundle.properties b/src/main/resources/messages/CycodeBundle.properties index 3bc047e..8ab1f32 100755 --- a/src/main/resources/messages/CycodeBundle.properties +++ b/src/main/resources/messages/CycodeBundle.properties @@ -21,9 +21,9 @@ missingCStandardLibraryErrorNotification=Plugin requires C standard library (lib unknownErrorNotification=Unknown error occurred. Please try again noOpenFileErrorNotification=Cycode scans the file that is currently opened. Please open a file and try again noProjectRootErrorNotification=Cycode scans the project that is currently opened. Please open a project and try again -scanFileResultNotification=Cycode has detected {0} {1} issues in your file. Check out your "Problems" tab to analyze. +scanFileResultNotification=Cycode has detected {0} {1} issues in your file. Check out your "Cycode" tab to analyze. scanFileNoResultNotification=No {0} issues were found. -openProblemsTabAction=Open "Problems" tab +openProblemsTabAction=Open "Cycode" tab # tool window toolWindowId=Cycode (beta) howToUseLabel=To learn more about how to use Cycode in the IDE by JetBrains, please visit our docs. From c9e9b5df7d276e4c304870d068bff8908717ca9e Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Tue, 20 Feb 2024 15:50:01 +0100 Subject: [PATCH 7/8] fix tool window content depending on state --- .../toolWindow/CycodeToolWindowFactory.kt | 28 ++++++++++++------- .../services/CycodePersistentStateService.kt | 4 +++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt index b6979cf..dfc841c 100755 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/CycodeToolWindowFactory.kt @@ -30,8 +30,8 @@ class CycodeToolWindowFactory : DumbAware, ToolWindowFactory { val contentTab = CycodeContentTab(project) TabManager.addTab(project, contentTab) - val defaultRightPanel = LoadingContentTab().getContent(service) - val toolWindowContent = createToolWindowContent(contentTab.updateContent(defaultRightPanel)) + val initRightPanel = getRightPanelDependingOnState(project) + val toolWindowContent = createToolWindowContent(contentTab.updateContent(initRightPanel)) toolWindow.contentManager.addContent(toolWindowContent) Disposer.register(service, toolWindowContent) @@ -66,6 +66,21 @@ private fun createToolWindowContent(component: JPanel): Content { return ContentFactory.SERVICE.getInstance().createContent(component, null, false) } +private fun getRightPanelDependingOnState(project: Project): JPanel { + val service = cycode(project) + val pluginState = pluginState() + + if (!pluginState.cliInstalled) { + return LoadingContentTab().getContent(service) + } + + return if (pluginState.cliAuthed) { + ScanContentTab().getContent(service) + } else { + AuthContentTab().getContent(service) + } +} + fun updateToolWindowStateForAllProjects() { // we are using this method to sync the state of the tool window for all open projects // for example, after changing the auth state @@ -79,16 +94,9 @@ fun updateToolWindowStateForAllProjects() { fun updateToolWindowState(project: Project) { - val pluginState = pluginState() - val service = cycode(project) - ApplicationManager.getApplication().invokeLater { WriteAction.run { - if (pluginState.cliAuthed) { - replaceToolWindowRightPanel(project, ScanContentTab().getContent(service)) - } else { - replaceToolWindowRightPanel(project, AuthContentTab().getContent(service)) - } + replaceToolWindowRightPanel(project, getRightPanelDependingOnState(project)) } } } diff --git a/src/main/kotlin/com/cycode/plugin/services/CycodePersistentStateService.kt b/src/main/kotlin/com/cycode/plugin/services/CycodePersistentStateService.kt index b2c9ab4..a1cf109 100644 --- a/src/main/kotlin/com/cycode/plugin/services/CycodePersistentStateService.kt +++ b/src/main/kotlin/com/cycode/plugin/services/CycodePersistentStateService.kt @@ -31,5 +31,9 @@ class CycodePersistentStateService : PersistentStateComponent Date: Wed, 21 Feb 2024 12:42:45 +0100 Subject: [PATCH 8/8] CM-32696 - Add summary of detections in tree view root nodes --- README.md | 2 +- .../toolWindow/components/treeView/TreeView.kt | 11 +++++++++++ src/main/resources/META-INF/plugin.xml | 4 ++-- src/main/resources/messages/CycodeBundle.properties | 6 +++--- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0ef240e..747e537 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Cycode IntelliJ Platform Plugin (beta) +# Cycode IntelliJ Platform Plugin diff --git a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt index 658018a..5ca912a 100644 --- a/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt +++ b/src/main/kotlin/com/cycode/plugin/components/toolWindow/components/treeView/TreeView.kt @@ -121,6 +121,13 @@ class TreeView( } } + private fun getDetectionSummary(sortedDetections: List): String { + // detections must be sorted by severity + return sortedDetections.groupBy { it.severity } + .map { (severity, detections) -> "$severity - ${detections.size}" } + .joinToString(" | ") + } + private fun createDetectionNodes( scanType: CliScanType, scanResults: ScanResultBase, @@ -129,13 +136,17 @@ class TreeView( val sortedDetections = scanResults.detections.sortedByDescending { getSeverityWeight(it.severity) } val detectionsByFile = sortedDetections.groupBy { it.detectionDetails.getFilepath() } + rootNodes.setNodeSummary(scanType, getDetectionSummary(sortedDetections)) + for ((filePath, detections) in detectionsByFile) { val fileName = File(filePath).name val summary = CycodeBundle.message("fileNodeSummary", detections.size) + val fileNode = createNode(FileNode(fileName, summary)) for (detection in detections) { fileNode.add(createNodeCallback(detection)) } + rootNodes.getScanTypeNode(scanType).add(fileNode) } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index e213d29..39c842b 100755 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -11,10 +11,10 @@ - + displayName="Cycode"/> diff --git a/src/main/resources/messages/CycodeBundle.properties b/src/main/resources/messages/CycodeBundle.properties index 8ab1f32..932fcd4 100755 --- a/src/main/resources/messages/CycodeBundle.properties +++ b/src/main/resources/messages/CycodeBundle.properties @@ -25,7 +25,7 @@ scanFileResultNotification=Cycode has detected {0} {1} issues in your file. Chec scanFileNoResultNotification=No {0} issues were found. openProblemsTabAction=Open "Cycode" tab # tool window -toolWindowId=Cycode (beta) +toolWindowId=Cycode howToUseLabel=To learn more about how to use Cycode in the IDE by JetBrains, please visit our docs. # auth content tab authBtn=Authenticate @@ -56,12 +56,12 @@ settingsCliAppUrlLabel=APP URL: settingsCliAdditionalParamsLabel=Additional parameters: # scan types display names secretDisplayName=Hardcoded Secrets -scaDisplayName=Open Source Threat +scaDisplayName=Open Source Threat (beta) sastDisplayName=Code Security iacDisplayName=Infrastructure As Code # tree view nodes summaries fileNodeSummary={0} vulnerabilities secretNodeSummary= -scaNodeSummary=(beta) +scaNodeSummary= sastNodeSummary=(coming soon) iacNodeSummary=(coming soon)