Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,15 @@ You can set the vulnerability severity alert level to `Error` or `Warning` for i
Default: `true`

#### Exclude manifests from analysis:
Specify glob patterns for manifests to be ignored for background analysis e.g. `**/test/**/package.json` will ignore all package.json files within `test/` or any subdirectories of it.
Specify glob patterns for manifests to be ignored for background analysis e.g. `**/test/**/package.json` will ignore all package.json files within `test/` or any subdirectories of it. These patterns are also propagated to the batch workspace analysis command as discovery ignore patterns.

**NOTE:** Only forward slash (`/`) is supported as a path separator. Please use forward slash as the path separator even for Windows paths.

#### Batch Workspace Analysis:
* `batchConcurrency` : Maximum number of parallel SBOM generations during batch workspace analysis. Default is `10`.
* `continueOnError` : When `true`, batch analysis skips failing packages and continues. When `false`, stops on the first error. Default is `true`.
* `batchMetadata` : When `true`, batch analysis includes metadata with per-package error details in the response. Default is `true`.

## Features

- **Component analysis**
Expand Down Expand Up @@ -206,6 +211,11 @@ Specify glob patterns for manifests to be ignored for background analysis e.g. `
* `podman.executable.path`: Specify the absolute path of `podman` executable
* `image.platform`: Specify the platform used for multi-arch images

- **Batch workspace analysis**
<br >Analyze all packages in a JavaScript/TypeScript monorepo or Cargo workspace at once using the _Red Hat Dependency Analytics Batch Report (Workspace)..._ command from the Command Palette.
The command detects the workspace root, discovers all sub-packages (via `pnpm-workspace.yaml`, `package.json` workspaces, or `cargo metadata`), generates SBOMs in parallel, and produces a combined analysis report.
Existing exclude patterns from `redHatDependencyAnalytics.exclude` are automatically applied to workspace package discovery.

- **Excluding dependencies with `exhortignore`**
<br >You can exclude a package from analysis by marking the package for exclusion.
How you exclude a package varies based on the your project's language:
Expand Down
48 changes: 36 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 26 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
"workspaceContains:**/build.gradle",
"workspaceContains:**/Cargo.toml",
"workspaceContains:**/Dockerfile",
"workspaceContains:**/Containerfile"
"workspaceContains:**/Containerfile",
"onCommand:rhda.stackAnalysisBatch"
],
"main": "./dist/extension",
"contributes": {
Expand Down Expand Up @@ -77,6 +78,11 @@
"command": "rhda.stackLogs",
"title": "Debug logs",
"category": "Red Hat Dependency Analytics"
},
{
"command": "rhda.stackAnalysisBatch",
"title": "Red Hat Dependency Analytics Batch Report (Workspace)...",
"category": "Red Hat Dependency Analytics"
}
],
"menus": {
Expand Down Expand Up @@ -401,6 +407,24 @@
},
"description": "List of path globs for manifests to ignore for analysis. Only forward slash is support as a path separator."
},
"redHatDependencyAnalytics.batchConcurrency": {
"type": "number",
"default": 10,
"description": "Maximum number of parallel SBOM generations during batch workspace analysis.",
"scope": "window"
},
"redHatDependencyAnalytics.continueOnError": {
"type": "boolean",
"default": true,
"description": "When true, batch analysis skips failing packages and continues. When false, stops on the first error.",
"scope": "window"
},
"redHatDependencyAnalytics.batchMetadata": {
"type": "boolean",
"default": true,
"description": "When true, batch analysis includes metadata with per-package error details in the response.",
"scope": "window"
},
"redHatDependencyAnalytics.oidc.endpoint": {
"type": "string",
"default": "https://sso.redhat.com/auth/realms/redhat-external",
Expand Down Expand Up @@ -475,7 +499,7 @@
"dependencies": {
"@redhat-developer/vscode-redhat-telemetry": "^0.8.0",
"@trustify-da/trustify-da-api-model": "^2.0.7",
"@trustify-da/trustify-da-javascript-client": "0.3.0-ea.608d6fa",
"@trustify-da/trustify-da-javascript-client": "0.3.0-ea.b8af0f8",
"@xml-tools/ast": "^5.0.5",
"@xml-tools/parser": "^1.0.11",
"cli-table3": "^0.6.5",
Expand Down
62 changes: 62 additions & 0 deletions src/batchAnalysis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use strict';

import * as vscode from 'vscode';

import { StatusMessages, Titles } from './constants';
import { buildBaseOptions, batchStackAnalysisService, BatchOptions } from './exhortServices';
import { globalConfig } from './config';
import { updateCurrentWebviewPanel } from './rhda';
import { buildLogErrorMessage } from './utils';
import { DepOutputChannel } from './depOutputChannel';
import { DependencyReportPanel } from './dependencyReportPanel';
import { TokenProvider } from './tokenProvider';

/**
* Executes the RHDA batch stack analysis process for a workspace.
* @param tokenProvider The token provider for authentication.
* @param workspaceRoot The file path to the workspace root directory.
* @param outputChannel The output channel for logging.
* @returns The batch stack analysis response string.
*/
export async function executeBatchStackAnalysis(tokenProvider: TokenProvider, workspaceRoot: string, outputChannel: DepOutputChannel): Promise<string> {
return await vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: Titles.EXT_TITLE }, async p => {
p.report({ message: StatusMessages.WIN_ANALYZING_DEPENDENCIES });

const options: BatchOptions = {
...buildBaseOptions(),
'TRUSTIFY_DA_TOKEN': await tokenProvider.getToken() ?? '',
'batchConcurrency': globalConfig.batchConcurrency,
'continueOnError': globalConfig.continueOnError,
'batchMetadata': globalConfig.batchMetadata,
'workspaceDiscoveryIgnore': globalConfig.excludePatterns.map(m => m.pattern),
};

try {
outputChannel.info(`generating batch stack analysis report for workspace "${workspaceRoot}"`);

DependencyReportPanel.createOrShowWebviewPanel();

const promise = batchStackAnalysisService(workspaceRoot, options);

p.report({ message: StatusMessages.WIN_GENERATING_DEPENDENCIES });

const resp = await promise;

updateCurrentWebviewPanel(resp);

outputChannel.info(`done generating batch stack analysis report for workspace "${workspaceRoot}"`);

p.report({ message: StatusMessages.WIN_SUCCESS_DEPENDENCY_ANALYSIS });

return resp;
} catch (err) {
p.report({ message: StatusMessages.WIN_FAILURE_DEPENDENCY_ANALYSIS });

updateCurrentWebviewPanel('error');

outputChannel.error(buildLogErrorMessage(err as Error));

throw err;
}
});
}
3 changes: 2 additions & 1 deletion src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export const STACK_ANALYSIS_FROM_PIE_BTN_COMMAND = 'rhda.stackAnalysisFromPieBtn
export const STACK_ANALYSIS_FROM_EDITOR_COMMAND = 'rhda.stackAnalysisFromEditor';
export const STACK_LOGS_COMMAND = 'rhda.stackLogs';
export const TRACK_RECOMMENDATION_ACCEPTANCE_COMMAND = 'rhda.trackRecommendationAcceptance';
export const LLM_MODELS_ANALYSIS_REPORT = 'rhda.llmModelsAnalysisReport';
export const LLM_MODELS_ANALYSIS_REPORT = 'rhda.llmModelsAnalysisReport';
export const STACK_ANALYSIS_BATCH_COMMAND = 'rhda.stackAnalysisBatch';
6 changes: 6 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ class Config {
exhortImagePlatform!: string;
excludePatterns!: Minimatch[];
licenseCheckEnabled!: boolean;
batchConcurrency!: number;
continueOnError!: boolean;
batchMetadata!: boolean;

private readonly DEFAULT_MVN_EXECUTABLE = 'mvn';
private readonly DEFAULT_GRADLE_EXECUTABLE = 'gradle';
Expand Down Expand Up @@ -149,6 +152,9 @@ class Config {
this.oidcClientId = rhdaConfig.get('oidc.clientId', 'rhda-vscode');
this.oidcAllowInsecure = rhdaConfig.get('oidc.allowInsecure', false);
this.licenseCheckEnabled = rhdaConfig.get('licenseCheckEnabled', true);
this.batchConcurrency = rhdaConfig.get('batchConcurrency', 10);
this.continueOnError = rhdaConfig.get('continueOnError', true);
this.batchMetadata = rhdaConfig.get('batchMetadata', true);
}

private getEffectiveHttpProxyUrl(): string {
Expand Down
Loading
Loading