Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JetBrains Plugin | Implement ASCA Engine (AST-69534) #284

Merged
merged 40 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
72b69cc
add asca checkbox and description
BenAlvo1 Oct 10, 2024
f1e173b
update asca description and made gap in the botton between additional…
BenAlvo1 Oct 10, 2024
60783c3
revert unrelated changes
BenAlvo1 Oct 10, 2024
6cc329a
add botton gap
BenAlvo1 Oct 10, 2024
4f106e7
added ASCA wrapper integration and colored notification in setting
BenAlvo1 Oct 10, 2024
2a76f3c
implement editor listener
BenAlvo1 Oct 10, 2024
988043b
implement AscaService.java
BenAlvo1 Oct 10, 2024
4d64688
Merge branch 'main' into feature/benalvo/asca-impl
AlvoBen Oct 10, 2024
e4e9008
implement AscaService.java
BenAlvo1 Oct 13, 2024
0249500
implement Asca inspections
BenAlvo1 Oct 14, 2024
518148d
delete editor listener
BenAlvo1 Oct 14, 2024
b324385
delete project param from scan asca function
BenAlvo1 Oct 14, 2024
707bea2
erradded error handling in asca scan
BenAlvo1 Oct 14, 2024
c9806ca
Change deprecated Information ProblemHighlight into Weak Warning
BenAlvo1 Oct 14, 2024
7a80a14
Add severity asca constants
BenAlvo1 Oct 14, 2024
ad6a18e
refactor code
BenAlvo1 Oct 15, 2024
d7c9f93
refactor code
BenAlvo1 Oct 15, 2024
e103d4d
refactor code
BenAlvo1 Oct 15, 2024
7a5d4e7
refactor code
BenAlvo1 Oct 15, 2024
32b94e2
fix inspections description from jetbrains settings
BenAlvo1 Oct 15, 2024
d359aa5
delete quickfix
BenAlvo1 Oct 15, 2024
72392d0
added asca quick fix - coping prompt
BenAlvo1 Oct 15, 2024
ccc1d58
upgrade prompt
BenAlvo1 Oct 15, 2024
fb63e33
trim problematic line and description for prompt
BenAlvo1 Oct 15, 2024
fa42a03
added annotation to scanDetail feild in AscaQuickFix
BenAlvo1 Oct 15, 2024
57c7a35
add try catch to copyToClipboard
BenAlvo1 Oct 15, 2024
962e6c3
fix asca problem
BenAlvo1 Oct 15, 2024
98f1a48
add documentation
BenAlvo1 Oct 15, 2024
7379dab
change prompt copy message notification
BenAlvo1 Oct 30, 2024
aff6ac9
added unitest
BenAlvo1 Nov 4, 2024
14df4ee
Merge branch 'main' into feature/benalvo/asca-impl
AlvoBen Nov 4, 2024
99bf0b0
added unitest
BenAlvo1 Nov 4, 2024
cb5a588
added unitest
BenAlvo1 Nov 4, 2024
e18b27b
added UI test
BenAlvo1 Nov 4, 2024
b883f28
added UI test clicking ASCA checkbox
BenAlvo1 Nov 5, 2024
bd3392d
resolve conversations and added UI tests
BenAlvo1 Nov 5, 2024
9d82087
revert comment
BenAlvo1 Nov 5, 2024
caf1316
update java wrapper
BenAlvo1 Nov 5, 2024
c9ef2d9
update log
BenAlvo1 Nov 6, 2024
f987c26
change quickfix name
BenAlvo1 Nov 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id 'io.freefair.lombok' version '8.6'
id 'org.jetbrains.intellij' version '1.17.3'
id 'org.jetbrains.intellij' version '1.17.4'
id 'java'
}

Expand Down
214 changes: 214 additions & 0 deletions src/main/java/com/checkmarx/intellij/ASCA/AscaService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package com.checkmarx.intellij.ASCA;

import com.checkmarx.ast.asca.ScanResult;
import com.checkmarx.ast.wrapper.CxConfig;
import com.checkmarx.ast.wrapper.CxException;
import com.checkmarx.intellij.Utils;
import com.checkmarx.intellij.commands.ASCA;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.Strings;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* Service class for handling ASCA (Application Security Code Analysis) operations.
*/
public class AscaService {

private static final String ASCA_DIR = "CxASCA";
private static Logger LOGGER = Utils.getLogger(AscaService.class);

/**
* Default constructor for AscaService.
*/
public AscaService() {
}

public AscaService(Logger logger) {
LOGGER = logger;
}

/**
* Runs the ASCA scan on the provided file and returns the ScanResult.
*
* @param file the file to scan
* @param project the current project
* @param ascLatestVersion whether to use the latest version of ASCA
* @param agent the agent name
* @return the scan result, or null if an error occurs
*/
@Nullable
public ScanResult runAscaScan(PsiFile file, Project project, boolean ascLatestVersion, String agent) {
if (file == null) {
return null;
}

VirtualFile virtualFile = file.getVirtualFile();

if (ignoreFiles(virtualFile)) {
return null;
}

String fileContent = getFileContent(file, project);
if (fileContent == null) {
return null;
}

String tempFilePath = saveTempFile(file.getName(), fileContent);
if (tempFilePath == null) {
LOGGER.warn("Failed to create temporary file for ASCA scan.");
return null;
}

try {
LOGGER.info(Strings.join("Starting ASCA scan on file: ", virtualFile.getPath()));
ScanResult scanResult = ASCA.scanAsca(tempFilePath, ascLatestVersion, agent);
handleScanResult(file, scanResult);
return scanResult;
} catch (Exception e) {
LOGGER.warn("Error during ASCA scan:", e);
return null;
} finally {
deleteFile(tempFilePath);
}
}

/**
* Gets the file content, either from in-memory document or from disk.
*
* @param file the file to get content from
* @param project the current project
* @return the file content as a string, or null if an error occurs
*/
private String getFileContent(PsiFile file, Project project) {
return ApplicationManager.getApplication().runReadAction((Computable<String>) () -> {
OrShamirCM marked this conversation as resolved.
Show resolved Hide resolved
Document document = PsiDocumentManager.getInstance(project).getDocument(file);
if (document != null) {
return document.getText();
}

VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) {
LOGGER.warn("Virtual file is null for the given PsiFile.");
return null;
}

try {
return new String(virtualFile.contentsToByteArray());
} catch (IOException e) {
LOGGER.warn("Failed to retrieve file content from virtual file:", e);
return null;
}
});
}

/**
* Handles the scan result, logs any errors or violations.
*
* @param file the file that was scanned
* @param scanResult the result of the scan
*/
private void handleScanResult(@NotNull PsiFile file, ScanResult scanResult) {
if (scanResult == null || scanResult.getError() != null) {
String errorDescription = scanResult != null ?
scanResult.getError().getDescription() : "Unknown error";
LOGGER.warn(String.join(": ", "ASCA scan error", errorDescription));
return;
}

String fileName = file.getName();
int violationCount = (scanResult.getScanDetails() != null) ? scanResult.getScanDetails().size() : 0;
if (violationCount == 0) {
LOGGER.info(String.join(" ", "No security best practice violations found in", fileName));
} else {
String violationMessage = violationCount == 1 ?
Strings.join("1 security best practice violation found in ", fileName) :
violationCount + Strings.join(" security best practice violations found in" + fileName);
LOGGER.info(String.join(" ", violationMessage, "in", fileName));
}
}

/**
* Saves content to a temporary file.
*
* @param fileName the name of the file
* @param content the content to save
* @return the path to the temporary file, or null if an error occurs
*/
@Nullable
private String saveTempFile(String fileName, String content) {
try {
Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), ASCA_DIR);
Files.createDirectories(tempDir);
Path tempFilePath = tempDir.resolve(fileName);
Files.write(tempFilePath, content.getBytes());
LOGGER.debug("Temp file saved at: " + tempFilePath);
return tempFilePath.toString();
} catch (IOException e) {
LOGGER.warn("Failed to save temporary file:", e);
return null;
}
}

/**
* Deletes a file by the given file path.
*
* @param filePath the path to the file to delete
*/
private void deleteFile(String filePath) {
try {
Path normalizedPath = Paths.get(filePath).toAbsolutePath().normalize();
File file = normalizedPath.toFile();
if (file.exists()) {
if (file.delete()) {
LOGGER.debug(Strings.join("Temporary file ", filePath, " deleted."));
}
}
} catch (Exception e) {
LOGGER.warn("Failed to delete file", e);
}
}

/**
* Determines whether the file should be ignored.
*
* @param file the file to check
* @return true if the file should be ignored, false otherwise
*/
private boolean ignoreFiles(VirtualFile file) {
return file == null || !file.isInLocalFileSystem();
}

/**
* Installs the ASCA CLI if not already installed.
*
* @return a message indicating the result of the installation
* @throws CxException if an error occurs during installation
* @throws CxConfig.InvalidCLIConfigException if the CLI configuration is invalid
* @throws IOException if an I/O error occurs
* @throws URISyntaxException if a URI syntax error occurs
* @throws InterruptedException if the installation is interrupted
*/
public boolean installAsca() throws CxException, CxConfig.InvalidCLIConfigException, IOException, URISyntaxException, InterruptedException {
ScanResult res = ASCA.installAsca();
if (res.getError() != null) {
LOGGER.warn(Strings.join("ASCA installation error: ", res.getError().getDescription()));
return false;
}
return true;
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/checkmarx/intellij/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ private Constants() {

public static final String FIELD_NAME_API_KEY = "apiKey";
public static final String FIELD_NAME_ADDITIONAL_PARAMETERS = "additionalParameters";
public static final String FIELD_NAME_ASCA = "ascaCheckBox";

public static final String SELECTED_PROJECT_PROPERTY = "Checkmarx.SelectedProject";
public static final String SELECTED_BRANCH_PROPERTY = "Checkmarx.SelectedBranch";
Expand Down Expand Up @@ -78,4 +79,8 @@ private Constants() {
public static final String SCAN_STATUS_RUNNING = "running";
public static final String SCAN_STATUS_COMPLETED = "completed";
public static final String JET_BRAINS_AGENT_NAME = "Jetbrains";
public static final String ASCA_CRITICAL_SEVERITY = "Critical";
public static final String ASCA_HIGH_SEVERITY = "High";
public static final String ASCA_MEDIUM_SEVERITY = "Medium";
public static final String ASCA_LOW_SEVERITY = "Low";
}
5 changes: 5 additions & 0 deletions src/main/java/com/checkmarx/intellij/Resource.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public enum Resource {
API_KEY,
SCAN_SECTION,
ADDITIONAL_PARAMETERS,
ASCA_CHECKBOX,
ASCA_DESCRIPTION,
ASCA_SCAN_WARNING,
ASCA_STARTED_MSG,
FAILED_INSTALL_ASCA,
VALIDATE_BUTTON,
VALIDATE_IN_PROGRESS,
VALIDATE_SUCCESS,
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/com/checkmarx/intellij/commands/ASCA.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.checkmarx.intellij.commands;

import com.checkmarx.ast.asca.ScanResult;
import com.checkmarx.ast.wrapper.CxConfig;
import com.checkmarx.ast.wrapper.CxException;
import com.checkmarx.intellij.Constants;
import com.checkmarx.intellij.settings.global.CxWrapperFactory;

import java.io.IOException;
import java.net.URISyntaxException;

public class ASCA {
public static ScanResult scanAsca(String path, boolean ascaLatestVersion, String agent)
throws
CxConfig.InvalidCLIConfigException,
IOException,
URISyntaxException,
CxException,
InterruptedException {
return CxWrapperFactory.build().ScanAsca(path, ascaLatestVersion, agent);
OrShamirCM marked this conversation as resolved.
Show resolved Hide resolved
}

public static ScanResult installAsca()
throws CxConfig.InvalidCLIConfigException,
IOException,
URISyntaxException,
CxException,
InterruptedException {
return CxWrapperFactory.build().ScanAsca("",true, Constants.JET_BRAINS_AGENT_NAME);
}
}
Loading
Loading