diff --git a/.travis.yml b/.travis.yml index d172cb6..faf76d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ install: - yarn install - pip3 install --user -r requirements.txt - curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $GOPATH/bin 1.2.0 - - export GOPATH=$GOPATH:${TRAVIS_BUILD_DIR}/test/fixtures/go + - export GOPATH=$GOPATH:${TRAVIS_BUILD_DIR}/test/fixtures/go:${TRAVIS_BUILD_DIR}/cache/go - npm install -g codecov script: diff --git a/bandit/bandit.js b/bandit/bandit.js deleted file mode 100755 index 8833799..0000000 --- a/bandit/bandit.js +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2018 VMware, Inc. -// SPDX-License-Identifier: BSD-2-Clause - -const { spawn } = require('child_process') -const path = require('path') -const parseOutput = require('../parse_output') - -/** - * Spawn a bandit process analyzing all given files in provided directory - * @param {string} directory Working directory for Bandit process - * @param {string[]} inputFiles List of input file paths relative to working directory - * @param {string?} params.reportFile Path to report file relative to working directory (default: bandit.json) - * @param {string?} params.baselineFile Path to baseline file relative to working directory - * @returns {Promise} results json - */ -module.exports = (directory, inputFiles, params) => { - const pyFiles = inputFiles.filter(fileName => fileName.endsWith('.py')) - if (pyFiles.length === 0) { - return null - } - - params = params || {} - params.reportFile = params.reportFile || 'bandit.json' - - const reportPath = path.join(directory, params.reportFile) - - let banditArgs = [...pyFiles, '--format', 'json', '-o', params.reportFile] - if (params.baselineFile) { - banditArgs.push('--baseline', params.baselineFile) - } - - const banditProcess = spawn('bandit', banditArgs, { cwd: directory }) - - return new Promise((resolve, reject) => { - banditProcess - .on('error', reject) - .on('close', () => { - parseOutput.readFile(reportPath, resolve, reject) - }) - }) -} diff --git a/gosec/gosec.js b/gosec/gosec.js deleted file mode 100644 index 0168a83..0000000 --- a/gosec/gosec.js +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2018 VMware, Inc. -// SPDX-License-Identifier: BSD-2-Clause - -const { spawn } = require('child_process') -const parse = require('../parse_output.js') -const path = require('path') -const fs = require('fs') - -/** - * Spawn a gosec process analyzing all the files in a given directory. - * @param {string} directory Working directory for the Gosec process - * @param {string[]} inputFiles List of input file paths for analyze - * @param {string?} reportFile Path to report file relative to working directory (default: gosec.json) - * @returns {Promise} The contents of the gosec report - */ -module.exports = (directory, inputFiles, reportFile) => { - const goFiles = inputFiles.filter(fileName => fileName.endsWith('.go')) - if (goFiles.length === 0) { - return null - } - reportFile = reportFile || 'gosec.json' - const currentDirectory = path.resolve(directory) - /** - * @argument gosec command which the child process will execute - * @argument -fmt output format of the command - * @argument out flag which redirects the gosec output to a file - * @argument reportFile the file where the output of gosec will be stored - * @argument goFiles files which will be analyzed by gosec - */ - let gosecArgs = ['-fmt=json', '-out', reportFile, './...'] - - let gosecProcess = spawn('gosec', gosecArgs, { cwd: currentDirectory }) - - let logs = '' - gosecProcess.stderr.on('data', function (data) { - logs += data.toString() - }) - - return new Promise((resolve, reject) => { - gosecProcess - .on('error', reject) - .on('close', () => { - if (!fs.existsSync(path.join(currentDirectory, reportFile))) { - console.log('The logs for Gosec are: ') - console.log(logs) - } - parse.readFile(path.join(currentDirectory, reportFile), resolve, reject) - }) - }) -} diff --git a/index.js b/index.js index db8cc82..2b20a26 100755 --- a/index.js +++ b/index.js @@ -1,16 +1,10 @@ // Copyright 2018 VMware, Inc. // SPDX-License-Identifier: BSD-2-Clause -const runBandit = require('./bandit/bandit') -const runGosec = require('./gosec/gosec') -const generateBanditReport = require('./bandit/bandit_report') -const generateGosecReport = require('./gosec/gosec_report') -const mergeReports = require('./merge_reports') const cache = require('./cache') const { config } = require('./config') const apiHelper = require('./github_api_helper') - -const path = require('path') +const { runLinters } = require('./runner') /** * @param {import('probot').Application} app - Probot's Application class. @@ -80,17 +74,10 @@ async function runLinterFromPRData (pullRequests, context, headSha) { const PR = pullRequests[0] const inputFiles = resolvedPRs[0] - const banditResults = await runBandit(cache.getBranchPath(repoID, PR.id, 'bandit'), inputFiles) - const banditReport = generateBanditReport(banditResults, cache.getBranchPath(repoID, PR.id, 'bandit')) - - const gosecResults = await runGosec(cache.getBranchPath(repoID, PR.id, 'gosec'), inputFiles) - const gosecReport = generateGosecReport(gosecResults, path.resolve(cache.getBranchPath(repoID, PR.id, 'gosec'))) + const report = await runLinters(inputFiles, repoID, PR.id) - const output = mergeReports(banditReport, gosecReport) - const resolvedCheckRunResponse = await checkRunResponse - const runID = resolvedCheckRunResponse.data.id - // Send results using the octokit APIrunID - apiHelper.sendResults(context, runID, output) + const runID = (await checkRunResponse).data.id + apiHelper.sendResults(context, runID, report) if (config.cleanupAfterRun) { cache.clear(repoID, PR.id) diff --git a/linters/bandit.js b/linters/bandit.js new file mode 100644 index 0000000..67b2960 --- /dev/null +++ b/linters/bandit.js @@ -0,0 +1,68 @@ +// Copyright 2018 VMware, Inc. +// SPDX-License-Identifier: BSD-2-Clause + +const cache = require('../cache') + +const report = require('../bandit/bandit_report') + +module.exports = class Bandit { + get name () { + return 'bandit' + } + + /** + * The name of the generated report file + */ + get reportFile () { + return 'bandit.json' + } + + get defaultReport () { + return report(null) + } + + /** + * Retains files that can be analyzed by this linter + * @param {string[]} files Names of files to analyze + * @returns {string[]} Filtered list of file names + */ + filter (files) { + return files.filter(name => name.endsWith('.py')) + } + + /** + * Returns the working directory for this analysis + * @param {string} repoID Unique repository id + * @param {string} prID PR id in repository + */ + workingDirectoryForPR (repoID, prID) { + return cache.getBranchPath(repoID, prID, 'bandit') + } + + /** + * Builds the command line args to pass to the linter process + * @param {string[]} files List of files to analyze + * @param {string} reportPath Path to the report file relative to working directory + */ + args (files, reportPath) { + return ['--format', 'json', '-o', reportPath, ...files] + } + + /** + * Parses the linter results + * @param {Buffer} data The raw linter results data + */ + parseResults (data) { + return JSON.parse(data) + } + + /** + * Generates a report in the format expected by GitHub checks + * from the linter results + * @param {any} results Linter results + * @returns GitHub checks report + */ + generateReport (results) { + return report(results) + } +} diff --git a/linters/gosec.js b/linters/gosec.js new file mode 100644 index 0000000..5ee4ac4 --- /dev/null +++ b/linters/gosec.js @@ -0,0 +1,68 @@ +// Copyright 2018 VMware, Inc. +// SPDX-License-Identifier: BSD-2-Clause + +const cache = require('../cache') + +const report = require('../gosec/gosec_report') + +module.exports = class Gosec { + get name () { + return 'gosec' + } + + /** + * The name of the generated report file + */ + get reportFile () { + return 'gosec.json' + } + + get defaultReport () { + return report(null) + } + + /** + * Retains files that can be analyzed by this linter + * @param {string[]} files Names of files to analyze + * @returns {string[]} Filtered list of file names + */ + filter (files) { + return files.filter(name => name.endsWith('.go')) + } + + /** + * Returns the working directory for this analysis + * @param {string} repoID Unique repository id + * @param {string} prID PR id in repository + */ + workingDirectoryForPR (repoID, prID) { + return cache.getBranchPath(repoID, prID, 'gosec') + } + + /** + * Builds the command line args to pass to the linter process + * @param {string[]} files List of files to analyze + * @param {string} reportPath Path to the report file relative to working directory + */ + args (files, reportPath) { + return ['-fmt=json', '-out', reportPath, './...'] + } + + /** + * Parses the linter results + * @param {Buffer} data The raw linter results data + */ + parseResults (data) { + return JSON.parse(data) + } + + /** + * Generates a report in the format expected by GitHub checks + * from the linter results + * @param {any} results Linter results + * @returns GitHub checks report + */ + generateReport (results) { + return report(results) + } +} diff --git a/linters/index.js b/linters/index.js new file mode 100644 index 0000000..fb55e34 --- /dev/null +++ b/linters/index.js @@ -0,0 +1,10 @@ +// Copyright 2018 VMware, Inc. +// SPDX-License-Identifier: BSD-2-Clause + +const Bandit = require('./bandit') +const Gosec = require('./gosec') + +module.exports = { + BANDIT: new Bandit(), + GOSEC: new Gosec() +} diff --git a/parse_output.js b/parse_output.js deleted file mode 100644 index dba1198..0000000 --- a/parse_output.js +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018 VMware, Inc. -// SPDX-License-Identifier: BSD-2-Clause - -const fs = require('fs') - -/** -* Function which parses JSON into text format -* @param {*} data - data to be parsed -*/ -function parseJSON (data) { - try { - return JSON.parse(data) - } catch (error) { - return null - } -} - -/** - * The function reads the content ot the file - * @param {String} filePath path to the file with content for read - * @param {function} resolve JS promise callback if everything succeeds - * @param {function} reject JS promise callback if something fails - */ -module.exports.readFile = (filePath, resolve, reject) => { - fs.readFile(filePath, 'utf8', (err, data) => { - if (err) { - console.log('Error when reading the file %s in the parse output file!', filePath) - reject(err) - } - const results = parseJSON(data) - resolve(results) - }) -} diff --git a/runner.js b/runner.js new file mode 100644 index 0000000..6d0676b --- /dev/null +++ b/runner.js @@ -0,0 +1,69 @@ +// Copyright 2018 VMware, Inc. +// SPDX-License-Identifier: BSD-2-Clause + +const { spawn } = require('child_process') +const fs = require('fs') +const path = require('path') + +const merge = require('./merge_reports') +const linters = require('./linters') + +/** + * Run all linters on specified files + * @param {string[]} files Files to analyze + * @param {string} repoID + * @param {string} prID + */ +async function runLinters (files, repoID, prID) { + // TODO: Sync directory with file download location resolution + const reports = Object.values(linters).map((linter) => run(linter, linter.workingDirectoryForPR(repoID, prID), files)) + const resolved = await Promise.all(reports) + + // TODO: rewrite merge to handle list of reports + return merge(resolved[0], resolved[1]) +} + +/** + * Linter driver logic: spawn a child process, gather the results and build + * a report + * @param {*} linter A linter instance + * @param {string} workingDirectory The path to the process working directory + * @param {string[]} files Files to analyze + * @returns {Promise} A promise for the report object with the analysis results + */ +function run (linter, workingDirectory, files) { + const filtered = linter.filter(files) + + if (filtered.length === 0) { return linter.defaultReport } + + const reportFilePath = path.join(workingDirectory, '..', linter.reportFile) + const process = spawn(linter.name, linter.args(filtered, path.join('..', linter.reportFile)), { cwd: workingDirectory }) + + let errorLogs = '' + process.stderr.on('data', (chunk) => { + errorLogs += chunk.toString() + }) + + // Promise report generation + return new Promise((resolve, reject) => { + process.on('error', reject) + process.on('close', () => reportHandler(linter, reportFilePath, resolve, reject, errorLogs)) + }) +} + +function reportHandler (linter, reportFilePath, resolve, reject, logs) { + fs.readFile(reportFilePath, 'utf8', (err, data) => { + if (err) { + console.log('Could not read linter results: ' + reportFilePath) + console.log('stderr: ' + logs) + return reject(err) + } else { + const results = linter.parseResults(data) + const report = linter.generateReport(results) + return resolve(report) + } + }) +} + +module.exports.runLinters = runLinters +module.exports.run = run diff --git a/test/bandit.report.test.js b/test/bandit.report.test.js index 508e671..ed7fab7 100755 --- a/test/bandit.report.test.js +++ b/test/bandit.report.test.js @@ -3,7 +3,7 @@ const generateReport = require('../bandit/bandit_report') const { config } = require('../config') -const banditResults = require('./fixtures/reports/mix_results.json') +const banditResults = require('./fixtures/reports/bandit_vulnerable.json') describe('Report generation', () => { let report @@ -41,12 +41,12 @@ describe('Report generation', () => { // This test caches a few cases at a time: when a pr scans python files without security issues // and when a PR doesn't have any python files test('Generate report on results from Bandit without security issues', async () => { - const jsonResults = require('./fixtures/reports/no_issues_report.json') + const results = require('./fixtures/reports/bandit_safe.json') - const trueReport = generateReport(jsonResults) + const report = generateReport(results) - expect(trueReport.title).toEqual(config.noIssuesResultTitle) - expect(trueReport.summary).toEqual(config.noIssuesResultSummary) - expect(trueReport.annotations.length).toEqual(0) + expect(report.title).toEqual(config.noIssuesResultTitle) + expect(report.summary).toEqual(config.noIssuesResultSummary) + expect(report.annotations.length).toEqual(0) }) }) diff --git a/test/bandit.spawn.test.js b/test/bandit.spawn.test.js new file mode 100755 index 0000000..9b819f6 --- /dev/null +++ b/test/bandit.spawn.test.js @@ -0,0 +1,39 @@ +// Copyright 2018 VMware, Inc. +// SPDX-License-Identifier: BSD-2-Clause + +const fs = require('fs-extra') + +const { run } = require('../runner') +const Bandit = require('../linters/bandit') + +function bandit (dir, files) { + return run(new Bandit(), dir, files) +} + +describe('Bandit runner', () => { + test('Finds issues in vulnerable file', async () => { + const report = await bandit('test/fixtures/python', ['mix.vulnerable.py']) + + expect(report.annotations.length).toEqual(4) + expect(report.annotations[0].start_line).toEqual(8) + expect(report.annotations[1].start_line).toEqual(11) + expect(report.annotations[2].start_line).toEqual(13) + expect(report.annotations[3].start_line).toEqual(15) + }) + + test('Passes on safe file', async () => { + const report = await bandit('test/fixtures/python', ['mix.safe.py']) + + expect(report.annotations.length).toEqual(0) + }) + + test('Handles empty input', async () => { + const report = await bandit('test/fixtures/python', []) + + expect(report.annotations.length).toEqual(0) + }) + + afterEach(() => { + fs.remove('test/fixtures/bandit.json') + }) +}) diff --git a/test/bandit.test.js b/test/bandit.test.js deleted file mode 100755 index 4224af1..0000000 --- a/test/bandit.test.js +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 VMware, Inc. -// SPDX-License-Identifier: BSD-2-Clause - -const fs = require('fs-extra') - -const runBandit = require('../bandit/bandit') - -describe('Bandit runner', () => { - test('Handles baseline option', async () => { - const baselineFile = '../reports/keysizes.baseline.json' - const results = await runBandit('test/fixtures/python', ['key_sizes.py'], { baselineFile }) - - expect(results.results.length).toBe(2) - expect(results.results[0].line_number).toBe(5) - expect(results.results[1].line_number).toBe(8) - }) - - test('Run Bandit without baseline on a problematic file', async () => { - const results = await runBandit('test/fixtures/python', ['mix.py']) - - expect(results.results[0].line_number).toBe(8) - expect(results.results[1].line_number).toBe(11) - expect(results.results[2].line_number).toBe(13) - expect(results.results[3].line_number).toBe(15) - expect(results.results.length).toEqual(4) - }) - - // This test is needed when a PR is without python files - // and when our app gets the content of the PR - // it wouldnt get any files because we filter them. - test('Handles empty input', async () => { - const results = await runBandit('test/fixtures', []) - - expect(results).toBeNull() - }) - - afterEach(() => { - fs.remove('test/fixtures/bandit.json') - }) -}) diff --git a/test/fixtures/go/src/non_go_files/hello_world.py b/test/fixtures/go/src/non_go_files/hello_world.py deleted file mode 100644 index c54041c..0000000 --- a/test/fixtures/go/src/non_go_files/hello_world.py +++ /dev/null @@ -1,3 +0,0 @@ - - -print("Hello world!") diff --git a/test/fixtures/go/src/secure_go_files/hello_world.go b/test/fixtures/go/src/safe/hello_world.go similarity index 100% rename from test/fixtures/go/src/secure_go_files/hello_world.go rename to test/fixtures/go/src/safe/hello_world.go diff --git a/test/fixtures/go/src/bad_files/bad_test_file.go b/test/fixtures/go/src/vulnerable/bad_test_file.go similarity index 100% rename from test/fixtures/go/src/bad_files/bad_test_file.go rename to test/fixtures/go/src/vulnerable/bad_test_file.go diff --git a/test/fixtures/go/src/multiple_bad_files/bad_test_file.go b/test/fixtures/go/src/vulnerable_package/bad_test_file.go similarity index 100% rename from test/fixtures/go/src/multiple_bad_files/bad_test_file.go rename to test/fixtures/go/src/vulnerable_package/bad_test_file.go diff --git a/test/fixtures/go/src/multiple_bad_files/networking_binding.go b/test/fixtures/go/src/vulnerable_package/networking_binding.go similarity index 100% rename from test/fixtures/go/src/multiple_bad_files/networking_binding.go rename to test/fixtures/go/src/vulnerable_package/networking_binding.go diff --git a/test/fixtures/go/src/multiple_bad_files/randNumTest.go b/test/fixtures/go/src/vulnerable_package/randNumTest.go similarity index 100% rename from test/fixtures/go/src/multiple_bad_files/randNumTest.go rename to test/fixtures/go/src/vulnerable_package/randNumTest.go diff --git a/test/fixtures/pull_request.files.added.json b/test/fixtures/pull_request.files.added.json deleted file mode 100644 index 2177dd1..0000000 --- a/test/fixtures/pull_request.files.added.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "data": [ - { - "filename": "key_sizes.old.py", - "status": "added" - } - ] -} diff --git a/test/fixtures/pull_request.files.modified.json b/test/fixtures/pull_request.files.modified.json deleted file mode 100755 index bcecfb7..0000000 --- a/test/fixtures/pull_request.files.modified.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "data": [ - { - "filename": "key_sizes.py", - "status": "modified" - } - ] -} diff --git a/test/fixtures/python/key_sizes.old.py b/test/fixtures/python/key_sizes.old.py deleted file mode 100755 index 2a9eb11..0000000 --- a/test/fixtures/python/key_sizes.old.py +++ /dev/null @@ -1,18 +0,0 @@ -from cryptography.hazmat import backends -from cryptography.hazmat.primitives.asymmetric import dsa -from cryptography.hazmat.primitives.asymmetric import rsa - -dsa.generate_private_key(key_size=2048, - backend=backends.default_backend()) - -rsa.generate_private_key(public_exponent=65537, - key_size=2048, - backend=backends.default_backend()) - - -dsa.generate_private_key(key_size=1024, - backend=backends.default_backend()) - -rsa.generate_private_key(public_exponent=65537, - key_size=1024, - backend=backends.default_backend()) diff --git a/test/fixtures/python/key_sizes.py b/test/fixtures/python/key_sizes.py deleted file mode 100755 index 83ab1b2..0000000 --- a/test/fixtures/python/key_sizes.py +++ /dev/null @@ -1,18 +0,0 @@ -from cryptography.hazmat import backends -from cryptography.hazmat.primitives.asymmetric import dsa -from cryptography.hazmat.primitives.asymmetric import rsa - -dsa.generate_private_key(key_size=512, # 2048 -> 512 - backend=backends.default_backend()) - -rsa.generate_private_key(public_exponent=65537, - key_size=512, # 2048 -> 512 - backend=backends.default_backend()) - - -dsa.generate_private_key(key_size=1024, - backend=backends.default_backend()) - -rsa.generate_private_key(public_exponent=65537, - key_size=1024, - backend=backends.default_backend()) diff --git a/test/fixtures/python/mix.safe.py b/test/fixtures/python/mix.safe.py new file mode 100755 index 0000000..a10370f --- /dev/null +++ b/test/fixtures/python/mix.safe.py @@ -0,0 +1,13 @@ +import ssl +from cryptography.hazmat import backends +from cryptography.hazmat.primitives.asymmetric import dsa +from cryptography.hazmat.primitives.ciphers.modes import CTR + +dsa.generate_private_key(key_size=2048, + backend=backends.default_backend()) +dsa.generate_private_key(key_size=4096, + backend=backends.default_backend()) + +ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLS) + +mode = CTR(iv) diff --git a/test/fixtures/python/mix.py b/test/fixtures/python/mix.vulnerable.py similarity index 100% rename from test/fixtures/python/mix.py rename to test/fixtures/python/mix.vulnerable.py diff --git a/test/fixtures/reports/no_issues_report.json b/test/fixtures/reports/bandit_safe.json similarity index 100% rename from test/fixtures/reports/no_issues_report.json rename to test/fixtures/reports/bandit_safe.json diff --git a/test/fixtures/reports/mix_results.json b/test/fixtures/reports/bandit_vulnerable.json similarity index 100% rename from test/fixtures/reports/mix_results.json rename to test/fixtures/reports/bandit_vulnerable.json diff --git a/test/fixtures/reports/gosec_mix_results.json b/test/fixtures/reports/gosec_vulnerable.json similarity index 100% rename from test/fixtures/reports/gosec_mix_results.json rename to test/fixtures/reports/gosec_vulnerable.json diff --git a/test/fixtures/reports/keysizes.baseline.json b/test/fixtures/reports/keysizes.baseline.json deleted file mode 100755 index ffd61e8..0000000 --- a/test/fixtures/reports/keysizes.baseline.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "errors": [], - "generated_at": "2018-09-12T17:27:00Z", - "metrics": { - "_totals": { - "CONFIDENCE.HIGH": 2.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 2.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 13, - "nosec": 0 - }, - "test/fixtures/python/key_sizes.py": { - "CONFIDENCE.HIGH": 2.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 2.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 13, - "nosec": 0 - } - }, - "results": [ - { - "code": "15 # Incorrect: weak key sizes\n16 dsa.generate_private_key(key_size=1024,\n17 backend=backends.default_backend())\n18 \n", - "filename": "key_sizes.py", - "issue_confidence": "HIGH", - "issue_severity": "MEDIUM", - "issue_text": "DSA key sizes below 2048 bits are considered breakable. ", - "line_number": 16, - "line_range": [ - 16, - 17 - ], - "more_info": "https://bandit.readthedocs.io/en/latest/plugins/b505_weak_cryptographic_key.html", - "test_id": "B505", - "test_name": "weak_cryptographic_key" - }, - { - "code": "18 \n19 rsa.generate_private_key(public_exponent=65537,\n20 key_size=1024,\n21 backend=backends.default_backend())\n", - "filename": "key_sizes.py", - "issue_confidence": "HIGH", - "issue_severity": "MEDIUM", - "issue_text": "RSA key sizes below 2048 bits are considered breakable. ", - "line_number": 19, - "line_range": [ - 19, - 20, - 21 - ], - "more_info": "https://bandit.readthedocs.io/en/latest/plugins/b505_weak_cryptographic_key.html", - "test_id": "B505", - "test_name": "weak_cryptographic_key" - } - ] -} diff --git a/test/gosec.report.test.js b/test/gosec.report.test.js index 73d240e..095e4ae 100644 --- a/test/gosec.report.test.js +++ b/test/gosec.report.test.js @@ -13,7 +13,7 @@ describe('Gosec report tests', () => { }) test('Generate valid report', () => { - const mixedResults = require('./fixtures/reports/gosec_mix_results.json') + const mixedResults = require('./fixtures/reports/gosec_vulnerable.json') const trueReport = gosecReport(mixedResults, './fixtures/reports/') expect(trueReport.title).toEqual(config.issuesFoundResultTitle) expect(trueReport.summary).not.toBe('') diff --git a/test/gosec.spawn.test.js b/test/gosec.spawn.test.js index 5bb7b3f..ec37dda 100644 --- a/test/gosec.spawn.test.js +++ b/test/gosec.spawn.test.js @@ -1,36 +1,47 @@ // Copyright 2018 VMware, Inc. // SPDX-License-Identifier: BSD-2-Clause -const gosec = require('../gosec/gosec') const fs = require('fs-extra') -describe('Spawn gosec tests', () => { - test('Empty input for gosec', async () => { - const gosecResult = await gosec('', []) - expect(gosecResult).toBeFalsy() +const { run } = require('../runner') +const Gosec = require('../linters/gosec') + +function gosec (dir, files) { + return run(new Gosec(), dir, files) +} + +describe('Gosec runner', () => { + test('Finds issues in vulnerable file', async () => { + const report = await gosec('test/fixtures/go/src/vulnerable', ['bad_test_file.go']) + + expect(report.annotations.length).toEqual(6) + expect(report.annotations[0].start_line).toEqual('15') + expect(report.annotations[1].start_line).toEqual('19') + expect(report.annotations[2].start_line).toEqual('26') + expect(report.annotations[3].start_line).toEqual('27') }) - test('Run gosec on non go files', async () => { - const gosecResult = await gosec('test/fixtures/go/src/non_go_files', ['hello_world.py']) - expect(gosecResult).toBeFalsy() + test('Passes on safe file', async () => { + const report = await gosec('test/fixtures/go/src/safe', ['hello_world.go']) + + expect(report.annotations.length).toEqual(0) }) - test('Run gosec on a go file without security problems', async () => { - const gosecResult = await gosec('test/fixtures/go/src/secure_go_files', ['hello_world.go']) - expect(gosecResult.Issues.length).toEqual(0) - fs.remove('test/fixtures/go/src/secure_go_files/gosec.json') + test('Handles packages with multiple files', async () => { + const report = await gosec('test/fixtures/go/src/vulnerable_package/', ['bad_test_file.go', 'networking_binding.go', 'randNumTest.go']) + + expect(report.annotations.length).toEqual(8) + expect(report.annotations[4].start_line).toEqual('9') + expect(report.annotations[7].start_line).toEqual('16') }) - test('Run gosec on go problematic file', async () => { - const gosecResult = await gosec('test/fixtures/go/src/bad_files', ['bad_test_file.go']) - expect(gosecResult.Stats.found).toBeGreaterThan(0) - fs.remove('test/fixtures/go/src/bad_files/gosec.json') + test('Handles empty input', async () => { + const report = await gosec('test/fixtures/go/src', []) + + expect(report.annotations.length).toEqual(0) }) - test('Run gosec multiple go files', async () => { - const gosecResult = await gosec('test/fixtures/go/src/multiple_bad_files/', ['bad_test_file.go', 'networking_binding_test.go', 'randNumTest.go']) - expect(gosecResult.Stats.found).toBeGreaterThan(0) - expect(gosecResult.Stats.files).toEqual(3) - fs.remove('test/fixtures/go/src/multiple_bad_files/gosec.json') + afterEach(() => { + fs.remove('test/fixtures/go/src/gosec.json') }) }) diff --git a/test/index.test.js b/test/index.test.js index 02f2938..37e7f3b 100755 --- a/test/index.test.js +++ b/test/index.test.js @@ -21,7 +21,6 @@ function mockPRContents (github, PR) { describe('Bandit-linter', () => { let app, github let mockFiles = {} - let fileRefs = {} beforeAll(() => { // Load all python files in the fixture directories and map names to contents in mock object @@ -29,9 +28,6 @@ describe('Bandit-linter', () => { files.forEach((filename) => { mockFiles[filename] = fs.readFileSync(path.join('test/fixtures/python', filename), 'utf8') }) - - fileRefs['head_ref'] = mockFiles['key_sizes.py'] - fileRefs['base_ref'] = mockFiles['key_sizes.old.py'] }) beforeEach(() => { @@ -147,8 +143,8 @@ describe('Bandit-linter', () => { test('handles PRs with mixed file types', async () => { // Manually load in the go file contents - mockFiles['networking_binding.go'] = fs.readFileSync('test/fixtures/go/src/multiple_bad_files/networking_binding.go', 'utf8') - mockFiles['bad_test_file.go'] = fs.readFileSync('test/fixtures/go/src/multiple_bad_files/bad_test_file.go', 'utf8') + mockFiles['networking_binding.go'] = fs.readFileSync('test/fixtures/go/src/vulnerable_package/networking_binding.go', 'utf8') + mockFiles['bad_test_file.go'] = fs.readFileSync('test/fixtures/go/src/vulnerable_package/bad_test_file.go', 'utf8') mockPRContents(github, sampleMixedPRFixture)