-
Notifications
You must be signed in to change notification settings - Fork 16
feat: integrate HTML config dialog from Language Server [IDE-1458] #426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b6ed57a
3865155
3e659ed
2a342ac
90a8c80
1b3d3e5
4196819
702daf9
cedeeb8
f9709ca
f4bccef
06a388e
9232e66
68288be
08d9ccd
37bee04
f178ac2
9aac05c
a63b385
ef5956d
5c7eb65
ca7bcac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,7 @@ public class AdditionalData | |
| public IList<int> Rows { get; set; } | ||
| public bool IsSecurityType { get; set; } | ||
| public int PriorityScore { get; set; } | ||
| public int RiskScore { get; set; } | ||
| public bool HasAIFix { get; set; } | ||
| public IList<DataFlow> DataFlow { get; set; } | ||
|
|
||
|
|
@@ -139,6 +140,74 @@ public class Issue | |
| public IgnoreDetails IgnoreDetails { get; set; } | ||
| public AdditionalData AdditionalData { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Product type for this issue (code, oss, iac). | ||
| /// Used to determine which score field to use for priority calculation. | ||
| /// </summary> | ||
| [JsonIgnore] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why ignored ?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is not in the JSON sent from the LS, it is calculated using the JSON, but not from it directly. |
||
| public string Product { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Gets the priority for sorting issues. | ||
| /// Uses severity as primary key (Critical > High > Medium > Low), | ||
| /// with score as tiebreaker within same severity level. | ||
| /// </summary> | ||
| [JsonIgnore] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is not in the JSON sent from the LS, it is calculated using the JSON, but not from it directly. |
||
| public int Priority | ||
| { | ||
| get | ||
| { | ||
| int severityPriority = GetSeverityPriority(Severity); | ||
| int scoreComponent = GetScoreComponent(); | ||
| return severityPriority + scoreComponent; | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Maps severity to millions (4M for critical, 3M for high, 2M for medium, 1M for low). | ||
| /// Using millions ensures severity always takes precedence over score-based tiebreakers, | ||
| /// since scores are typically in the hundreds/thousands range. | ||
| /// </summary> | ||
| private int GetSeverityPriority(string severity) | ||
| { | ||
| if (string.IsNullOrEmpty(severity)) | ||
| return 0; | ||
|
|
||
| // Case-insensitive comparison | ||
| switch (severity.ToLowerInvariant()) | ||
|
nick-y-snyk marked this conversation as resolved.
|
||
| { | ||
| case "critical": | ||
| return 4_000_000; | ||
|
nick-y-snyk marked this conversation as resolved.
|
||
| case "high": | ||
| return 3_000_000; | ||
| case "medium": | ||
| return 2_000_000; | ||
| case "low": | ||
| return 1_000_000; | ||
| default: | ||
| return 0; | ||
| } | ||
| } | ||
|
|
||
| private int GetScoreComponent() | ||
| { | ||
| if (AdditionalData == null) | ||
| return 0; | ||
|
|
||
| // OSS and IaC use riskScore, Code uses priorityScore | ||
| if (Product == Snyk.VisualStudio.Extension.Product.Oss || | ||
| Product == Snyk.VisualStudio.Extension.Product.Iac) | ||
| { | ||
| return AdditionalData.RiskScore; | ||
| } | ||
| else if (Product == Snyk.VisualStudio.Extension.Product.Code) | ||
| { | ||
| return AdditionalData.PriorityScore; | ||
| } | ||
|
|
||
| throw new InvalidOperationException($"Unknown product type: {Product}"); | ||
| } | ||
|
|
||
| public string GetDisplayTitle() => string.IsNullOrEmpty(this.Title) ? this.AdditionalData?.Message : this.Title; | ||
|
|
||
| public bool HasFix() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,6 @@ | ||
| using System; | ||
| // ABOUTME: This file implements custom JSON-RPC message handlers for the Snyk Language Client | ||
| // ABOUTME: It processes diagnostics, authentication, and scan results from the Language Server | ||
| using System; | ||
| using System.Collections.Concurrent; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
|
|
@@ -10,6 +12,7 @@ | |
| using Snyk.VisualStudio.Extension.Authentication; | ||
| using Snyk.VisualStudio.Extension.Extension; | ||
| using Snyk.VisualStudio.Extension.Service; | ||
| using Snyk.VisualStudio.Extension.Settings; | ||
|
|
||
| namespace Snyk.VisualStudio.Extension.Language | ||
| { | ||
|
|
@@ -186,6 +189,15 @@ public async Task OnFolderConfig(JToken arg) | |
|
|
||
| serviceProvider.SnykOptionsManager.Save(serviceProvider.Options, false); | ||
|
|
||
| // Trigger first scan after folder config is received. | ||
| // | ||
| // AutoScan vs InternalAutoScan vs ScanningMode: | ||
| // - AutoScan: Persisted user preference ("I want auto-scanning") | ||
| // - InternalAutoScan: Runtime flag, starts false each session to prevent scanning until we are actually ready. | ||
| // This controls ScanningMode, the string sent to LS ("auto"/"manual"). | ||
| // | ||
| // We always start with InternalAutoScan=false and therefore ScanningMode="manual" during LS initialization to prevent the LS from auto-scanning before we are fully ready. | ||
| // Now folder configs have arrived, we can set InternalAutoScan=AutoScan and trigger the first scan if necessary. | ||
| if (serviceProvider.Options.AutoScan) | ||
| { | ||
| var isFolderTrusted = await this.serviceProvider.TasksService.IsFolderTrustedAsync(); | ||
|
|
@@ -195,7 +207,10 @@ public async Task OnFolderConfig(JToken arg) | |
|
|
||
| if (!serviceProvider.Options.InternalAutoScan) | ||
| { | ||
| // AutoScan is enabled but we haven't triggered the first scan yet (InternalAutoScan is still false). | ||
| // So set InternalAutoScan=true, update LS with the true ScanningMode ("auto") and trigger the first scan. | ||
| serviceProvider.Options.InternalAutoScan = true; | ||
| await serviceProvider.LanguageClientManager.DidChangeConfigurationAsync(SnykVSPackage.Instance.DisposalToken); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is this needed here?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a bunch of comments above explaining the logic, please verify you are happy with them. |
||
| serviceProvider.TasksService.ScanAsync().FireAndForget(); | ||
|
nick-y-snyk marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
@@ -265,6 +280,9 @@ public async Task OnHasAuthenticated(JToken arg) | |
|
|
||
| await serviceProvider.GeneralOptionsDialogPage.HandleAuthenticationSuccess(token, apiUrl); | ||
|
|
||
| // Notify HTML settings window of auth token change | ||
| HtmlSettingsWindow.Instance?.UpdateAuthToken(token); | ||
|
|
||
| if (!serviceProvider.Options.ApiToken.IsValid()) | ||
| return; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.