Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
730c7e5
docs AST-146800: Add Cloud.md standardization file
cx-aniket-shinde Apr 15, 2026
6310f05
AST-101305: Disable Branch and Scan dropdown when no project is selected
cx-aniket-shinde Apr 17, 2026
644dae9
Fix: Route authentication logs to Eclipse Error Log (AST-136023) (#244)
cx-aniket-shinde Apr 20, 2026
0260961
Fix: Clear detail panels on severity filter change (AST-136035) (#245)
cx-aniket-shinde Apr 20, 2026
72be7a1
Fix: Truncate long custom state names in filter menu (AST-137779) (#246)
cx-aniket-shinde Apr 20, 2026
d30b7f0
Toolyip custom state
cx-aniket-shinde May 14, 2026
b023509
Parity and project combobox
cx-aniket-shinde May 14, 2026
636b0e1
Merge branch 'bug/AST-136045' into integration/eclipse-bug-fixes
cx-aniket-shinde May 15, 2026
4a33466
Merge branch 'bug/AST-101305' into integration/eclipse-bug-fixes
cx-aniket-shinde May 15, 2026
992bf41
CISO-920: remove broken Teams notify job (secret CXONE_SCAN_WEBHOOK_U…
Apr 27, 2026
885d96a
[StepSecurity] Apply security best practices (#251)
stepsecurity-app[bot] May 22, 2026
2f1d998
[StepSecurity] Apply security best practices (#252)
stepsecurity-app[bot] May 30, 2026
33b6352
remove dependabot (#254)
cx-alon-rosenhek Jun 16, 2026
2f50808
Merge branch 'main' of https://github.com/Checkmarx/ast-eclipse-plugi…
cx-aniket-shinde Jun 19, 2026
b341d9a
Merge branch 'main' of https://github.com/Checkmarx/ast-eclipse-plugi…
cx-aniket-shinde Jun 19, 2026
074dda9
Merge branch 'integration/eclipse-bug-fixes' into release/integration
cx-aniket-shinde Jun 23, 2026
b1fe437
rerun
cx-nisan-benabu Jun 24, 2026
f0fe389
Bumped java wrapper version
cx-atish-jadhav Jun 25, 2026
6581d2f
bump java wrapper version to 2.4.24
cx-atish-jadhav Jun 24, 2026
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
9 changes: 9 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we have added this file ?

"permissions": {
"allow": [
"Bash(git log *)",
"Bash(git pull *)",
"Bash(git stash *)"
]
}
}
346 changes: 346 additions & 0 deletions Cloud.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

public abstract class BaseUITest {

private static final String INFO_SUCCESSFUL_CONNECTION = "Successfully authenticated to Checkmarx One server!";
private static final String INFO_SUCCESSFUL_CONNECTION = "You are connected to Checkmarx One";

protected static final String ASSERT_FILTER_ACTIONS_IN_TOOLBAR = "All filter actions must be in the tool bar";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@

import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.slf4j.Logger;

import com.checkmarx.ast.wrapper.CxException;
import com.checkmarx.ast.wrapper.CxWrapper;
import com.checkmarx.eclipse.runner.Authenticator;
import com.checkmarx.eclipse.utils.CxLogger;
import com.checkmarx.eclipse.utils.PluginConstants;

class AuthenticatorTest {
Expand All @@ -24,14 +26,15 @@ void testDoAuthenticationSuccess() throws Exception {

try (MockedConstruction<CxWrapper> mocked =
Mockito.mockConstruction(CxWrapper.class,
(mock, context) -> when(mock.authValidate()).thenReturn("SUCCESS"))) {
(mock, context) -> when(mock.authValidate()).thenReturn("SUCCESS"));
MockedStatic<CxLogger> mockedCxLogger = Mockito.mockStatic(CxLogger.class)) {

Authenticator authenticator = new Authenticator(mockLogger);

String result = authenticator.doAuthentication("dummyKey", "--param");

assertEquals("SUCCESS", result);
verify(mockLogger).info("Authentication Status: SUCCESS");
mockedCxLogger.verify(() -> CxLogger.info(String.format(PluginConstants.INFO_AUTHENTICATION_STATUS, "SUCCESS")));
}
}

Expand All @@ -43,17 +46,18 @@ void testDoAuthenticationIOException() throws Exception {
try (MockedConstruction<CxWrapper> mocked =
Mockito.mockConstruction(CxWrapper.class,
(mock, context) -> when(mock.authValidate())
.thenThrow(new IOException("IO error")))) {
.thenThrow(new IOException("IO error")));
MockedStatic<CxLogger> mockedCxLogger = Mockito.mockStatic(CxLogger.class)) {

Authenticator authenticator = new Authenticator(mockLogger);

String result = authenticator.doAuthentication("dummyKey", "--param");

assertEquals("IO error", result);
verify(mockLogger).error(
eq(String.format(PluginConstants.ERROR_AUTHENTICATING_AST, "IO error")),
any(IOException.class)
);
mockedCxLogger.verify(() -> CxLogger.error(
eq(String.format(PluginConstants.ERROR_AUTHENTICATING_AST, "IO error")),
any(IOException.class)
));
}
}

Expand All @@ -65,17 +69,18 @@ void testDoAuthenticationInterruptedException() throws Exception {
try (MockedConstruction<CxWrapper> mocked =
Mockito.mockConstruction(CxWrapper.class,
(mock, context) -> when(mock.authValidate())
.thenThrow(new InterruptedException("Interrupted")))) {
.thenThrow(new InterruptedException("Interrupted")));
MockedStatic<CxLogger> mockedCxLogger = Mockito.mockStatic(CxLogger.class)) {

Authenticator authenticator = new Authenticator(mockLogger);

String result = authenticator.doAuthentication("dummyKey", "--param");

assertEquals("Interrupted", result);
verify(mockLogger).error(
eq(String.format(PluginConstants.ERROR_AUTHENTICATING_AST, "Interrupted")),
any(InterruptedException.class)
);
mockedCxLogger.verify(() -> CxLogger.error(
eq(String.format(PluginConstants.ERROR_AUTHENTICATING_AST, "Interrupted")),
any(InterruptedException.class)
));
}
}

Expand All @@ -87,17 +92,18 @@ void testDoAuthenticationCxException() throws Exception {
try (MockedConstruction<CxWrapper> mocked =
Mockito.mockConstruction(CxWrapper.class,
(mock, context) -> when(mock.authValidate())
.thenThrow(new CxException(1, "Cx error")))) {
.thenThrow(new CxException(1, "Cx error")));
MockedStatic<CxLogger> mockedCxLogger = Mockito.mockStatic(CxLogger.class)) {

Authenticator authenticator = new Authenticator(mockLogger);

String result = authenticator.doAuthentication("dummyKey", "--param");

assertEquals("Cx error", result);
verify(mockLogger).error(
eq(String.format(PluginConstants.ERROR_AUTHENTICATING_AST, "Cx error")),
any(CxException.class)
);
mockedCxLogger.verify(() -> CxLogger.error(
eq(String.format(PluginConstants.ERROR_AUTHENTICATING_AST, "Cx error")),
any(CxException.class)
));
}
}

Expand Down
4 changes: 4 additions & 0 deletions checkmarx-ast-eclipse-plugin/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@
</perspectiveExtension>
</extension>

<extension point="org.eclipse.ui.startup">
<startup class="com.checkmarx.eclipse.startup.PluginStartup"/>
</extension>

</plugin>
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,23 @@ public void widgetSelected(SelectionEvent e) {
return t.getMessage();
}
}).thenAccept((result) -> Display.getDefault().syncExec(() -> {
connectionLabel.setText(result);
connectionLabel.setText(mapAuthResult(result));
getFieldEditorParent().layout();
connectionButton.setEnabled(true);
}));
}
});
}



private static String mapAuthResult(String result) {
if (result != null && result.contains(PluginConstants.AUTH_SUCCESS_PATTERN)) {
return PluginConstants.AUTH_SUCCESS_DISPLAY;
}
return result;
}

private FieldEditor space() {
return new LabelFieldEditor("", getFieldEditorParent());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ public String doAuthentication(String apiKey, String additionalParams) {
try {
CxWrapper wrapper = new CxWrapper(config, log);
String cxValidateOutput = wrapper.authValidate();
log.info(AUTH_STATUS + cxValidateOutput);
CxLogger.info(String.format(PluginConstants.INFO_AUTHENTICATION_STATUS, cxValidateOutput));
return cxValidateOutput;
} catch (IOException | InterruptedException | CxException e) {
log.error(String.format(PluginConstants.ERROR_AUTHENTICATING_AST, e.getMessage()), e);
CxLogger.error(String.format(PluginConstants.ERROR_AUTHENTICATING_AST, e.getMessage()), e);
return e.getMessage();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.checkmarx.eclipse.startup;

import org.eclipse.ui.IStartup;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;

import com.checkmarx.eclipse.utils.CxLogger;

public class PluginStartup implements IStartup {

private static final String VIEW_ID = "com.checkmarx.eclipse.views.CheckmarxView";

@Override
public void earlyStartup() {
PlatformUI.getWorkbench().getDisplay().asyncExec(() -> {
try {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window != null) {
IWorkbenchPage page = window.getActivePage();
if (page != null && page.findView(VIEW_ID) == null) {
page.showView(VIEW_ID);
}
}
} catch (PartInitException e) {
CxLogger.error("Failed to open Checkmarx One view on startup: " + e.getMessage(), e);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public class PluginConstants {
public static final String INFO_CHANGE_SCAN_EVENT_NOT_TRIGGERED = "Change scan id event not triggered. Request already running: %s. Scan id results already retrieved: %s";
public static final String INFO_CHANGE_BRANCH_EVENT_NOT_TRIGGERED = "Change branch event not triggered. Branch already selected";
public static final String INFO_CHANGE_PROJECT_EVENT_NOT_TRIGGERED = "Change project event not triggered. Project already selected";
public static final String AUTH_SUCCESS_PATTERN = "Successfully authenticated";
public static final String AUTH_SUCCESS_DISPLAY = "You are connected to Checkmarx One";

/******************************** TREE MESSAGES ********************************/
public static final String TREE_INVALID_SCAN_ID_FORMAT = "Invalid scan id format.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
Expand Down Expand Up @@ -160,6 +164,7 @@ public class CheckmarxView extends ViewPart implements EventHandler {
private Text commentText;
private DisplayModel rootModel;
private String selectedSeverity, selectedState;
private DisplayModel currentlyDisplayedItem;
private Button triageButton;
private SelectionAdapter triageButtonAdapter, codeBashingAdapter;
private Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
Expand Down Expand Up @@ -626,12 +631,29 @@ private void createResultViewPanel(Composite resultsComposite) {
combo_1.setLayoutData(gd_combo_1);

triageStateComboViewer = new ComboViewer(triageView, SWT.READ_ONLY);
triageStateComboViewer.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
String s = element instanceof String ? (String) element : super.getText(element);
return s.length() > 50 ? s.substring(0, 47) + "..." : s;
}
});
Combo combo_2 = triageStateComboViewer.getCombo();
combo_2.setEnabled(true);
combo_2.setData(PluginConstants.DATA_ID_KEY, PluginConstants.TRIAGE_STATE_COMBO_ID);
GridData gd_combo_2 = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
// gd_combo_2.widthHint = 180;
combo_2.setLayoutData(gd_combo_2);
combo_2.addMouseTrackListener(new MouseTrackAdapter() {
@Override
public void mouseHover(MouseEvent e) {
IStructuredSelection sel = (IStructuredSelection) triageStateComboViewer.getSelection();
if (!sel.isEmpty()) {
String fullName = (String) sel.getFirstElement();
combo_2.setToolTipText(fullName.length() > 50 ? fullName : "");
}
}
});

triageButton = new Button(triageView, SWT.FLAT | SWT.CENTER);
triageButton.setData(PluginConstants.DATA_ID_KEY, PluginConstants.TRIAGE_BUTTON_ID);
Expand Down Expand Up @@ -904,7 +926,26 @@ protected IStatus run(IProgressMonitor monitor) {
debounceTimer.schedule(pendingSearchTask, DEBOUNCE_DELAY_MS);

}
});
});

// Add FocusListener to disable branch combo when project is cleared and focus lost
projectComboViewer.getCombo().addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent e) {
// When user clicks outside project combo, check if project is empty
String enteredProject = projectComboViewer.getCombo().getText().trim();
// If project field is empty or contains only the placeholder text, disable branch combo
if (enteredProject.isEmpty() || enteredProject.equals(PROJECT_COMBO_VIEWER_TEXT)) {
currentProjectId = PluginConstants.EMPTY_STRING;
PluginUtils.enableComboViewer(branchComboViewer, false);
}
}

@Override
public void focusGained(FocusEvent e) {
// No action needed on focus gain
}
});

}
/**
Expand Down Expand Up @@ -1082,8 +1123,7 @@ private void createScanIdComboBox(Composite parent) {
scanIdComboViewer.setContentProvider(ArrayContentProvider.getInstance());
scanIdComboViewer.setInput(new ArrayList<>());

GridData gridData = new GridData();
gridData.widthHint = 520;
GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
scanIdComboViewer.getCombo().setLayoutData(gridData);

scanIdComboViewer.getCombo().addListener(SWT.DefaultSelection, new Listener() {
Expand Down Expand Up @@ -1264,13 +1304,31 @@ protected IStatus run(IProgressMonitor arg0) {
List<Project> projectList = getProjects();
if (projectList.isEmpty())
return null;
String projectName = getProjectFromId(projectList, projectId);

// Fetch the project directly by ID — the full list may not contain it (e.g. pagination limits)
Project fetchedProject = DataProvider.getInstance().getProjectById(projectId);

// Determine project name: prefer the directly-fetched result, fall back to list lookup
String projectName = (fetchedProject != null)
? fetchedProject.getName()
: getProjectFromId(projectList, projectId);

// If the project was not already in the list, prepend it so it's visible in the dropdown
if (fetchedProject != null && projectList.stream().noneMatch(p -> p.getId().equals(projectId))) {
projectList = new ArrayList<>(projectList);
projectList.add(0, fetchedProject);
}
final List<Project> finalProjectList = projectList;

currentProjectId = projectId;
GlobalSettings.storeInPreferences(GlobalSettings.PARAM_PROJECT_ID, currentProjectId);

sync.asyncExec(() -> {
projectComboViewer.setInput(projectList);
currentProjects = finalProjectList;
storeCurrentProjects = finalProjectList;
projectComboViewer.setInput(finalProjectList);
PluginUtils.setTextForComboViewer(projectComboViewer, projectName);
PluginUtils.enableComboViewer(projectComboViewer, true);
setSelectionForBranchComboViewer(scan.getBranch(), projectId);
setSelectionForScanIdComboViewer(scan.getId(), scan.getBranch());
updateStartScanButton(true);
Expand Down Expand Up @@ -1386,6 +1444,7 @@ protected IStatus run(IProgressMonitor arg0) {

if (selectedItem.getResult() != null && selectedItem.getResult().getSimilarityId() != null) {
sync.asyncExec(() -> {
currentlyDisplayedItem = selectedItem;
createTriageSeverityAndStateCombos(selectedItem);
populateTriageChanges(selectedItem);
resultViewComposite.setVisible(true);
Expand Down Expand Up @@ -2473,6 +2532,8 @@ private Image findSeverityImage(DisplayModel model) {
private void listener(PluginListenerDefinition definition) {
switch (definition.getListenerType()) {
case FILTER_CHANGED:
updateResultsTree(definition.getResutls(), true);
break;
case GET_RESULTS:
updateResultsTree(definition.getResutls(), false);
break;
Expand All @@ -2489,9 +2550,15 @@ private void listener(PluginListenerDefinition definition) {

private void updateResultsTree(List<DisplayModel> results, boolean expand) {
sync.asyncExec(() -> {
if (currentlyDisplayedItem == null
|| currentlyDisplayedItem.getSeverity() == null
|| !FilterState.isSeverityEnabled(currentlyDisplayedItem.getSeverity())) {
resultViewComposite.setVisible(false);
attackVectorCompositePanel.setVisible(false);
}
Object[] expanded = resultsTree.getExpandedElements();
rootModel.children.clear();
rootModel.children.addAll(results);
Object[] expanded = resultsTree.getExpandedElements();
resultsTree.refresh();
if (expand) {
Set<String> expandedDMNames = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,27 @@ public List<Project> getProjects() throws Exception {
return projectList;
}

/**
* Fetch a single project directly by its ID using the project show command.
* Returns null if the project cannot be retrieved.
*/
public Project getProjectById(String projectId) {
try {
CxWrapper cxWrapper = getWrapper();
if (cxWrapper != null && projectId != null && !projectId.isEmpty()) {
return cxWrapper.projectShow(UUID.fromString(projectId));
}
} catch (Exception e) {
CxLogger.error(String.format(PluginConstants.ERROR_GETTING_PROJECTS, e.getMessage()), e);
}
return null;
}

/**
* Get One projects filtered by name
*
*
* @return
* @throws Exception
* @throws Exception
*/
public List<Project> getProjects(String projectName) throws Exception {
List<Project> projectList = new ArrayList<Project>();
Expand Down
Loading
Loading