Skip to content
This repository has been archived by the owner on Jan 16, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2 from quantum-sec/feature/VAPT-87
Browse files Browse the repository at this point in the history
VAPT-87: Add support for Zed Attack Proxy full scan
  • Loading branch information
elliate authored Oct 28, 2021
2 parents a565afb + 982df5e commit 88e224b
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 26 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ are any of the following **optional** arguments:
| [sonarqube](https://github.com/SonarSource/sonarqube) | SAST, DAST | C / C++ / Objective-C<br />C#<br />Go<br />Java<br />JavaScript / TypeScript<br />Kotlin<br />PHP<br />Python<br />Ruby<br />Scala<br />Swift<br />Visual Basic | [quantumsec/docker-pipeline-sonarqube](https://hub.docker.com/repository/docker/quantumsec/docker-pipeline-sonarqube) |
| [trivy](https://github.com/aquasecurity/trivy) | SAST | Terraform<br />Dockerfile<br />Kubernetes | [quantumsec/docker-pipeline-trivy](https://hub.docker.com/repository/docker/quantumsec/docker-pipeline-trivy) |
| [tfsec](https://github.com/aquasecurity/tfsec)<br />_(Planned)_ | SAST | Terraform | [quantumsec/docker-pipeline-tfsec](https://hub.docker.com/repository/docker/quantumsec/docker-pipeline-tfsec) |
| [ZAP](https://github.com/zaproxy/zaproxy) | SAST | HTTP | [quantumsec/docker-pipeline-zap](https://hub.docker.com/repository/docker/quantumsec/docker-pipeline-zap) |


## Code of Conduct
Expand Down
41 changes: 20 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 10 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,17 @@
"prepublishOnly": "npm run build"
},
"license": "Apache-2.0",
"bin": "dist/index.js",
"bin": {
"ci-analysis-collector": "dist/index.js"
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@quantum-sec/eslint-config-typescript": "^2.0.2",
"@quantum-sec/nyc-config-typescript": "^1.1.2",
"@quantum-sec/typescript-config": "^1.0.5",
"@types/jasmine": "^3.5.1",
"@types/jasmine": "^3.9.1",
"@types/node": "^15.12.5",
"@types/yargs": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^4.28.0",
Expand All @@ -55,8 +57,13 @@
"dependencies": {
"axios": "^0.21.1",
"chalk": "^2.4.2",
"tslib": "^1.13.0",
"dotenv": "^10.0.0",
"uuid": "^3.4.0",
"yargs": "^16.2.0"
}
},
"bugs": {
"url": "https://github.com/quantum-sec/ci-analysis-collector/issues"
},
"homepage": "https://github.com/quantum-sec/ci-analysis-collector#readme"
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env node

import { CheckovCollector, Logger, SonarqubeCollector, TrivyCollector } from './lib';
import { CheckovCollector, Logger, SonarqubeCollector, TrivyCollector, ZapCollector } from './lib';
import fs from 'fs';
import { argv } from 'yargs';

Expand All @@ -10,6 +10,7 @@ const collectors = {
checkov: CheckovCollector,
sonarqube: SonarqubeCollector,
trivy: TrivyCollector,
zap: ZapCollector,
};

/* eslint-disable complexity */
Expand Down
1 change: 1 addition & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './checkov';
export * from './sonarqube';
export * from './trivy';
export * from './utils';
export * from './zap';
5 changes: 5 additions & 0 deletions src/lib/result.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,9 @@ export interface IResult {
*/
packageVersion?: string;

/**
* The check method of the tool, e.g. get, post, etc.
*/
checkMethod?: string;

}
1 change: 1 addition & 0 deletions src/lib/zap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ZapCollector } from './zap-collector';
116 changes: 116 additions & 0 deletions src/lib/zap/zap-collector.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { Logger } from '../utils';
import { createLoggerFixture } from '../test/logger.fixture';
import { ZapCollector } from './zap-collector';
import { CheckResult } from '../check-result';

describe('ZapCollector', () => {

let collector: ZapCollector;
let logger: Logger;

beforeEach(() => {
logger = createLoggerFixture();
collector = new ZapCollector(logger);

spyOn(collector, 'spawn').and.returnValue(new Promise((resolve) => {
resolve('TEST_OUTPUT');
}));
});

describe('constructor()', () => {
it('should set the tool ID', () => {
expect(collector.toolId).toEqual('zap');
});
});

describe('getToolVersion()', () => {
it('should call zap with the -version flag', async () => {
const result = await collector.getToolVersion({});
expect(result).toEqual('TEST_OUTPUT');
expect(collector.spawn).toHaveBeenCalledTimes(1);
expect(collector.spawn).toHaveBeenCalledWith('zap.sh',
['-cmd -version'],
{});
});
});

describe('getResults()', () => {
it('should call zap with preset options', async () => {
collector._argv = {
'target-name': 'TEST_TARGET',
} as any;
spyOn(collector.fs, 'readFileSync').and.returnValue('TEST_OUTPUT');
spyOn(collector, 'parseResults').and.returnValue('TEST_RESULTS' as any);
const result = await collector.getResults({});
expect(result).toEqual('TEST_RESULTS' as any);

const expectedArgs = [
'-t',
'TEST_TARGET',
'-J zapreport.json',
'-s',
];
expect(collector.spawn).toHaveBeenCalledTimes(1);
expect(collector.spawn).toHaveBeenCalledWith('zap-full-scan.py', expectedArgs, {});

expect(collector.parseResults).toHaveBeenCalledTimes(1);
expect(collector.parseResults).toHaveBeenCalledWith('TEST_OUTPUT');
});
it('should error when target name is not specified', async () => {
await expectAsync(collector.getResults({}))
.toBeRejectedWith(new Error('You must specify an --target-name argument.'));
});

});

describe('parseResults()', () => {

let raw: string;

beforeEach(()=> {
raw = JSON.stringify([{
alerts: [{
pluginid: 'TEST_PLUGIN_ID',
alert: 'TEST_ALERT',
instances: {
uri: 'TEST_URI',
method: 'TEST_METHOD',
},
}],
}]);
});

it('should report passing when the result contains no vulnerabilities', () => {
raw = JSON.stringify([{}]);
const result = collector.parseResults(raw)[0];
expect(result.checkResult).toEqual(CheckResult.PASS);
});

it('should report failing when no vulnerabilities were found', () => {
const result = collector.parseResults(raw)[0];
expect(result.checkResult).toEqual(CheckResult.FAIL);
});

it('should set the checkId to pluginid', () => {
const result = collector.parseResults(raw)[0];
expect(result.checkId).toEqual('TEST_PLUGIN_ID');
});

it('should set the checkName to the alert name', () => {
const result = collector.parseResults(raw)[0];
expect(result.checkName).toEqual('TEST_ALERT');
});

it('should set the resourceId to instances.uri', () => {
const result = collector.parseResults(raw)[0];
expect(result.resourceId).toEqual('TEST_URI');
});

it('should set the checkMethod to instances.method', () => {
const result = collector.parseResults(raw)[0];
expect(result.checkMethod).toEqual('TEST_METHOD');
});

});

});
71 changes: 71 additions & 0 deletions src/lib/zap/zap-collector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { AnalysisCollectorBase } from '../analysis-collector-base';
import { CheckResult } from '../check-result';
import { IResult } from '../result.interface';
import { Logger } from '../utils';
import * as fs from 'fs';

export class ZapCollector extends AnalysisCollectorBase {
public fs = fs;

public constructor(logger: Logger) {
super('zap', logger);
}

public override async getToolVersion(options: any): Promise<string> {
const args = ['-cmd -version'];
return await this.spawn('zap.sh', args, options);
}

public override async getResults(options: any): Promise<IResult[]> {
const targetName = this._argv['target-name'];
if (!targetName) {
throw new Error('You must specify an --target-name argument.');
}

const args = ['-t', targetName, '-J zapreport.json', '-s'];
const output = await this.spawn('zap-full-scan.py', args, options);


const jsonFileContents: string = this.fs.readFileSync('zapreport.json', 'utf8');
this.logger.debug(JSON.stringify(output, null, 2));

return this.parseResults(jsonFileContents);
}

public parseResults(output: string): IResult[] {
const parsed = JSON.parse(output);

const results = [];

for (const set of parsed) {
if (!set.alerts) {
const result: IResult = {
checkId: 'vulnerabilities',
checkName: 'No vulnerabilities found.',
checkType: 'website',
checkResult: CheckResult.PASS,
resourceId: set.name,
};

results.push(result);
continue;
}

results.push(...set.alerts.map((v) => {
const result: IResult = {
checkId: v.pluginid,
checkName: v.alert,
checkType: 'website',
checkResult: CheckResult.FAIL,
resourceId: v.instances.uri,
checkMethod: v.instances.method,
};

return result;
}));

}
return results;
}

}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"extends": "@quantum-sec/typescript-config",
"compilerOptions": {
"rootDir": "src",
"esModuleInterop": true
"esModuleInterop": true,
"importHelpers": true
}
}

0 comments on commit 88e224b

Please sign in to comment.