diff --git a/.gitattributes b/.gitattributes index 433866f7..b9b6fd84 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,3 +12,4 @@ checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.18.jar filter=lfs diff checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.20.jar filter=lfs diff=lfs merge=lfs -text checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.21.jar filter=lfs diff=lfs merge=lfs -text checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.23.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.24.jar filter=lfs diff=lfs merge=lfs -text diff --git a/Cloud.md b/Cloud.md new file mode 100644 index 00000000..459c1fac --- /dev/null +++ b/Cloud.md @@ -0,0 +1,346 @@ +# Cloud.md — Checkmarx One Eclipse Plugin + +> Standardized Cloud MD file for [ast-eclipse-plugin](https://github.com/Checkmarx/ast-eclipse-plugin) +> Following the Cloud MD standardization template defined in epic AST-146793. + +--- + +## Project Overview + +The **Checkmarx One Eclipse Plugin** integrates the full Checkmarx One security platform directly into the Eclipse IDE. It enables developers to discover and remediate vulnerabilities without leaving their editor — embodying the shift-left AppSec philosophy. + +**Key capabilities:** +- Import scan results (SAST, SCA, IaC Security) from Checkmarx One directly into Eclipse +- Run new scans from the IDE before committing code +- Navigate from a vulnerability directly to the affected source line +- Triage results (adjust severity, state, add comments) without leaving the IDE +- Filter and group results by severity, state, or query name +- View vulnerability descriptions, attack vectors, and Codebashing remediation links +- Best Fix Location (BFL) highlighting for SAST findings + +**Supported Eclipse versions:** 2019-03 (4.11) and above +**Supported platforms:** Windows, macOS, Linux/GTK + +--- + +## Architecture + +The plugin follows a standard Eclipse **ViewPart** architecture backed by an **OSGi** bundle lifecycle. + +``` +┌─────────────────────────────────────────────────────┐ +│ Eclipse IDE │ +│ ┌──────────────────────────────────────────────┐ │ +│ │ CheckmarxView (ViewPart) │ │ +│ │ ┌──────────┐ ┌──────────┐ ┌────────────┐ │ │ +│ │ │ Project │ │ Branch │ │ Scan ID │ │ │ +│ │ │ Combo │ │ Combo │ │ Combo │ │ │ +│ │ └──────────┘ └──────────┘ └────────────┘ │ │ +│ │ ┌────────────────────────────────────────┐ │ │ +│ │ │ Results Tree (SWT TreeViewer) │ │ │ +│ │ │ Grouped by: Severity / Query / State │ │ │ +│ │ └────────────────────────────────────────┘ │ │ +│ │ ┌───────────────┐ ┌──────────────────────┐ │ │ +│ │ │ Description │ │ Attack Vector / │ │ │ +│ │ │ & Triage │ │ Package Data / │ │ │ +│ │ │ Panel │ │ BFL Panel │ │ │ +│ │ └───────────────┘ └──────────────────────┘ │ │ +│ └──────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────┘ + │ EventBus (Guava) + ▼ +┌─────────────────────┐ ┌──────────────────────┐ +│ DataProvider │◄──────►│ ast-cli-java-wrapper │ +│ (Singleton) │ │ (Checkmarx One API) │ +└─────────────────────┘ └──────────────────────┘ +``` + +**Key architectural decisions:** +- **Event-driven UI:** Google Guava `EventBus` decouples UI actions (filter changes, scan loads) from the view rendering. Events: `FILTER_CHANGED`, `GET_RESULTS`, `CLEAN_AND_REFRESH`, `LOAD_RESULTS_FOR_SCAN`. +- **CLI wrapper:** All communication with the Checkmarx One platform is delegated to `ast-cli-java-wrapper`, which wraps the Checkmarx CLI binary. No direct REST calls from the plugin. +- **Singleton DataProvider:** Holds all loaded scan results, filter state, and project/branch/scan metadata for the current session. +- **Static FilterState:** Severity and state filter flags are stored as static fields persisted to Eclipse preferences via `GlobalSettings`. + +--- + +## Repository Structure + +``` +ast-eclipse-plugin/ +├── checkmarx-ast-eclipse-plugin/ # Main OSGi plugin bundle +│ ├── src/com/checkmarx/eclipse/ +│ │ ├── Activator.java # OSGi bundle lifecycle +│ │ ├── enums/ # Severity, State, ActionName enums +│ │ ├── properties/ # Eclipse preferences page & fields +│ │ ├── runner/ # Authentication runner +│ │ ├── utils/ # CxLogger, PluginUtils, PluginConstants +│ │ └── views/ +│ │ ├── CheckmarxView.java # Main ViewPart (~2600 lines) +│ │ ├── DataProvider.java # Singleton data/state manager +│ │ ├── DisplayModel.java # Tree node model +│ │ ├── GlobalSettings.java # Eclipse preference store wrapper +│ │ ├── actions/ # Toolbar actions (filters, scan, triage) +│ │ ├── filters/ # FilterState, ActionFilters +│ │ └── provider/ # TreeContentProvider, ColumnProvider +│ ├── META-INF/MANIFEST.MF # OSGi bundle descriptor +│ ├── plugin.xml # Eclipse extension points +│ ├── icons/ # Severity and UI icons +│ └── lib/ # Bundled JAR dependencies +├── checkmarx-ast-eclipse-plugin-tests/ # Test bundle +│ └── src/test/java/.../tests/ +│ ├── integration/ # Integration tests (auth) +│ ├── ui/ # SWTBot UI tests +│ └── unit/ # Unit tests +├── com.checkmarx.eclipse.feature/ # Eclipse feature descriptor +├── com.checkmarx.eclipse.site/ # Eclipse p2 update site +├── pom.xml # Root Maven/Tycho POM +├── ast-cli-java-wrapper.version # Pinned wrapper version +└── .github/workflows/ # CI/CD pipelines +``` + +--- + +## Technology Stack + +| Layer | Technology | Version | +|-------|-----------|---------| +| Language | Java | 17 (Temurin) | +| IDE Framework | Eclipse OSGi / RCP | 4.11+ | +| UI Toolkit | SWT / JFace | Bundled with Eclipse | +| Build System | Maven + Eclipse Tycho | Tycho 4.0.11 | +| Platform API | ast-cli-java-wrapper | 2.4.23 | +| Event Bus | Google Guava | Bundled with Eclipse | +| Git Integration | JGit | Bundled with Eclipse | +| JSON | Jackson | 2.21.1 | +| Utilities | Apache Commons Lang3 | 3.18.0 | +| Logging | SLF4J + Eclipse ILog (CxLogger) | 2.0.17 | + +--- + +## Development Setup + +### Prerequisites + +1. **Java 17** (Temurin recommended) +2. **Eclipse IDE for RCP and RAP Developers** (2019-03 or later) — includes PDE (Plugin Development Environment) +3. **Maven 3.x** with Tycho support +4. **Checkmarx One account** with an API key (`ast-scanner` + `default-roles` IAM roles) + +### Clone and Import + +```bash +git clone https://github.com/Checkmarx/ast-eclipse-plugin.git +cd ast-eclipse-plugin +``` + +Import into Eclipse: +- `File → Import → Maven → Existing Maven Projects` +- Select the repo root — all four modules will be detected + +### Build from CLI + +```bash +# Full build (plugin + feature + site + tests) +mvn clean verify + +# Build plugin only (skip tests) +mvn clean package -pl checkmarx-ast-eclipse-plugin -am -DskipTests +``` + +### Run in Development + +1. Open `checkmarx-ast-eclipse-plugin/plugin.xml` in Eclipse +2. Click **Launch an Eclipse Application** (creates a new Eclipse instance with the plugin loaded) +3. Configure credentials: `Window → Preferences → Checkmarx` + +### Run Tests + +```bash +# UI tests (requires Xvfb on Linux) +Xvfb -ac :99 -screen 0 1920x1080x16 & +mvn verify -Dtest.includes="**/ui/*.java" \ + -DCX_BASE_URI= -DCX_TENANT= \ + -DCX_APIKEY= -DCX_TEST_SCAN= + +# Unit tests only +mvn test -pl checkmarx-ast-eclipse-plugin-tests +``` + +--- + +## Coding Standards + +- **Java 17** language level — use modern constructs (streams, lambdas, records where appropriate) +- **Logging:** Always use `CxLogger` (Eclipse ILog wrapper), never raw `System.out` or SLF4J directly in plugin code. SLF4J is available only for passing to the CLI wrapper internals. +- **UI thread safety:** All SWT widget updates must happen on the UI thread. Use `UISynchronizeImpl.asyncExec()` for background-to-UI transitions. +- **EventBus events:** Post events via `pluginEventBus.post(new PluginListenerDefinition(...))`. Subscribe with `@Subscribe`. Never call UI update methods directly from non-UI threads. +- **Constants:** Add all string literals used in UI or logic to `PluginConstants.java`. Never hardcode strings inline. +- **SWT layout:** Use `GridData`/`GridLayout` for all composites. Avoid fixed `widthHint` on combos that may contain variable-length content — use `SWT.FILL` with `grabExcessHorizontalSpace = true` instead. +- **Null safety:** Check `selectedItem.getResult()` and `selectedItem.getSeverity()` before accessing them — tree nodes may be group-level nodes with no attached result. + +--- + +## Project Rules + +- **All PRs target `main`** (or an integration branch when batching multiple bug fixes). +- **Branch naming:** + - Bug fixes: `bug/AST-XXXXX` + - Features: `feature/AST-XXXXX` + - Documentation: `docs/AST-XXXXX` + - Other: `other/AST-XXXXX` +- **Commit messages** must reference the Jira ticket: `Fix AST-XXXXX: ` +- **Never commit secrets.** Checkmarx credentials are injected via environment variables or Eclipse preferences at runtime — never hardcoded. +- **Wrapper version** is pinned in `ast-cli-java-wrapper.version`. Update this file and the JAR in `lib/` when upgrading the CLI wrapper. +- **Icons** must be placed in `checkmarx-ast-eclipse-plugin/icons/` and registered in `plugin.xml` if used as action images. +- **PR size:** Keep PRs focused on a single ticket. Use an integration branch to batch multiple related fixes before merging to main. + +--- + +## Testing Strategy + +### Test Types + +| Type | Location | Runner | Purpose | +|------|----------|--------|---------| +| Unit | `unit/` | JUnit | Test logic in isolation (DataProvider, FilterState, PluginUtils) | +| UI (SWTBot) | `ui/` | SWTBot + JUnit | Test full plugin behavior inside a headless Eclipse instance | +| Integration | `integration/` | JUnit | Test authentication and API connectivity against a real Checkmarx One tenant | + +### CI Triggers + +- All tests run on **every PR to `main`** via GitHub Actions (`.github/workflows/ci.yml`) +- UI tests run on **Ubuntu** with **Xvfb** (virtual display) +- Integration tests require secrets: `CX_BASE_URI`, `CX_TENANT`, `CX_APIKEY`, `CX_TEST_SCAN` + +### Coverage + +- JaCoCo coverage reports generated per run +- Reports uploaded as GitHub Actions artifacts +- Coverage badge auto-generated via `cicirello/jacoco-badge-generator` + +--- + +## External Integrations + +| Integration | Purpose | How | +|-------------|---------|-----| +| **Checkmarx One Platform** | Fetch projects, branches, scans, results; submit triage | Via `ast-cli-java-wrapper` (wraps the Checkmarx CLI binary) | +| **JGit** | Detect current git branch to auto-select in branch combo | `RefsChangedListener` on local repo | +| **Eclipse Marketplace** | Plugin distribution and install | p2 update site published on release | +| **Codebashing** | Remediation lesson links per vulnerability | REST call to Checkmarx Codebashing API | + +--- + +## Deployment + +### Release Process + +Releases are created via `.github/workflows/release.yml` (triggered manually or via `workflow_call`): + +1. Input: `tag` (semver), `jira_ticket`, optional `rbranch` for dev releases +2. Tycho builds the p2 update site into `com.checkmarx.eclipse.site/target/` +3. Site artifact is published as a GitHub Release +4. Dev releases are cleaned up automatically before publishing a stable release + +### Distribution + +- **Eclipse Marketplace:** [checkmarx-ast-plugin](https://marketplace.eclipse.org/content/checkmarx-ast-plugin) +- **p2 Update Site:** published as a GitHub Release asset + +### Install (End Users) + +``` +Help → Install New Software → Add repository URL (GitHub Release asset) +``` + +--- + +## Security & Access + +- **API Key authentication:** Users configure a Checkmarx One API key in `Window → Preferences → Checkmarx`. The key is stored in the Eclipse secure preferences store. +- **Required roles:** `ast-scanner` (composite role) + `default-roles` IAM role on the Checkmarx One tenant. +- **No credentials in code:** All secrets are injected at runtime via preferences or environment variables (CI). Never commit API keys or tokens. +- **TLS:** All communication with Checkmarx One is HTTPS, enforced by the CLI wrapper. +- **Triage permissions:** Triage actions (severity/state changes) require the user's API key to have write permissions on the project. + +--- + +## Logging + +The plugin uses two logging mechanisms — use the right one for the right context: + +| Logger | Class | Output | When to use | +|--------|-------|--------|-------------| +| `CxLogger` | `com.checkmarx.eclipse.utils.CxLogger` | Eclipse Error Log view + `.metadata/.log` | All plugin-level log messages | +| SLF4J | `org.slf4j.Logger` | No-op inside OSGi (dropped) | Only for passing to `CxWrapper` internals | + +**Usage:** +```java +CxLogger.info("Loading results for scan: " + scanId); +CxLogger.error("Failed to fetch projects: " + e.getMessage(), e); +CxLogger.warning("Could not fetch platform states: " + e.getMessage()); +``` + +**Viewing logs:** +- Eclipse IDE: `Window → Show View → Error Log` +- File: `/.metadata/.log` + +--- + +## Debugging Steps + +### Plugin not loading + +1. Check `Window → Show View → Error Log` for bundle activation errors +2. Verify Java 17 is set as the JRE: `Window → Preferences → Java → Installed JREs` +3. Confirm the plugin is enabled: `Help → About Eclipse → Installation Details` + +### Authentication failures + +1. Verify API key in `Window → Preferences → Checkmarx` — click **Authenticate** +2. Check Error Log for `CxLogger` messages containing `authentication` or `CxException` +3. Confirm the API key has `ast-scanner` + `default-roles` roles on the tenant + +### No results / empty tree + +1. Confirm project, branch, and scan ID are selected in the top combos +2. Check filter state — all severity filters may be disabled (toolbar toggle buttons) +3. Check Error Log for errors from `DataProvider.getResultsForScanId()` + +### UI not updating after filter change + +1. Confirm you are on a build that includes the AST-136035 fix +2. If the tree collapses entirely, check that `FILTER_CHANGED` calls `updateResultsTree(..., true)` + +### Custom state dropdown overflow + +1. Fixed in AST-137779 — ensure you are on a build that includes the `truncate()` fix in `ActionFilterStatePreference` + +### Running UI tests locally (Linux) + +```bash +Xvfb -ac :99 -screen 0 1920x1080x16 & +export DISPLAY=:99.0 +mvn verify -Dtest.includes="**/ui/*.java" \ + -DCX_BASE_URI=$CX_BASE_URI \ + -DCX_TENANT=$CX_TENANT \ + -DCX_APIKEY=$CX_APIKEY \ + -DCX_TEST_SCAN=$CX_TEST_SCAN +``` + +--- + +## Known Issues + +| Issue | Ticket | Status | +|-------|--------|--------| +| Severity filter clears description/attack vector panels | AST-136035 | Fixed | +| Severity filter collapses entire results tree | AST-136035 | Fixed | +| Authentication logs not routed to Eclipse Error Log | AST-136023 | Fixed | +| Custom State dropdown occupies entire screen | AST-137779 | Fixed | +| Scan ID combo overflows window on small screens | AST-136035 | Fixed | +| New scan ID not marked as latest in scan list after notification | AST-137779 | Open | + +--- + +*Generated for AST-146800 · Checkmarx Integrations Team* diff --git a/ast-cli-java-wrapper.version b/ast-cli-java-wrapper.version index 88b796b8..0cb980f1 100644 --- a/ast-cli-java-wrapper.version +++ b/ast-cli-java-wrapper.version @@ -1 +1 @@ -2.4.23 +2.4.24 diff --git a/checkmarx-ast-eclipse-plugin-tests/src/test/java/checkmarx/ast/eclipse/plugin/tests/ui/BaseUITest.java b/checkmarx-ast-eclipse-plugin-tests/src/test/java/checkmarx/ast/eclipse/plugin/tests/ui/BaseUITest.java index 2211c71b..175febc8 100644 --- a/checkmarx-ast-eclipse-plugin-tests/src/test/java/checkmarx/ast/eclipse/plugin/tests/ui/BaseUITest.java +++ b/checkmarx-ast-eclipse-plugin-tests/src/test/java/checkmarx/ast/eclipse/plugin/tests/ui/BaseUITest.java @@ -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"; diff --git a/checkmarx-ast-eclipse-plugin-tests/src/test/java/checkmarx/ast/eclipse/plugin/tests/unit/runner/AuthenticatorTest.java b/checkmarx-ast-eclipse-plugin-tests/src/test/java/checkmarx/ast/eclipse/plugin/tests/unit/runner/AuthenticatorTest.java index 740e12a6..3df473f4 100644 --- a/checkmarx-ast-eclipse-plugin-tests/src/test/java/checkmarx/ast/eclipse/plugin/tests/unit/runner/AuthenticatorTest.java +++ b/checkmarx-ast-eclipse-plugin-tests/src/test/java/checkmarx/ast/eclipse/plugin/tests/unit/runner/AuthenticatorTest.java @@ -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 { @@ -24,14 +26,15 @@ void testDoAuthenticationSuccess() throws Exception { try (MockedConstruction mocked = Mockito.mockConstruction(CxWrapper.class, - (mock, context) -> when(mock.authValidate()).thenReturn("SUCCESS"))) { + (mock, context) -> when(mock.authValidate()).thenReturn("SUCCESS")); + MockedStatic 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"))); } } @@ -43,17 +46,18 @@ void testDoAuthenticationIOException() throws Exception { try (MockedConstruction mocked = Mockito.mockConstruction(CxWrapper.class, (mock, context) -> when(mock.authValidate()) - .thenThrow(new IOException("IO error")))) { + .thenThrow(new IOException("IO error"))); + MockedStatic 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) + )); } } @@ -65,17 +69,18 @@ void testDoAuthenticationInterruptedException() throws Exception { try (MockedConstruction mocked = Mockito.mockConstruction(CxWrapper.class, (mock, context) -> when(mock.authValidate()) - .thenThrow(new InterruptedException("Interrupted")))) { + .thenThrow(new InterruptedException("Interrupted"))); + MockedStatic 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) + )); } } @@ -87,17 +92,18 @@ void testDoAuthenticationCxException() throws Exception { try (MockedConstruction mocked = Mockito.mockConstruction(CxWrapper.class, (mock, context) -> when(mock.authValidate()) - .thenThrow(new CxException(1, "Cx error")))) { + .thenThrow(new CxException(1, "Cx error"))); + MockedStatic 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) + )); } } diff --git a/checkmarx-ast-eclipse-plugin/.classpath b/checkmarx-ast-eclipse-plugin/.classpath index 11e91569..13cfdfcd 100644 --- a/checkmarx-ast-eclipse-plugin/.classpath +++ b/checkmarx-ast-eclipse-plugin/.classpath @@ -12,7 +12,7 @@ - + diff --git a/checkmarx-ast-eclipse-plugin/META-INF/MANIFEST.MF b/checkmarx-ast-eclipse-plugin/META-INF/MANIFEST.MF index 5cfffce7..d19780e5 100644 --- a/checkmarx-ast-eclipse-plugin/META-INF/MANIFEST.MF +++ b/checkmarx-ast-eclipse-plugin/META-INF/MANIFEST.MF @@ -30,6 +30,6 @@ Bundle-ClassPath: ., lib/jackson-core-2.21.1.jar, lib/jackson-databind-2.21.1.jar, lib/commons-lang3-3.18.0.jar, - lib/ast-cli-java-wrapper-2.4.23.jar, + lib/ast-cli-java-wrapper-2.4.24.jar, lib/org.eclipse.mylyn.commons.ui_4.9.0.v20251121-0615.jar, lib/org-eclipse-mylyn-commons-core.jar diff --git a/checkmarx-ast-eclipse-plugin/build.properties b/checkmarx-ast-eclipse-plugin/build.properties index d8501be9..680259c9 100644 --- a/checkmarx-ast-eclipse-plugin/build.properties +++ b/checkmarx-ast-eclipse-plugin/build.properties @@ -8,7 +8,7 @@ bin.includes = plugin.xml,\ lib/jackson-annotations-2.21.jar,\ lib/jackson-core-2.21.1.jar,\ lib/commons-lang3-3.18.0.jar,\ - lib/ast-cli-java-wrapper-2.4.23.jar,\ + lib/ast-cli-java-wrapper-2.4.24.jar,\ lib/org.eclipse.mylyn.commons.ui_4.9.0.v20251121-0615.jar,\ lib/jackson-databind-2.21.1.jar,\ .,\ diff --git a/checkmarx-ast-eclipse-plugin/lib/.gitattributes b/checkmarx-ast-eclipse-plugin/lib/.gitattributes index 34a12683..b9b6fd84 100644 --- a/checkmarx-ast-eclipse-plugin/lib/.gitattributes +++ b/checkmarx-ast-eclipse-plugin/lib/.gitattributes @@ -1 +1,15 @@ checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.1.8.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.0.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.1.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.2.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.3.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.4.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.9.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.14-oss.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.15.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.16-dev.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.18.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.20.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.21.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.23.jar filter=lfs diff=lfs merge=lfs -text +checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.24.jar filter=lfs diff=lfs merge=lfs -text diff --git a/checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.23.jar b/checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.23.jar deleted file mode 100644 index 7097bf5f..00000000 --- a/checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.23.jar +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dcb4f3c947c76a2499e99e0550623e05a7773ab614eb6793432f7ffb9638c787 -size 135802454 diff --git a/checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.24.jar b/checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.24.jar new file mode 100644 index 00000000..b4e1e934 --- /dev/null +++ b/checkmarx-ast-eclipse-plugin/lib/ast-cli-java-wrapper-2.4.24.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e664771fd767accd5bd47057c5a6d4cc86d292c93191200d061ded6e3e527bdf +size 135732567 diff --git a/checkmarx-ast-eclipse-plugin/plugin.xml b/checkmarx-ast-eclipse-plugin/plugin.xml index 362a4c37..e0f787b1 100644 --- a/checkmarx-ast-eclipse-plugin/plugin.xml +++ b/checkmarx-ast-eclipse-plugin/plugin.xml @@ -39,4 +39,8 @@ + + + + diff --git a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/properties/PreferencesPage.java b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/properties/PreferencesPage.java index 49cb12d8..3c5af098 100644 --- a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/properties/PreferencesPage.java +++ b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/properties/PreferencesPage.java @@ -137,7 +137,7 @@ 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); })); @@ -145,6 +145,15 @@ public void widgetSelected(SelectionEvent e) { }); } + + + 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()); } diff --git a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/runner/Authenticator.java b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/runner/Authenticator.java index 9484950e..202baa99 100644 --- a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/runner/Authenticator.java +++ b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/runner/Authenticator.java @@ -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(); } } diff --git a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/startup/PluginStartup.java b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/startup/PluginStartup.java new file mode 100644 index 00000000..e520f992 --- /dev/null +++ b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/startup/PluginStartup.java @@ -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); + } + }); + } +} diff --git a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/utils/PluginConstants.java b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/utils/PluginConstants.java index ad48cd29..524b1136 100644 --- a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/utils/PluginConstants.java +++ b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/utils/PluginConstants.java @@ -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."; diff --git a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/CheckmarxView.java b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/CheckmarxView.java index 43c16a47..6ccb14d1 100644 --- a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/CheckmarxView.java +++ b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/CheckmarxView.java @@ -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; @@ -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(); @@ -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); @@ -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 + } + }); } /** @@ -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() { @@ -1264,13 +1304,31 @@ protected IStatus run(IProgressMonitor arg0) { List 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 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); @@ -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); @@ -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; @@ -2489,9 +2550,15 @@ private void listener(PluginListenerDefinition definition) { private void updateResultsTree(List 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 expandedDMNames = new HashSet<>(); diff --git a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/DataProvider.java b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/DataProvider.java index d0229325..efe9f5e2 100644 --- a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/DataProvider.java +++ b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/DataProvider.java @@ -112,11 +112,27 @@ public List 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 getProjects(String projectName) throws Exception { List projectList = new ArrayList(); diff --git a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/actions/ActionFilterStatePreference.java b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/actions/ActionFilterStatePreference.java index f67d6899..4482e6f5 100644 --- a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/actions/ActionFilterStatePreference.java +++ b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/actions/ActionFilterStatePreference.java @@ -5,16 +5,21 @@ import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuCreator; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MenuAdapter; +import org.eclipse.swt.events.MenuEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.ToolItem; +import org.eclipse.swt.widgets.ToolTip; import com.checkmarx.eclipse.Activator; import com.checkmarx.eclipse.enums.ActionName; @@ -27,6 +32,9 @@ class ActionFilterStatePreference extends Action implements IMenuCreator { private Menu menu; + private ToolTip activeTip; + private Listener armFilter; + private Runnable tipTimer; private static final String ACTION_FILTER_STATE_TOOLTIP = "State"; private static final String ACTION_FILTER_STATE_ICON_PATH = "/icons/filter_ps.png"; private EventBus pluginEventBus; @@ -75,6 +83,12 @@ public Menu getMenu(final Control parent) { menu.dispose(); } menu = new Menu(parent); + menu.addMenuListener(new MenuAdapter() { + @Override + public void menuHidden(MenuEvent e) { + disposeActiveTip(); + } + }); createMenuItem(menu, FILTER_CONFIRMED, FilterState.confirmed, State.CONFIRMED); createMenuItem(menu, FILTER_NOT_EXPLOITABLE, FilterState.notExploitable, State.NOT_EXPLOITABLE); createMenuItem(menu, FILTER_PROPOSED_NON_EXPLOITABLE, FilterState.proposedNotExploitable, @@ -89,8 +103,19 @@ public Menu getMenu(final Control parent) { for (String customState : customStates) { MenuItem item = new MenuItem(menu, SWT.CHECK); - item.setText(customState); + item.setText(truncate(customState)); item.setSelection(FilterState.isCustomStateSelected(customState)); + if (customState.length() > 50) { + item.addArmListener(e -> { + disposeActiveTip(); + activeTip = new ToolTip(menu.getShell(), SWT.NONE); + activeTip.setMessage(customState); + Point loc = Display.getCurrent().getCursorLocation(); + activeTip.setLocation(loc.x + 16, loc.y + 16); + activeTip.setVisible(true); + installArmFilter(item); + }); + } item.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { @@ -127,4 +152,35 @@ public void widgetSelected(SelectionEvent e) { public Menu getMenu(final Menu parent) { return null; } + + private void installArmFilter(MenuItem armedItem) { + Display d = Display.getCurrent(); + if (armFilter != null) { + d.removeFilter(SWT.Arm, armFilter); + } + armFilter = event -> { if (event.widget != armedItem) disposeActiveTip(); }; + d.addFilter(SWT.Arm, armFilter); + tipTimer = this::disposeActiveTip; + d.timerExec(1800, tipTimer); + } + + private void disposeActiveTip() { + Display d = Display.getCurrent(); + if (armFilter != null) { + d.removeFilter(SWT.Arm, armFilter); + armFilter = null; + } + if (tipTimer != null) { + d.timerExec(-1, tipTimer); + tipTimer = null; + } + if (activeTip != null && !activeTip.isDisposed()) { + activeTip.dispose(); + } + activeTip = null; + } + + private static String truncate(String text) { + return text.length() > 50 ? text.substring(0, 47) + "..." : text; + } } \ No newline at end of file diff --git a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/actions/ActionStartScan.java b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/actions/ActionStartScan.java index 43a5cb9c..972a5d68 100644 --- a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/actions/ActionStartScan.java +++ b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/actions/ActionStartScan.java @@ -220,7 +220,7 @@ private String getCurrentGitBranch() { */ private boolean cxProjectMatchesWorkspaceProject() { Results results = DataProvider.getInstance().getCurrentResults(); - boolean noResultsInScan = results == null || results.getResults().isEmpty(); + boolean noResultsInScan = results == null || results.getResults() == null || results.getResults().isEmpty(); boolean noFilesInWorkspace = ResourcesPlugin.getWorkspace().getRoot().getProjects().length == 0; if (noResultsInScan || noFilesInWorkspace) { diff --git a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/filters/FilterState.java b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/filters/FilterState.java index a3c41d05..e5957112 100644 --- a/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/filters/FilterState.java +++ b/checkmarx-ast-eclipse-plugin/src/com/checkmarx/eclipse/views/filters/FilterState.java @@ -15,8 +15,8 @@ public class FilterState { public static boolean critical = true; public static boolean high = true; public static boolean medium = true; - public static boolean low = false; - public static boolean info = false; + public static boolean low = true; + public static boolean info = true; public static boolean groupBySeverity = true; public static boolean groupByQueryName = false; public static boolean groupByStateName = false; @@ -42,8 +42,8 @@ public static void loadFiltersFromSettings() { critical = Boolean.parseBoolean(GlobalSettings.getFromPreferences(Severity.CRITICAL.name(), "true")); high = Boolean.parseBoolean(GlobalSettings.getFromPreferences(Severity.HIGH.name(), "true")); medium = Boolean.parseBoolean(GlobalSettings.getFromPreferences(Severity.MEDIUM.name(), "true")); - low = Boolean.parseBoolean(GlobalSettings.getFromPreferences(Severity.LOW.name(), "false")); - info = Boolean.parseBoolean(GlobalSettings.getFromPreferences(Severity.INFO.name(), "false")); + low = Boolean.parseBoolean(GlobalSettings.getFromPreferences(Severity.LOW.name(), "true")); + info = Boolean.parseBoolean(GlobalSettings.getFromPreferences(Severity.INFO.name(), "true")); groupBySeverity = Boolean .parseBoolean(GlobalSettings.getFromPreferences(Severity.GROUP_BY_SEVERITY.name(), "true")); groupByQueryName = Boolean