Skip to content

Commit f59b6c3

Browse files
committed
CM-44178 - Add proper support for disabled modules
1 parent 005c883 commit f59b6c3

17 files changed

+123
-61
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
## [Unreleased]
66

7+
- Add proper support for disabled modules
8+
79
## [1.8.0] - 2024-12-20
810

911
- Add the "Ignore this violation" button for the violation card of SCA

src/extension/Cycode.VisualStudio.Extension.Shared/Cli/DTO/StatusResult.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ public class StatusResult {
2323
}
2424

2525
public class SupportedModulesStatus {
26-
// TODO(MarshalX): respect enabled/disabled scanning modules
2726
[JsonProperty(Required = Required.Always)]
2827
public bool SecretScanning { get; set; }
2928
[JsonProperty(Required = Required.Always)]

src/extension/Cycode.VisualStudio.Extension.Shared/Commands/RunAllScansCommand.cs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
using Cycode.VisualStudio.Extension.Shared.Cli.DTO;
2-
using Cycode.VisualStudio.Extension.Shared.DTO;
1+
using System.Collections.Generic;
2+
using Cycode.VisualStudio.Extension.Shared.Cli.DTO;
33
using Cycode.VisualStudio.Extension.Shared.Services;
44

55
namespace Cycode.VisualStudio.Extension.Shared.Commands;
66

77
[Command(PackageIds.ToolbarRunAllScansCommand)]
88
internal sealed class RunAllScansCommand : BaseCommand<RunAllScansCommand> {
99
protected override async Task ExecuteAsync(OleMenuCmdEventArgs e) {
10-
IStateService stateService = ServiceLocator.GetService<IStateService>();
11-
ExtensionState pluginState = stateService.Load();
12-
if (!pluginState.CliAuthed) {
10+
ITemporaryStateService tempState = ServiceLocator.GetService<ITemporaryStateService>();
11+
if (!tempState.CliAuthed) {
1312
await VS.StatusBar.ShowMessageAsync("Please authenticate with Cycode first.");
1413
return;
1514
}
@@ -20,12 +19,22 @@ protected override async Task ExecuteAsync(OleMenuCmdEventArgs e) {
2019

2120
try {
2221
ICycodeService cycode = ServiceLocator.GetService<ICycodeService>();
23-
await Task.WhenAll(
24-
cycode.StartProjectScanAsync(CliScanType.Secret),
25-
cycode.StartProjectScanAsync(CliScanType.Sca),
26-
cycode.StartProjectScanAsync(CliScanType.Iac),
27-
cycode.StartProjectScanAsync(CliScanType.Sast)
28-
);
22+
List<Task> scanTasks = [];
23+
24+
if (tempState.IsSecretScanningEnabled) {
25+
scanTasks.Add(cycode.StartProjectScanAsync(CliScanType.Secret));
26+
}
27+
if (tempState.IsScaScanningEnabled) {
28+
scanTasks.Add(cycode.StartProjectScanAsync(CliScanType.Sca));
29+
}
30+
if (tempState.IsIacScanningEnabled) {
31+
scanTasks.Add(cycode.StartProjectScanAsync(CliScanType.Iac));
32+
}
33+
if (tempState.IsSastScanningEnabled) {
34+
scanTasks.Add(cycode.StartProjectScanAsync(CliScanType.Sast));
35+
}
36+
37+
await Task.WhenAll(scanTasks);
2938
} finally {
3039
Command.Enabled = true;
3140
Command.Text = originalText;

src/extension/Cycode.VisualStudio.Extension.Shared/Components/ToolWindows/CycodeToolWindowViewModel.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Cycode.VisualStudio.Extension.Shared.Components.ToolWindows;
1313

1414
public class CycodeToolWindowViewModel : INotifyPropertyChanged {
1515
private readonly CycodeTreeViewControl _cycodeTreeView;
16-
private readonly ExtensionState _state = ServiceLocator.GetService<IStateService>().Load();
16+
private readonly ITemporaryStateService _tempState = ServiceLocator.GetService<ITemporaryStateService>();
1717
private UserControl _leftSideView;
1818
private UserControl _rightSideView;
1919

@@ -51,10 +51,10 @@ private void OnPropertyChanged(string propertyName) {
5151
private UserControl GetStateDependentRightSideView() {
5252
UserControl newRightSideView;
5353

54-
if (!_state.CliInstalled)
54+
if (!_tempState.CliInstalled)
5555
newRightSideView = new LoadingControl();
5656
else
57-
newRightSideView = _state.CliAuthed switch {
57+
newRightSideView = _tempState.CliAuthed switch {
5858
true => new MainControl(),
5959
false => new AuthControl()
6060
};

src/extension/Cycode.VisualStudio.Extension.Shared/Components/ToolWindows/MainControl.xaml.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ namespace Cycode.VisualStudio.Extension.Shared.Components.ToolWindows;
88
public partial class MainControl {
99
public MainControl() {
1010
InitializeComponent();
11+
12+
ScanSecretsBtn.IsEnabled = _tempState.IsSecretScanningEnabled;
13+
ScanScaBtn.IsEnabled = _tempState.IsScaScanningEnabled;
14+
ScanIacBtn.IsEnabled = _tempState.IsIacScanningEnabled;
15+
ScanSastBtn.IsEnabled = _tempState.IsSastScanningEnabled;
1116
}
1217

13-
private static ILoggerService Logger => ServiceLocator.GetService<ILoggerService>();
14-
private static ICycodeService Cycode => ServiceLocator.GetService<ICycodeService>();
18+
private static readonly ILoggerService _logger = ServiceLocator.GetService<ILoggerService>();
19+
private static readonly ICycodeService _cycode = ServiceLocator.GetService<ICycodeService>();
20+
private static readonly ITemporaryStateService _tempState = ServiceLocator.GetService<ITemporaryStateService>();
1521

1622
private static async Task ExecuteWithButtonStateAsync(Button button, Func<Task> action) {
1723
string originalContent = button.Content.ToString();
@@ -30,39 +36,39 @@ private static async Task ExecuteWithButtonStateAsync(Button button, Func<Task>
3036
private async void ScanSecretsClickAsync(object sender, RoutedEventArgs e) {
3137
await ExecuteWithButtonStateAsync(ScanSecretsBtn, async () => {
3238
try {
33-
await Cycode.StartProjectScanAsync(CliScanType.Secret);
39+
await _cycode.StartProjectScanAsync(CliScanType.Secret);
3440
} catch (Exception ex) {
35-
Logger.Error(ex, "Failed to scan secrets");
41+
_logger.Error(ex, "Failed to scan secrets");
3642
}
3743
});
3844
}
3945

4046
private async void ScanScaClickAsync(object sender, RoutedEventArgs e) {
4147
await ExecuteWithButtonStateAsync(ScanScaBtn, async () => {
4248
try {
43-
await Cycode.StartProjectScanAsync(CliScanType.Sca);
49+
await _cycode.StartProjectScanAsync(CliScanType.Sca);
4450
} catch (Exception ex) {
45-
Logger.Error(ex, "Failed to scan SCA");
51+
_logger.Error(ex, "Failed to scan SCA");
4652
}
4753
});
4854
}
4955

5056
private async void ScanIacClickAsync(object sender, RoutedEventArgs e) {
5157
await ExecuteWithButtonStateAsync(ScanIacBtn, async () => {
5258
try {
53-
await Cycode.StartProjectScanAsync(CliScanType.Iac);
59+
await _cycode.StartProjectScanAsync(CliScanType.Iac);
5460
} catch (Exception ex) {
55-
Logger.Error(ex, "Failed to scan IaC");
61+
_logger.Error(ex, "Failed to scan IaC");
5662
}
5763
});
5864
}
5965

6066
private async void ScanSastClickAsync(object sender, RoutedEventArgs e) {
6167
await ExecuteWithButtonStateAsync(ScanSastBtn, async () => {
6268
try {
63-
await Cycode.StartProjectScanAsync(CliScanType.Sast);
69+
await _cycode.StartProjectScanAsync(CliScanType.Sast);
6470
} catch (Exception ex) {
65-
Logger.Error(ex, "Failed to scan SAST");
71+
_logger.Error(ex, "Failed to scan SAST");
6672
}
6773
});
6874
}

src/extension/Cycode.VisualStudio.Extension.Shared/Components/ViolationCards/IacViolationCardControl.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
Title="AI Remediation" />
5959
<common:Hr Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="2" />
6060
<Button Grid.Row="11" Grid.Column="1"
61+
x:Name="GenerateAiRemediationButton"
6162
Content="Generate AI Remediation"
6263
HorizontalAlignment="Right"
6364
VerticalAlignment="Bottom"

src/extension/Cycode.VisualStudio.Extension.Shared/Components/ViolationCards/IacViolationCardControl.xaml.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ public partial class IacViolationCardControl {
1212
private const int _customRemediationGuidelinesRowIndex = 7;
1313
private const int _cycodeRemediationGuidelinesRowIndex = 8;
1414
private const int _aiRemediationRowIndex = 9;
15-
private readonly ICycodeService _cycodeService = ServiceLocator.GetService<ICycodeService>();
15+
16+
private static readonly ICycodeService _cycodeService = ServiceLocator.GetService<ICycodeService>();
17+
private static readonly ITemporaryStateService _tempState = ServiceLocator.GetService<ITemporaryStateService>();
1618

1719
private readonly IacDetection _detection;
1820

@@ -44,6 +46,7 @@ public IacViolationCardControl(IacDetection detection) {
4446
}
4547

4648
GridHelper.HideRow(Grid, _aiRemediationRowIndex);
49+
GenerateAiRemediationButton.IsEnabled = _tempState.IsAiLargeLanguageModelEnabled;
4750
}
4851

4952
private async void GenerateAiRemediationButton_OnClickAsync(object sender, RoutedEventArgs e) {

src/extension/Cycode.VisualStudio.Extension.Shared/Components/ViolationCards/SastViolationCardControl.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
Title="AI Remediation" />
6767
<common:Hr Grid.Row="12" Grid.Column="0" Grid.ColumnSpan="2" />
6868
<Button Grid.Row="13" Grid.Column="1"
69+
x:Name="GenerateAiRemediationButton"
6970
Content="Generate AI Remediation"
7071
HorizontalAlignment="Right"
7172
VerticalAlignment="Bottom"

src/extension/Cycode.VisualStudio.Extension.Shared/Components/ViolationCards/SastViolationCardControl.xaml.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ public partial class SastViolationCardControl {
1313
private const int _customRemediationGuidelinesRowIndex = 9;
1414
private const int _cycodeRemediationGuidelinesRowIndex = 10;
1515
private const int _aiRemediationRowIndex = 11;
16-
private readonly ICycodeService _cycodeService = ServiceLocator.GetService<ICycodeService>();
17-
16+
17+
private static readonly ICycodeService _cycodeService = ServiceLocator.GetService<ICycodeService>();
18+
private static readonly ITemporaryStateService _tempState = ServiceLocator.GetService<ITemporaryStateService>();
19+
1820
private readonly SastDetection _detection;
1921

2022
public SastViolationCardControl(SastDetection detection) {
@@ -63,6 +65,7 @@ public SastViolationCardControl(SastDetection detection) {
6365
}
6466

6567
GridHelper.HideRow(Grid, _aiRemediationRowIndex);
68+
GenerateAiRemediationButton.IsEnabled = _tempState.IsAiLargeLanguageModelEnabled;
6669
}
6770

6871
private async void GenerateAiRemediationButton_OnClickAsync(object sender, RoutedEventArgs e) {

src/extension/Cycode.VisualStudio.Extension.Shared/Cycode.VisualStudio.Extension.Shared.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<Compile Include="$(MSBuildThisFileDirectory)Services\SuggestedActions\Actions\OpenViolationCardAction.cs"/>
101101
<Compile Include="$(MSBuildThisFileDirectory)Services\SuggestedActions\SuggestedActionsSource.cs"/>
102102
<Compile Include="$(MSBuildThisFileDirectory)Services\SuggestedActions\SuggestedActionsSourceProvider.cs"/>
103+
<Compile Include="$(MSBuildThisFileDirectory)Services\TemporaryStateService.cs" />
103104
<Compile Include="$(MSBuildThisFileDirectory)Services\ToolWindowMessengerService.cs"/>
104105
<Compile Include="$(MSBuildThisFileDirectory)Startup.cs"/>
105106
<Compile Include="$(MSBuildThisFileDirectory)Services\LoggerService.cs"/>
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
namespace Cycode.VisualStudio.Extension.Shared.DTO;
22

33
public class ExtensionState {
4-
public bool CliInstalled { get; set; } = false;
5-
public bool CliAuthed { get; set; } = false;
6-
public string CliVer { get; set; } = null;
7-
public string CliHash { get; set; } = null;
8-
public long? CliLastUpdateCheckedAt { get; set; } = null;
9-
public bool IsAiLargeLanguageModelEnabled { get; set; } = false;
4+
public string CliVer { get; set; }
5+
public string CliHash { get; set; }
6+
public long? CliLastUpdateCheckedAt { get; set; }
107
}

src/extension/Cycode.VisualStudio.Extension.Shared/Services/CliService.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Task<bool> DoIgnoreAsync(
4949
public class CliService(
5050
ILoggerService logger,
5151
IStateService stateService,
52+
ITemporaryStateService tempState,
5253
IScanResultsService scanResultsService,
5354
IErrorTaskCreatorService errorTaskCreatorService
5455
) : ICliService {
@@ -58,19 +59,20 @@ IErrorTaskCreatorService errorTaskCreatorService
5859
public async Task SyncStatusAsync(CancellationToken cancellationToken = default) {
5960
CliResult<StatusResult> result = await _cli.ExecuteCommandAsync<StatusResult>(["status"], cancellationToken);
6061
CliResult<StatusResult>.Success processedResult = ProcessResult(result);
61-
62+
6263
if (processedResult == null) {
6364
ResetPluginCliState();
6465
return;
6566
}
6667

67-
_pluginState.CliInstalled = true;
68+
tempState.CliInstalled = true;
69+
tempState.CliAuthed = processedResult.Result.IsAuthenticated;
70+
tempState.CliStatus = processedResult.Result;
71+
6872
_pluginState.CliVer = processedResult.Result.Version;
69-
_pluginState.CliAuthed = processedResult.Result.IsAuthenticated;
70-
_pluginState.IsAiLargeLanguageModelEnabled = processedResult.Result.SupportedModules.AiLargeLanguageModel;
7173
stateService.Save();
72-
73-
if (!_pluginState.CliAuthed)
74+
75+
if (!tempState.CliAuthed)
7476
ShowErrorNotification("You are not authenticated in Cycode. Please authenticate");
7577
else {
7678
if (processedResult.Result.UserId != null && processedResult.Result.TenantId != null)
@@ -83,12 +85,11 @@ public async Task<bool> DoAuthAsync(CancellationToken cancellationToken = defaul
8385
CliResult<AuthResult>.Success processedResult = ProcessResult(result);
8486
if (processedResult == null) return false;
8587

86-
_pluginState.CliAuthed = processedResult.Result.Result;
87-
stateService.Save();
88+
tempState.CliAuthed = processedResult.Result.Result;
8889

89-
if (!_pluginState.CliAuthed) ShowErrorNotification("Authentication failed. Please try again");
90+
if (!tempState.CliAuthed) ShowErrorNotification("Authentication failed. Please try again");
9091

91-
return _pluginState.CliAuthed;
92+
return tempState.CliAuthed;
9293
}
9394

9495
public async Task ScanPathsSecretsAsync(
@@ -151,8 +152,8 @@ public async Task ScanPathsSastAsync(
151152
public void ResetPluginCliState() {
152153
logger.Debug("Resetting plugin CLI state");
153154

154-
_pluginState.CliAuthed = false;
155-
_pluginState.CliInstalled = false;
155+
tempState.CliAuthed = false;
156+
tempState.CliInstalled = false;
156157
_pluginState.CliVer = null;
157158
stateService.Save();
158159
}

src/extension/Cycode.VisualStudio.Extension.Shared/Services/CycodeService.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,13 @@ Task ApplyDetectionIgnoreAsync(
2727

2828
public class CycodeService(
2929
ILoggerService logger,
30-
IStateService stateService,
30+
ITemporaryStateService tempState,
3131
ICliDownloadService cliDownloadService,
3232
ICliService cliService,
3333
IToolWindowMessengerService toolWindowMessengerService,
3434
IScanResultsService scanResultsService,
3535
IErrorTaskCreatorService errorTaskCreatorService
3636
) : ICycodeService {
37-
private readonly ExtensionState _pluginState = stateService.Load();
38-
3937
private readonly IDictionary<CliScanType, PerformScanFunc> _scanFunctions =
4038
new Dictionary<CliScanType, PerformScanFunc> {
4139
{ CliScanType.Secret, cliService.ScanPathsSecretsAsync },
@@ -95,7 +93,7 @@ private static async Task WrapWithStatusCenterAsync(
9593
#endif
9694

9795
private void UpdateToolWindowDependingOnState() {
98-
if (_pluginState.CliAuthed) {
96+
if (tempState.CliAuthed) {
9997
logger.Info("Successfully authenticated with Cycode CLI");
10098
toolWindowMessengerService.Send(new MessageEventArgs(MessengerCommand.LoadMainControl));
10199
} else {
@@ -140,7 +138,7 @@ await WrapWithStatusCenterAsync(
140138
}
141139

142140
private async Task StartAuthInternalAsync(CancellationToken cancellationToken) {
143-
if (!_pluginState.CliAuthed) {
141+
if (!tempState.CliAuthed) {
144142
logger.Debug("[AUTH] Start authing");
145143
await cliService.DoAuthAsync(cancellationToken);
146144
await cliService.SyncStatusAsync(cancellationToken);
@@ -162,7 +160,7 @@ public async Task StartProjectScanAsync(CliScanType scanType, bool onDemand = tr
162160
}
163161

164162
public async Task StartPathScanAsync(CliScanType scanType, List<string> pathsToScan, bool onDemand = false) {
165-
if (!_pluginState.CliAuthed) {
163+
if (!tempState.CliAuthed) {
166164
logger.Debug("Not authenticated with Cycode CLI. Aborting scan...");
167165
return;
168166
}

src/extension/Cycode.VisualStudio.Extension.Shared/Services/DocTableEventsHandlerService.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Linq;
44
using System.Threading.Tasks;
55
using Cycode.VisualStudio.Extension.Shared.Cli.DTO;
6-
using Cycode.VisualStudio.Extension.Shared.DTO;
76
using Cycode.VisualStudio.Extension.Shared.Options;
87
using Microsoft.VisualStudio;
98
using Microsoft.VisualStudio.Shell.Interop;
@@ -18,11 +17,10 @@ public interface IDocTableEventsHandlerService {
1817
public class DocTableEventsHandlerService(
1918
ILoggerService logger,
2019
ICycodeService cycode,
21-
IStateService stateService
20+
ITemporaryStateService tempState
2221
) : IDocTableEventsHandlerService, IVsRunningDocTableEvents {
2322
private readonly HashSet<string> _collectedPathsToScan = [];
2423
private readonly object _lock = new();
25-
private readonly ExtensionState _pluginState = stateService.Load();
2624

2725
private IServiceProvider _serviceProvider;
2826
private uint rdtCookie;
@@ -126,16 +124,16 @@ private async Task ScanPathsFlushAsync() {
126124
_collectedPathsToScan.Clear();
127125
}
128126

129-
if (!_pluginState.CliAuthed) return;
127+
if (!tempState.CliAuthed) return;
130128

131129
List<string> scaPathsToScan = ExcludeNonScaRelatedPaths(pathsToScan);
132130
List<string> iacPathsToScan = ExcludeNonIacRelatedPaths(pathsToScan);
133131

134132
// Wait for all three await calls to complete
135133
await Task.WhenAll(
136-
pathsToScan.Any() ? cycode.StartPathScanAsync(CliScanType.Secret, pathsToScan) : Task.CompletedTask,
137-
scaPathsToScan.Any() ? cycode.StartPathScanAsync(CliScanType.Sca, scaPathsToScan) : Task.CompletedTask,
138-
iacPathsToScan.Any() ? cycode.StartPathScanAsync(CliScanType.Iac, iacPathsToScan) : Task.CompletedTask
134+
pathsToScan.Any() && tempState.IsSecretScanningEnabled ? cycode.StartPathScanAsync(CliScanType.Secret, pathsToScan) : Task.CompletedTask,
135+
scaPathsToScan.Any() && tempState.IsScaScanningEnabled ? cycode.StartPathScanAsync(CliScanType.Sca, scaPathsToScan) : Task.CompletedTask,
136+
iacPathsToScan.Any() && tempState.IsIacScanningEnabled ? cycode.StartPathScanAsync(CliScanType.Iac, iacPathsToScan) : Task.CompletedTask
139137
);
140138
}
141139

src/extension/Cycode.VisualStudio.Extension.Shared/Services/StateService.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ public void Save() {
5252

5353
private void MergeState(ExtensionState extensionState) {
5454
lock (_lockObject) {
55-
_extensionState.CliInstalled = extensionState.CliInstalled;
56-
_extensionState.CliAuthed = extensionState.CliAuthed;
5755
_extensionState.CliVer = extensionState.CliVer;
5856
_extensionState.CliHash = extensionState.CliHash;
5957
_extensionState.CliLastUpdateCheckedAt = extensionState.CliLastUpdateCheckedAt;

0 commit comments

Comments
 (0)