diff --git a/ast-visual-studio-extension/CxExtension/CxWindowPackage.cs b/ast-visual-studio-extension/CxExtension/CxWindowPackage.cs
index 5c6c47c..4c6e3f0 100644
--- a/ast-visual-studio-extension/CxExtension/CxWindowPackage.cs
+++ b/ast-visual-studio-extension/CxExtension/CxWindowPackage.cs
@@ -1,4 +1,5 @@
using ast_visual_studio_extension.CxExtension.Commands;
+using ast_visual_studio_extension.CxExtension.DevAssist.Commands;
using log4net;
using log4net.Appender;
using log4net.Config;
@@ -69,6 +70,12 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke
// Command to create Checkmarx extension main window
await CxWindowCommand.InitializeAsync(this);
+
+ // Initialize AI Chat Command (Fix with Checkmarx One Assist)
+ await AIChatCommand.InitializeAsync(this);
+
+ // Set package on CopilotIntegration so ASCA "Fix with AI" can run extension-manager checks
+ DevAssist.Services.CopilotIntegration.Package = this;
}
catch (Exception ex)
{
diff --git a/ast-visual-studio-extension/CxExtension/CxWindowPackage.vsct b/ast-visual-studio-extension/CxExtension/CxWindowPackage.vsct
index 2d6d9c2..8d9e8f8 100644
--- a/ast-visual-studio-extension/CxExtension/CxWindowPackage.vsct
+++ b/ast-visual-studio-extension/CxExtension/CxWindowPackage.vsct
@@ -34,6 +34,14 @@
Checkmarx
+
@@ -46,6 +54,7 @@
+
diff --git a/ast-visual-studio-extension/CxExtension/DevAssist/Commands/AIChatCommand.cs b/ast-visual-studio-extension/CxExtension/DevAssist/Commands/AIChatCommand.cs
new file mode 100644
index 0000000..2f53761
--- /dev/null
+++ b/ast-visual-studio-extension/CxExtension/DevAssist/Commands/AIChatCommand.cs
@@ -0,0 +1,143 @@
+using Microsoft.VisualStudio.Shell;
+using System;
+using System.ComponentModel.Design;
+using System.Threading.Tasks;
+using ast_visual_studio_extension.CxExtension.DevAssist.Services;
+using ast_visual_studio_extension.CxWrapper.Models;
+
+namespace ast_visual_studio_extension.CxExtension.DevAssist.Commands
+{
+ public class AIChatCommand
+ {
+ public const int CommandId = 0x0300;
+ public static readonly Guid CommandSet = new Guid("e46cd6d8-268d-4e77-9074-071e72a25f39");
+
+ private readonly AsyncPackage _package;
+ private readonly CopilotIntegration _copilotService;
+ private readonly PromptBuilderService _promptBuilder;
+
+ private AIChatCommand(AsyncPackage package)
+ {
+ _package = package ?? throw new ArgumentNullException(nameof(package));
+ _copilotService = new CopilotIntegration();
+ _promptBuilder = new PromptBuilderService();
+ }
+
+ public static async Task InitializeAsync(AsyncPackage package)
+ {
+ await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
+
+ var commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
+ if (commandService != null)
+ {
+ var command = new AIChatCommand(package);
+ var menuCommandID = new CommandID(CommandSet, CommandId);
+ var menuItem = new MenuCommand(command.Execute, menuCommandID);
+ commandService.AddCommand(menuItem);
+ }
+ }
+
+ ///
+ /// Execute AI Chat command with vulnerability data
+ ///
+ private async void Execute(object sender, EventArgs e)
+ {
+ try
+ {
+ // Get vulnerability data from command parameter or context
+ var vulnerabilityData = GetVulnerabilityDataFromContext(e);
+
+ if (vulnerabilityData == null)
+ {
+ System.Windows.MessageBox.Show("No vulnerability data available for AI assistance.",
+ "AI Chat", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Warning);
+ return;
+ }
+
+ // Build appropriate prompt based on vulnerability type
+ string prompt = BuildPromptForVulnerability(vulnerabilityData);
+
+ // Open Copilot with the prompt
+ bool success = await _copilotService.OpenCopilotChatAsync(prompt, _package);
+
+ if (!success)
+ {
+ System.Windows.MessageBox.Show("Failed to open GitHub Copilot. Please ensure it's installed and try again.",
+ "AI Chat Error", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Warning);
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Windows.MessageBox.Show($"Error opening AI Chat: {ex.Message}",
+ "Error", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
+ }
+ }
+
+ ///
+ /// Public method to execute AI chat with specific vulnerability data
+ ///
+ public async Task ExecuteWithDataAsync(CxAscaDetail ascaData)
+ {
+ try
+ {
+ string prompt = _promptBuilder.BuildASCAPrompt(
+ ascaData.RuleName,
+ ascaData.RemediationAdvise,
+ ascaData.Severity,
+ ascaData.FileName,
+ ascaData.Line
+ );
+
+ await _copilotService.OpenCopilotChatAsync(prompt, _package);
+ }
+ catch (Exception ex)
+ {
+ System.Windows.MessageBox.Show($"Error opening AI Chat: {ex.Message}",
+ "AI Chat Error", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
+ }
+ }
+
+ ///
+ /// Public method to execute AI chat with SCA vulnerability data
+ ///
+ public async Task ExecuteWithSCADataAsync(string packageName, string version, string severity, string packageManager = null)
+ {
+ try
+ {
+ string prompt = _promptBuilder.BuildSCAPrompt(packageName, version, severity, packageManager);
+ await _copilotService.OpenCopilotChatAsync(prompt, _package);
+ }
+ catch (Exception ex)
+ {
+ System.Windows.MessageBox.Show($"Error opening AI Chat: {ex.Message}",
+ "AI Chat Error", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
+ }
+ }
+
+ private object GetVulnerabilityDataFromContext(EventArgs e)
+ {
+ // This would extract vulnerability data from the command context
+ // Implementation depends on how data is passed to the command
+ // For now, return null - will be implemented based on UI integration
+ return null;
+ }
+
+ private string BuildPromptForVulnerability(object vulnerabilityData)
+ {
+ // Build prompt based on vulnerability data type
+ if (vulnerabilityData is CxAscaDetail ascaData)
+ {
+ return _promptBuilder.BuildASCAPrompt(
+ ascaData.RuleName,
+ ascaData.RemediationAdvise,
+ ascaData.Severity,
+ ascaData.FileName,
+ ascaData.Line
+ );
+ }
+
+ // Add other vulnerability types as needed
+ return _promptBuilder.BuildGenericPrompt("Unknown vulnerability", "Unknown");
+ }
+ }
+}
diff --git a/ast-visual-studio-extension/CxExtension/DevAssist/Services/CopilotIntegration.cs b/ast-visual-studio-extension/CxExtension/DevAssist/Services/CopilotIntegration.cs
new file mode 100644
index 0000000..a85acf6
--- /dev/null
+++ b/ast-visual-studio-extension/CxExtension/DevAssist/Services/CopilotIntegration.cs
@@ -0,0 +1,176 @@
+using ast_visual_studio_extension.CxExtension.Utils;
+using EnvDTE;
+using EnvDTE80;
+using Microsoft.VisualStudio.ExtensionManager;
+using Microsoft.VisualStudio.Shell;
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace ast_visual_studio_extension.CxExtension.DevAssist.Services
+{
+ public class CopilotIntegration
+ {
+ ///
+ /// Optional package set by the hosting VS package (e.g. CxWindowPackage) so that
+ /// OpenCopilotChatAsync can run extension-manager checks when called without an explicit package (e.g. from ASCA marker).
+ ///
+ public static AsyncPackage Package { get; set; }
+
+ private DTE2 _dte;
+ private OutputWindowPane _outputPane;
+
+ public CopilotIntegration()
+ {
+ ThreadHelper.ThrowIfNotOnUIThread();
+ _dte = Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(EnvDTE.DTE)) as DTE2;
+ }
+
+ private void Log(string message)
+ {
+ try
+ {
+ ThreadHelper.ThrowIfNotOnUIThread();
+ if (_dte == null)
+ {
+ System.Diagnostics.Debug.WriteLine($"{DateTime.Now:HH:mm:ss.fff} [Copilot] {message}");
+ return;
+ }
+ if (_outputPane == null)
+ _outputPane = OutputPaneUtils.InitializeOutputPane(_dte.ToolWindows.OutputWindow, CxConstants.EXTENSION_TITLE);
+ _outputPane?.OutputString($"{DateTime.Now:HH:mm:ss.fff} [Copilot] {message}\n");
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"[CopilotIntegration] Log failed: {ex.Message}");
+ }
+ }
+
+ ///
+ /// Detect if Copilot Chat extension is installed (GitHub.CopilotChat VSIX).
+ /// Returns true if the Copilot Chat extension is in the list of installed extensions.
+ ///
+ public async Task IsCopilotChatEnabledAsync(AsyncPackage package)
+ {
+ if (package == null)
+ {
+ Log("[IsCopilotChatEnabled] package is null -> false");
+ return false;
+ }
+
+ await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ var extensionManager = await package.GetServiceAsync(typeof(SVsExtensionManager)) as IVsExtensionManager;
+ if (extensionManager == null)
+ {
+ Log("[IsCopilotChatEnabled] IVsExtensionManager is null -> false");
+ return false;
+ }
+
+ const string CopilotChatVsixId = "Component.VisualStudio.GitHub.Copilot";
+
+ bool found = extensionManager.GetInstalledExtensions()
+ .Any(e => e.Header.Identifier.Equals(CopilotChatVsixId, StringComparison.OrdinalIgnoreCase));
+
+ Log(found ? "[IsCopilotChatEnabled] Copilot Chat extension installed -> true" : "[IsCopilotChatEnabled] Copilot Chat extension not found -> false");
+ return found;
+ }
+
+ ///
+ /// Check if GitHub Copilot for Visual Studio is installed and Chat is available (legacy/alias).
+
+ public async Task IsCopilotInstalledAsync(AsyncPackage package)
+ {
+ return await IsCopilotChatEnabledAsync(package);
+ }
+
+ /// Open GitHub Copilot Chat with optional prompt.
+ public async Task OpenCopilotChatAsync(string prompt = null, AsyncPackage package = null)
+ {
+ await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+ AsyncPackage packageToUse = package ?? Package;
+ if (packageToUse == null)
+ Log("[OpenCopilotChatAsync] WARNING: package is null and CopilotIntegration.Package was not set (e.g. CxWindowPackage should set it)");
+
+ try
+ {
+ bool success = await TryOpenCopilotChatAsync(packageToUse);
+
+ if (success && !string.IsNullOrEmpty(prompt))
+ {
+ await Task.Delay(1000);
+ await SendPromptToCopilotAsync(prompt);
+ }
+ else
+ {
+ if (string.IsNullOrEmpty(prompt)) Log("[OpenCopilotChatAsync] Skipping prompt: no prompt");
+ }
+ return success;
+ }
+ catch (Exception ex)
+ {
+ ShowError($"Failed to open GitHub Copilot: {ex.Message}");
+ return false;
+ }
+ }
+ private async Task TryOpenCopilotChatAsync(AsyncPackage package)
+ {
+ await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+
+ // default keyboard shortcut (Ctrl+Backslash then C) to open GitHub Copilot Chat
+ try
+ {
+ System.Windows.Forms.SendKeys.SendWait("^\\c");
+ Log("[TryOpenCopilotChatAsync] Default shortcut (Ctrl+\\ then C) sent");
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Log($"[TryOpenCopilotChatAsync] Shortcut fallback failed: {ex.Message}");
+ }
+ return false;
+ }
+
+ ///
+ /// Enumerates DTE commands whose name contains "Copilot" or "GitHub" and logs them to Output.
+ /// Use this to find the exact command name that opens Copilot Chat on your machine.
+ ///
+
+ private async Task SendPromptToCopilotAsync(string prompt)
+ {
+ Log("[SendPromptToCopilotAsync] Enter");
+ Log($"[SendPromptToCopilotAsync] prompt length={prompt?.Length ?? 0}");
+ try
+ {
+ Log("[SendPromptToCopilotAsync] Method 1: clipboard + paste");
+ Clipboard.SetText(prompt);
+ Log("[SendPromptToCopilotAsync] Clipboard.SetText done, waiting 100ms");
+ await Task.Delay(100);
+ System.Windows.Forms.SendKeys.SendWait("^v{ENTER}");
+ Log("[SendPromptToCopilotAsync] SendKeys ^v{ENTER} sent");
+ }
+ catch (Exception ex)
+ {
+ Log($"[SendPromptToCopilotAsync] Method 1 failed: {ex.Message}");
+ Log("[SendPromptToCopilotAsync] Method 2: direct SendKeys (fallback)");
+ try
+ {
+ System.Windows.Forms.SendKeys.SendWait(prompt.Replace("{", "{{").Replace("}", "}}"));
+ System.Windows.Forms.SendKeys.SendWait("{ENTER}");
+ Log("[SendPromptToCopilotAsync] Method 2 completed");
+ }
+ catch (Exception ex2)
+ {
+ Log($"[SendPromptToCopilotAsync] Method 2 failed: {ex2.Message}");
+ }
+ }
+ }
+ private void ShowError(string message)
+ {
+ Log($"[ShowError] {message}");
+ MessageBox.Show(message, "Copilot Integration Error",
+ MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+}
diff --git a/ast-visual-studio-extension/CxExtension/DevAssist/Services/PromptBuilderService.cs b/ast-visual-studio-extension/CxExtension/DevAssist/Services/PromptBuilderService.cs
new file mode 100644
index 0000000..3ac9035
--- /dev/null
+++ b/ast-visual-studio-extension/CxExtension/DevAssist/Services/PromptBuilderService.cs
@@ -0,0 +1,154 @@
+namespace ast_visual_studio_extension.CxExtension.DevAssist.Services
+{
+ public class PromptBuilderService
+ {
+ ///
+ /// Build prompt for ASCA (SAST) vulnerabilities
+ ///
+ public string BuildASCAPrompt(string ruleName, string remediationAdvice, string severity, string filePath = null, int lineNumber = 0)
+ {
+ var locationInfo = !string.IsNullOrEmpty(filePath) && lineNumber > 0
+ ? $"**Location**: {filePath} (Line {lineNumber})\n"
+ : "";
+
+ return $@"You are Checkmarx One Assist, an AI security expert.
+
+I need help fixing a security vulnerability in my code:
+
+**Rule**: {ruleName}
+**Severity**: {severity}
+{locationInfo}**Remediation Advice**: {remediationAdvice}
+
+Please provide:
+1. **Root Cause Analysis**: Explain what makes this code vulnerable
+2. **Step-by-Step Fix**: Specific code changes to resolve the issue
+3. **Secure Code Example**: Show the corrected implementation
+4. **Validation**: How to verify the fix works properly
+
+Focus on practical, actionable solutions that I can implement immediately.";
+ }
+
+ ///
+ /// Build prompt for SCA (package) vulnerabilities
+ ///
+ public string BuildSCAPrompt(string packageName, string version, string severity, string packageManager = null)
+ {
+ var managerInfo = !string.IsNullOrEmpty(packageManager)
+ ? $" (Package Manager: {packageManager})"
+ : "";
+
+ return $@"You are Checkmarx One Assist, an AI security expert.
+
+I have a vulnerable dependency in my project:
+
+**Package**: {packageName} v{version}{managerInfo}
+**Severity**: {severity}
+
+Please help me fix this vulnerability:
+1. **Risk Assessment**: What security risks does this vulnerability pose?
+2. **Update Strategy**: What version should I upgrade to?
+3. **Implementation Steps**: Exact commands/changes needed
+4. **Testing**: How to verify the update doesn't break functionality
+5. **Alternatives**: If no safe version exists, suggest alternative packages
+
+Provide specific, actionable remediation steps.";
+ }
+
+ ///
+ /// Build prompt for Secrets detection
+ ///
+ public string BuildSecretsPrompt(string secretType, string description, string severity, string filePath = null, int lineNumber = 0)
+ {
+ var locationInfo = !string.IsNullOrEmpty(filePath) && lineNumber > 0
+ ? $"**Location**: {filePath} (Line {lineNumber})\n"
+ : "";
+
+ return $@"You are Checkmarx One Assist, an AI security expert.
+
+A secret has been detected in my code:
+
+**Type**: {secretType}
+**Severity**: {severity}
+{locationInfo}**Description**: {description}
+
+Please help me secure this secret:
+1. **Risk Analysis**: Why is this secret exposure dangerous?
+2. **Immediate Action**: Steps to remove the secret from code
+3. **Secure Storage**: Best practices for storing this type of secret
+4. **Code Changes**: Examples of secure implementation
+5. **Prevention**: How to avoid similar issues in the future
+
+Provide specific remediation steps with code examples.";
+ }
+
+ ///
+ /// Build prompt for Infrastructure as Code (IaC) issues
+ ///
+ public string BuildIaCPrompt(string title, string description, string severity, string expectedValue = null, string actualValue = null)
+ {
+ var valueInfo = !string.IsNullOrEmpty(expectedValue) && !string.IsNullOrEmpty(actualValue)
+ ? $"**Expected Value**: {expectedValue}\n**Actual Value**: {actualValue}\n"
+ : "";
+
+ return $@"You are Checkmarx One Assist, an AI security expert.
+
+I have a security misconfiguration in my Infrastructure as Code:
+
+**Issue**: {title}
+**Severity**: {severity}
+{valueInfo}**Description**: {description}
+
+Please help me fix this configuration issue:
+1. **Security Impact**: What risks does this misconfiguration create?
+2. **Configuration Fix**: Exact changes needed in the IaC template
+3. **Best Practices**: Secure configuration recommendations
+4. **Validation**: How to test the fix works correctly
+
+Provide specific configuration examples and remediation steps.";
+ }
+
+ ///
+ /// Build prompt for Container security issues
+ ///
+ public string BuildContainersPrompt(string imageName, string imageTag, string severity, string issueType)
+ {
+ return $@"You are Checkmarx One Assist, an AI security expert.
+
+I have a security issue in my container configuration:
+
+**Container Image**: {imageName}:{imageTag}
+**Issue Type**: {issueType}
+**Severity**: {severity}
+
+Please help me fix this container security issue:
+1. **Vulnerability Analysis**: What security risks does this create?
+2. **Image Fix**: Steps to resolve the issue (update, rebuild, etc.)
+3. **Dockerfile Changes**: Any needed changes to container configuration
+4. **Security Hardening**: Additional container security best practices
+5. **Validation**: How to verify the container is now secure
+
+Provide specific remediation steps for container security.";
+ }
+
+ ///
+ /// Build generic prompt when vulnerability type is unknown
+ ///
+ public string BuildGenericPrompt(string description, string severity)
+ {
+ return $@"You are Checkmarx One Assist, an AI security expert.
+
+I need help with a security issue:
+
+**Issue**: {description}
+**Severity**: {severity}
+
+Please help me understand and fix this security vulnerability:
+1. **Analysis**: What type of security issue is this?
+2. **Risk Assessment**: What are the potential impacts?
+3. **Remediation**: Step-by-step fix instructions
+4. **Best Practices**: How to prevent similar issues
+
+Provide specific, actionable guidance to resolve this security concern.";
+ }
+ }
+}
diff --git a/ast-visual-studio-extension/CxExtension/Services/ASCAUIManager.cs b/ast-visual-studio-extension/CxExtension/Services/ASCAUIManager.cs
index 2bb89f2..ceb374e 100644
--- a/ast-visual-studio-extension/CxExtension/Services/ASCAUIManager.cs
+++ b/ast-visual-studio-extension/CxExtension/Services/ASCAUIManager.cs
@@ -1,4 +1,5 @@
using ast_visual_studio_extension.CxWrapper.Models;
+using ast_visual_studio_extension.CxExtension.DevAssist.Services;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
@@ -315,18 +316,57 @@ public void OnBeforeBufferClose()
public int GetMarkerCommandInfo(IVsTextMarker pMarker, int iItem, string[] pbstrText, uint[] pcmdf)
{
- if (pbstrText != null && pbstrText.Length > 0)
- pbstrText[0] = string.Empty;
- if (pcmdf != null && pcmdf.Length > 0)
- pcmdf[0] = 0;
+ const uint OLECMDF_ENABLED = 0x02;
+ const uint OLECMDF_SUPPORTED = 0x01;
+ uint enabledSupported = OLECMDF_ENABLED | OLECMDF_SUPPORTED;
+
+ switch (iItem)
+ {
+ case 0:
+ if (pbstrText != null && pbstrText.Length > 0)
+ pbstrText[0] = "Fix with Checkmarx One Assist";
+ if (pcmdf != null && pcmdf.Length > 0)
+ pcmdf[0] = enabledSupported;
+ return VSConstants.S_OK;
+ case 1:
+ if (pbstrText != null && pbstrText.Length > 0)
+ pbstrText[0] = string.Empty;
+ if (pcmdf != null && pcmdf.Length > 0)
+ pcmdf[0] = 0;
+ return VSConstants.S_OK;
+ }
return VSConstants.E_NOTIMPL;
}
public int ExecMarkerCommand(IVsTextMarker pMarker, int iItem)
{
+ switch (iItem)
+ {
+ case 0: // Fix with AI
+ _ = ThreadHelper.JoinableTaskFactory.RunAsync(async () => await ExecuteFixWithAIAsync());
+ return VSConstants.S_OK;
+ }
return VSConstants.E_NOTIMPL;
}
+ private async Task ExecuteFixWithAIAsync()
+ {
+ try
+ {
+ await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+ var copilotService = new CopilotIntegration();
+ var promptBuilder = new PromptBuilderService();
+ string prompt = promptBuilder.BuildASCAPrompt(_ruleName, _remediation, "", "",0);
+ await copilotService.OpenCopilotChatAsync(prompt);
+ }
+ catch (Exception ex)
+ {
+ await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+ System.Windows.MessageBox.Show($"Error opening AI Chat: {ex.Message}", "AI Chat Error",
+ System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Warning);
+ }
+ }
+
///
/// Called after the span is reloaded. No action needed in our implementation.
///
diff --git a/ast-visual-studio-extension/ast-visual-studio-extension.csproj b/ast-visual-studio-extension/ast-visual-studio-extension.csproj
index e15da91..ff85e52 100644
--- a/ast-visual-studio-extension/ast-visual-studio-extension.csproj
+++ b/ast-visual-studio-extension/ast-visual-studio-extension.csproj
@@ -1,4 +1,4 @@
-
+
17.0
@@ -8,7 +8,7 @@
v4.7.2
true
- true
+ false
@@ -20,9 +20,11 @@
false
+ bin\Debug\
false
+ bin\Release\
@@ -82,6 +84,9 @@
+
+
+
@@ -190,6 +195,7 @@
19.225.1
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all