Skip to content

Commit

Permalink
Support JFrog Apps Config file
Browse files Browse the repository at this point in the history
  • Loading branch information
yahavi committed Sep 20, 2023
1 parent 793e1d8 commit 410eca7
Show file tree
Hide file tree
Showing 23 changed files with 515 additions and 271 deletions.
78 changes: 38 additions & 40 deletions src/main/scanLogic/scanManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,31 @@ import * as vscode from 'vscode';

import { ExtensionComponent } from '../extensionComponent';

import { LogManager } from '../log/logManager';
import { ConnectionManager } from '../connect/connectionManager';
import { ConnectionUtils, EntitlementScanFeature } from '../connect/connectionUtils';
import { LogManager } from '../log/logManager';

import { RootNode } from '../treeDataProviders/dependenciesTree/dependenciesRoot/rootTree';
import { IGraphResponse, XrayScanProgress } from 'jfrog-client-js';
import { GraphScanLogic } from './scanGraphLogic';
import { ApplicabilityRunner, ApplicabilityScanResponse } from './scanRunners/applicabilityScan';
import { EosRunner, EosScanRequest, EosScanResponse } from './scanRunners/eosScan';
import { RootNode } from '../treeDataProviders/dependenciesTree/dependenciesRoot/rootTree';
import { AnalyzerUtils } from '../treeDataProviders/utils/analyzerUtils';
import { StepProgress } from '../treeDataProviders/utils/stepProgress';
import { ExcludeScanner, Module } from '../types/jfrogAppsConfig';
import { AppsConfigUtils } from '../utils/appConfigUtils';
import { Configuration } from '../utils/configuration';
import { Resource } from '../utils/resource';
import { BinaryRunner } from './scanRunners/binaryRunner';
import { ScanUtils } from '../utils/scanUtils';
import { StepProgress } from '../treeDataProviders/utils/stepProgress';
import { Utils } from '../utils/utils';
import { GraphScanLogic } from './scanGraphLogic';
import { ApplicabilityRunner, ApplicabilityScanResponse } from './scanRunners/applicabilityScan';
import { BinaryRunner } from './scanRunners/binaryRunner';
import { IacRunner, IacScanResponse } from './scanRunners/iacScan';
import { EosScanResponse, SastRunner } from './scanRunners/sastScan';
import { SecretsRunner, SecretsScanResponse } from './scanRunners/secretsScan';

export interface SupportedScans {
dependencies: boolean;
applicability: boolean;
eos: boolean;
sast: boolean;
iac: boolean;
secrets: boolean;
}
Expand Down Expand Up @@ -167,9 +169,9 @@ export class ScanManager implements ExtensionComponent {
}

/**
* Check if Eos scan is supported for the user
* Check if SAST scan is supported for the user
*/
public async isEosSupported(): Promise<boolean> {
public async isSastSupported(): Promise<boolean> {
return true;
}

Expand Down Expand Up @@ -200,8 +202,8 @@ export class ScanManager implements ExtensionComponent {
.catch(err => ScanUtils.onScanError(err, this._logManager, true))
);
requests.push(
this.isEosSupported()
.then(res => (supportedScans.eos = res))
this.isSastSupported()
.then(res => (supportedScans.sast = res))
.catch(err => ScanUtils.onScanError(err, this._logManager, true))
);
await Promise.all(requests);
Expand Down Expand Up @@ -250,61 +252,57 @@ export class ScanManager implements ExtensionComponent {

/**
* Scan directory for 'Infrastructure As Code' (Iac) issues.
* @param directory - the directory that will be scan
* @param module - the module that will be scanned
* @param checkCancel - check if should cancel
* @returns the Iac scan response
*/
public async scanIac(directory: string, checkCancel: () => void): Promise<IacScanResponse> {
public async scanIac(module: Module, checkCancel: () => void): Promise<IacScanResponse> {
let iacRunner: IacRunner = new IacRunner(this._connectionManager, this.logManager);
if (!iacRunner.validateSupported()) {
this._logManager.logMessage('Iac runner could not find binary to run', 'WARN');
return {} as IacScanResponse;
}
let skipFiles: string[] = AnalyzerUtils.getAnalyzerManagerExcludePattern(Configuration.getScanExcludePattern());
this._logManager.logMessage("Scanning directory '" + directory + "', for Iac issues. Skipping files: " + skipFiles, 'DEBUG');
return await iacRunner.scan(directory, checkCancel, skipFiles);
if (AppsConfigUtils.ShouldSkipScanner(module, ExcludeScanner.Iac)) {
this._logManager.debug('Skipping IaC scanning');
return {} as IacScanResponse;
}
return await iacRunner.scan(module, checkCancel);
}
/**
* Scan directory for secrets issues.
* @param directory - the directory that will be scan
* @param module - the module that will be scanned
* @param checkCancel - check if should cancel
* @returns the Secrets scan response
*/
public async scanSecrets(directory: string, checkCancel: () => void): Promise<SecretsScanResponse> {
public async scanSecrets(module: Module, checkCancel: () => void): Promise<SecretsScanResponse> {
let secretsRunner: SecretsRunner = new SecretsRunner(this._connectionManager, this.logManager);
if (!secretsRunner.validateSupported()) {
this._logManager.logMessage('Secrets runner could not find binary to run', 'WARN');
return {} as SecretsScanResponse;
}
let skipFiles: string[] = AnalyzerUtils.getAnalyzerManagerExcludePattern(Configuration.getScanExcludePattern());
this._logManager.logMessage("Scanning directory '" + directory + "', for Secrets issues. Skipping files: " + skipFiles, 'DEBUG');
return await secretsRunner.scan(directory, checkCancel, skipFiles);
if (AppsConfigUtils.ShouldSkipScanner(module, ExcludeScanner.Secrets)) {
this._logManager.debug('Skipping secrets scanning');
return {} as SecretsScanResponse;
}
return await secretsRunner.scan(module, checkCancel);
}

/**
* Scan for Eos issues.
* @param checkCancel - check if should cancel
* @param requests - the Eos requests to run
* Scan for SAST issues.
* @param module - the module that will be scanned
* @param requests - the SAST requests to run
* @returns the scan response
*/
public async scanEos(checkCancel: () => void, runDirectory?: string, ...requests: EosScanRequest[]): Promise<EosScanResponse> {
let eosRunner: EosRunner = new EosRunner(this._connectionManager, this._logManager, undefined, undefined, runDirectory);
if (!eosRunner.validateSupported()) {
this._logManager.logMessage('Eos runner could not find binary to run', 'WARN');
public async scanSast(module: Module, checkCancel: () => void): Promise<EosScanResponse> {
let sastRunner: SastRunner = new SastRunner(this._connectionManager, this._logManager);
if (!sastRunner.validateSupported()) {
this._logManager.logMessage('Sast runner could not find binary to run', 'WARN');
return {} as EosScanResponse;
}
if (requests.length === 0) {
this._logManager.logMessage('Eos runner must receive at least one request to run', 'ERR');
if (AppsConfigUtils.ShouldSkipScanner(module, ExcludeScanner.Sast)) {
this._logManager.debug('Skipping SAST scanning');
return {} as EosScanResponse;
}
let skipFiles: string[] = AnalyzerUtils.getAnalyzerManagerExcludePattern(Configuration.getScanExcludePattern());
this._logManager.logMessage(
'Scanning for Eos issues in ' +
requests.map(request => `(Language '${request.language}', roots: [${request.roots.join()}])`) +
'. Skipping files: ' +
skipFiles,
'DEBUG'
);
return eosRunner.scan(checkCancel, skipFiles, ...requests);
return sastRunner.scan(module, checkCancel);
}
}
2 changes: 1 addition & 1 deletion src/main/scanLogic/scanRunners/analyzerModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface AnalyzerRequest {
export enum ScanType {
ContextualAnalysis = 'analyze-applicability',
Iac = 'iac-scan-modules',
Eos = 'analyze-codebase',
Sast = 'sast',
Secrets = 'secrets-scan'
}

Expand Down
42 changes: 20 additions & 22 deletions src/main/scanLogic/scanRunners/binaryRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,11 @@ export abstract class BinaryRunner {
return url;
}

public async run(checkCancel: () => void, ...requests: AnalyzeScanRequest[]): Promise<AnalyzerScanResponse | undefined> {
public async run(checkCancel: () => void, request: AnalyzeScanRequest): Promise<AnalyzerScanResponse | undefined> {
if (!this.validateSupported()) {
return undefined;
}
let args: RunArgs = this.createRunArguments(...requests);
let args: RunArgs = this.createRunArguments(request);
try {
if (args.requests.length == 0) {
return undefined;
Expand All @@ -250,27 +250,25 @@ export abstract class BinaryRunner {
* @param requests - the run requests information
* @return run arguments for the given requests
*/
private createRunArguments(...requests: AnalyzeScanRequest[]): RunArgs {
private createRunArguments(request: AnalyzeScanRequest): RunArgs {
let args: RunArgs = new RunArgs(ScanUtils.createTmpDir());
let processedRoots: Set<string> = new Set<string>();

for (const request of requests) {
if (request.roots.length > 0 && request.roots.every(root => !processedRoots.has(root))) {
// Prepare request information and insert as an actual request
const requestPath: string = path.join(args.directory, 'request_' + args.requests.length);
const responsePath: string = path.join(args.directory, 'response_' + args.requests.length);
request.output = responsePath;
request.type = this._type;
request.roots.forEach(root => processedRoots.add(root));
// Add request to run
args.requests.push({
type: request.type,
request: this.requestsToYaml(request),
requestPath: requestPath,
roots: request.roots,
responsePath: responsePath
} as RunRequest);
}
if (request.roots.length > 0 && request.roots.every(root => !processedRoots.has(root))) {
// Prepare request information and insert as an actual request
const requestPath: string = path.join(args.directory, 'request_' + args.requests.length);
const responsePath: string = path.join(args.directory, 'response_' + args.requests.length);
request.output = responsePath;
request.type = this._type;
request.roots.forEach(root => processedRoots.add(root));
// Add request to run
args.requests.push({
type: request.type,
request: this.requestsToYaml(request),
requestPath: requestPath,
roots: request.roots,
responsePath: responsePath
} as RunRequest);
}

return args;
Expand All @@ -297,7 +295,7 @@ export abstract class BinaryRunner {
this.runRequest(
checkCancel,
args.requests[i].request,
args.requests[i].type === ScanType.Eos ? args.requests[i].responsePath : args.requests[i].requestPath,
args.requests[i].type === ScanType.Sast ? args.requests[i].responsePath : args.requests[i].requestPath,
args.requests[i].type,
args.requests[i].responsePath
)
Expand Down Expand Up @@ -390,7 +388,7 @@ export abstract class BinaryRunner {
responsePath: string
): Promise<AnalyzerScanResponse> {
// 1. Save requests as yaml file in folder
if (type !== ScanType.Eos) {
if (type !== ScanType.Sast) {
fs.writeFileSync(requestPath, request);
}
// 2. Run the binary
Expand Down
12 changes: 9 additions & 3 deletions src/main/scanLogic/scanRunners/iacScan.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ConnectionManager } from '../../connect/connectionManager';
import { LogManager } from '../../log/logManager';
import { AnalyzerUtils, FileWithSecurityIssues } from '../../treeDataProviders/utils/analyzerUtils';
import { Module } from '../../types/jfrogAppsConfig';
import { AppsConfigUtils } from '../../utils/appConfigUtils';
import { Resource } from '../../utils/resource';
import { ScanUtils } from '../../utils/scanUtils';
import { AnalyzeScanRequest, AnalyzerScanResponse, ScanType } from './analyzerModels';
Expand Down Expand Up @@ -28,12 +30,16 @@ export class IacRunner extends BinaryRunner {
await this.executeBinary(checkCancel, ['iac', yamlConfigPath], executionLogDirectory);
}

public async scan(directory: string, checkCancel: () => void, skipFolders: string[] = []): Promise<IacScanResponse> {
public async scan(module: Module, checkCancel: () => void): Promise<IacScanResponse> {
let request: AnalyzeScanRequest = {
type: ScanType.Iac,
roots: [directory],
skipped_folders: skipFolders
roots: AppsConfigUtils.GetSourceRoots(module, module.scanners?.iac),
skipped_folders: AppsConfigUtils.GetExcludePatterns(module, module.scanners?.iac)
} as AnalyzeScanRequest;
this._logManager.logMessage(
"Scanning directories '" + request.roots + "', for Iac issues. Skipping folders: " + request.skipped_folders,
'DEBUG'
);
return await this.run(checkCancel, request).then(runResult => this.convertResponse(runResult));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
import { ConnectionManager } from '../../connect/connectionManager';
import { LogManager } from '../../log/logManager';
import { BinaryRunner } from './binaryRunner';
import { AnalyzerUtils } from '../../treeDataProviders/utils/analyzerUtils';
import { Module, SastScanner } from '../../types/jfrogAppsConfig';
import { Severity } from '../../types/severity';
import { AppsConfigUtils } from '../../utils/appConfigUtils';
import { Resource } from '../../utils/resource';
import { ScanUtils } from '../../utils/scanUtils';
import { Translators } from '../../utils/translators';
import {
AnalyzeIssue,
AnalyzerScanResponse,
AnalyzeScanRequest,
AnalyzeLocation,
FileRegion,
FileLocation,
AnalyzeScanRequest,
AnalyzerScanResponse,
CodeFlow,
FileLocation,
FileRegion,
ScanType
} from './analyzerModels';
import { ConnectionManager } from '../../connect/connectionManager';
import { AnalyzerUtils } from '../../treeDataProviders/utils/analyzerUtils';
import { Resource } from '../../utils/resource';
import { Severity } from '../../types/severity';
import { Translators } from '../../utils/translators';
import { ScanUtils } from '../../utils/scanUtils';
import { BinaryRunner } from './binaryRunner';

export interface EosScanRequest extends AnalyzeScanRequest {
language: LanguageType;
/**
* The request that is sent to the binary to scan Sast
*/
export interface SastScanRequest extends AnalyzeScanRequest {
language: string;
exclude_patterns: string[];
excluded_rules: string[];
}

export type LanguageType = 'python' | 'javascript' | 'java';
export type LanguageType = 'python' | 'javascript' | 'typescript' | 'java';

export interface EosScanResponse {
filesWithIssues: EosFileIssues[];
Expand All @@ -46,15 +52,14 @@ export interface EosIssueLocation {
threadFlows: FileLocation[][];
}

export class EosRunner extends BinaryRunner {
export class SastRunner extends BinaryRunner {
constructor(
connectionManager: ConnectionManager,
logManager: LogManager,
binary?: Resource,
timeout: number = ScanUtils.ANALYZER_TIMEOUT_MILLISECS,
runDirectory?: string
timeout: number = ScanUtils.ANALYZER_TIMEOUT_MILLISECS
) {
super(connectionManager, timeout, ScanType.Eos, logManager, binary, runDirectory);
super(connectionManager, timeout, ScanType.Sast, logManager, binary);
}

/** @override */
Expand All @@ -63,17 +68,26 @@ export class EosRunner extends BinaryRunner {
}

/**
* Scan for EOS issues
* Scan for SAST issues
* @param checkCancel - check if cancel
* @param requests - requests to run
* @returns the response generated from the scan
*/
public async scan(checkCancel: () => void, skipFiles: string[], ...requests: EosScanRequest[]): Promise<EosScanResponse> {
requests.forEach(request => {
request.type = ScanType.Eos;
request.exclude_patterns = skipFiles;
});
return await this.run(checkCancel, ...requests).then(runResult => this.generateScanResponse(runResult));
public async scan(module: Module, checkCancel: () => void): Promise<EosScanResponse> {
let sastScanner: SastScanner | undefined = module.scanners?.sast;
let request: SastScanRequest = {
type: ScanType.Sast,
roots: AppsConfigUtils.GetSourceRoots(module, sastScanner),
language: sastScanner?.language,
excluded_rules: sastScanner?.excluded_rules,
exclude_patterns: AppsConfigUtils.GetExcludePatterns(module, sastScanner)
} as SastScanRequest;
this._logManager.logMessage(
"Scanning directories '" + request.roots + "', for SAST issues. Skipping folders: " + request.skipped_folders,
'DEBUG'
);

return await this.run(checkCancel, request).then(runResult => this.generateScanResponse(runResult));
}

/**
Expand Down
8 changes: 5 additions & 3 deletions src/main/scanLogic/scanRunners/secretsScan.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ConnectionManager } from '../../connect/connectionManager';
import { LogManager } from '../../log/logManager';
import { AnalyzerUtils, FileWithSecurityIssues } from '../../treeDataProviders/utils/analyzerUtils';
import { Module } from '../../types/jfrogAppsConfig';
import { AppsConfigUtils } from '../../utils/appConfigUtils';
import { Resource } from '../../utils/resource';
import { ScanUtils } from '../../utils/scanUtils';
import { AnalyzeScanRequest, AnalyzerScanResponse, ScanType } from './analyzerModels';
Expand Down Expand Up @@ -28,11 +30,11 @@ export class SecretsRunner extends BinaryRunner {
await this.executeBinary(checkCancel, ['sec', yamlConfigPath], executionLogDirectory);
}

public async scan(directory: string, checkCancel: () => void, skipFolders: string[] = []): Promise<SecretsScanResponse> {
public async scan(module: Module, checkCancel: () => void): Promise<SecretsScanResponse> {
let request: AnalyzeScanRequest = {
type: ScanType.Secrets,
roots: [directory],
skipped_folders: skipFolders
roots: AppsConfigUtils.GetSourceRoots(module, module.scanners?.iac),
skipped_folders: AppsConfigUtils.GetExcludePatterns(module, module.scanners?.iac)
} as AnalyzeScanRequest;
return await this.run(checkCancel, request).then(runResult => this.convertResponse(runResult));
}
Expand Down
Loading

0 comments on commit 410eca7

Please sign in to comment.