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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Change Log

## [v1.6.0]

- Add Infrastructure as Code (IaC) support
- Add icons for file nodes in the tree view
- Add a full path of file nodes in the tree view

## [v1.5.0]

- Migrate to the new architecture that auto-manages the CLI
Expand Down Expand Up @@ -42,6 +48,8 @@

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

[v1.6.0]: https://github.com/cycodehq/vscode-extension/releases/tag/v1.6.0

[v1.5.0]: https://github.com/cycodehq/vscode-extension/releases/tag/v1.5.0

[v1.4.0]: https://github.com/cycodehq/vscode-extension/releases/tag/v1.4.0
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ open-source packages' vulnerabilities. The extension provides functionalities su
- Scanning categories:
- Hardcoded Secrets
- Open-source Threats (SCA)
- Coming soon: Code Security (SAST), and Infrastructure as Code.
- Infrastructure as Code (IaC)
- Coming soon: Code Security (SAST).
- Files
- Cycode console features a "View Problem" card that enables in-depth violation analysis with remediation
recommendations.
Expand Down
16 changes: 15 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"url": "https://github.com/cycodehq/vscode-extension"
},
"homepage": "https://cycode.com/",
"version": "1.5.0",
"version": "1.6.0",
"publisher": "cycode",
"engines": {
"vscode": "^1.63.0"
Expand Down Expand Up @@ -62,10 +62,19 @@
"when": "viewItem == SCA",
"group": "inline"
},
{
"command": "cycode.iacScanForProject",
"when": "viewItem == IaC",
"group": "inline"
},
{
"command": "cycode.secretScanForProject",
"when": "view == scan.treeView && viewItem == Secrets"
},
{
"command": "cycode.iacScanForProject",
"when": "view == scan.treeView && viewItem == IaC"
},
{
"command": "cycode.scaScan",
"when": "view == scan.treeView && viewItem == SCA"
Expand Down Expand Up @@ -130,6 +139,11 @@
"title": "Cycode: Scan for hardcoded secrets",
"icon": "$(testing-run-icon)"
},
{
"command": "cycode.iacScanForProject",
"title": "Cycode: Scan for Infrastructure As Code",
"icon": "$(testing-run-icon)"
},
{
"command": "cycode.scaScan",
"title": "Cycode: Scan for package vulnerabilities",
Expand Down
35 changes: 33 additions & 2 deletions src/cli-wrapper/cli-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const cliWrapper = {
printToOutput: true,
});
},
getRunnableSecretsScanCommand: (params: {
getRunnableSecretScanCommand: (params: {
config: IConfig;
path: string;
workspaceFolderPath?: string;
Expand Down Expand Up @@ -81,7 +81,7 @@ export const cliWrapper = {
commandParams.push(CommandParameters.OutputFormatJson);
commandParams.push(CliCommands.Scan);
commandParams.push(CommandParameters.scanType);
commandParams.push(CommandParameters.SCAScanType);
commandParams.push(CommandParameters.scaScanType);

if (config.experimentalScaSyncFlow) {
// TODO(MarshalX): remove experimental setting if stable
Expand All @@ -100,6 +100,37 @@ export const cliWrapper = {
printToOutput: true,
});
},
getRunnableIacScanCommand: (params: {
config: IConfig;
path: string;
workspaceFolderPath?: string;
}): RunCliResult => {
const {config, workspaceFolderPath} = params;
const {cliPath, cliEnv} = config;

const commandParams: string[] = [];
config.additionalParams.forEach((param) => {
commandParams.push(param);
});

commandParams.push(generateUserAgentCommandParam(config));
commandParams.push(CommandParameters.OutputFormatJson);

commandParams.push(CliCommands.Scan);
commandParams.push(CommandParameters.scanType);
commandParams.push(CommandParameters.iacScanType);

commandParams.push(CliCommands.Path);
commandParams.push(`"${params.path}"`);

return getRunnableCliCommand({
cliPath,
workspaceFolderPath,
commandParams,
cliEnv,
printToOutput: true,
});
},
getRunnableAuthCommand: (params: {
config: IConfig;
workspaceFolderPath?: string;
Expand Down
6 changes: 2 additions & 4 deletions src/cli-wrapper/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {ScanType} from '../constants';
export enum CliCommands {
Path = 'path',
Scan = 'scan',
Configure = 'configure',
Auth = 'auth',
AuthCheck = 'auth check',
Ignore = 'ignore',
Expand All @@ -12,14 +11,13 @@ export enum CliCommands {

export enum CommandParameters {
OutputFormatJson = '--output=json',
Usage = '--help',
ByRule = '--by-rule',
ByValue = '--by-value',
ByPath = '--by-path',
UserAgent = '--user-agent',
Version = '--version',
scanType = '--scan-type',
SCAScanType = 'sca',
scaScanType = 'sca',
iacScanType = 'iac',
Sync = '--sync',
NoRestore = '--no-restore',
}
Expand Down
20 changes: 19 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ const _SCA_CONFIGURATION_SCAN_LOCK_FILE_TO_PACKAGE_FILE: { [key: string]: string
const _SCA_CONFIGURATION_SCAN_SUPPORTED_LOCK_FILES: ReadonlyArray<string> =
Object.keys(_SCA_CONFIGURATION_SCAN_LOCK_FILE_TO_PACKAGE_FILE);

// keep in lowercase.
// source: https://github.com/cycodehq/cycode-cli/blob/ec8333707ab2590518fd0f36454c8636ccbf1061/cycode/cli/consts.py#L16
const _INFRA_CONFIGURATION_SCAN_SUPPORTED_FILE_SUFFIXES: ReadonlyArray<string> = [
'.tf',
'.tf.json',
'.json',
'.yaml',
'.yml',
'dockerfile',
];

export const isSupportedIacFile = (fileName: string): boolean => {
const lowerCaseFileName = fileName.toLowerCase();
return _INFRA_CONFIGURATION_SCAN_SUPPORTED_FILE_SUFFIXES.some(
(fileSuffix) => lowerCaseFileName.endsWith(fileSuffix)
);
};

export const isSupportedPackageFile = (fileName: string): boolean => {
const lowerCaseFileName = fileName.toLowerCase();
return _SCA_CONFIGURATION_SCAN_SUPPORTED_FILES.some((fileSuffix) => lowerCaseFileName.endsWith(fileSuffix));
Expand Down Expand Up @@ -114,7 +132,7 @@ export const getScanTypeDisplayName = (scanType: string): string => {

export const DIAGNOSTIC_CODE_SEPARATOR = '::';

export const REQUIRED_CLI_VERSION = '1.9.1';
export const REQUIRED_CLI_VERSION = '1.9.2';

export const CLI_GITHUB = {
OWNER: 'cycodehq',
Expand Down
79 changes: 74 additions & 5 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import {extensionOutput} from './logging/extension-output';
import {secretScan} from './services/secretScanner';
import {secretScan} from './services/scanners/SecretScanner';
import {scaScan} from './services/scanners/ScaScanner';
import {iacScan} from './services/scanners/IacScanner';
import {auth} from './services/auth';
import {extensionName} from './utils/texts';
import {VscodeCommands} from './utils/commands';
Expand All @@ -20,8 +22,7 @@ import AuthenticatingView from './views/authenticating/authenticating-view';
import {TreeView, TreeViewDisplayedData} from './providers/tree-view/types';
import {TreeViewDataProvider} from './providers/tree-view/provider';
import {TreeViewItem} from './providers/tree-view/item';
import {scaScan} from './services/scaScanner';
import {isSupportedPackageFile, ScanType} from './constants';
import {isSupportedIacFile, isSupportedPackageFile, ScanType} from './constants';
import {createPanel} from './panels/violation/violation-panel';
import {AnyDetection} from './types/detection';
import {VscodeStates} from './utils/states';
Expand Down Expand Up @@ -109,6 +110,18 @@ export async function activate(context: vscode.ExtensionContext) {
);
}

if (isSupportedIacFile(document.fileName)) {
iacScan(
{
config,
pathToScan: fileFsPath,
workspaceFolderPath,
diagnosticCollection,
},
treeView,
);
}

// run Secrets scan on any saved file. CLI will exclude irrelevant files
secretScan(
{
Expand Down Expand Up @@ -209,8 +222,7 @@ function initCommands(
() => {
// scan the current open document if opened

if (
!vscode.window.activeTextEditor?.document ||
if (!vscode.window.activeTextEditor?.document ||
vscode.window?.activeTextEditor?.document?.uri.scheme === 'output'
) {
TrayNotifications.showMustBeFocusedOnFile();
Expand Down Expand Up @@ -260,6 +272,61 @@ function initCommands(
}
);

const iacScanCommand = vscode.commands.registerCommand(
VscodeCommands.IacScanCommandId,
() => {
// scan the current open document if opened

if (!vscode.window.activeTextEditor?.document ||
vscode.window?.activeTextEditor?.document?.uri.scheme === 'output'
) {
TrayNotifications.showMustBeFocusedOnFile();

return;
}

if (validateConfig()) {
return;
}

iacScan(
{
config,
pathToScan: vscode.window.activeTextEditor.document.fileName,
workspaceFolderPath: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath,
diagnosticCollection,
onDemand: true,
},
treeView
);
}
);

const iacScanForCurrentProjectCommand = vscode.commands.registerCommand(
VscodeCommands.IacScanForProjectCommandId,
() => {
if (validateConfig()) {
return;
}

const projectPath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
if (!projectPath) {
return;
}

iacScan(
{
config,
pathToScan: projectPath,
workspaceFolderPath: projectPath,
diagnosticCollection,
onDemand: true,
},
treeView
);
}
);

const authCommand = vscode.commands.registerCommand(
VscodeCommands.AuthCommandId,
() => {
Expand Down Expand Up @@ -391,6 +458,8 @@ function initCommands(
secretScanCommand,
secretScanForCurrentProjectCommand,
scaScanCommand,
iacScanCommand,
iacScanForCurrentProjectCommand,
authCommand,
onTreeItemClickCommand,
onOpenViolationInFileFromTreeItemContextMenuCommand,
Expand Down
7 changes: 5 additions & 2 deletions src/providers/code-actions/CodeActions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as vscode from 'vscode';
import {DiagnosticCode} from '../../services/common';
import {ScanType} from '../../constants';
import {createCommandCodeActions as createSecretsCommandCodeActions} from './secretsCodeActions';
import {createCommandCodeActions as createSecretCommandCodeActions} from './secretsCodeActions';
import {createCommandCodeActions as createScaCommandCodeActions} from './scaCodeActions';
import {createCommandCodeActions as createIacCommandCodeActions} from './iacCodeActions';
import {aggregateDiagnosticsByCode} from './uniqueDiagnostics';

export class CycodeActions implements vscode.CodeActionProvider {
Expand Down Expand Up @@ -34,9 +35,11 @@ export class CycodeActions implements vscode.CodeActionProvider {
const diagnosticCode = DiagnosticCode.fromString(rawDiagnosticCode);
switch (diagnosticCode.scanType) {
case ScanType.Secrets:
return createSecretsCommandCodeActions(document, range, diagnostics, diagnosticCode);
return createSecretCommandCodeActions(document, range, diagnostics, diagnosticCode);
case ScanType.Sca:
return createScaCommandCodeActions(document, diagnostics, diagnosticCode);
case ScanType.Iac:
return createIacCommandCodeActions(document, diagnostics, diagnosticCode);
default:
return [];
}
Expand Down
14 changes: 14 additions & 0 deletions src/providers/code-actions/iacCodeActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as vscode from 'vscode';
import {DiagnosticCode} from '../../services/common';
import {createIgnorePathAction, createIgnoreRuleAction} from './commonActions';

export const createCommandCodeActions = (
document: vscode.TextDocument,
diagnostics: vscode.Diagnostic[],
diagnosticCode: DiagnosticCode,
): vscode.CodeAction[] => {
return [
createIgnoreRuleAction(diagnostics, diagnosticCode, document),
createIgnorePathAction(diagnostics, diagnosticCode, document),
];
};
7 changes: 3 additions & 4 deletions src/providers/tree-view/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,12 @@ const getSastSectionItem = (_: string): TreeViewItem => new TreeViewItem({
description: '(coming soon)', // use fun arg when implemented
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const getIacSectionItem = (_: string): TreeViewItem => new TreeViewItem({
const getIacSectionItem = (description: string): TreeViewItem => new TreeViewItem({
title: ScanTypeDisplayName.Iac,
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
scanSectionType: ScanType.Iac,
customIconPath: getScanTypeIconPath(ScanType.Iac),
description: '(coming soon)', // use fun arg when implemented
description,
});

const _SCAN_TYPE_TO_SECTION_ITEM_CREATOR: { [key: string]: ((description: string) => TreeViewItem)} = {
Expand All @@ -67,7 +66,7 @@ const _SCAN_TYPE_TO_SECTION_ITEM_CREATOR: { [key: string]: ((description: string
[ScanType.Iac]: getIacSectionItem,
};

export const SECTIONS_ORDER: ReadonlyArray<ScanType> = [ScanType.Secrets, ScanType.Sca, ScanType.Sast, ScanType.Iac];
export const SECTIONS_ORDER: ReadonlyArray<ScanType> = [ScanType.Secrets, ScanType.Sca, ScanType.Iac, ScanType.Sast];

export const getSectionItem = (scanType: string, description: string): TreeViewItem => {
if (!(scanType in _SCAN_TYPE_TO_SECTION_ITEM_CREATOR)) {
Expand Down
5 changes: 5 additions & 0 deletions src/providers/tree-view/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ export class TreeViewItem extends vscode.TreeItem {
this.vulnerability = options.vulnerability;
// file tree item
this.vulnerabilities = options.vulnerabilities;
if (options.vulnerabilities && options.fullFilePath) {
// used to enable file theme icon
this.iconPath = vscode.ThemeIcon.File;
this.resourceUri = vscode.Uri.file(options.fullFilePath);
}

if (options.customIconPath) {
this.iconPath = {
Expand Down
Loading