Skip to content

Commit 22a0c71

Browse files
authored
CM-41712 - Add support for Eclipse Theia (#114)
1 parent a00c092 commit 22a0c71

17 files changed

+162
-76
lines changed

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
## [Unreleased]
44

5+
## [v1.11.2]
6+
7+
- Add support for Theia IDE
8+
- Add auto publishing the extension to the Open VSX Registry
9+
- Fix false positive status bar changes
10+
- Fix CLI output handling
11+
512
## [v1.11.1]
613

714
- Fix CliError parsing
@@ -107,6 +114,8 @@
107114

108115
The first stable release with the support of Secrets, SCA, TreeView, Violation Card, and more.
109116

117+
[v1.11.2]: https://github.com/cycodehq/vscode-extension/releases/tag/v1.11.2
118+
110119
[v1.11.1]: https://github.com/cycodehq/vscode-extension/releases/tag/v1.11.1
111120

112121
[v1.11.0]: https://github.com/cycodehq/vscode-extension/releases/tag/v1.11.0
@@ -147,4 +156,4 @@ The first stable release with the support of Secrets, SCA, TreeView, Violation C
147156

148157
[v1.0.0]: https://github.com/cycodehq/vscode-extension/releases/tag/v1.0.0
149158

150-
[Unreleased]: https://github.com/cycodehq/vscode-extension/compare/v1.11.1...HEAD
159+
[Unreleased]: https://github.com/cycodehq/vscode-extension/compare/v1.11.2...HEAD

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{
22
"name": "cycode",
33
"displayName": "Cycode",
4-
"version": "1.11.1",
4+
"version": "1.11.2",
55
"publisher": "cycode",
66
"description": "Boost security in your dev lifecycle via SAST, SCA, Secrets & IaC scanning.",
77
"repository": {
88
"type": "git",
99
"url": "https://github.com/cycodehq/vscode-extension"
1010
},
1111
"homepage": "https://cycode.com/",
12-
"license": "SEE LICENSE IN LICENSE.MD",
12+
"license": "MIT",
1313
"icon": "resources/cycode124.png",
1414
"galleryBanner": {
1515
"theme": "dark",
@@ -43,12 +43,12 @@
4343
},
4444
{
4545
"command": "cycode.treeViewCollapseAllCommand",
46-
"when": "view == cycode.view.tree",
46+
"when": "cycode:env.isVsCode && view == cycode.view.tree",
4747
"group": "navigation@1"
4848
},
4949
{
5050
"command": "cycode.treeViewExpandAllCommand",
51-
"when": "view == cycode.view.tree",
51+
"when": "cycode:env.isVsCode && view == cycode.view.tree",
5252
"group": "navigation@1"
5353
},
5454
{

src/cli/cli-wrapper.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { CliError, isCliError } from './models/cli-error';
1212
import { ExitCode } from './exit-code';
1313
import { CommandParameters } from './constants';
1414
import { getUserAgentArg } from './user-agent';
15+
import { captureException } from '../sentry';
1516

1617
export class CliWrapper {
1718
public workDirectory?: string;
@@ -27,10 +28,19 @@ export class CliWrapper {
2728
): CliResult<T> {
2829
if (classConst == null) {
2930
// in case when we do not expect any output and want just call command like "ignore" command
31+
this.logger.debug('No classConst provided. Returning CliResultSuccess(null)');
3032
return new CliResultSuccess(null);
3133
}
3234

33-
const camelCasedObj = JSON_.parse(out);
35+
let camelCasedObj;
36+
try {
37+
camelCasedObj = JSON_.parse(out);
38+
} catch (e) {
39+
captureException(e);
40+
this.logger.debug('Failed to parse output as JSON. Returning CliResultPanic');
41+
return new CliResultPanic(exitCode, out);
42+
}
43+
3444
if (isCliError(camelCasedObj)) {
3545
this.logger.debug('Found CliError in output. Returning CliResultError');
3646
const cliError = plainToInstance(CliError, camelCasedObj);
@@ -94,11 +104,11 @@ export class CliWrapper {
94104
childProcess.on('close', (code: number) => {
95105
// we receive all "data" events before close
96106
this.logger.debug(`Streams of a command have been closed with code: ${code}`);
97-
resolve(this.parseCliResult(classConst, stdout, exitCode));
107+
resolve(this.parseCliResult(classConst, stdout || stderr, exitCode));
98108
});
99109

100110
childProcess.on('error', (error: { errno: number }) => {
101-
resolve(this.parseCliResult(classConst, stderr, error.errno));
111+
resolve(this.parseCliResult(classConst, stderr || stdout, error.errno));
102112
});
103113

104114
childProcess.stdout.on('data', (data) => {

src/commands/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ export enum VscodeCommands {
4040
TreeViewExpandAllCommand = 'cycode.treeViewExpandAllCommand',
4141
TreeViewCollapseAllCommand = 'cycode.treeViewCollapseAllCommand',
4242

43-
// built-in or created automatically by vscode:
43+
/*
44+
* Warning: These commands do not exist in Theia API.
45+
*
46+
* Built-in or created automatically by vscode:
47+
*/
4448
WorkbenchShowProblemsTab = 'workbench.action.problems.focus',
4549
WorkbenchShowCycodeView = 'workbench.view.extension.cycode',
4650
WorkbenchTreeViewCollapseAll = 'workbench.actions.treeView.cycode.view.tree.collapseAll',

src/commands/open-violation-panel-command.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ExtensionServiceSymbol } from '../symbols';
55
import { DetectionBase } from '../cli/models/scan-result/detection-base';
66
import { CliScanType } from '../cli/models/cli-scan-type';
77

8-
export default (scanType: CliScanType, detection: DetectionBase) => {
8+
export default async (scanType: CliScanType, detection: DetectionBase) => {
99
const extension = container.resolve<IExtensionService>(ExtensionServiceSymbol);
10-
createAndInitPanel(extension.extensionContext, scanType, detection);
10+
await createAndInitPanel(extension.extensionContext, scanType, detection);
1111
};

src/extension.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import './ioc';
77
import * as vscode from 'vscode';
88
import { extensionName } from './utils/texts';
99
import statusBar from './utils/status-bar';
10+
import { config } from './utils/config';
1011
import { captureException, initSentry } from './sentry';
1112
import { container } from 'tsyringe';
1213
import { ICycodeService } from './services/cycode-service';
@@ -65,6 +66,11 @@ export function activate(context: vscode.ExtensionContext) {
6566
statusBar.showAuthIsRequired();
6667
}
6768

69+
if (config.isTheiaIde) {
70+
stateService.globalState.EnvVsCode = false;
71+
stateService.save();
72+
}
73+
6874
registerCommands(context);
6975
registerActivityBar(context);
7076
registerCodeLensProvider(context);

src/services/cli-service.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,29 +81,31 @@ export class CliService implements ICliService {
8181
}
8282

8383
private processCliResult<T>(result: CliResult<T>): CliResult<T> | null {
84-
if (isCliResultError(result)) {
85-
this.logger.error(result.result.message);
86-
this.showErrorNotification(result.result.message);
87-
return null;
88-
}
89-
9084
if (isCliResultPanic(result)) {
9185
if (result.exitCode === ExitCode.TERMINATION) {
9286
// don't notify user about user-requested terminations
9387
return null;
9488
}
9589

96-
this.logger.error(result.errorMessage);
90+
this.logger.error(`[processCliResult] CLI panic: ${result.errorMessage}`);
9791
this.showErrorNotification(result.errorMessage);
9892
return null;
9993
}
10094

95+
if (isCliResultError(result)) {
96+
this.logger.error(`[processCliResult] CLI error: ${result.result.message}`);
97+
this.showErrorNotification(result.result.message);
98+
return null;
99+
}
100+
101101
if (isCliResultSuccess(result) && result.result instanceof ScanResultBase) {
102102
const errors = result.result.errors;
103103
if (!errors.length) {
104+
this.logger.info('[processCliResult] CLI scan results success');
104105
return result;
105106
}
106107

108+
this.logger.error('[processCliResult] CLI scan results success with errors');
107109
errors.forEach((error) => {
108110
this.logger.error(error.message);
109111
this.showErrorNotification(error.message);
@@ -113,6 +115,7 @@ export class CliService implements ICliService {
113115
return null;
114116
}
115117

118+
this.logger.error('[processCliResult] CLI success');
116119
return result;
117120
}
118121

@@ -241,7 +244,7 @@ export class CliService implements ICliService {
241244
.showInformationMessage(
242245
`Cycode has detected ${detectionsCount} ${scanTypeDisplayName}
243246
issues in your files. Check out your “Problems” tab to analyze.`,
244-
TrayNotificationTexts.OpenProblemsTab,
247+
this.state.EnvVsCode ? TrayNotificationTexts.OpenProblemsTab : '', // show button only in VSCode
245248
)
246249
.then((buttonPressed) => {
247250
if (buttonPressed === TrayNotificationTexts.OpenProblemsTab) {

src/services/cycode-service.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { ProgressOptions } from 'vscode';
1212
import { ILoggerService } from './logger-service';
1313
import { getScanTypeDisplayName } from '../constants';
1414
import statusBar from '../utils/status-bar';
15-
import { TrayNotificationTexts } from '../utils/texts';
1615
import { captureException } from '../sentry';
1716
import { CliIgnoreType } from '../cli/models/cli-ignore-type';
1817
import { IScanResultsService } from './scan-results-service';
@@ -47,19 +46,15 @@ export class CycodeService implements ICycodeService {
4746
await vscode.window.withProgress(
4847
options,
4948
async (progress: ProgressBar, cancellationToken: vscode.CancellationToken) => {
50-
progress.report({ message });
5149
try {
52-
statusBar.showScanningInProgress();
50+
progress.report({ message });
5351
await fn(cancellationToken);
54-
statusBar.showScanComplete();
5552
} catch (error: unknown) {
5653
captureException(error);
5754
if (error instanceof Error) {
5855
this.logger.error(`Error during progress: ${error.message}`);
56+
vscode.window.showErrorMessage(`Cycode error: ${error.message}`);
5957
}
60-
61-
statusBar.showScanError();
62-
vscode.window.showErrorMessage(TrayNotificationTexts.ScanError);
6358
} finally {
6459
progress.report({ increment: 100 });
6560
}
@@ -121,19 +116,22 @@ export class CycodeService implements ICycodeService {
121116
};
122117

123118
const scanMethod = scanMethods[scanType];
124-
if (scanMethod) {
125-
await this.withProgressBar(
126-
`Cycode is scanning files for ${getScanTypeDisplayName(scanType)}...`,
127-
async (cancellationToken: vscode.CancellationToken) => {
128-
this.logger.debug(`[${scanType}] Start scanning paths: ${paths}`);
129-
await scanMethod(cancellationToken);
130-
this.logger.debug(`[${scanType}] Finish scanning paths: ${paths}`);
131-
},
132-
this.getScanProgressBarOptions(onDemand),
133-
);
134-
} else {
119+
if (!scanMethod) {
135120
this.logger.error(`Unknown scan type: ${scanType}`);
121+
return;
136122
}
123+
124+
await this.withProgressBar(
125+
`Cycode is scanning files for ${getScanTypeDisplayName(scanType)}...`,
126+
async (cancellationToken: vscode.CancellationToken) => {
127+
this.logger.debug(`[${scanType}] Start scanning paths: ${paths}`);
128+
statusBar.showScanningInProgress();
129+
await scanMethod(cancellationToken);
130+
statusBar.showScanComplete();
131+
this.logger.debug(`[${scanType}] Finish scanning paths: ${paths}`);
132+
},
133+
this.getScanProgressBarOptions(onDemand),
134+
);
137135
}
138136

139137
private async applyDetectionIgnoreInUi(ignoreType: CliIgnoreType, value: string) {

src/services/state-service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ILoggerService } from './logger-service';
55
import { GlobalKeyValueStorage, LocalKeyValueStorage } from './key-value-storage-service';
66

77
export class GlobalExtensionState {
8+
public EnvVsCode = true;
89
public CliInstalled = false;
910
public CliAuthed = false;
1011
public CliVer: string | null = null;
@@ -24,12 +25,14 @@ const _GLOBAL_STATE_KEY = 'cycode:globalState';
2425
const _LOCAL_STATE_KEY = 'cycode:localState';
2526

2627
enum VscodeStates {
28+
IsVsCodeEnv = 'env.isVsCode',
2729
IsAuthorized = 'auth.isAuthed',
2830
IsInstalled = 'cli.isInstalled',
2931
}
3032

3133
const _CONTEXT_EXPORTED_GLOBAL_STATE_KEYS: Record<string, string> = {
3234
// map global state keys to vscode context keys
35+
EnvVsCode: VscodeStates.IsVsCodeEnv,
3336
CliAuthed: VscodeStates.IsAuthorized,
3437
CliInstalled: VscodeStates.IsInstalled,
3538
};
@@ -148,6 +151,7 @@ export class StateService implements IStateService {
148151
}
149152

150153
private mergeGlobalState(extensionState: GlobalExtensionState): void {
154+
if (extensionState.EnvVsCode !== undefined) (this._globalState.EnvVsCode = extensionState.EnvVsCode);
151155
if (extensionState.CliInstalled !== undefined) (this._globalState.CliInstalled = extensionState.CliInstalled);
152156
if (extensionState.CliAuthed !== undefined) (this._globalState.CliAuthed = extensionState.CliAuthed);
153157
if (extensionState.CliVer !== undefined) (this._globalState.CliVer = extensionState.CliVer);

src/ui/panels/violation/js.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default (detectionType: CliScanType) => `
99
const vscode = acquireVsCodeApi();
1010
const prevState = vscode.getState();
1111
12-
let severityIcons = (prevState && prevState.severityIcons) || {};
12+
let severityIcons = (prevState && prevState.severityIcons) || undefined;
1313
let detection = (prevState && prevState.detection) || undefined;
1414
let uniqueDetectionId = (prevState && prevState.uniqueDetectionId) || undefined;
1515
@@ -60,12 +60,12 @@ export default (detectionType: CliScanType) => `
6060
${detectionType === CliScanType.Iac ? iacRenderer : ''}
6161
${detectionType === CliScanType.Sast ? sastRenderer : ''}
6262
<script>
63-
if (detection) {
63+
if (severityIcons && detection) {
6464
renderDetection(detection);
6565
}
6666
6767
const updateState = () => {
68-
vscode.setState({ severityIcons: severityIcons, detection: detection });
68+
vscode.setState({ severityIcons, detection });
6969
};
7070
7171
const messageHandler = event => {
@@ -81,11 +81,18 @@ export default (detectionType: CliScanType) => `
8181
} else if (message.detection) {
8282
detection = message.detection;
8383
updateState();
84+
}
8485
85-
renderDetection(message.detection);
86+
if (severityIcons && detection) {
87+
renderDetection(detection);
8688
}
8789
};
8890
8991
window.addEventListener('message', messageHandler);
92+
window.onload = () => {
93+
vscode.postMessage({
94+
command: 'ready',
95+
});
96+
}
9097
</script>
9198
`;

src/ui/panels/violation/renderer/iac.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ const _resetDomState = () => {
1111
const renderDetection = detection => {
1212
_resetDomState();
1313
14-
const severityFirstLetter = detection.severity;
15-
ge('severity-icon').src = severityIcons[severityFirstLetter];
14+
ge('severity-icon').src = severityIcons[detection.severity];
1615
1716
ge('title').innerText = detection.message;
1817
ge('short-details').innerText = detection.severity;

src/ui/panels/violation/renderer/sast.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ const _resetDomState = () => {
1111
const renderDetection = detection => {
1212
_resetDomState();
1313
14-
const severityFirstLetter = detection.severity;
15-
ge('severity-icon').src = severityIcons[severityFirstLetter];
14+
ge('severity-icon').src = severityIcons[detection.severity];
1615
1716
ge('title').innerText = detection.detectionDetails.policyDisplayName;
1817

src/ui/panels/violation/renderer/sca.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ const _resetDomState = () => {
2020
const renderDetection = detection => {
2121
_resetDomState();
2222
23-
const severityFirstLetter = detection.severity;
24-
ge('severity-icon').src = severityIcons[severityFirstLetter];
23+
ge('severity-icon').src = severityIcons[detection.severity];
2524
ge('package').innerText = detection.detectionDetails.packageName;
2625
ge('version').innerText = detection.detectionDetails.packageVersion;
2726
ge('dependency-path-value').innerText = detection.detectionDetails.dependencyPaths;

src/ui/panels/violation/renderer/secret.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ const renderDetection = detection => {
1515
vscode.postMessage({ command: 'ignoreSecretByValue', uniqueDetectionId });
1616
};
1717
18-
const severityFirstLetter = detection.severity;
19-
ge('severity-icon').src = severityIcons[severityFirstLetter];
18+
ge('severity-icon').src = severityIcons[detection.severity];
2019
2120
ge('title').innerText = 'Hardcoded ' + detection.type + ' is used';
2221
ge('short-details').innerText = detection.severity;

0 commit comments

Comments
 (0)