Commit 974c3fe0 authored by Lukas Eipert's avatar Lukas Eipert

Remove outdated Dependency Scanning frontend code

Since we now retrieve data from the Backend, we can remove the parsing
log from the Frontend. See:
https://gitlab.com/groups/gitlab-org/-/epics/1425
parent 1ff5881c
......@@ -127,11 +127,6 @@ export const fetchDastDiff = ({ state, dispatch }) => {
/**
* DEPENDENCY SCANNING
*/
export const setDependencyScanningHeadPath = ({ commit }, path) =>
commit(types.SET_DEPENDENCY_SCANNING_HEAD_PATH, path);
export const setDependencyScanningBasePath = ({ commit }, path) =>
commit(types.SET_DEPENDENCY_SCANNING_BASE_PATH, path);
export const setDependencyScanningDiffEndpoint = ({ commit }, path) =>
commit(types.SET_DEPENDENCY_SCANNING_DIFF_ENDPOINT, path);
......@@ -139,12 +134,6 @@ export const setDependencyScanningDiffEndpoint = ({ commit }, path) =>
export const requestDependencyScanningReports = ({ commit }) =>
commit(types.REQUEST_DEPENDENCY_SCANNING_REPORTS);
export const receiveDependencyScanningReports = ({ commit }, response) =>
commit(types.RECEIVE_DEPENDENCY_SCANNING_REPORTS, response);
export const receiveDependencyScanningError = ({ commit }, error) =>
commit(types.RECEIVE_DEPENDENCY_SCANNING_ERROR, error);
export const receiveDependencyScanningDiffSuccess = ({ commit }, response) =>
commit(types.RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS, response);
......@@ -173,32 +162,6 @@ export const fetchDependencyScanningDiff = ({ state, dispatch }) => {
});
};
export const fetchDependencyScanningReports = ({ state, dispatch }) => {
const { base, head } = state.dependencyScanning.paths;
dispatch('requestDependencyScanningReports');
return Promise.all([
head ? axios.get(head) : Promise.resolve(),
base ? axios.get(base) : Promise.resolve(),
axios.get(state.vulnerabilityFeedbackPath, {
params: {
category: 'dependency_scanning',
},
}),
])
.then(values => {
dispatch('receiveDependencyScanningReports', {
head: values[0] ? values[0].data : null,
base: values[1] ? values[1].data : null,
enrichData: values && values[2] ? values[2].data : [],
});
})
.catch(() => {
dispatch('receiveDependencyScanningError');
});
};
export const updateDependencyScanningIssue = ({ commit }, issue) =>
commit(types.UPDATE_DEPENDENCY_SCANNING_ISSUE, issue);
......
......@@ -26,12 +26,8 @@ export const RECEIVE_DAST_DIFF_SUCCESS = 'RECEIVE_DAST_DIFF_SUCCESS';
export const RECEIVE_DAST_DIFF_ERROR = 'RECEIVE_DAST_DIFF_ERROR';
// DEPENDENCY_SCANNING
export const SET_DEPENDENCY_SCANNING_HEAD_PATH = 'SET_DEPENDENCY_SCANNING_HEAD_PATH';
export const SET_DEPENDENCY_SCANNING_BASE_PATH = 'SET_DEPENDENCY_SCANNING_BASE_PATH';
export const SET_DEPENDENCY_SCANNING_DIFF_ENDPOINT = 'SET_DEPENDENCY_SCANNING_DIFF_ENDPOINT';
export const REQUEST_DEPENDENCY_SCANNING_REPORTS = 'REQUEST_DEPENDENCY_SCANNING_REPORTS';
export const RECEIVE_DEPENDENCY_SCANNING_REPORTS = 'RECEIVE_DEPENDENCY_SCANNING_REPORTS';
export const RECEIVE_DEPENDENCY_SCANNING_ERROR = 'RECEIVE_DEPENDENCY_SCANNING_ERROR';
export const RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS = 'RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS';
export const RECEIVE_DEPENDENCY_SCANNING_DIFF_ERROR = 'RECEIVE_DEPENDENCY_SCANNING_DIFF_ERROR';
......
import Vue from 'vue';
import * as types from './mutation_types';
import { parseDependencyScanningIssues, findIssueIndex, parseDiff } from './utils';
import filterByKey from './utils/filter_by_key';
import { findIssueIndex, parseDiff } from './utils';
import getFileLocation from './utils/get_file_location';
import { visitUrl } from '~/lib/utils/url_utility';
......@@ -107,14 +106,6 @@ export default {
// DEPENDECY SCANNING
[types.SET_DEPENDENCY_SCANNING_HEAD_PATH](state, path) {
Vue.set(state.dependencyScanning.paths, 'head', path);
},
[types.SET_DEPENDENCY_SCANNING_BASE_PATH](state, path) {
Vue.set(state.dependencyScanning.paths, 'base', path);
},
[types.SET_DEPENDENCY_SCANNING_DIFF_ENDPOINT](state, path) {
Vue.set(state.dependencyScanning.paths, 'diffEndpoint', path);
},
......@@ -123,56 +114,6 @@ export default {
Vue.set(state.dependencyScanning, 'isLoading', true);
},
/**
* Compares dependency scanning results and returns the formatted report
*
* Dependency report has 3 types of issues, newIssues, resolvedIssues and allIssues.
*
* When we have both base and head:
* - newIssues = head - base
* - resolvedIssues = base - head
* - allIssues = head - newIssues - resolvedIssues
*
* When we only have head
* - newIssues = head
* - resolvedIssues = 0
* - allIssues = 0
*/
[types.RECEIVE_DEPENDENCY_SCANNING_REPORTS](state, reports) {
if (reports.base && reports.head) {
const filterKey = 'cve';
const parsedHead = parseDependencyScanningIssues(
reports.head,
reports.enrichData,
state.blobPath.head,
);
const parsedBase = parseDependencyScanningIssues(
reports.base,
reports.enrichData,
state.blobPath.base,
);
const newIssues = filterByKey(parsedHead, parsedBase, filterKey);
const resolvedIssues = filterByKey(parsedBase, parsedHead, filterKey);
const allIssues = filterByKey(parsedHead, newIssues.concat(resolvedIssues), filterKey);
Vue.set(state.dependencyScanning, 'newIssues', newIssues);
Vue.set(state.dependencyScanning, 'resolvedIssues', resolvedIssues);
Vue.set(state.dependencyScanning, 'allIssues', allIssues);
Vue.set(state.dependencyScanning, 'isLoading', false);
}
if (reports.head && !reports.base) {
const newIssues = parseDependencyScanningIssues(
reports.head,
reports.enrichData,
state.blobPath.head,
);
Vue.set(state.dependencyScanning, 'newIssues', newIssues);
Vue.set(state.dependencyScanning, 'isLoading', false);
}
},
[types.RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS](state, { diff, enrichData }) {
const { added, fixed, existing } = parseDiff(diff, enrichData);
const baseReportOutofDate = diff.base_report_out_of_date || false;
......@@ -191,11 +132,6 @@ export default {
Vue.set(state.dependencyScanning, 'hasError', true);
},
[types.RECEIVE_DEPENDENCY_SCANNING_ERROR](state) {
Vue.set(state.dependencyScanning, 'isLoading', false);
Vue.set(state.dependencyScanning, 'hasError', true);
},
[types.SET_ISSUE_MODAL_DATA](state, payload) {
const { issue, status } = payload;
const fileLocation = getFileLocation(issue.location);
......
import sha1 from 'sha1';
import _ from 'underscore';
import { n__, s__, sprintf } from '~/locale';
/**
......@@ -10,32 +8,6 @@ import { n__, s__, sprintf } from '~/locale';
export const findIssueIndex = (issues, issue) =>
issues.findIndex(el => el.project_fingerprint === issue.project_fingerprint);
/**
*
* Returns whether a vulnerability has a match in an array of fixes
*
* @param fixes {Array} Array of fixes (vulnerability identifiers) of a remediation
* @param vulnerability {Object} Vulnerability
* @returns {boolean}
*/
const hasMatchingFix = (fixes, vulnerability) =>
Array.isArray(fixes) ? fixes.some(fix => _.isMatch(vulnerability, fix)) : false;
/**
*
* Returns the remediations that fix the given vulnerability
*
* @param {Array} remediations
* @param {Object} vulnerability
* @returns {Array}
*/
export const findMatchingRemediations = (remediations, vulnerability) => {
if (!Array.isArray(remediations)) {
return [];
}
return remediations.filter(rem => hasMatchingFix(rem.fixes, vulnerability));
};
/**
* Returns given vulnerability enriched with the corresponding
* feedback (`dismissal` or `issue` type)
......@@ -68,109 +40,6 @@ export const enrichVulnerabilityWithFeedback = (vulnerability, feedback = []) =>
return vuln;
}, vulnerability);
/**
* Generates url to repository file and highlight section between start and end lines.
*
* @param {Object} location
* @param {String} pathPrefix
* @returns {String}
*/
function fileUrl(location, pathPrefix) {
let lineSuffix = '';
if (location.start_line) {
lineSuffix += `#L${location.start_line}`;
if (location.end_line) {
lineSuffix += `-${location.end_line}`;
}
}
return `${pathPrefix}/${location.file}${lineSuffix}`;
}
/**
* Parses issues with deprecated JSON format and adapts it to the new one.
*
* @param {Object} issue
* @returns {Object}
*/
function adaptDeprecatedIssueFormat(issue) {
// Skip issue with new format (old format does not have a location property)
if (issue.location) {
return issue;
}
const adapted = {
...issue,
};
// Add the new links property
const links = [];
if (!_.isEmpty(adapted.url)) {
links.push({ url: adapted.url });
}
Object.assign(adapted, {
// Add the new location property
location: {
file: adapted.file,
start_line: adapted.line ? parseInt(adapted.line, 10) : undefined,
},
links,
});
return adapted;
}
/**
*
* Wraps old report formats (plain array of vulnerabilities).
*
* @param {Array|Object} report
* @returns {Object}
*/
function adaptDeprecatedReportFormat(report) {
if (Array.isArray(report)) {
return {
vulnerabilities: report,
remediations: [],
};
}
return report;
}
/**
* Parses Dependency Scanning results into a common format to allow to use the same Vue component.
*
* @param {Array|Object} report
* @param {Array} feedback
* @param {String} path
* @returns {Array}
*/
export const parseDependencyScanningIssues = (report = [], feedback = [], path = '') => {
const { vulnerabilities, remediations } = adaptDeprecatedReportFormat(report);
return vulnerabilities.map(issue => {
const parsed = {
...adaptDeprecatedIssueFormat(issue),
category: 'dependency_scanning',
project_fingerprint: sha1(issue.cve),
title: issue.message,
};
const matchingRemediations = findMatchingRemediations(remediations, parsed);
if (remediations) {
parsed.remediations = matchingRemediations;
}
return {
...parsed,
path: parsed.location.file,
urlPath: fileUrl(parsed.location, path),
...enrichVulnerabilityWithFeedback(parsed, feedback),
};
});
};
export const groupedTextBuilder = ({
reportType = '',
paths = {},
......
......@@ -10,450 +10,6 @@ export const sastParsedIssues = [
},
];
export const sastIssues = [
{
tool: 'bundler_audit',
category: 'sast',
message: 'Arbitrary file existence disclosure in Action Pack',
cve: 'CVE-2014-7829',
solution: 'upgrade to ~> 3.2.21, ~> 4.0.11.1, ~> 4.0.12, ~> 4.1.7.1, >= 4.1.8',
location: {
file: 'Gemfile.lock',
start_line: 5,
end_line: 10,
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/rMTQy4oRCGk',
},
],
identifiers: [
{
type: 'CVE',
name: 'CVE-2014-7829',
value: 'CVE-2014-7829',
link: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-7829',
},
],
},
{
tool: 'bundler_audit',
category: 'sast',
message: 'Possible Information Leak Vulnerability in Action View',
cve: 'CVE-2016-0752',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
location: {
file: 'Gemfile.lock',
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
},
],
identifiers: [
{
type: 'CVE',
name: 'CVE-2016-0752',
value: 'CVE-2016-0752',
link: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0752',
},
],
},
{
tool: 'bundler_audit',
category: 'sast',
message: 'Possible Object Leak and Denial of Service attack in Action Pack',
cve: 'CVE-2016-0751',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
location: {
file: 'Gemfile.lock',
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/9oLY_FCzvoc',
},
],
identifiers: [
{
type: 'CVE',
name: 'CVE-2016-0751',
value: 'CVE-2016-0751',
link: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0751',
},
],
},
];
export const sastIssuesBase = [
{
tool: 'bundler_audit',
category: 'sast',
message: 'Test Information Leak Vulnerability in Action View',
cve: 'CVE-2016-9999',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
location: {
file: 'Gemfile.lock',
start_line: 5,
end_line: 10,
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
},
],
identifiers: [
{
type: 'CVE',
name: 'CVE-2016-9999',
value: 'CVE-2016-9999',
link: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-9999',
},
],
},
{
tool: 'bundler_audit',
category: 'sast',
message: 'Possible Information Leak Vulnerability in Action View',
cve: 'CVE-2016-0752',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
location: {
file: 'Gemfile.lock',
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
},
],
identifiers: [
{
type: 'CVE',
name: 'CVE-2016-0752',
value: 'CVE-2016-0752',
link: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0752',
},
],
},
];
export const dependencyScanningIssuesOld = [
{
tool: 'bundler_audit',
message: 'Arbitrary file existence disclosure in Action Pack',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/rMTQy4oRCGk',
cve: 'CVE-2014-7829',
file: 'Gemfile.lock',
line: '5',
solution: 'upgrade to ~> 3.2.21, ~> 4.0.11.1, ~> 4.0.12, ~> 4.1.7.1, >= 4.1.8',
},
{
tool: 'bundler_audit',
message: 'Possible Information Leak Vulnerability in Action View',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
cve: 'CVE-2016-0752',
file: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
},
{
tool: 'bundler_audit',
message: 'Possible Object Leak and Denial of Service attack in Action Pack',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/9oLY_FCzvoc',
cve: 'CVE-2016-0751',
file: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
},
];
export const dependencyScanningIssues = [
{
category: 'dependency_scanning',
message: 'ruby-ffi DDL loading issue on Windows OS',
cve: 'sast-sample-rails/Gemfile.lock:ffi:cve:CVE-2018-1000201',
severity: 'High',
solution: 'upgrade to \u003e= 1.9.24',
scanner: {
id: 'bundler_audit',
name: 'bundler-audit',
},
location: {
file: 'sast-sample-rails/Gemfile.lock',
dependency: {
package: {
name: 'ffi',
},
version: '1.9.18',
},
},
identifiers: [
{
type: 'cve',
name: 'CVE-2018-1000201',
value: 'CVE-2018-1000201',
url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1000201',
},
],
links: [
{
url: 'https://github.com/ffi/ffi/releases/tag/1.9.24',
},
],
},
{
category: 'dependency_scanning',
message: 'XSS vulnerability in rails-html-sanitizer',
cve: 'sast-sample-rails/Gemfile.lock:rails-html-sanitizer:cve:CVE-2018-3741',
severity: 'Unknown',
solution: 'upgrade to \u003e= 1.0.4',
scanner: {
id: 'bundler_audit',
name: 'bundler-audit',
},
location: {
file: 'sast-sample-rails/Gemfile.lock',
dependency: {
package: {
name: 'rails-html-sanitizer',
},
version: '1.0.3',
},
},
identifiers: [
{
type: 'cve',
name: 'CVE-2018-3741',
value: 'CVE-2018-3741',
url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3741',
},
],
links: [
{
url: 'https://groups.google.com/d/msg/rubyonrails-security/tP7W3kLc5u4/uDy2Br7xBgAJ',
},
],
},
{
category: 'dependency_scanning',
message: 'Vulnerability in ansi2html',
cve: ':ansi2html:npm:51',
severity: 'High',
scanner: {
id: 'retire.js',
name: 'Retire.js',
},
location: {
dependency: {
package: {
name: 'ansi2html',
},
version: '0.0.1',
},
},
identifiers: [
{
type: 'npm',
name: 'NPM-51',
value: '51',
url: 'https://www.npmjs.com/advisories/51',
},
],
links: [
{
url: 'https://nodesecurity.io/advisories/51',
},
],
},
];
export const dependencyScanningIssuesMajor2 = {
version: '2.0',
vulnerabilities: dependencyScanningIssues,
remediations: [
{
fixes: [{ cve: dependencyScanningIssues[0].cve }],
summary: 'Fixes the first dependency Scanning issue',
},
],
};
export const dependencyScanningIssuesBase = [
{
tool: 'bundler_audit',
message: 'Test Information Leak Vulnerability in Action View',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
cve: 'CVE-2016-9999',
file: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
},
{
tool: 'bundler_audit',
message: 'Possible Information Leak Vulnerability in Action View',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
cve: 'CVE-2016-0752',
file: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
},
];
export const parsedDependencyScanningIssuesStore = [
{
tool: 'bundler_audit',
message: 'Arbitrary file existence disclosure in Action Pack',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/rMTQy4oRCGk',
cve: 'CVE-2014-7829',
file: 'Gemfile.lock',
line: '5',
solution: 'upgrade to ~> 3.2.21, ~> 4.0.11.1, ~> 4.0.12, ~> 4.1.7.1, >= 4.1.8',
title: 'Arbitrary file existence disclosure in Action Pack',
path: 'Gemfile.lock',
urlPath: 'path/Gemfile.lock#L5',
category: 'dependency_scanning',
project_fingerprint: 'f55331d66fd4f3bfb4237d48e9c9fa8704bd33c6',
remediations: [],
location: {
file: 'Gemfile.lock',
start_line: 5,
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/rMTQy4oRCGk',
},
],
},
{
tool: 'bundler_audit',
message: 'Possible Information Leak Vulnerability in Action View',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
cve: 'CVE-2016-0752',
file: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
title: 'Possible Information Leak Vulnerability in Action View',
path: 'Gemfile.lock',
urlPath: 'path/Gemfile.lock',
category: 'dependency_scanning',
project_fingerprint: 'a6b61a2eba59071178d5899b26dd699fb880de1e',
remediations: [],
location: {
file: 'Gemfile.lock',
start_line: undefined,
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
},
],
},
{
tool: 'bundler_audit',
message: 'Possible Object Leak and Denial of Service attack in Action Pack',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/9oLY_FCzvoc',
cve: 'CVE-2016-0751',
file: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
title: 'Possible Object Leak and Denial of Service attack in Action Pack',
path: 'Gemfile.lock',
urlPath: 'path/Gemfile.lock',
category: 'dependency_scanning',
project_fingerprint: '830f85e5fb011408bab365eb809cd97a45b0aa17',
remediations: [],
location: {
file: 'Gemfile.lock',
start_line: undefined,
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/9oLY_FCzvoc',
},
],
},
];
export const parsedDependencyScanningIssuesHead = [
{
tool: 'bundler_audit',
message: 'Arbitrary file existence disclosure in Action Pack',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/rMTQy4oRCGk',
cve: 'CVE-2014-7829',
file: 'Gemfile.lock',
line: '5',
solution: 'upgrade to ~> 3.2.21, ~> 4.0.11.1, ~> 4.0.12, ~> 4.1.7.1, >= 4.1.8',
title: 'Arbitrary file existence disclosure in Action Pack',
path: 'Gemfile.lock',
urlPath: 'path/Gemfile.lock#L5',
category: 'dependency_scanning',
project_fingerprint: 'f55331d66fd4f3bfb4237d48e9c9fa8704bd33c6',
remediations: [],
location: {
file: 'Gemfile.lock',
start_line: 5,
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/rMTQy4oRCGk',
},
],
},
{
tool: 'bundler_audit',
message: 'Possible Object Leak and Denial of Service attack in Action Pack',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/9oLY_FCzvoc',
cve: 'CVE-2016-0751',
file: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
title: 'Possible Object Leak and Denial of Service attack in Action Pack',
path: 'Gemfile.lock',
urlPath: 'path/Gemfile.lock',
category: 'dependency_scanning',
project_fingerprint: '830f85e5fb011408bab365eb809cd97a45b0aa17',
remediations: [],
location: {
file: 'Gemfile.lock',
start_line: undefined,
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/9oLY_FCzvoc',
},
],
},
];
export const parsedDependencyScanningBaseStore = [
{
title: 'Test Information Leak Vulnerability in Action View',
tool: 'bundler_audit',
message: 'Test Information Leak Vulnerability in Action View',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
cve: 'CVE-2016-9999',
file: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
path: 'Gemfile.lock',
urlPath: 'path/Gemfile.lock',
category: 'dependency_scanning',
project_fingerprint: '3f5608c99f0c7442ba59bc6c0c1864d0000f8e1a',
remediations: [],
location: {
file: 'Gemfile.lock',
start_line: undefined,
},
links: [
{
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
},
],
},
];
export const dockerReportParsed = {
unapproved: [
{
......@@ -621,31 +177,6 @@ export const parsedDast = [
},
];
export const sastFeedbacks = [
{
id: 3,
project_id: 17,
author_id: 1,
issue_iid: null,
pipeline_id: 132,
category: 'sast',
feedback_type: 'dismissal',
branch: 'try_new_container_scanning',
project_fingerprint: 'f55331d66fd4f3bfb4237d48e9c9fa8704bd33c6',
},
{
id: 4,
project_id: 17,
author_id: 1,
issue_iid: 123,
pipeline_id: 132,
category: 'sast',
feedback_type: 'issue',
branch: 'try_new_container_scanning',
project_fingerprint: 'f55331d66fd4f3bfb4237d48e9c9fa8704bd33c6',
},
];
export const dependencyScanningFeedbacks = [
{
id: 3,
......
......@@ -9,12 +9,7 @@ import {
setCanCreateFeedbackPermission,
requestSastContainerReports,
requestDastReports,
setDependencyScanningHeadPath,
setDependencyScanningBasePath,
requestDependencyScanningReports,
receiveDependencyScanningError,
receiveDependencyScanningReports,
fetchDependencyScanningReports,
openModal,
setModalData,
requestDismissVulnerability,
......@@ -62,9 +57,6 @@ import state from 'ee/vue_shared/security_reports/store/state';
import testAction from 'helpers/vuex_action_helper';
import axios from '~/lib/utils/axios_utils';
import {
sastIssues,
sastIssuesBase,
sastFeedbacks,
dastFeedbacks,
containerScanningFeedbacks,
dependencyScanningFeedbacks,
......@@ -272,42 +264,6 @@ describe('security reports actions', () => {
});
});
describe('setDependencyScanningHeadPath', () => {
it('should commit set head blob path', done => {
testAction(
setDependencyScanningHeadPath,
'path',
mockedState,
[
{
type: types.SET_DEPENDENCY_SCANNING_HEAD_PATH,
payload: 'path',
},
],
[],
done,
);
});
});
describe('setDependencyScanningBasePath', () => {
it('should commit set head blob path', done => {
testAction(
setDependencyScanningBasePath,
'path',
mockedState,
[
{
type: types.SET_DEPENDENCY_SCANNING_BASE_PATH,
payload: 'path',
},
],
[],
done,
);
});
});
describe('requestDependencyScanningReports', () => {
it('should commit request mutation', done => {
testAction(
......@@ -325,157 +281,6 @@ describe('security reports actions', () => {
});
});
describe('receiveDependencyScanningReports', () => {
it('should commit sast receive mutation', done => {
testAction(
receiveDependencyScanningReports,
{},
mockedState,
[
{
type: types.RECEIVE_DEPENDENCY_SCANNING_REPORTS,
payload: {},
},
],
[],
done,
);
});
});
describe('receiveDependencyScanningError', () => {
it('should commit dependency scanning error mutation', done => {
const error = new Error('test');
testAction(
receiveDependencyScanningError,
error,
mockedState,
[
{
type: types.RECEIVE_DEPENDENCY_SCANNING_ERROR,
payload: error,
},
],
[],
done,
);
});
});
describe('fetchDependencyScanningReports', () => {
describe('with head and base', () => {
it('should dispatch `receiveDependencyScanningReports`', done => {
mock.onGet('foo').reply(200, sastIssues);
mock.onGet('bar').reply(200, sastIssuesBase);
mock
.onGet('vulnerabilities_path', {
params: {
category: 'dependency_scanning',
},
})
.reply(200, sastFeedbacks);
mockedState.vulnerabilityFeedbackPath = 'vulnerabilities_path';
mockedState.dependencyScanning.paths.head = 'foo';
mockedState.dependencyScanning.paths.base = 'bar';
testAction(
fetchDependencyScanningReports,
null,
mockedState,
[],
[
{
type: 'requestDependencyScanningReports',
},
{
type: 'receiveDependencyScanningReports',
payload: { head: sastIssues, base: sastIssuesBase, enrichData: sastFeedbacks },
},
],
done,
);
});
it('should dispatch `receiveDependencyScanningError`', done => {
mock.onGet('foo').reply(500, {});
mockedState.dependencyScanning.paths.head = 'foo';
mockedState.dependencyScanning.paths.base = 'bar';
testAction(
fetchDependencyScanningReports,
null,
mockedState,
[],
[
{
type: 'requestDependencyScanningReports',
},
{
type: 'receiveDependencyScanningError',
},
],
done,
);
});
});
describe('with head', () => {
it('should dispatch `receiveDependencyScanningReports`', done => {
mock.onGet('foo').reply(200, sastIssues);
mock
.onGet('vulnerabilities_path', {
params: {
category: 'dependency_scanning',
},
})
.reply(200, sastFeedbacks);
mockedState.vulnerabilityFeedbackPath = 'vulnerabilities_path';
mockedState.dependencyScanning.paths.head = 'foo';
testAction(
fetchDependencyScanningReports,
null,
mockedState,
[],
[
{
type: 'requestDependencyScanningReports',
},
{
type: 'receiveDependencyScanningReports',
payload: { head: sastIssues, base: null, enrichData: sastFeedbacks },
},
],
done,
);
});
it('should dispatch `receiveDependencyScanningError`', done => {
mock.onGet('foo').reply(500, {});
mockedState.dependencyScanning.paths.head = 'foo';
testAction(
fetchDependencyScanningReports,
null,
mockedState,
[],
[
{
type: 'requestDependencyScanningReports',
},
{
type: 'receiveDependencyScanningError',
},
],
done,
);
});
});
});
describe('openModal', () => {
it('dispatches setModalData action', done => {
testAction(
......
import state from 'ee/vue_shared/security_reports/store/state';
import mutations from 'ee/vue_shared/security_reports/store/mutations';
import * as types from 'ee/vue_shared/security_reports/store/mutation_types';
import {
dependencyScanningIssuesOld,
dependencyScanningIssuesBase,
parsedDependencyScanningIssuesHead,
parsedDependencyScanningBaseStore,
parsedDependencyScanningIssuesStore,
mockFindings,
} from '../mock_data';
import { mockFindings } from '../mock_data';
import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility', () => ({
......@@ -94,22 +87,6 @@ describe('security reports mutations', () => {
});
});
describe('SET_DEPENDENCY_SCANNING_HEAD_PATH', () => {
it('should set dependency scanning head path', () => {
mutations[types.SET_DEPENDENCY_SCANNING_HEAD_PATH](stateCopy, 'head_path');
expect(stateCopy.dependencyScanning.paths.head).toEqual('head_path');
});
});
describe('SET_DEPENDENCY_SCANNING_BASE_PATH', () => {
it('should set dependency scanning base path', () => {
mutations[types.SET_DEPENDENCY_SCANNING_BASE_PATH](stateCopy, 'base_path');
expect(stateCopy.dependencyScanning.paths.base).toEqual('base_path');
});
});
describe('REQUEST_DEPENDENCY_SCANNING_REPORTS', () => {
it('should set dependency scanning loading flag to true', () => {
mutations[types.REQUEST_DEPENDENCY_SCANNING_REPORTS](stateCopy);
......@@ -118,46 +95,6 @@ describe('security reports mutations', () => {
});
});
describe('RECEIVE_DEPENDENCY_SCANNING_REPORTS', () => {
describe('with head and base', () => {
it('should set new, fixed and all issues', () => {
mutations[types.SET_BASE_BLOB_PATH](stateCopy, 'path');
mutations[types.SET_HEAD_BLOB_PATH](stateCopy, 'path');
mutations[types.RECEIVE_DEPENDENCY_SCANNING_REPORTS](stateCopy, {
head: dependencyScanningIssuesOld,
base: dependencyScanningIssuesBase,
});
expect(stateCopy.dependencyScanning.isLoading).toEqual(false);
expect(stateCopy.dependencyScanning.newIssues).toEqual(parsedDependencyScanningIssuesHead);
expect(stateCopy.dependencyScanning.resolvedIssues).toEqual(
parsedDependencyScanningBaseStore,
);
});
});
describe('with head', () => {
it('should set new issues', () => {
mutations[types.SET_HEAD_BLOB_PATH](stateCopy, 'path');
mutations[types.RECEIVE_DEPENDENCY_SCANNING_REPORTS](stateCopy, {
head: dependencyScanningIssuesOld,
});
expect(stateCopy.dependencyScanning.isLoading).toEqual(false);
expect(stateCopy.dependencyScanning.newIssues).toEqual(parsedDependencyScanningIssuesStore);
});
});
});
describe('RECEIVE_DEPENDENCY_SCANNING_ERROR', () => {
it('should set dependency scanning loading flag to false and error flag to true', () => {
mutations[types.RECEIVE_DEPENDENCY_SCANNING_ERROR](stateCopy);
expect(stateCopy.dependencyScanning.isLoading).toEqual(false);
expect(stateCopy.dependencyScanning.hasError).toEqual(true);
});
});
describe('SET_ISSUE_MODAL_DATA', () => {
it('has default data', () => {
expect(stateCopy.modal.data.description.value).toEqual(null);
......@@ -535,11 +472,11 @@ describe('security reports mutations', () => {
describe('UPDATE_DEPENDENCY_SCANNING_ISSUE', () => {
it('updates issue in the new issues list', () => {
stateCopy.dependencyScanning.newIssues = parsedDependencyScanningIssuesHead;
stateCopy.dependencyScanning.newIssues = mockFindings;
stateCopy.dependencyScanning.resolvedIssues = [];
stateCopy.dependencyScanning.allIssues = [];
const updatedIssue = {
...parsedDependencyScanningIssuesHead[0],
...mockFindings[0],
foo: 'bar',
};
......@@ -550,10 +487,10 @@ describe('security reports mutations', () => {
it('updates issue in the resolved issues list', () => {
stateCopy.dependencyScanning.newIssues = [];
stateCopy.dependencyScanning.resolvedIssues = parsedDependencyScanningIssuesHead;
stateCopy.dependencyScanning.resolvedIssues = mockFindings;
stateCopy.dependencyScanning.allIssues = [];
const updatedIssue = {
...parsedDependencyScanningIssuesHead[0],
...mockFindings[0],
foo: 'bar',
};
......@@ -565,9 +502,9 @@ describe('security reports mutations', () => {
it('updates issue in the all issues list', () => {
stateCopy.dependencyScanning.newIssues = [];
stateCopy.dependencyScanning.resolvedIssues = [];
stateCopy.dependencyScanning.allIssues = parsedDependencyScanningIssuesHead;
stateCopy.dependencyScanning.allIssues = mockFindings;
const updatedIssue = {
...parsedDependencyScanningIssuesHead[0],
...mockFindings[0],
foo: 'bar',
};
......
import sha1 from 'sha1';
import {
findIssueIndex,
findMatchingRemediations,
parseDependencyScanningIssues,
groupedTextBuilder,
statusIcon,
countIssues,
......@@ -10,12 +7,6 @@ import {
} from 'ee/vue_shared/security_reports/store/utils';
import filterByKey from 'ee/vue_shared/security_reports/store/utils/filter_by_key';
import getFileLocation from 'ee/vue_shared/security_reports/store/utils/get_file_location';
import {
dependencyScanningIssuesOld,
dependencyScanningIssues,
dependencyScanningIssuesMajor2,
dependencyScanningFeedbacks,
} from '../mock_data';
describe('security reports utils', () => {
describe('findIssueIndex', () => {
......@@ -46,114 +37,6 @@ describe('security reports utils', () => {
});
});
describe('findMatchingRemediations', () => {
const remediation1 = {
fixes: [
{
cve: '123',
},
{
foobar: 'baz',
},
],
summary: 'Update to x.y.z',
};
const remediation2 = { ...remediation1, summary: 'Remediation2' };
const impossibleRemediation = {
fixes: [],
summary: 'Impossible',
};
const remediations = [impossibleRemediation, remediation1, remediation2];
it('returns null for empty vulnerability', () => {
expect(findMatchingRemediations(remediations, {})).toHaveLength(0);
expect(findMatchingRemediations(remediations, null)).toHaveLength(0);
expect(findMatchingRemediations(remediations, undefined)).toHaveLength(0);
});
it('returns empty arrays for empty remediations', () => {
expect(findMatchingRemediations([], { cve: '123' })).toHaveLength(0);
expect(findMatchingRemediations(null, { cve: '123' })).toHaveLength(0);
expect(findMatchingRemediations(undefined, { cve: '123' })).toHaveLength(0);
});
it('returns an empty array for vulnerabilities without a remediation', () => {
expect(findMatchingRemediations(remediations, { cve: 'NOT_FOUND' })).toHaveLength(0);
});
it('returns all matching remediations for a vulnerability', () => {
expect(findMatchingRemediations(remediations, { cve: '123' })).toEqual([
remediation1,
remediation2,
]);
expect(findMatchingRemediations(remediations, { foobar: 'baz' })).toEqual([
remediation1,
remediation2,
]);
});
});
describe('parseDependencyScanningIssues', () => {
it('should parse the received issues', () => {
const parsed = parseDependencyScanningIssues(dependencyScanningIssuesOld, [], 'path')[0];
expect(parsed.title).toEqual(dependencyScanningIssuesOld[0].message);
expect(parsed.path).toEqual(dependencyScanningIssuesOld[0].file);
expect(parsed.location.start_line).toEqual(parseInt(dependencyScanningIssuesOld[0].line, 10));
expect(parsed.location.end_line).toBeUndefined();
expect(parsed.urlPath).toEqual('path/Gemfile.lock#L5');
expect(parsed.project_fingerprint).toEqual(sha1(dependencyScanningIssuesOld[0].cve));
});
it('should parse the received issues with new JSON format', () => {
const raw = dependencyScanningIssues[0];
const parsed = parseDependencyScanningIssues(dependencyScanningIssues, [], 'path')[0];
expect(parsed.title).toEqual(raw.message);
expect(parsed.path).toEqual(raw.location.file);
expect(parsed.location.start_line).toBeUndefined();
expect(parsed.location.end_line).toBeUndefined();
expect(parsed.urlPath).toEqual(`path/${raw.location.file}`);
expect(parsed.project_fingerprint).toEqual(sha1(raw.cve));
});
it('should parse the received issues with new JSON format (2.0)', () => {
const raw = dependencyScanningIssues[0];
const parsed = parseDependencyScanningIssues(dependencyScanningIssuesMajor2, [], 'path')[0];
expect(parsed.title).toEqual(raw.message);
expect(parsed.path).toEqual(raw.location.file);
expect(parsed.location.start_line).toBeUndefined();
expect(parsed.location.end_line).toBeUndefined();
expect(parsed.urlPath).toEqual(`path/${raw.location.file}`);
expect(parsed.project_fingerprint).toEqual(sha1(raw.cve));
expect(parsed.remediations).toEqual([dependencyScanningIssuesMajor2.remediations[0]]);
});
it('generate correct path to file when there is no line', () => {
const parsed = parseDependencyScanningIssues(dependencyScanningIssuesOld, [], 'path')[1];
expect(parsed.urlPath).toEqual('path/Gemfile.lock');
});
it('includes vulnerability feedbacks', () => {
const parsed = parseDependencyScanningIssues(
dependencyScanningIssuesOld,
dependencyScanningFeedbacks,
'path',
)[0];
expect(parsed.hasIssue).toEqual(true);
expect(parsed.isDismissed).toEqual(true);
expect(parsed.dismissalFeedback).toEqual(dependencyScanningFeedbacks[0]);
expect(parsed.issue_feedback).toEqual(dependencyScanningFeedbacks[1]);
});
});
describe('filterByKey', () => {
it('filters the array with the provided key', () => {
const array1 = [{ id: '1234' }, { id: 'abg543' }, { id: '214swfA' }];
......
......@@ -2501,7 +2501,7 @@ chardet@^0.5.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029"
integrity sha512-9ZTaoBaePSCFvNlNGrsyI8ZVACP2svUtq0DkM7t4K2ClAa96sqOIRjAzDTc8zXzFt1cZR46rRzLTiHFSJ+Qw0g==
"charenc@>= 0.0.1", charenc@~0.0.1:
charenc@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
......@@ -3114,7 +3114,7 @@ cross-spawn@^5.0.1:
shebang-command "^1.2.0"
which "^1.2.9"
"crypt@>= 0.0.1", crypt@~0.0.1:
crypt@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
......@@ -10136,14 +10136,6 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
sha1@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/sha1/-/sha1-1.1.1.tgz#addaa7a93168f393f19eb2b15091618e2700f848"
integrity sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=
dependencies:
charenc ">= 0.0.1"
crypt ">= 0.0.1"
shallow-clone@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment