Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/IJ-latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: 17
java-version: 21
distribution: 'temurin'
cache: 'gradle'
- name: Grant execute permission for gradlew
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/IJ.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: 17
java-version: 21
distribution: 'temurin'
cache: 'gradle'
- name: Grant execute permission for gradlew
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:

steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: 17
java-version: 21
distribution: 'temurin'
cache: 'gradle'
- name: Grant execute permission for gradlew
Expand All @@ -34,10 +34,10 @@ jobs:

steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: 17
java-version: 21
distribution: 'temurin'
cache: 'gradle'
- name: Grant execute permission for gradlew
Expand All @@ -53,10 +53,10 @@ jobs:

steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: 17
java-version: 21
distribution: 'temurin'
cache: 'gradle'
- name: Grant execute permission for gradlew
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-marketplace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: 17
java-version: 21
distribution: 'temurin'
cache: 'gradle'

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: 17
java-version: 21
distribution: 'temurin'
cache: 'gradle'
- name: Grant execute permission for gradlew
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ jobs:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install Java 17
- name: Install Java 21
uses: actions/setup-java@v3
with:
java-version: 17
java-version: 21
distribution: 'oracle'
cache: 'gradle'

Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ according to your preferences.
- **Proxy Configuration** :
<br >From IntelliJ IDEA Appearance & Behavior > System Settings > HTTP Proxy, you can configure a static proxy for all HTTP requests made by the plugin. This is useful when your environment requires going through a proxy to access external services. For example:`http://proxy.example.com:8080`

- **Batch Analysis** :
<br >Configure settings for batch workspace analysis, which analyzes all packages in a JS/TS monorepo or Cargo workspace at once.
<br >**Concurrency**: Maximum number of concurrent analyses during batch workspace analysis (default: 10).
<br >**Continue on Error**: Continue analyzing remaining packages when one package analysis fails (default: enabled).
<br >**Include Metadata**: Include additional metadata in batch analysis results (default: enabled).

- **Manifest Exclusion Patterns** :
<br >You can exclude manifest files from component analysis using glob patterns. This is useful for excluding third-party dependencies, test files, or other manifests that should not be analyzed.
<br >Enter one pattern per line. Examples: `**/node_modules/**/package.json` to exclude all package.json files in node_modules directories, or `test/**/pom.xml` to exclude all Maven files in test directories.
Expand Down Expand Up @@ -396,6 +402,16 @@ When modifying the grammar or lexer files, you need to regenerate the parser cla
<br >Right-click on any manifest file and select **Exclude from Component Analysis** to quickly add an exclusion pattern for that specific file.


- **Batch Workspace Analysis**
<br >For JS/TS monorepos (npm, pnpm, yarn workspaces) and Cargo workspaces, you can run a batch analysis that scans
all packages in the workspace at once and generates a combined vulnerability report.
<br >To run a batch analysis, right-click in the **Project** window and click **Batch Workspace Analysis Report**.
<br >The workspace root must contain a supported workspace layout:
- JS/TS workspace: `package.json` with a lock file (`package-lock.json`, `pnpm-lock.yaml`, or `yarn.lock`)
- Cargo workspace: `Cargo.toml` with `Cargo.lock`
<br >Exclusion patterns configured in **Manifest Exclusion Patterns** are applied during workspace discovery to skip
specific packages from the batch analysis.

- **Red Hat Dependency Analytics report**
<br >The Red Hat Dependency Analytics report is a temporary HTML file that exist if the **Red Hat Dependency Analytics
Report** tab remains open.
Expand Down
2 changes: 2 additions & 0 deletions USAGE_DATA.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@
* when plugin is started
* when plugin analyse dependency file for vulnerability(s) and file name
* when plugin analyse dependency file fails, error message and file name
* when plugin runs batch workspace analysis on a workspace root
* when plugin batch workspace analysis fails, error message
* when plugin is shutdown
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ version = providers.gradleProperty("projectVersion").get() // Plugin version
val platformVersion = providers.gradleProperty("ideaVersion").get()
// Set the JVM language level used to build the project.
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
Comment on lines +18 to +19

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Java target set to 21 📎 Requirement gap ⚙ Maintainability

The build configuration changes the project source/target compatibility to Java 21, which violates
the repository convention requirement to target Java 17.
Agent Prompt
## Issue description
The project is configured to build with Java 21, but the repository convention requires Java 17.

## Issue Context
This PR changed Gradle `sourceCompatibility`/`targetCompatibility` to `VERSION_21`.

## Fix Focus Areas
- build.gradle.kts[17-18]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This change is required because trustify-da-java-client 0.0.16-SNAPSHOT is compiled with maven.compiler.release=21 (upgraded in guacsec/trustify-da-java-client#390). Building with Java 17 fails with class file has wrong version 65.0, should be 61.0. We need to match the client's Java target to use the batch API.

withSourcesJar()
withJavadocJar()
}
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ caffeine = "3.1.8"
commons-compress = "1.21"
commons-io = "2.16.1"
trustify-da-api-spec = "2.0.2"
trustify-da-java-client = "0.0.15"
trustify-da-java-client = "0.0.16"
github-api = "1.314"
junit = "4.13.2"
mockito = "4.11.0"
mockito = "5.14.2"
packageurl-java = "1.4.1"

# plugins
Expand Down
96 changes: 78 additions & 18 deletions src/main/java/org/jboss/tools/intellij/exhort/ApiService.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
Expand Down Expand Up @@ -87,6 +91,36 @@ public Path getStackAnalysis(final String packageManager, final String manifestN
}
}

/**
* Performs batch stack analysis on all workspace members in the given directory,
* returning the path to a temporary HTML report file.
*
* @param workspacePath the workspace root directory path
* @param ignorePatterns glob patterns for paths to exclude from workspace discovery
* @return the path to the generated HTML report file
*/
public Path getBatchStackAnalysis(final String workspacePath, final List<String> ignorePatterns) {
var telemetryMsg = TelemetryService.instance().action("batch-stack-analysis");
telemetryMsg.property(TelemetryKeys.PLATFORM.toString(), System.getProperty("os.name"));
telemetryMsg.property(TelemetryKeys.TRUST_DA_TOKEN.toString(), ApiSettingsState.getInstance().rhdaToken);

try {
setBatchRequestProperties();
Set<String> ignorePatternsSet = new HashSet<>(ignorePatterns);
var htmlContent = exhortApi.stackAnalysisBatchHtml(Path.of(workspacePath), ignorePatternsSet);
var tmpFile = Files.createTempFile("exhort_batch_", ".html");
Files.write(tmpFile, htmlContent.get());

telemetryMsg.send();
return tmpFile;

} catch (IOException | InterruptedException | ExecutionException exc) {
telemetryMsg.error(exc);
telemetryMsg.send();
throw new RuntimeException(exc);
}
}

public ComponentAnalysisResult getComponentAnalysis(final String packageManager, final String manifestName, final String manifestPath) {
var telemetryMsg = TelemetryService.instance().action("component-analysis");
telemetryMsg.property(TelemetryKeys.ECOSYSTEM.toString(), packageManager);
Expand Down Expand Up @@ -117,7 +151,15 @@ public ComponentAnalysisResult getComponentAnalysis(final String packageManager,
return null;
}

private void setRequestProperties(final String manifestName) {
/**
* Sets up common request properties shared across all analysis types (stack, batch, image).
* Configures the plugin descriptor, backend connection, all tool paths, and proxy settings.
* Not all analysis types use every property configured here (e.g., batch analysis does not use
* Maven/Gradle/Python-specific properties, and image analysis does not use any of the package
* manager tool paths), but setting them unconditionally is harmless as unused properties are
* simply ignored by the backend.
*/
public static void setCommonRequestProperties() {
String ideName = ApplicationInfo.getInstance().getFullApplicationName();
PluginDescriptor pluginDescriptor = PluginManagerCore.getPlugin(PluginId.getId("org.jboss.tools.intellij.analytics"));
if (pluginDescriptor != null) {
Expand Down Expand Up @@ -205,13 +247,6 @@ private void setRequestProperties(final String manifestName) {
} else {
System.clearProperty("TRUSTIFY_DA_CARGO_PATH");
}
if ("go.mod".equals(manifestName)) {
if (settings.goMatchManifestVersions) {
System.setProperty("MATCH_MANIFEST_VERSIONS", "true");
} else {
System.clearProperty("MATCH_MANIFEST_VERSIONS");
}
}
if (settings.usePython2) {
if (settings.pythonPath != null && !settings.pythonPath.isBlank()) {
System.setProperty("TRUSTIFY_DA_PYTHON_PATH", settings.pythonPath);
Expand Down Expand Up @@ -250,16 +285,6 @@ private void setRequestProperties(final String manifestName) {
System.clearProperty("TRUSTIFY_DA_PYTHON_VIRTUAL_ENV");
System.clearProperty("TRUSTIFY_DA_PYTHON_INSTALL_BEST_EFFORTS");
}
if ("requirements.txt".equals(manifestName) || "pyproject.toml".equals(manifestName)) {
if (settings.pythonMatchManifestVersions) {
System.setProperty("MATCH_MANIFEST_VERSIONS", "true");
} else {
System.setProperty("MATCH_MANIFEST_VERSIONS","false");
}
}
if (!"go.mod".equals(manifestName) && !"requirements.txt".equals(manifestName) && !"pyproject.toml".equals(manifestName)) {
System.clearProperty("MATCH_MANIFEST_VERSIONS");
}
if (settings.licenseCheckEnabled) {
System.setProperty("TRUSTIFY_DA_LICENSE_CHECK", "true");
} else {
Expand All @@ -274,6 +299,41 @@ private void setRequestProperties(final String manifestName) {
}
}

private void setRequestProperties(final String manifestName) {
setCommonRequestProperties();

if ("go.mod".equals(manifestName)) {
ApiSettingsState settings = ApiSettingsState.getInstance();
if (settings.goMatchManifestVersions) {
System.setProperty("MATCH_MANIFEST_VERSIONS", "true");
} else {
System.clearProperty("MATCH_MANIFEST_VERSIONS");
}
} else if ("requirements.txt".equals(manifestName)) {
ApiSettingsState settings = ApiSettingsState.getInstance();
if (settings.pythonMatchManifestVersions) {
System.setProperty("MATCH_MANIFEST_VERSIONS", "true");
} else {
System.setProperty("MATCH_MANIFEST_VERSIONS", "false");
}
} else {
System.clearProperty("MATCH_MANIFEST_VERSIONS");
}
}

void setBatchRequestProperties() {
setCommonRequestProperties();

ApiSettingsState settings = ApiSettingsState.getInstance();
if (settings.batchConcurrency != null && !settings.batchConcurrency.isBlank()) {
System.setProperty("TRUSTIFY_DA_BATCH_CONCURRENCY", settings.batchConcurrency);
} else {
System.setProperty("TRUSTIFY_DA_BATCH_CONCURRENCY", "10");
}
System.setProperty("TRUSTIFY_DA_CONTINUE_ON_ERROR", String.valueOf(settings.batchContinueOnError));
System.setProperty("TRUSTIFY_DA_BATCH_METADATA", String.valueOf(settings.batchMetadata));
}

public static void setBackendUrl() {
String backendUrl = System.getenv(TRUSTIFY_DA_BACKEND_URL_PROPERTY);
if (backendUrl == null || backendUrl.isBlank()) {
Expand Down
27 changes: 2 additions & 25 deletions src/main/java/org/jboss/tools/intellij/image/ApiService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@

package org.jboss.tools.intellij.image;

import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.Service;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginDescriptor;
import com.intellij.openapi.extensions.PluginId;
import io.github.guacsec.trustifyda.Api;
import io.github.guacsec.trustifyda.api.v5.AnalysisReport;
import io.github.guacsec.trustifyda.image.ImageRef;
Expand All @@ -29,16 +25,14 @@
import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.jboss.tools.intellij.exhort.ApiService.createExhortApiWithBackendUrl;
import static org.jboss.tools.intellij.exhort.ApiService.getProxyUrl;
import static org.jboss.tools.intellij.exhort.ApiService.setBackendUrl;
import static org.jboss.tools.intellij.exhort.ApiService.setCommonRequestProperties;

@Service(Service.Level.APP)
public final class ApiService {
Expand Down Expand Up @@ -114,19 +108,9 @@ Path getImageAnalysisReport(final Set<ImageRef> imageRefs) {
}

private void setServiceEnvironment() {
var ideName = ApplicationInfo.getInstance().getFullApplicationName();
PluginDescriptor pluginDescriptor = PluginManagerCore.getPlugin(PluginId.getId("org.jboss.tools.intellij.analytics"));
if (pluginDescriptor != null) {
var pluginName = pluginDescriptor.getName() + " " + pluginDescriptor.getVersion();
System.setProperty("TRUST_DA_SOURCE", ideName + " / " + pluginName);
} else {
System.setProperty("TRUST_DA_SOURCE", ideName);
}
setCommonRequestProperties();

var settings = ApiSettingsState.getInstance();
System.setProperty("TRUST_DA_TOKEN", settings.rhdaToken);

setBackendUrl();

if (settings.syftPath != null && !settings.syftPath.isBlank()) {
System.setProperty("TRUSTIFY_DA_SYFT_PATH", settings.syftPath);
Expand Down Expand Up @@ -169,12 +153,5 @@ private void setServiceEnvironment() {
} else {
System.clearProperty("TRUSTIFY_DA_IMAGE_PLATFORM");
}

Optional<String> proxyUrlOpt = getProxyUrl();
if (proxyUrlOpt.isPresent()) {
System.setProperty("TRUSTIFY_DA_PROXY_URL", proxyUrlOpt.get());
} else {
System.clearProperty("TRUSTIFY_DA_PROXY_URL");
}
}
}
Loading
Loading