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
21 changes: 6 additions & 15 deletions ide_extension/vscode/devsecops/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,24 +71,15 @@ Take advantage of the integration with **GitHub Copilot** for an intelligent, as
- Details potential impact and security risks
- Helps you understand the issue before taking action

### 3. 📦 Generate Update Solution *(Dependencies Only)*
### 3. 📦 Generate Update Solution *(Dependencies & Images)*
- **Color:** Orange
- **Icon:** 📦
- **Function:**
- Specific for dependency vulnerabilities
- Generates CLI commands to update affected libraries
- Shows which direct dependencies need upgrading
- Suggests `npm`, `yarn`, or `maven` commands based on project type

### 4. 🤖 Auto-Fix with Agent *(Dependencies Only)*
- **Color:** Green
- **Icon:** 🤖
- **Function:**
- Requires GitHub Copilot Agent mode
- Tries to apply fixes semi-automatically
- Scans files like `package.json`, `pom.xml`, etc.
- Generates a complete prompt with contextual details
- Suggests direct file changes
- Available for dependency vulnerabilities and container image vulnerabilities
- Targets **all** vulnerabilities found in that scan, not just the one you clicked
- Includes a compact CVE + fixed version list per finding (to keep the prompt short) instead of full details for each one
- For dependencies: generates a single consolidated set of CLI commands (`npm`, `yarn`, `maven`, etc.) to update all affected libraries
- For images: generates a single consolidated update plan (base image/package updates, Dockerfile changes) to fix all affected packages

---

Expand Down
22 changes: 16 additions & 6 deletions ide_extension/vscode/devsecops/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"displayName": "DevSecOps Engine Tools",
"publisher": "GrupoBancolombiaOSPO",
"description": "",
"version": "1.27.0",
"version": "1.28.0",
"engines": {
"vscode": "^1.95.0"
},
Expand Down Expand Up @@ -238,8 +238,8 @@
"title": "Generate Dependency Update Solution"
},
{
"command": "devsecops.autoFixDependenciesWithAgent",
"title": "Auto-Fix Dependencies with Copilot Agent"
"command": "devsecops.generateImageUpdate",
"title": "Generate Image Update Solution"
},
{
"command": "devsecops.deleteScanResult",
Expand Down Expand Up @@ -321,9 +321,19 @@
"group": "copilot@3"
},
{
"command": "devsecops.autoFixDependenciesWithAgent",
"when": "view == devsecops-results && viewItem == findingItem-dependencies",
"group": "copilot@4"
"command": "devsecops.fixVulnerabilityWithCopilot",
"when": "view == devsecops-results && viewItem == findingItem-image",
"group": "copilot@1"
},
{
"command": "devsecops.explainVulnerabilityWithCopilot",
"when": "view == devsecops-results && viewItem == findingItem-image",
"group": "copilot@2"
},
{
"command": "devsecops.generateImageUpdate",
"when": "view == devsecops-results && viewItem == findingItem-image",
"group": "copilot@3"
},
{
"command": "devsecops.showGeneralFindingWebview",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export function registerDependenciesScanCommand(
: ErrorHandlingService.isSelfSignedCertificateError(errorMessage)
? "SSL certificate error: self-signed certificate detected. Please update your certificates and try again."
: ErrorHandlingService.isMicroserviceError(errorMessage)
? "The microservice is unavailable or the connection was interrupted. Please try again."
? "The microservice is experiencing high transaction load and the scan was retried automatically, but it still could not complete. Please try again later."
: "Dependencies Scan failed - Check Output for details";
void vscode.window.showErrorMessage(userMessage);
// Mark the scan as failed but keep it visible
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export function registerIacScanCommand(
: ErrorHandlingService.isSelfSignedCertificateError(errorMessage)
? "SSL certificate error: self-signed certificate detected. Please update your certificates and try again."
: ErrorHandlingService.isMicroserviceError(errorMessage)
? "The microservice is unavailable or the connection was interrupted. Please try again."
? "The microservice is experiencing high transaction load and the scan was retried automatically, but it still could not complete. Please try again later."
: "Iac Scan failed - Check Output for details";
void vscode.window.showErrorMessage(userMessage);
// Mark the scan as failed but keep it visible
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export function registerImageScanCommand(
: ErrorHandlingService.isSelfSignedCertificateError(errorMessage)
? "SSL certificate error: self-signed certificate detected. Please update your certificates and try again."
: ErrorHandlingService.isMicroserviceError(errorMessage)
? "The microservice is unavailable or the connection was interrupted. Please try again."
? "The microservice is experiencing high transaction load and the scan was retried automatically, but it still could not complete. Please try again later."
: "Image Scan failed - Check Output for details";
void vscode.window.showErrorMessage(userMessage);
// Mark the scan as failed but keep it visible
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,40 +48,35 @@ export function registerVulnerabilityCopilotCommands(context: vscode.ExtensionCo
}

const finding: Finding = findingItem.finding;

const allFindings: Finding[] = findingItem.allFindings || [];

AiMetricsService.track('generate_dependency_update', finding, 'tree_context_menu');
await generateDependencyUpdateSolution(finding);
await generateDependencyUpdateSolution(finding, allFindings);
}
);

// Command to auto-fix dependencies with Copilot Agent
const autoFixDependenciesCommand = vscode.commands.registerCommand(
'devsecops.autoFixDependenciesWithAgent',
// Command to generate image update solutions
const generateImageUpdateCommand = vscode.commands.registerCommand(
'devsecops.generateImageUpdate',
async (findingItem: any) => {
if (!findingItem || !findingItem.finding) {
void vscode.window.showErrorMessage('No vulnerability selected');
return;
}

const finding: Finding = findingItem.finding;

AiMetricsService.track('auto_fix_with_agent', finding, 'tree_context_menu');
const allFindings: Finding[] = findingItem.allFindings || [];

// Show info message about Agent mode requirement
void vscode.window.showInformationMessage(
'🤖 This feature requires Copilot Chat in AGENT MODE to automatically edit files. Please switch to Agent mode when the chat opens.',
{ modal: false }
);

await autoFixDependenciesWithAgent(finding);
AiMetricsService.track('generate_image_update', finding, 'tree_context_menu');
await generateImageUpdateSolution(finding, allFindings);
}
);

context.subscriptions.push(
fixVulnerabilityCommand,
explainVulnerabilityCommand,
generateDependencyUpdateCommand,
autoFixDependenciesCommand
generateImageUpdateCommand
);
}

Expand Down Expand Up @@ -199,13 +194,13 @@ async function executeVulnerabilityExplanationWithCopilot(finding: Finding, sour
await openCopilotChatWithPrompt(prompt);
}

async function generateDependencyUpdateSolution(finding: Finding): Promise<void> {
const prompt = generateDependencyUpdatePrompt(finding);
async function generateDependencyUpdateSolution(finding: Finding, allFindings: Finding[] = []): Promise<void> {
const prompt = generateDependencyUpdatePrompt(finding, allFindings);
await openCopilotChatWithPrompt(prompt);
}

async function autoFixDependenciesWithAgent(finding: Finding): Promise<void> {
const prompt = generateAutoFixAgentPrompt(finding);
async function generateImageUpdateSolution(finding: Finding, allFindings: Finding[] = []): Promise<void> {
const prompt = generateImageUpdatePrompt(finding, allFindings);
await openCopilotChatWithPrompt(prompt);
}

Expand Down Expand Up @@ -235,7 +230,11 @@ function generateFixPrompt(finding: Finding, sourceType: string): string {
basePrompt += `

**Dependency Vulnerability Context:**
This is a dependency vulnerability that may require updating package versions or changing dependency configurations.`;
This is a dependency vulnerability that may require updating package versions or changing dependency configurations.

If this is a Gradle project and a direct version bump in build.gradle doesn't resolve the vulnerability (common with transitive dependencies), use this alternative mitigation method:

${GRADLE_FORCED_VERSION_GUIDANCE}`;

// Add impact paths if available
if (finding.getAdditionalField('impact_paths_prompt')) {
Expand Down Expand Up @@ -324,94 +323,129 @@ Provide a clear, educational explanation suitable for developers and security te
return basePrompt;
}

function generateDependencyUpdatePrompt(finding: Finding): string {
const vulnerabilityId = finding.getId() || 'Unknown';
const description = finding.getDescription() || 'No description available';
const severity = finding.getSeverity() || 'Unknown';
const GRADLE_FORCED_VERSION_GUIDANCE = `**Gradle Alternative Mitigation (use only if this is a Gradle project):**

let basePrompt = `Dependency Update Strategy
1. Check whether a \`dependencyMgmt.gradle\` file already exists in the project root. If it does NOT exist yet, create it there. This script forces specific versions for transitive dependencies that carry vulnerabilities/conflicts and/or excludes transitive dependencies that are unnecessary or problematic. If the file already exists, reuse it and just add/update the required rules instead of overwriting the rest of its content.

**Vulnerability Details:**
- ID: ${vulnerabilityId}
- Severity: ${severity}
- Description: ${description}`;
2. Its content should look like this:
\`\`\`gradle
// Applied lazily to every configuration of the project
configurations.configureEach {

// Add impact paths with formatting
const impactPathsPrompt = finding.getAdditionalField('impact_paths_prompt');
if (impactPathsPrompt) {
basePrompt += `\n\n**Dependency Chain Analysis:**\n${impactPathsPrompt}`;
}
/**
* -------------------------------
* Force dependency versions
* -------------------------------
*/
resolutionStrategy.eachDependency { DependencyResolveDetails details ->

basePrompt += `
// Example 1: force by group (applies to every dependency of that group)
if (details.requested.group == 'io.example') {
details.useVersion("\${exampleVersion}")
}

// Example 2: force by group and name (applies only to a specific dependency)
if (details.requested.group == 'com.example' && details.requested.name == 'example-lib') {
details.useVersion("\${exampleVersion}")
}
}
}
\`\`\`

3. Apply the script in both the root project and the specific module (check first that the line isn't already present to avoid duplicates):
- In the root \`build.gradle\`, inside the \`allprojects\` block, add: \`apply from: "\${rootDir}/dependencyMgmt.gradle"\`
- Additionally (recommended in practice, even though \`allprojects\` should be enough), add the same line as the **first line** of \`/applications/app-service/build.gradle\` (or the equivalent app module) so the configuration is reliably applied at every level.`;

function generateDependencyUpdatePrompt(finding: Finding, allFindings: Finding[] = []): string {
// Scope to dependency findings from this same scan; fall back to the single selected finding
const dependencyFindings = allFindings.filter((f) => f.getModule() === 'engine_dependencies');
const findingsToFix = dependencyFindings.length > 0 ? dependencyFindings : [finding];
const count = findingsToFix.length;

// Keep each entry to the essentials (CVE + fixed version) so the prompt stays short even with many findings
const vulnerabilityList = findingsToFix
.map((f) => {
const cve = f.getId() || 'Unknown';
const packageName = f.getAdditionalField('package_name') || 'Unknown package';
const fixedVersion = f.getAdditionalField('fixed_version') || 'No fix available';
return `- ${cve} | ${packageName} → fix: ${fixedVersion}`;
})
.join('\n');

return `Dependency Update Strategy - Fix All Vulnerabilities in This Scan

**Scan Summary:** ${count} dependency vulnerabilit${count === 1 ? 'y was' : 'ies were'} found in this scan and must ALL be remediated together.

**Vulnerabilities (CVE | Package → Fixed Version):**
${vulnerabilityList}

**Request:**
Based on the dependency vulnerability and impact paths above, please provide:
Your goal is to resolve **all ${count} vulnerabilit${count === 1 ? 'y' : 'ies'} listed above** with a single, consolidated update plan for this project (not just the vulnerability that was clicked). Please provide:

1. **Immediate Actions:**
- Which exact dependencies need to be updated
- Specific version ranges to target
- Command-line instructions for updates
1. **Consolidated Update Plan:**
- The exact target version to use for each package (if a package appears more than once, use the highest fixed version required)
- Group the updates by package manager/manifest file (package.json, requirements.txt, pom.xml, go.mod, etc.)

2. **Update Strategy:**
- Step-by-step update process
- Compatibility considerations
- Testing recommendations
2. **Commands:**
- Ready-to-run package manager commands (npm/yarn/pnpm/pip/maven/gradle/go) that apply all the updates at once
- Lock file regeneration steps

3. **Package Manager Commands:**
- npm/yarn/pip/maven/gradle specific commands
- Lock file considerations
- Version pinning strategies
3. **Compatibility & Risk:**
- Potential breaking changes introduced by these specific updates
- Any conflicts between the required fixed versions of the listed packages
- Testing steps to validate the project after updating everything together

4. **Risk Assessment:**
- Breaking change potential
- Alternative solutions if direct update isn't possible
- Temporary mitigation strategies
4. **If a direct update isn't possible for any package:**
- Suggest safe alternatives or temporary mitigations for that specific CVE

5. **Prevention:**
- Dependency scanning tools
- Update policies
- Security monitoring setup
5. **If this is a Gradle project:**
- Apply the Gradle Alternative Mitigation described below instead

Please provide specific, actionable commands and configurations.`;
${GRADLE_FORCED_VERSION_GUIDANCE}

return basePrompt;
Provide one unified, actionable solution that addresses every vulnerability in the list above.`;
}

function generateAutoFixAgentPrompt(finding: Finding): string {
const vulnerabilityId = finding.getId() || 'Unknown';
const description = finding.getDescription() || 'No description available';
const severity = finding.getSeverity() || 'Unknown';

let prompt = `I need you to automatically fix a security vulnerability in the project dependencies.
function generateImageUpdatePrompt(finding: Finding, allFindings: Finding[] = []): string {
// Scope to image findings from this same scan; fall back to the single selected finding
const imageFindings = allFindings.filter((f) => f.getModule() === 'engine_container' || f.getModule() === 'engine_image');
const findingsToFix = imageFindings.length > 0 ? imageFindings : [finding];
const count = findingsToFix.length;

**Vulnerability Details:**
- ID: ${vulnerabilityId}
- Severity: ${severity}
- Description: ${description}`;
// Keep each entry to the essentials (CVE + fixed version) so the prompt stays short even with many findings
const vulnerabilityList = findingsToFix
.map((f) => {
const cve = f.getId() || 'Unknown';
const packageName = f.getAdditionalField('package_name') || 'Unknown package';
const fixedVersion = f.getAdditionalField('fixed_version') || 'No fix available';
return `- ${cve} | ${packageName} → fix: ${fixedVersion}`;
})
.join('\n');

// Add impact paths if available (using clean text format for prompts)
const impactPathsPrompt = finding.getAdditionalField('impact_paths_prompt');
if (impactPathsPrompt && impactPathsPrompt.trim() !== '') {
prompt += `\n\n**Impact Paths:**\n${impactPathsPrompt}`;
}
return `Container Image Update Strategy - Fix All Vulnerabilities in This Scan

**Scan Summary:** ${count} image vulnerabilit${count === 1 ? 'y was' : 'ies were'} found in this scan and must ALL be remediated together.

**Vulnerabilities (CVE | Package → Fixed Version):**
${vulnerabilityList}

**Request:**
Your goal is to resolve **all ${count} vulnerabilit${count === 1 ? 'y' : 'ies'} listed above** with a single, consolidated update plan for this container image (not just the vulnerability that was clicked). Please provide:

prompt += `
1. **Consolidated Update Plan:**
- The exact target version to use for each package (if a package appears more than once, use the highest fixed version required)
- Whether updating the base image (e.g. a newer tag/digest) resolves multiple vulnerabilities at once, versus patching individual OS packages

**Instructions:**
1. **Analyze** the vulnerability and identify which exact dependencies need to be updated
2. **Locate** the dependency files in the workspace (package.json, pom.xml, build.gradle, requirements.txt, etc.)
3. **Update** the dependency files automatically to fix the security issue
4. **Ensure** compatibility by checking version constraints
5. **Update** lock files if they exist
6. **Provide** a summary of changes made
2. **Commands/Changes:**
- Ready-to-apply Dockerfile changes (base image tag, RUN commands with package manager updates: apt/yum/apk/etc.)

**Requirements:**
- Update to the minimum safe version that fixes the vulnerability
- Maintain backward compatibility where possible
- Provide clear explanations of changes
- Test the changes to ensure nothing breaks
3. **Compatibility & Risk:**
- Potential breaking changes introduced by these specific updates
- Any conflicts between the required fixed versions of the listed packages
- Testing steps to validate the image still works after updating everything together

Please proceed to fix the vulnerability by updating the appropriate dependency files.`;
4. **If a direct update isn't possible for any package:**
- Suggest safe alternatives or temporary mitigations for that specific CVE

return prompt;
Provide one unified, actionable solution that addresses every vulnerability in the list above.`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export class Mappers {
vendor_id: imageScanContext.vendor_id || "",
vulnerability_status: imageScanContext.vulnerability_status || "unknown",
target_image: imageScanContext.target_image || "",
package_name: imageScanContext.package_name || "",
installed_version: imageScanContext.installed_version || "",
fixed_version: imageScanContext.fixed_version || "",
cvss_score: imageScanContext.cvss_score || "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export type AiAction =
| 'fix_with_copilot'
| 'explain_with_copilot'
| 'generate_dependency_update'
| 'auto_fix_with_agent';
| 'generate_image_update';

export type AiTriggerOrigin = 'webview' | 'code_action' | 'tree_context_menu';

Expand Down
Loading
Loading