Skip to content

Commit a438936

Browse files
Displaying and managing custom states in Eclipse IDE
1 parent a9bd569 commit a438936

7 files changed

Lines changed: 376 additions & 127 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package checkmarx.ast.eclipse.plugin.tests.integration;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertTrue;
5+
6+
import java.util.HashSet;
7+
import java.util.List;
8+
import java.util.Optional;
9+
import java.util.Set;
10+
11+
import org.junit.Test;
12+
13+
import com.checkmarx.eclipse.views.DataProvider;
14+
import com.checkmarx.eclipse.views.filters.FilterState;
15+
16+
public class CustomStateIntegrationTest extends BaseIntegrationTest {
17+
18+
private final DataProvider provider = DataProvider.getInstance();
19+
20+
// 1. SAST includes at least one custom state
21+
@Test
22+
public void testSastIncludesAtLeastOneCustomState() {
23+
List<String> sastStates = provider.getStatesForEngine("SAST");
24+
25+
boolean hasCustomState = sastStates.stream()
26+
.anyMatch(s -> !FilterState.PREDEFINED_STATE_SET.contains(s.toUpperCase()));
27+
28+
assertTrue("SAST should include at least one custom state", hasCustomState);
29+
}
30+
31+
// 2. Check that KICS and SCA contain only predefined states
32+
@Test
33+
public void testNonSastEnginesIncludeOnlyPredefinedStates() {
34+
List<String> kicsStates = provider.getStatesForEngine("KICS");
35+
List<String> scaStates = provider.getStatesForEngine("SCA");
36+
//
37+
assertEquals("KICS should include only predefined states", FilterState.PREDEFINED_STATES.size(),
38+
kicsStates.size());
39+
assertEquals("SCA should include only predefined states", FilterState.PREDEFINED_STATES.size(),
40+
scaStates.size());
41+
42+
for (String kics : kicsStates) {
43+
assertTrue("KICS state must be predefined", FilterState.PREDEFINED_STATE_SET.contains(kics.toUpperCase()));
44+
}
45+
46+
for (String sca : scaStates) {
47+
assertTrue("SCA state must be predefined", FilterState.PREDEFINED_STATE_SET.contains(sca.toUpperCase()));
48+
}
49+
}
50+
51+
// 3. No duplicates in SAST
52+
@Test
53+
public void testNoDuplicateStatesInSast() {
54+
List<String> sastStates = provider.getStatesForEngine("SAST");
55+
56+
Set<String> deduplicated = new HashSet<>(sastStates);
57+
58+
assertEquals("SAST states should not contain duplicates", sastStates.size(), deduplicated.size());
59+
}
60+
61+
// 4. Optional: See if a custom state disappears on next fetch
62+
@Test
63+
public void testCustomStateStillExistsAfterRefetch() {
64+
List<String> initialStates = provider.getStatesForEngine("SAST");
65+
66+
Optional<String> firstCustom = initialStates.stream()
67+
.filter(s -> !FilterState.PREDEFINED_STATE_SET.contains(s.toUpperCase())).findFirst();
68+
69+
if (!firstCustom.isPresent()) {
70+
System.out.println("No custom state found in SAST — skipping recheck.");
71+
return;
72+
}
73+
74+
String custom = firstCustom.get();
75+
List<String> refetched = provider.getStatesForEngine("SAST");
76+
77+
assertTrue("Custom state should still exist after re-fetch", refetched.contains(custom));
78+
}
79+
}

checkmarx-ast-eclipse-plugin-tests/src/test/java/checkmarx/ast/eclipse/plugin/tests/ui/TestFilterState.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void testGroupByActionsInToolBar() throws TimeoutException {
4747

4848
SWTBotTreeItem ll = getFirstResultNode();
4949
ArrayList<String> severityFilters = new ArrayList<>(Arrays.asList(Severity.HIGH.name(), Severity.MEDIUM.name(),Severity.LOW.name(),Severity.INFO.name()));
50-
ArrayList<String> stateFilters = new ArrayList<>(Arrays.asList(State.CONFIRMED.name(),State.IGNORED.name(),State.NOT_EXPLOITABLE.name(),State.NOT_IGNORED.name(),State.PROPOSED_NOT_EXPLOITABLE.name(),State.TO_VERIFY.name(),State.URGENT.name()));
50+
ArrayList<String> stateFilters = new ArrayList<>(Arrays.asList(State.CONFIRMED.getName(),State.IGNORED.getName(),State.NOT_EXPLOITABLE.getName(),State.NOT_IGNORED.getName(),State.PROPOSED_NOT_EXPLOITABLE.getName(),State.TO_VERIFY.getName(),State.URGENT.getName()));
5151
assertTrue(!severityFilters.contains(ll.getText()));
5252

5353
//enable group by severity (1st level group)
Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,47 @@
11
package com.checkmarx.eclipse.enums;
22

3-
public enum State {
4-
5-
TO_VERIFY,
6-
NOT_EXPLOITABLE,
7-
PROPOSED_NOT_EXPLOITABLE,
8-
CONFIRMED,
9-
NOT_IGNORED,
10-
IGNORED,
11-
URGENT;
12-
13-
public static State getState(String state) {
14-
return State.valueOf(state);
3+
import java.util.Collections;
4+
import java.util.LinkedHashMap;
5+
import java.util.Map;
6+
7+
public class State {
8+
9+
private static final Map<String, State> STATES = new LinkedHashMap<>();
10+
11+
// Predefined states
12+
public static final State TO_VERIFY = new State("TO_VERIFY");
13+
public static final State NOT_EXPLOITABLE = new State("NOT_EXPLOITABLE");
14+
public static final State PROPOSED_NOT_EXPLOITABLE = new State("PROPOSED_NOT_EXPLOITABLE");
15+
public static final State CONFIRMED = new State("CONFIRMED");
16+
public static final State NOT_IGNORED = new State("NOT_IGNORED");
17+
public static final State IGNORED = new State("IGNORED");
18+
public static final State URGENT = new State("URGENT");
19+
20+
private final String name;
21+
22+
private State(String name) {
23+
this.name = name;
24+
STATES.put(name, this);
25+
}
26+
27+
public String getName() {
28+
return name;
29+
}
30+
31+
public static State of(String name) {
32+
return STATES.computeIfAbsent(name, State::new); // register custom states dynamically
33+
}
34+
35+
public static State getState(String name) {
36+
return STATES.get(name);
37+
}
38+
39+
public static Map<String, State> values() {
40+
return Collections.unmodifiableMap(STATES);
41+
}
42+
43+
@Override
44+
public String toString() {
45+
return name;
1546
}
1647
}

checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/CheckmarxView.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1330,7 +1330,8 @@ public void selectionChanged(SelectionChangedEvent event) {
13301330
String currentState = selectedItem.getState();
13311331
selectedState = selectedItem.getResult().getState();
13321332

1333-
String[] state = { "TO_VERIFY", "NOT_EXPLOITABLE", "PROPOSED_NOT_EXPLOITABLE", "CONFIRMED", "URGENT" };
1333+
// Fetch dynamic states from DataProvider
1334+
List<String> state = DataProvider.getInstance().getStatesForEngine(selectedItem.getType());
13341335

13351336
triageStateComboViewer.setContentProvider(ArrayContentProvider.getInstance());
13361337
triageStateComboViewer.setInput(state);
@@ -1952,6 +1953,22 @@ protected IStatus run(IProgressMonitor arg0) {
19521953
addLearnMoreSectionsToComposite(learnMoreComposite, PluginConstants.LEARN_MORE_CAUSE, learnMore.getCause().trim());
19531954
addLearnMoreSectionsToComposite(learnMoreComposite, PluginConstants.LEARN_MORE_GENERAL_RECOMMENDATIONS, learnMore.getGeneralRecommendations().trim());
19541955

1956+
// Adding CWE link in Learn More section of SAST vulnerability
1957+
String cweId = selectedItem.getResult().getVulnerabilityDetails().getCweId();
1958+
if (cweId != null && !cweId.isEmpty()) {
1959+
String cweUrl = "https://cwe.mitre.org/data/definitions/" + cweId + ".html";
1960+
Link cweLink = new Link(learnMoreComposite, SWT.NONE);
1961+
cweLink.setText("<a>CWE-" + cweId + "</a>");
1962+
cweLink.addListener(SWT.Selection, e -> {
1963+
try {
1964+
PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser()
1965+
.openURL(new java.net.URL(cweUrl));
1966+
} catch (Exception ex) {
1967+
CxLogger.error("Failed to open CWE link: " + ex.getMessage(), ex);
1968+
}
1969+
});
1970+
}
1971+
19551972
learnMoreScrolledComposite.setMinSize(learnMoreComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
19561973
learnMoreComposite.layout();
19571974
}

checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/DataProvider.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import com.checkmarx.ast.codebashing.CodeBashing;
2222
import com.checkmarx.ast.learnMore.LearnMore;
23+
import com.checkmarx.ast.predicate.CustomState;
2324
import com.checkmarx.ast.predicate.Predicate;
2425
import com.checkmarx.ast.project.Project;
2526
import com.checkmarx.ast.results.ReportFormat;
@@ -57,6 +58,7 @@ public class DataProvider {
5758
private String currentScanId;
5859
private String projectId;
5960
private List<DisplayModel> currentResultsTransformed;
61+
private List<String> platformStates = new ArrayList<>();
6062

6163
/**
6264
* Singleton data provider instance
@@ -201,6 +203,12 @@ public List<DisplayModel> getResultsForScanId(String scanId) {
201203

202204
setCurrentScanId(scanId);
203205

206+
try {
207+
platformStates = getAllStatesFromPlatform();
208+
} catch (Exception e) {
209+
CxLogger.warning("Failed to fetch all platform states on scan load: " + e.getMessage());
210+
}
211+
204212
try {
205213
CxLogger.info(String.format(PluginConstants.INFO_FETCHING_RESULTS, scanId));
206214
CxWrapper cxWrapper = getWrapper();
@@ -239,6 +247,18 @@ public Scan getScanInformation(String scanId) throws Exception {
239247
return scan;
240248
}
241249

250+
public List<String> getAvailableStates() {
251+
return platformStates != null ? platformStates : Collections.emptyList();
252+
}
253+
254+
public List<String> getStatesForEngine(String engineType) {
255+
if ("SAST".equalsIgnoreCase(engineType)) {
256+
return platformStates != null ? platformStates : Collections.emptyList();
257+
} else {
258+
return new ArrayList<>(com.checkmarx.eclipse.enums.State.values().keySet());
259+
}
260+
}
261+
242262
/**
243263
* Process results to be displayed in the tree
244264
*
@@ -771,4 +791,26 @@ public void cancelScan(String scanId) throws IOException, InterruptedException,
771791
public boolean isScanAllowed() throws CxException, IOException, InterruptedException, Exception {
772792
return authenticateWithAST().ideScansEnabled();
773793
}
794+
795+
/**
796+
* Fetch ALL platform states (predefined + custom) irrespective of
797+
* vulnerabilities.
798+
*/
799+
private List<String> getAllStatesFromPlatform() throws Exception {
800+
if (currentScanId == null || projectId == null) {
801+
return Collections.emptyList();
802+
}
803+
804+
CxWrapper cxWrapper = authenticateWithAST();
805+
List<String> allStates = new ArrayList<>();
806+
807+
try {
808+
List<CustomState> customStates = cxWrapper.triageGetStates(false);
809+
allStates = customStates.stream().map(CustomState::getName).collect(Collectors.toList());
810+
} catch (Exception e) {
811+
CxLogger.warning("Could not fetch platform states: " + e.getMessage());
812+
}
813+
814+
return allStates;
815+
}
774816
}

checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/actions/ActionFilterStatePreference.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,19 @@ public Menu getMenu(final Control parent) {
8282
createMenuItem(menu, FILTER_IGNORED, FilterState.ignored, State.IGNORED);
8383
createMenuItem(menu, FILTER_NOT_IGNORED, FilterState.not_ignored, State.NOT_IGNORED);
8484

85+
// Add CUSTOM STATE filter option
86+
MenuItem customItem = new MenuItem(menu, SWT.CHECK);
87+
customItem.setText("CUSTOM STATE");
88+
customItem.setSelection(FilterState.customState);
89+
customItem.addSelectionListener(new SelectionAdapter() {
90+
@Override
91+
public void widgetSelected(SelectionEvent e) {
92+
FilterState.setCustomStateFilter();
93+
pluginEventBus.post(new PluginListenerDefinition(PluginListenerType.FILTER_CHANGED,
94+
DataProvider.getInstance().sortResults()));
95+
}
96+
});
97+
8598
return menu;
8699
}
87100

@@ -94,6 +107,7 @@ private void createMenuItem(Menu menu, String filterText, boolean filterState, S
94107

95108
private SelectionListener StateFilterSectionListener(State state) {
96109
return new SelectionAdapter() {
110+
@Override
97111
public void widgetSelected(SelectionEvent e) {
98112
FilterState.setFilterState(state);
99113
pluginEventBus.post(new PluginListenerDefinition(PluginListenerType.FILTER_CHANGED,

0 commit comments

Comments
 (0)