Commit 1c4e95cb authored by Mark Florian's avatar Mark Florian

Merge branch 'secure-remove-outdated-ds-store' into 'master'

Remove outdated Secure VueX frontend code

See merge request gitlab-org/gitlab!23624
parents cbc62341 974c3fe0
......@@ -50,11 +50,6 @@ export const setCanCreateFeedbackPermission = ({ commit }, permission) =>
/**
* SAST CONTAINER
*/
export const setSastContainerHeadPath = ({ commit }, path) =>
commit(types.SET_SAST_CONTAINER_HEAD_PATH, path);
export const setSastContainerBasePath = ({ commit }, path) =>
commit(types.SET_SAST_CONTAINER_BASE_PATH, path);
export const setSastContainerDiffEndpoint = ({ commit }, path) =>
commit(types.SET_SAST_CONTAINER_DIFF_ENDPOINT, path);
......@@ -62,12 +57,6 @@ export const setSastContainerDiffEndpoint = ({ commit }, path) =>
export const requestSastContainerReports = ({ commit }) =>
commit(types.REQUEST_SAST_CONTAINER_REPORTS);
export const receiveSastContainerReports = ({ commit }, response) =>
commit(types.RECEIVE_SAST_CONTAINER_REPORTS, response);
export const receiveSastContainerError = ({ commit }, error) =>
commit(types.RECEIVE_SAST_CONTAINER_ERROR, error);
export const receiveSastContainerDiffSuccess = ({ commit }, response) =>
commit(types.RECEIVE_SAST_CONTAINER_DIFF_SUCCESS, response);
......@@ -96,77 +85,16 @@ export const fetchSastContainerDiff = ({ state, dispatch }) => {
});
};
export const fetchSastContainerReports = ({ state, dispatch }) => {
const { base, head } = state.sastContainer.paths;
dispatch('requestSastContainerReports');
return Promise.all([
head ? axios.get(head) : Promise.resolve(),
base ? axios.get(base) : Promise.resolve(),
axios.get(state.vulnerabilityFeedbackPath, {
params: {
category: 'container_scanning',
},
}),
])
.then(values => {
dispatch('receiveSastContainerReports', {
head: values[0] ? values[0].data : null,
base: values[1] ? values[1].data : null,
enrichData: values && values[2] ? values[2].data : [],
});
})
.catch(() => {
dispatch('receiveSastContainerError');
});
};
export const updateContainerScanningIssue = ({ commit }, issue) =>
commit(types.UPDATE_CONTAINER_SCANNING_ISSUE, issue);
/**
* DAST
*/
export const setDastHeadPath = ({ commit }, path) => commit(types.SET_DAST_HEAD_PATH, path);
export const setDastBasePath = ({ commit }, path) => commit(types.SET_DAST_BASE_PATH, path);
export const setDastDiffEndpoint = ({ commit }, path) => commit(types.SET_DAST_DIFF_ENDPOINT, path);
export const requestDastReports = ({ commit }) => commit(types.REQUEST_DAST_REPORTS);
export const receiveDastReports = ({ commit }, response) =>
commit(types.RECEIVE_DAST_REPORTS, response);
export const receiveDastError = ({ commit }, error) => commit(types.RECEIVE_DAST_ERROR, error);
export const fetchDastReports = ({ state, dispatch }) => {
const { base, head } = state.dast.paths;
dispatch('requestDastReports');
return Promise.all([
head ? axios.get(head) : Promise.resolve(),
base ? axios.get(base) : Promise.resolve(),
axios.get(state.vulnerabilityFeedbackPath, {
params: {
category: 'dast',
},
}),
])
.then(values => {
dispatch('receiveDastReports', {
head: values && values[0] ? values[0].data : null,
base: values && values[1] ? values[1].data : null,
enrichData: values && values[2] ? values[2].data : [],
});
})
.catch(() => {
dispatch('receiveDastError');
});
};
export const updateDastIssue = ({ commit }, issue) => commit(types.UPDATE_DAST_ISSUE, issue);
export const receiveDastDiffSuccess = ({ commit }, response) =>
......@@ -199,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);
......@@ -211,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);
......@@ -245,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);
......
......@@ -2,48 +2,10 @@ import axios from '~/lib/utils/axios_utils';
import pollUntilComplete from '~/lib/utils/poll_until_complete';
import * as types from './mutation_types';
export const setHeadPath = ({ commit }, path) => commit(types.SET_HEAD_PATH, path);
export const setBasePath = ({ commit }, path) => commit(types.SET_BASE_PATH, path);
export const setDiffEndpoint = ({ commit }, path) => commit(types.SET_DIFF_ENDPOINT, path);
export const requestReports = ({ commit }) => commit(types.REQUEST_REPORTS);
export const receiveReports = ({ commit }, response) => commit(types.RECEIVE_REPORTS, response);
export const receiveError = ({ commit }, error) => commit(types.RECEIVE_REPORTS_ERROR, error);
export const fetchReports = ({ state, rootState, dispatch }) => {
const { base, head } = state.paths;
const { blobPath, vulnerabilityFeedbackPath } = rootState;
dispatch('requestReports');
return Promise.all([
head ? axios.get(head) : Promise.resolve(),
base ? axios.get(base) : Promise.resolve(),
axios.get(vulnerabilityFeedbackPath, {
params: {
category: 'sast',
},
}),
])
.then(values => {
dispatch('receiveReports', {
reports: {
head: values && values[0] ? values[0].data : null,
base: values && values[1] ? values[1].data : null,
enrichData: values && values[2] ? values[2].data : [],
},
blobPath,
});
})
.catch(() => {
dispatch('receiveError');
});
};
export const updateVulnerability = ({ commit }, vulnerability) =>
commit(types.UPDATE_VULNERABILITY, vulnerability);
......
export const RECEIVE_DIFF_SUCCESS = 'RECEIVE_DIFF_SUCCESS';
export const RECEIVE_DIFF_ERROR = 'RECEIVE_DIFF_ERROR';
export const RECEIVE_REPORTS = 'RECEIVE_REPORTS';
export const RECEIVE_REPORTS_ERROR = 'RECEIVE_REPORTS_ERROR';
export const REQUEST_REPORTS = 'REQUEST_REPORTS';
export const SET_BASE_PATH = 'SET_BASE_PATH';
export const SET_DIFF_ENDPOINT = 'SET_DIFF_ENDPOINT';
export const SET_HEAD_PATH = 'SET_HEAD_PATH';
export const UPDATE_VULNERABILITY = 'UPDATE_VULNERABILITY';
import Vue from 'vue';
import * as types from './mutation_types';
import { parseSastIssues, findIssueIndex, parseDiff } from '../../utils';
import filterByKey from '../../utils/filter_by_key';
import { findIssueIndex, parseDiff } from '../../utils';
export default {
[types.SET_HEAD_PATH](state, path) {
Vue.set(state.paths, 'head', path);
},
[types.SET_BASE_PATH](state, path) {
Vue.set(state.paths, 'base', path);
},
[types.SET_DIFF_ENDPOINT](state, path) {
Vue.set(state.paths, 'diffEndpoint', path);
},
......@@ -20,45 +11,6 @@ export default {
state.isLoading = true;
},
/**
* Compares sast results and returns the formatted report
*
* Sast 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_REPORTS](state, payload) {
const { reports, blobPath } = payload;
if (reports.base && reports.head) {
const filterKey = 'cve';
const parsedHead = parseSastIssues(reports.head, reports.enrichData, blobPath.head);
const parsedBase = parseSastIssues(reports.base, reports.enrichData, blobPath.base);
const newIssues = filterByKey(parsedHead, parsedBase, filterKey);
const resolvedIssues = filterByKey(parsedBase, parsedHead, filterKey);
const allIssues = filterByKey(parsedHead, newIssues.concat(resolvedIssues), filterKey);
state.newIssues = newIssues;
state.resolvedIssues = resolvedIssues;
state.allIssues = allIssues;
state.isLoading = false;
} else if (reports.head && !reports.base) {
const newIssues = parseSastIssues(reports.head, reports.enrichData, blobPath.head);
state.newIssues = newIssues;
state.isLoading = false;
}
},
[types.RECEIVE_DIFF_SUCCESS](state, { diff, enrichData }) {
const { added, fixed, existing } = parseDiff(diff, enrichData);
const baseReportOutofDate = diff.base_report_out_of_date || false;
......@@ -77,11 +29,6 @@ export default {
state.hasError = true;
},
[types.RECEIVE_REPORTS_ERROR](state) {
state.isLoading = false;
state.hasError = true;
},
[types.UPDATE_VULNERABILITY](state, issue) {
const newIssuesIndex = findIssueIndex(state.newIssues, issue);
if (newIssuesIndex !== -1) {
......
......@@ -14,32 +14,20 @@ export const SET_CAN_CREATE_ISSUE_PERMISSION = 'SET_CAN_CREATE_ISSUE_PERMISSION'
export const SET_CAN_CREATE_FEEDBACK_PERMISSION = 'SET_CAN_CREATE_FEEDBACK_PERMISSION';
// SAST CONTAINER
export const SET_SAST_CONTAINER_HEAD_PATH = 'SET_SAST_CONTAINER_HEAD_PATH';
export const SET_SAST_CONTAINER_BASE_PATH = 'SET_SAST_CONTAINER_BASE_PATH';
export const SET_SAST_CONTAINER_DIFF_ENDPOINT = 'SET_SAST_CONTAINER_DIFF_ENDPOINT';
export const REQUEST_SAST_CONTAINER_REPORTS = 'REQUEST_SAST_CONTAINER_REPORTS';
export const RECEIVE_SAST_CONTAINER_REPORTS = 'RECEIVE_SAST_CONTAINER_REPORTS';
export const RECEIVE_SAST_CONTAINER_ERROR = 'RECEIVE_SAST_CONTAINER_ERROR';
export const RECEIVE_SAST_CONTAINER_DIFF_SUCCESS = 'RECEIVE_SAST_CONTAINER_DIFF_SUCCESS';
export const RECEIVE_SAST_CONTAINER_DIFF_ERROR = 'RECEIVE_SAST_CONTAINER_DIFF_ERROR';
// DAST
export const SET_DAST_HEAD_PATH = 'SET_DAST_HEAD_PATH';
export const SET_DAST_DIFF_ENDPOINT = 'SET_DAST_DIFF_ENDPOINT';
export const SET_DAST_BASE_PATH = 'SET_DAST_BASE_PATH';
export const REQUEST_DAST_REPORTS = 'REQUEST_DAST_REPORTS';
export const RECEIVE_DAST_REPORTS = 'RECEIVE_DAST_REPORTS';
export const RECEIVE_DAST_ERROR = 'RECEIVE_DAST_ERROR';
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,
parseDastIssues,
getUnapprovedVulnerabilities,
findIssueIndex,
parseDiff,
} from './utils';
import filterByKey from './utils/filter_by_key';
import { findIssueIndex, parseDiff } from './utils';
import getFileLocation from './utils/get_file_location';
import { parseSastContainer } from './utils/container_scanning';
import { visitUrl } from '~/lib/utils/url_utility';
export default {
......@@ -58,14 +50,6 @@ export default {
},
// SAST CONTAINER
[types.SET_SAST_CONTAINER_HEAD_PATH](state, path) {
Vue.set(state.sastContainer.paths, 'head', path);
},
[types.SET_SAST_CONTAINER_BASE_PATH](state, path) {
Vue.set(state.sastContainer.paths, 'base', path);
},
[types.SET_SAST_CONTAINER_DIFF_ENDPOINT](state, path) {
Vue.set(state.sastContainer.paths, 'diffEndpoint', path);
},
......@@ -74,38 +58,6 @@ export default {
Vue.set(state.sastContainer, 'isLoading', true);
},
/**
* For sast container we only render unapproved vulnerabilities.
*/
[types.RECEIVE_SAST_CONTAINER_REPORTS](state, reports) {
if (reports.base && reports.head) {
const headIssues = getUnapprovedVulnerabilities(
parseSastContainer(reports.head.vulnerabilities, reports.enrichData, reports.head.image),
reports.head.unapproved,
);
const baseIssues = getUnapprovedVulnerabilities(
parseSastContainer(reports.base.vulnerabilities, reports.enrichData, reports.base.image),
reports.base.unapproved,
);
const filterKey = 'vulnerability';
const newIssues = filterByKey(headIssues, baseIssues, filterKey);
const resolvedIssues = filterByKey(baseIssues, headIssues, filterKey);
Vue.set(state.sastContainer, 'newIssues', newIssues);
Vue.set(state.sastContainer, 'resolvedIssues', resolvedIssues);
Vue.set(state.sastContainer, 'isLoading', false);
} else if (reports.head && !reports.base) {
const newIssues = getUnapprovedVulnerabilities(
parseSastContainer(reports.head.vulnerabilities, reports.enrichData, reports.head.image),
reports.head.unapproved,
);
Vue.set(state.sastContainer, 'newIssues', newIssues);
Vue.set(state.sastContainer, 'isLoading', false);
}
},
[types.RECEIVE_SAST_CONTAINER_DIFF_SUCCESS](state, { diff, enrichData }) {
const { added, fixed, existing } = parseDiff(diff, enrichData);
const baseReportOutofDate = diff.base_report_out_of_date || false;
......@@ -124,21 +76,8 @@ export default {
Vue.set(state.sastContainer, 'hasError', true);
},
[types.RECEIVE_SAST_CONTAINER_ERROR](state) {
Vue.set(state.sastContainer, 'isLoading', false);
Vue.set(state.sastContainer, 'hasError', true);
},
// DAST
[types.SET_DAST_HEAD_PATH](state, path) {
Vue.set(state.dast.paths, 'head', path);
},
[types.SET_DAST_BASE_PATH](state, path) {
Vue.set(state.dast.paths, 'base', path);
},
[types.SET_DAST_DIFF_ENDPOINT](state, path) {
Vue.set(state.dast.paths, 'diffEndpoint', path);
},
......@@ -147,25 +86,6 @@ export default {
Vue.set(state.dast, 'isLoading', true);
},
[types.RECEIVE_DAST_REPORTS](state, reports) {
if (reports.head && reports.base) {
const headIssues = parseDastIssues(reports.head.site, reports.enrichData);
const baseIssues = parseDastIssues(reports.base.site, reports.enrichData);
const filterKey = 'pluginid';
const newIssues = filterByKey(headIssues, baseIssues, filterKey);
const resolvedIssues = filterByKey(baseIssues, headIssues, filterKey);
Vue.set(state.dast, 'newIssues', newIssues);
Vue.set(state.dast, 'resolvedIssues', resolvedIssues);
Vue.set(state.dast, 'isLoading', false);
} else if (reports.head && reports.head.site && !reports.base) {
const newIssues = parseDastIssues(reports.head.site, reports.enrichData);
Vue.set(state.dast, 'newIssues', newIssues);
Vue.set(state.dast, 'isLoading', false);
}
},
[types.RECEIVE_DAST_DIFF_SUCCESS](state, { diff, enrichData }) {
const { added, fixed, existing } = parseDiff(diff, enrichData);
const baseReportOutofDate = diff.base_report_out_of_date || false;
......@@ -184,21 +104,8 @@ export default {
Vue.set(state.dast, 'hasError', true);
},
[types.RECEIVE_DAST_ERROR](state) {
Vue.set(state.dast, 'isLoading', false);
Vue.set(state.dast, 'hasError', true);
},
// 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);
},
......@@ -207,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;
......@@ -275,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 { stripHtml } from '~/lib/utils/text_utility';
import { n__, s__, sprintf } from '~/locale';
/**
......@@ -11,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)
......@@ -69,200 +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 SAST 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 parseSastIssues = (report = [], feedback = [], path = '') =>
adaptDeprecatedReportFormat(report).vulnerabilities.map(issue => {
const parsed = {
...adaptDeprecatedIssueFormat(issue),
category: 'sast',
project_fingerprint: sha1(issue.cve),
title: issue.message,
};
return {
...parsed,
path: parsed.location.file,
urlPath: fileUrl(parsed.location, path),
...enrichVulnerabilityWithFeedback(parsed, feedback),
};
});
/**
* 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),
};
});
};
/**
* Forces the site property to be an Array in DAST reports.
* We do this to also support single-site legacy DAST reports.
*
* @param {Object|Array} sites
*/
export const getDastSites = sites => (Array.isArray(sites) ? sites : [sites]);
/**
* Parses DAST into a common format to allow to use the same Vue component.
* DAST report is currently the straigh output from the underlying tool (ZAProxy)
* hence the formatting happenning here.
*
* @param {Array} sites
* @param {Array} feedback
* @returns {Array}
*/
export const parseDastIssues = (sites = [], feedback = []) =>
getDastSites(sites).reduce(
(acc, site) => [
...acc,
...(site.alerts || []).map(issue => {
const parsed = {
...issue,
category: 'dast',
project_fingerprint: sha1(issue.pluginid),
title: issue.name,
description: stripHtml(issue.desc, ' '),
solution: stripHtml(issue.solution, ' '),
};
if (!_.isEmpty(issue.cweid)) {
Object.assign(parsed, {
identifiers: [
{
type: 'CWE',
name: `CWE-${issue.cweid}`,
value: issue.cweid,
url: `https://cwe.mitre.org/data/definitions/${issue.cweid}.html`,
},
],
});
}
if (issue.riskdesc && issue.riskdesc !== '') {
// Split riskdesc into severity and confidence.
// Riskdesc format is: "severity (confidence)"
const [, severity, confidence] = issue.riskdesc.match(/(.*) \((.*)\)/);
Object.assign(parsed, {
severity,
confidence,
});
}
return {
...parsed,
...enrichVulnerabilityWithFeedback(parsed, feedback),
};
}),
],
[],
);
export const getUnapprovedVulnerabilities = (issues = [], unapproved = []) =>
issues.filter(item => unapproved.find(el => el === item.vulnerability));
export const groupedTextBuilder = ({
reportType = '',
paths = {},
......
import { SEVERITY_LEVELS } from 'ee/security_dashboard/store/constants';
import sha1 from 'sha1';
import _ from 'underscore';
import { s__, sprintf } from '~/locale';
import { enrichVulnerabilityWithFeedback } from '../utils';
/*
Container scanning mapping utils
This file contains all functions for mapping container scanning vulnerabilities
to match the representation that we are building in the backend:
https://gitlab.com/gitlab-org/gitlab/blob/bbcd07475f0334/ee/lib/gitlab/ci/parsers/security/container_scanning.rb
All these function can hopefully be removed as soon as we retrieve the data from the backend.
*/
export const formatContainerScanningDescription = ({
description,
namespace,
vulnerability,
featurename,
featureversion,
}) => {
if (!_.isEmpty(description)) {
return description;
}
let generated;
if (featurename && featureversion) {
generated = `${featurename}:${featureversion}`;
} else if (featurename) {
generated = featurename;
} else {
generated = namespace;
}
return sprintf(s__('ciReport|%{namespace} is affected by %{vulnerability}.'), {
namespace: generated,
vulnerability,
});
};
export const formatContainerScanningMessage = ({ vulnerability, featurename }) => {
if (featurename) {
return sprintf(s__('ciReport|%{vulnerability} in %{featurename}'), {
vulnerability,
featurename,
});
}
return vulnerability;
};
export const formatContainerScanningSolution = ({ fixedby, featurename, featureversion }) => {
if (!_.isEmpty(fixedby)) {
if (!_.isEmpty(featurename)) {
if (!_.isEmpty(featureversion)) {
return sprintf(s__('ciReport|Upgrade %{name} from %{version} to %{fixed}.'), {
name: featurename,
version: featureversion,
fixed: fixedby,
});
}
return sprintf(s__('ciReport|Upgrade %{name} to %{fixed}.'), {
name: featurename,
fixed: fixedby,
});
}
return sprintf(s__('ciReport|Upgrade to %{fixed}.'), {
fixed: fixedby,
});
}
return null;
};
export const parseContainerScanningSeverity = severity => {
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
if (severity === 'Defcon1') {
return SEVERITY_LEVELS.critical;
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
} else if (severity === 'Negligible') {
return SEVERITY_LEVELS.low;
}
return severity;
};
/**
* Parses Container Scanning results into a common format to allow to use the same Vue component.
* Container Scanning report is currently the straight output from the underlying tool
* (clair scanner) hence the formatting happening here.
*
* @param {Array} issues
* @param {Array} feedback
* @param {String} image name
* @returns {Array}
*/
export const parseSastContainer = (issues = [], feedback = [], image) =>
issues.map(issue => {
const message = formatContainerScanningMessage(issue);
/*
The following fields are copying the backend data structure, as can be found in:
https://gitlab.com/gitlab-org/gitlab/blob/f8f5724bb47712df0a618ae0a447b69a6ef47c0c/ee/lib/gitlab/ci/parsers/security/container_scanning.rb#L42-72
*/
const parsed = {
category: 'container_scanning',
message,
description: formatContainerScanningDescription(issue),
cve: issue.vulnerability,
severity: parseContainerScanningSeverity(issue.severity),
confidence: SEVERITY_LEVELS.medium,
location: {
image,
operating_system: issue.namespace,
},
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
scanner: { id: 'clair', name: 'Clair' },
identifiers: [
{
type: 'CVE',
name: issue.vulnerability,
value: issue.vulnerability,
url: `https://cve.mitre.org/cgi-bin/cvename.cgi?name=${issue.vulnerability}`,
},
],
};
const solution = formatContainerScanningSolution(issue);
if (solution) {
parsed.solution = solution;
}
if (issue.featurename) {
const dependency = {
package: {
name: issue.featurename,
},
};
if (issue.featureversion) {
dependency.version = issue.featureversion;
}
parsed.location.dependency = dependency;
}
if (issue.link) {
parsed.links = [{ url: issue.link }];
}
/*
The following properties are set only created in the frontend.
This is done for legacy reasons and they should be made obsolete,
before switching to the Backend implementation
*/
const frontendOnly = {
project_fingerprint: sha1(issue.vulnerability),
title: message,
vulnerability: issue.vulnerability,
};
return {
...parsed,
...frontendOnly,
...enrichVulnerabilityWithFeedback(frontendOnly, feedback),
};
});
const libTiffCveFingerprint = 'e503c23a7776dd5e2c35ac63c8cce6b6468be9ba';
const libTiffCveFingerprint2 = '29af456d1107381bc2511646e2ae488ddfe9a8ed';
export const sastParsedIssues = [
......@@ -11,604 +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 sastIssuesMajor2 = {
version: '2.0',
vulnerabilities: sastIssues,
};
export const oldSastIssues = [
{
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',
},
];
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 parsedSastContainerBaseStore = [
{
category: 'container_scanning',
message: 'CVE-2014-8130',
description: 'debian:8 is affected by CVE-2014-8130.',
cve: 'CVE-2014-8130',
severity: 'Low',
confidence: 'Medium',
location: { image: 'registry.example.com/example/master:1234', operating_system: 'debian:8' },
scanner: { id: 'clair', name: 'Clair' },
identifiers: [
{
name: 'CVE-2014-8130',
type: 'CVE',
url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-8130',
value: 'CVE-2014-8130',
},
],
project_fingerprint: 'e1f22cd89e3c306541d7c804b29255b5cc275d6d',
title: 'CVE-2014-8130',
vulnerability: 'CVE-2014-8130',
},
];
export const dockerReport = {
image: 'registry.example.com/example/master:1234',
unapproved: ['CVE-2017-12944', 'CVE-2017-16232'],
vulnerabilities: [
{
vulnerability: 'CVE-2017-12944',
namespace: 'debian:8',
severity: 'Medium',
},
{
vulnerability: 'CVE-2017-16232',
namespace: 'debian:8',
severity: 'Negligible',
},
{
vulnerability: 'CVE-2014-8130',
namespace: 'debian:8',
severity: 'Negligible',
},
],
};
export const dockerBaseReport = {
image: 'registry.example.com/example/master:1234',
unapproved: ['CVE-2017-12944', 'CVE-2014-8130'],
vulnerabilities: [
{
vulnerability: 'CVE-2017-12944',
namespace: 'debian:8',
severity: 'Medium',
},
{
vulnerability: 'CVE-2017-16232',
namespace: 'debian:8',
severity: 'Negligible',
},
{
vulnerability: 'CVE-2014-8130',
namespace: 'debian:8',
severity: 'Negligible',
},
],
};
export const dockerNewIssues = [
{
category: 'container_scanning',
message: 'CVE-2017-16232',
description: 'debian:8 is affected by CVE-2017-16232.',
cve: 'CVE-2017-16232',
severity: 'Low',
confidence: 'Medium',
location: { image: 'registry.example.com/example/master:1234', operating_system: 'debian:8' },
scanner: { id: 'clair', name: 'Clair' },
identifiers: [
{
type: 'CVE',
name: 'CVE-2017-16232',
value: 'CVE-2017-16232',
url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16232',
},
],
project_fingerprint: libTiffCveFingerprint,
title: 'CVE-2017-16232',
vulnerability: 'CVE-2017-16232',
},
];
export const dockerOnlyHeadParsed = [
{
category: 'container_scanning',
message: 'CVE-2017-12944',
description: 'debian:8 is affected by CVE-2017-12944.',
cve: 'CVE-2017-12944',
severity: 'Medium',
confidence: 'Medium',
location: { image: 'registry.example.com/example/master:1234', operating_system: 'debian:8' },
scanner: { id: 'clair', name: 'Clair' },
identifiers: [
{
type: 'CVE',
name: 'CVE-2017-12944',
value: 'CVE-2017-12944',
url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-12944',
},
],
project_fingerprint: libTiffCveFingerprint2,
title: 'CVE-2017-12944',
vulnerability: 'CVE-2017-12944',
},
{
category: 'container_scanning',
message: 'CVE-2017-16232',
description: 'debian:8 is affected by CVE-2017-16232.',
cve: 'CVE-2017-16232',
severity: 'Low',
confidence: 'Medium',
location: { image: 'registry.example.com/example/master:1234', operating_system: 'debian:8' },
scanner: { id: 'clair', name: 'Clair' },
identifiers: [
{
type: 'CVE',
name: 'CVE-2017-16232',
value: 'CVE-2017-16232',
url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16232',
},
],
project_fingerprint: libTiffCveFingerprint,
title: 'CVE-2017-16232',
vulnerability: 'CVE-2017-16232',
},
];
export const dockerReportParsed = {
unapproved: [
{
......@@ -708,259 +109,6 @@ export const dockerReportParsed = {
],
};
export const multiSitesDast = {
site: [
{
'@port': '8080',
'@host': 'goat',
'@name': 'http://goat:8080',
alerts: [
{
name: 'Absence of Anti-CSRF Tokens',
riskcode: '1',
riskdesc: 'Low (Medium)',
cweid: '3',
desc: '<p>No Anti-CSRF tokens were found in a HTML submission form.</p>',
pluginid: '123',
solution: '<p>Update to latest</p>',
instances: [
{
uri: 'http://192.168.32.236:3001/explore?sort=latest_activity_desc',
method: 'GET',
evidence:
"<form class='form-inline' action='/search' accept-charset='UTF-8' method='get'>",
},
{
uri: 'http://192.168.32.236:3001/help/user/group/subgroups/index.md',
method: 'GET',
evidence:
"<form class='form-inline' action='/search' accept-charset='UTF-8' method='get'>",
},
],
},
{
alert: 'X-Content-Type-Options Header Missing',
name: 'X-Content-Type-Options Header Missing',
riskdesc: 'Low (Medium)',
cweid: '4',
desc:
'<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff".</p>',
pluginid: '3456',
solution: '<p>Update to latest</p>',
instances: [
{
uri: 'http://192.168.32.236:3001/assets/webpack/main.bundle.js',
method: 'GET',
param: 'X-Content-Type-Options',
},
],
},
],
'@ssl': 'false',
},
{
'@port': '8081',
'@host': 'nginx',
'@name': 'http://nginx:8081',
alerts: [
{
alert: 'X-Content-Type-Options Header Missing',
name: 'X-Content-Type-Options Header Missing',
riskdesc: 'Low (Medium)',
cweid: '4',
desc:
'<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff".</p>',
pluginid: '3456',
solution: '<p>Update to latest</p>',
instances: [
{
uri: 'http://192.168.32.236:3001/assets/webpack/main.bundle.js',
method: 'GET',
param: 'X-Content-Type-Options',
},
],
},
],
'@ssl': 'false',
},
],
};
export const dast = {
site: {
alerts: [
{
name: 'Absence of Anti-CSRF Tokens',
riskcode: '1',
riskdesc: 'Low (Medium)',
cweid: '3',
desc: '<p>No Anti-CSRF tokens were found in a HTML submission form.</p>',
pluginid: '123',
solution: '<p>Update to latest</p>',
instances: [
{
uri: 'http://192.168.32.236:3001/explore?sort=latest_activity_desc',
method: 'GET',
evidence:
"<form class='form-inline' action='/search' accept-charset='UTF-8' method='get'>",
},
{
uri: 'http://192.168.32.236:3001/help/user/group/subgroups/index.md',
method: 'GET',
evidence:
"<form class='form-inline' action='/search' accept-charset='UTF-8' method='get'>",
},
],
},
{
alert: 'X-Content-Type-Options Header Missing',
name: 'X-Content-Type-Options Header Missing',
riskdesc: 'Low (Medium)',
cweid: '4',
desc:
'<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff".</p>',
pluginid: '3456',
solution: '<p>Update to latest</p>',
instances: [
{
uri: 'http://192.168.32.236:3001/assets/webpack/main.bundle.js',
method: 'GET',
param: 'X-Content-Type-Options',
},
],
},
],
},
};
export const dastBase = {
site: {
alerts: [
{
name: 'Absence of Anti-CSRF Tokens',
riskcode: '1',
riskdesc: 'Low (Medium)',
cweid: '03',
desc: '<p>No Anti-CSRF tokens were found in a HTML submission form.</p>',
pluginid: '123',
solution: '<p>Update to latest</p>',
instances: [
{
uri: 'http://192.168.32.236:3001/explore?sort=latest_activity_desc',
method: 'GET',
evidence:
"<form class='form-inline' action='/search' accept-charset='UTF-8' method='get'>",
},
{
uri: 'http://192.168.32.236:3001/help/user/group/subgroups/index.md',
method: 'GET',
evidence:
"<form class='form-inline' action='/search' accept-charset='UTF-8' method='get'>",
},
],
},
],
},
};
export const parsedMultiSitesDast = [
{
category: 'dast',
project_fingerprint: '40bd001563085fc35165329ea1ff5c5ecbdbbeef',
name: 'Absence of Anti-CSRF Tokens',
title: 'Absence of Anti-CSRF Tokens',
riskcode: '1',
riskdesc: 'Low (Medium)',
severity: 'Low',
confidence: 'Medium',
cweid: '3',
desc: '<p>No Anti-CSRF tokens were found in a HTML submission form.</p>',
pluginid: '123',
identifiers: [
{
type: 'CWE',
name: 'CWE-3',
value: '3',
url: 'https://cwe.mitre.org/data/definitions/3.html',
},
],
instances: [
{
uri: 'http://192.168.32.236:3001/explore?sort=latest_activity_desc',
method: 'GET',
evidence: "<form class='form-inline' action='/search' accept-charset='UTF-8' method='get'>",
},
{
uri: 'http://192.168.32.236:3001/help/user/group/subgroups/index.md',
method: 'GET',
evidence: "<form class='form-inline' action='/search' accept-charset='UTF-8' method='get'>",
},
],
solution: ' Update to latest ',
description: ' No Anti-CSRF tokens were found in a HTML submission form. ',
},
{
category: 'dast',
project_fingerprint: 'ae8fe380dd9aa5a7a956d9085fe7cf6b87d0d028',
alert: 'X-Content-Type-Options Header Missing',
name: 'X-Content-Type-Options Header Missing',
title: 'X-Content-Type-Options Header Missing',
riskdesc: 'Low (Medium)',
identifiers: [
{
type: 'CWE',
name: 'CWE-4',
value: '4',
url: 'https://cwe.mitre.org/data/definitions/4.html',
},
],
severity: 'Low',
confidence: 'Medium',
cweid: '4',
desc: '<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff".</p>',
pluginid: '3456',
instances: [
{
uri: 'http://192.168.32.236:3001/assets/webpack/main.bundle.js',
method: 'GET',
param: 'X-Content-Type-Options',
},
],
solution: ' Update to latest ',
description: ' The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff". ',
},
{
category: 'dast',
project_fingerprint: 'ae8fe380dd9aa5a7a956d9085fe7cf6b87d0d028',
alert: 'X-Content-Type-Options Header Missing',
name: 'X-Content-Type-Options Header Missing',
title: 'X-Content-Type-Options Header Missing',
riskdesc: 'Low (Medium)',
identifiers: [
{
type: 'CWE',
name: 'CWE-4',
value: '4',
url: 'https://cwe.mitre.org/data/definitions/4.html',
},
],
severity: 'Low',
confidence: 'Medium',
cweid: '4',
desc: '<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff".</p>',
pluginid: '3456',
instances: [
{
uri: 'http://192.168.32.236:3001/assets/webpack/main.bundle.js',
method: 'GET',
param: 'X-Content-Type-Options',
},
],
solution: ' Update to latest ',
description: ' The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff". ',
},
];
export const parsedDast = [
{
category: 'dast',
......@@ -1029,64 +177,6 @@ export const parsedDast = [
},
];
export const parsedDastNewIssues = [
{
category: 'dast',
project_fingerprint: 'ae8fe380dd9aa5a7a956d9085fe7cf6b87d0d028',
alert: 'X-Content-Type-Options Header Missing',
name: 'X-Content-Type-Options Header Missing',
title: 'X-Content-Type-Options Header Missing',
riskdesc: 'Low (Medium)',
identifiers: [
{
type: 'CWE',
name: 'CWE-4',
value: '4',
url: 'https://cwe.mitre.org/data/definitions/4.html',
},
],
severity: 'Low',
confidence: 'Medium',
cweid: '4',
desc: '<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff".</p>',
pluginid: '3456',
instances: [
{
uri: 'http://192.168.32.236:3001/assets/webpack/main.bundle.js',
method: 'GET',
param: 'X-Content-Type-Options',
},
],
solution: ' Update to latest ',
description: ' The Anti-MIME-Sniffing header X-Content-Type-Options was not set to "nosniff". ',
},
];
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,
......
......@@ -7,24 +7,9 @@ import {
setPipelineId,
setCanCreateIssuePermission,
setCanCreateFeedbackPermission,
setSastContainerHeadPath,
setSastContainerBasePath,
requestSastContainerReports,
receiveSastContainerReports,
receiveSastContainerError,
fetchSastContainerReports,
setDastHeadPath,
setDastBasePath,
requestDastReports,
receiveDastReports,
receiveDastError,
fetchDastReports,
setDependencyScanningHeadPath,
setDependencyScanningBasePath,
requestDependencyScanningReports,
receiveDependencyScanningError,
receiveDependencyScanningReports,
fetchDependencyScanningReports,
openModal,
setModalData,
requestDismissVulnerability,
......@@ -72,13 +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,
dast,
dastBase,
dockerReport,
dockerBaseReport,
sastFeedbacks,
dastFeedbacks,
containerScanningFeedbacks,
dependencyScanningFeedbacks,
......@@ -252,42 +230,6 @@ describe('security reports actions', () => {
});
});
describe('setSastContainerHeadPath', () => {
it('should commit set head blob path', done => {
testAction(
setSastContainerHeadPath,
'path',
mockedState,
[
{
type: types.SET_SAST_CONTAINER_HEAD_PATH,
payload: 'path',
},
],
[],
done,
);
});
});
describe('setSastContainerBasePath', () => {
it('should commit set head blob path', done => {
testAction(
setSastContainerBasePath,
'path',
mockedState,
[
{
type: types.SET_SAST_CONTAINER_BASE_PATH,
payload: 'path',
},
],
[],
done,
);
});
});
describe('requestSastContainerReports', () => {
it('should commit request mutation', done => {
testAction(
......@@ -305,198 +247,6 @@ describe('security reports actions', () => {
});
});
describe('receiveSastContainerReports', () => {
it('should commit sast receive mutation', done => {
testAction(
receiveSastContainerReports,
{},
mockedState,
[
{
type: types.RECEIVE_SAST_CONTAINER_REPORTS,
payload: {},
},
],
[],
done,
);
});
});
describe('receiveSastContainerError', () => {
it('should commit sast error mutation', done => {
const error = new Error('test');
testAction(
receiveSastContainerError,
error,
mockedState,
[
{
type: types.RECEIVE_SAST_CONTAINER_ERROR,
payload: error,
},
],
[],
done,
);
});
});
describe('fetchSastContainerReports', () => {
describe('with head and base', () => {
it('should dispatch `receiveSastContainerReports`', done => {
mock.onGet('foo').reply(200, dockerReport);
mock.onGet('bar').reply(200, dockerBaseReport);
mock
.onGet('vulnerabilities_path', {
params: {
category: 'container_scanning',
},
})
.reply(200, containerScanningFeedbacks);
mockedState.vulnerabilityFeedbackPath = 'vulnerabilities_path';
mockedState.sastContainer.paths.head = 'foo';
mockedState.sastContainer.paths.base = 'bar';
testAction(
fetchSastContainerReports,
null,
mockedState,
[],
[
{
type: 'requestSastContainerReports',
},
{
type: 'receiveSastContainerReports',
payload: {
head: dockerReport,
base: dockerBaseReport,
enrichData: containerScanningFeedbacks,
},
},
],
done,
);
});
it('should dispatch `receiveSastContainerError`', done => {
mock.onGet('foo').reply(500, {});
mockedState.sastContainer.paths.head = 'foo';
mockedState.sastContainer.paths.base = 'bar';
testAction(
fetchSastContainerReports,
null,
mockedState,
[],
[
{
type: 'requestSastContainerReports',
},
{
type: 'receiveSastContainerError',
},
],
done,
);
});
});
describe('with head', () => {
it('should dispatch `receiveSastContainerReports`', done => {
mock.onGet('foo').reply(200, dockerReport);
mock
.onGet('vulnerabilities_path', {
params: {
category: 'container_scanning',
},
})
.reply(200, containerScanningFeedbacks);
mockedState.vulnerabilityFeedbackPath = 'vulnerabilities_path';
mockedState.sastContainer.paths.head = 'foo';
testAction(
fetchSastContainerReports,
null,
mockedState,
[],
[
{
type: 'requestSastContainerReports',
},
{
type: 'receiveSastContainerReports',
payload: { head: dockerReport, base: null, enrichData: containerScanningFeedbacks },
},
],
done,
);
});
it('should dispatch `receiveSastContainerError`', done => {
mock.onGet('foo').reply(500, {});
mockedState.sastContainer.paths.head = 'foo';
testAction(
fetchSastContainerReports,
null,
mockedState,
[],
[
{
type: 'requestSastContainerReports',
},
{
type: 'receiveSastContainerError',
},
],
done,
);
});
});
});
describe('setDastHeadPath', () => {
it('should commit set head blob path', done => {
testAction(
setDastHeadPath,
'path',
mockedState,
[
{
type: types.SET_DAST_HEAD_PATH,
payload: 'path',
},
],
[],
done,
);
});
});
describe('setDastBasePath', () => {
it('should commit set head blob path', done => {
testAction(
setDastBasePath,
'path',
mockedState,
[
{
type: types.SET_DAST_BASE_PATH,
payload: 'path',
},
],
[],
done,
);
});
});
describe('requestDastReports', () => {
it('should commit request mutation', done => {
testAction(
......@@ -514,194 +264,6 @@ describe('security reports actions', () => {
});
});
describe('receiveDastReports', () => {
it('should commit sast receive mutation', done => {
testAction(
receiveDastReports,
{},
mockedState,
[
{
type: types.RECEIVE_DAST_REPORTS,
payload: {},
},
],
[],
done,
);
});
});
describe('receiveDastError', () => {
it('should commit sast error mutation', done => {
const error = new Error('test');
testAction(
receiveDastError,
error,
mockedState,
[
{
type: types.RECEIVE_DAST_ERROR,
payload: error,
},
],
[],
done,
);
});
});
describe('fetchDastReports', () => {
describe('with head and base', () => {
it('should dispatch `receiveDastReports`', done => {
mock.onGet('foo').reply(200, dast);
mock.onGet('bar').reply(200, dastBase);
mock
.onGet('vulnerabilities_path', {
params: {
category: 'dast',
},
})
.reply(200, dastFeedbacks);
mockedState.vulnerabilityFeedbackPath = 'vulnerabilities_path';
mockedState.dast.paths.head = 'foo';
mockedState.dast.paths.base = 'bar';
testAction(
fetchDastReports,
null,
mockedState,
[],
[
{
type: 'requestDastReports',
},
{
type: 'receiveDastReports',
payload: { head: dast, base: dastBase, enrichData: dastFeedbacks },
},
],
done,
);
});
it('should dispatch `receiveDastError`', done => {
mock.onGet('foo').reply(500, {});
mockedState.dast.paths.head = 'foo';
mockedState.dast.paths.base = 'bar';
testAction(
fetchDastReports,
null,
mockedState,
[],
[
{
type: 'requestDastReports',
},
{
type: 'receiveDastError',
},
],
done,
);
});
});
describe('with head', () => {
it('should dispatch `receiveSastContainerReports`', done => {
mock.onGet('foo').reply(200, dast);
mock
.onGet('vulnerabilities_path', {
params: {
category: 'dast',
},
})
.reply(200, dastFeedbacks);
mockedState.vulnerabilityFeedbackPath = 'vulnerabilities_path';
mockedState.dast.paths.head = 'foo';
testAction(
fetchDastReports,
null,
mockedState,
[],
[
{
type: 'requestDastReports',
},
{
type: 'receiveDastReports',
payload: { head: dast, base: null, enrichData: dastFeedbacks },
},
],
done,
);
});
it('should dispatch `receiveDastError`', done => {
mock.onGet('foo').reply(500, {});
mockedState.dast.paths.head = 'foo';
testAction(
fetchDastReports,
null,
mockedState,
[],
[
{
type: 'requestDastReports',
},
{
type: 'receiveDastError',
},
],
done,
);
});
});
});
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(
......@@ -719,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(
......
......@@ -6,8 +6,6 @@ import * as types from 'ee/vue_shared/security_reports/store/modules/sast/mutati
import * as actions from 'ee/vue_shared/security_reports/store/modules/sast/actions';
import axios from '~/lib/utils/axios_utils';
const headPath = 'head-path.json';
const basePath = 'base-path.json';
const diffEndpoint = 'diff-endpoint.json';
const blobPath = 'blob-path.json';
const reports = {
......@@ -28,42 +26,6 @@ describe('sast report actions', () => {
state = createState();
});
describe('setHeadPath', () => {
it(`should commit ${types.SET_HEAD_PATH} with the correct path`, done => {
testAction(
actions.setHeadPath,
headPath,
state,
[
{
type: types.SET_HEAD_PATH,
payload: headPath,
},
],
[],
done,
);
});
});
describe('setBasePath', () => {
it(`should commit ${types.SET_BASE_PATH} with the correct path`, done => {
testAction(
actions.setBasePath,
basePath,
state,
[
{
type: types.SET_BASE_PATH,
payload: basePath,
},
],
[],
done,
);
});
});
describe('setDiffEndpoint', () => {
it(`should commit ${types.SET_DIFF_ENDPOINT} with the correct path`, done => {
testAction(
......@@ -88,113 +50,6 @@ describe('sast report actions', () => {
});
});
describe('receiveReports', () => {
it(`should commit ${types.RECEIVE_REPORTS} with the correct response`, done => {
testAction(
actions.receiveReports,
reports,
state,
[
{
type: types.RECEIVE_REPORTS,
payload: reports,
},
],
[],
done,
);
});
});
describe('receiveError', () => {
it(`should commit ${types.RECEIVE_REPORTS_ERROR} with the correct response`, done => {
testAction(
actions.receiveError,
error,
state,
[
{
type: types.RECEIVE_REPORTS_ERROR,
payload: error,
},
],
[],
done,
);
});
});
describe('fetchReports', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
state.paths.head = headPath;
state.paths.base = basePath;
});
afterEach(() => {
mock.restore();
});
describe('when everything goes according to plan', () => {
beforeEach(() => {
mock
.onGet(headPath)
.replyOnce(200, reports.head)
.onGet(basePath)
.replyOnce(200, reports.base)
.onGet(vulnerabilityFeedbackPath)
.replyOnce(200, reports.enrichData);
});
it('should dispatch the `receiveReports` action', done => {
const { head, base, enrichData } = reports;
testAction(
actions.fetchReports,
{},
{ ...rootState, ...state },
[],
[
{ type: 'requestReports' },
{
type: 'receiveReports',
payload: {
blobPath,
reports: { head, base, enrichData },
},
},
],
done,
);
});
});
describe('when the vulnerability feedback endpoint fails', () => {
beforeEach(() => {
mock
.onGet(headPath)
.replyOnce(200, reports.head)
.onGet(basePath)
.replyOnce(200, reports.base)
.onGet(vulnerabilityFeedbackPath)
.replyOnce(404);
});
it('should dispatch the `receiveError` action', done => {
testAction(
actions.fetchReports,
{},
{ ...rootState, ...state },
[],
[{ type: 'requestReports' }, { type: 'receiveError' }],
done,
);
});
});
});
describe('receiveDiffSuccess', () => {
it(`should commit ${types.RECEIVE_DIFF_SUCCESS} with the correct response`, done => {
testAction(
......
......@@ -12,22 +12,6 @@ describe('sast module mutations', () => {
state = createState();
});
describe(types.SET_HEAD_PATH, () => {
it('should set the SAST head path', () => {
mutations[types.SET_HEAD_PATH](state, path);
expect(state.paths.head).toBe(path);
});
});
describe(types.SET_BASE_PATH, () => {
it('should set the SAST base path', () => {
mutations[types.SET_BASE_PATH](state, path);
expect(state.paths.base).toBe(path);
});
});
describe(types.SET_DIFF_ENDPOINT, () => {
it('should set the SAST diff endpoint', () => {
mutations[types.SET_DIFF_ENDPOINT](state, path);
......@@ -44,21 +28,6 @@ describe('sast module mutations', () => {
});
});
describe(types.RECEIVE_REPORTS_ERROR, () => {
beforeEach(() => {
state.isLoading = true;
mutations[types.RECEIVE_REPORTS_ERROR](state);
});
it('should set the `isLoading` status to `false`', () => {
expect(state.isLoading).toBe(false);
});
it('should set the `hasError` status to `true`', () => {
expect(state.hasError).toBe(true);
});
});
describe(types.UPDATE_VULNERABILITY, () => {
let newIssue;
let resolvedIssue;
......@@ -120,72 +89,6 @@ describe('sast module mutations', () => {
});
});
describe(types.RECEIVE_REPORTS, () => {
const head = [
createIssue({ cve: 'CVE-1' }),
createIssue({ cve: 'CVE-4' }),
createIssue({ cve: 'CVE-5' }),
createIssue({ cve: 'CVE-6' }),
];
const base = [
createIssue({ cve: 'CVE-1' }),
createIssue({ cve: 'CVE-2' }),
createIssue({ cve: 'CVE-3' }),
];
const enrichData = [];
const blobPath = 'blobPath';
beforeEach(() => {
state.isLoading = true;
});
describe('with only the head report', () => {
beforeEach(() => {
const reports = { head, enrichData };
mutations[types.RECEIVE_REPORTS](state, { reports, blobPath });
});
it('should set the `isLoading` status to `false`', () => {
expect(state.isLoading).toBe(false);
});
it('should have the relevant `new` issues', () => {
expect(state.newIssues.length).toBe(4);
});
it('should not have any `resolved` issues', () => {
expect(state.resolvedIssues.length).toBe(0);
});
it('should not have any `all` issues', () => {
expect(state.allIssues.length).toBe(0);
});
});
describe('with the base and head reports', () => {
beforeEach(() => {
const reports = { head, base, enrichData };
mutations[types.RECEIVE_REPORTS](state, { reports, blobPath });
});
it('should set the `isLoading` status to `false`', () => {
expect(state.isLoading).toBe(false);
});
it('should have the relevant `new` issues', () => {
expect(state.newIssues.length).toBe(3);
});
it('should have the relevant `resolved` issues', () => {
expect(state.resolvedIssues.length).toBe(2);
});
it('should have the relevant `all` issues', () => {
expect(state.allIssues.length).toBe(1);
});
});
});
describe(types.RECEIVE_DIFF_SUCCESS, () => {
beforeEach(() => {
const reports = {
......
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,
parsedSastContainerBaseStore,
dockerReport,
dockerBaseReport,
dockerNewIssues,
dockerOnlyHeadParsed,
dast,
dastBase,
parsedDastNewIssues,
parsedDast,
} from '../mock_data';
import { mockFindings } from '../mock_data';
import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility', () => ({
......@@ -86,22 +71,6 @@ describe('security reports mutations', () => {
});
});
describe('SET_SAST_CONTAINER_HEAD_PATH', () => {
it('should set sast container head path', () => {
mutations[types.SET_SAST_CONTAINER_HEAD_PATH](stateCopy, 'head_path');
expect(stateCopy.sastContainer.paths.head).toEqual('head_path');
});
});
describe('SET_SAST_CONTAINER_BASE_PATH', () => {
it('should set sast container base path', () => {
mutations[types.SET_SAST_CONTAINER_BASE_PATH](stateCopy, 'base_path');
expect(stateCopy.sastContainer.paths.base).toEqual('base_path');
});
});
describe('REQUEST_SAST_CONTAINER_REPORTS', () => {
it('should set sast container loading flag to true', () => {
mutations[types.REQUEST_SAST_CONTAINER_REPORTS](stateCopy);
......@@ -110,57 +79,6 @@ describe('security reports mutations', () => {
});
});
describe('RECEIVE_SAST_CONTAINER_REPORTS', () => {
describe('with head and base', () => {
it('should set new and resolved issues', () => {
mutations[types.RECEIVE_SAST_CONTAINER_REPORTS](stateCopy, {
head: dockerReport,
base: dockerBaseReport,
});
expect(stateCopy.sastContainer.isLoading).toEqual(false);
expect(stateCopy.sastContainer.newIssues).toEqual(dockerNewIssues);
expect(stateCopy.sastContainer.resolvedIssues).toEqual(parsedSastContainerBaseStore);
});
});
describe('with head', () => {
it('should set new issues', () => {
mutations[types.RECEIVE_SAST_CONTAINER_REPORTS](stateCopy, {
head: dockerReport,
});
expect(stateCopy.sastContainer.isLoading).toEqual(false);
expect(stateCopy.sastContainer.newIssues).toEqual(dockerOnlyHeadParsed);
});
});
});
describe('RECEIVE_SAST_CONTAINER_ERROR', () => {
it('should set sast container loading flag to false and error flag to true', () => {
mutations[types.RECEIVE_SAST_CONTAINER_ERROR](stateCopy);
expect(stateCopy.sastContainer.isLoading).toEqual(false);
expect(stateCopy.sastContainer.hasError).toEqual(true);
});
});
describe('SET_DAST_HEAD_PATH', () => {
it('should set dast head path', () => {
mutations[types.SET_DAST_HEAD_PATH](stateCopy, 'head_path');
expect(stateCopy.dast.paths.head).toEqual('head_path');
});
});
describe('SET_DAST_BASE_PATH', () => {
it('should set dast base path', () => {
mutations[types.SET_DAST_BASE_PATH](stateCopy, 'base_path');
expect(stateCopy.dast.paths.base).toEqual('base_path');
});
});
describe('REQUEST_DAST_REPORTS', () => {
it('should set dast loading flag to true', () => {
mutations[types.REQUEST_DAST_REPORTS](stateCopy);
......@@ -169,110 +87,6 @@ describe('security reports mutations', () => {
});
});
describe('RECEIVE_DAST_REPORTS', () => {
const makeDastWithSiteArray = dastReport => ({
site: [dastReport.site],
});
describe('with head and base', () => {
it('sets new and resolved issues with the given data', () => {
mutations[types.RECEIVE_DAST_REPORTS](stateCopy, {
head: dast,
base: dastBase,
});
expect(stateCopy.dast.isLoading).toEqual(false);
expect(stateCopy.dast.newIssues).toEqual(parsedDastNewIssues);
expect(stateCopy.dast.resolvedIssues).toEqual([]);
});
it("parses site property if it's an array instead of an object", () => {
const dastWithSiteArray = makeDastWithSiteArray(dast);
const dastBaseWithSiteArray = makeDastWithSiteArray(dastBase);
mutations[types.RECEIVE_DAST_REPORTS](stateCopy, {
head: dastWithSiteArray,
base: dastBaseWithSiteArray,
});
expect(stateCopy.dast.isLoading).toEqual(false);
expect(stateCopy.dast.newIssues).toEqual(parsedDastNewIssues);
expect(stateCopy.dast.resolvedIssues).toEqual([]);
});
it('does not report any vulnerability if site is an empty array', () => {
mutations[types.RECEIVE_DAST_REPORTS](stateCopy, {
head: { site: [] },
base: { site: [] },
});
expect(stateCopy.dast.isLoading).toEqual(false);
expect(stateCopy.dast.newIssues).toEqual([]);
expect(stateCopy.dast.resolvedIssues).toEqual([]);
});
});
describe('with head', () => {
it('sets new issues with the given data', () => {
mutations[types.RECEIVE_DAST_REPORTS](stateCopy, {
head: dast,
});
expect(stateCopy.dast.isLoading).toEqual(false);
expect(stateCopy.dast.newIssues).toEqual(parsedDast);
});
it("parses site property if it's an array instead of an object", () => {
const dastWithSiteArray = makeDastWithSiteArray(dast);
mutations[types.RECEIVE_DAST_REPORTS](stateCopy, {
head: dastWithSiteArray,
});
expect(stateCopy.dast.isLoading).toEqual(false);
expect(stateCopy.dast.newIssues).toEqual(parsedDast);
});
it('does not report any vulnerability if site is an empty array', () => {
mutations[types.RECEIVE_DAST_REPORTS](stateCopy, {
head: { site: [] },
});
expect(stateCopy.dast.isLoading).toEqual(false);
expect(stateCopy.dast.newIssues).toEqual([]);
expect(stateCopy.dast.resolvedIssues).toEqual([]);
});
});
});
describe('RECEIVE_DAST_ERROR', () => {
it('should set dast loading flag to false and error flag to true', () => {
mutations[types.RECEIVE_DAST_ERROR](stateCopy);
expect(stateCopy.dast.isLoading).toEqual(false);
expect(stateCopy.dast.hasError).toEqual(true);
});
});
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);
......@@ -281,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);
......@@ -698,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',
};
......@@ -713,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',
};
......@@ -728,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',
};
......@@ -742,10 +516,10 @@ describe('security reports mutations', () => {
describe('UPDATE_CONTAINER_SCANNING_ISSUE', () => {
it('updates issue in the new issues list', () => {
stateCopy.sastContainer.newIssues = dockerNewIssues;
stateCopy.sastContainer.newIssues = mockFindings;
stateCopy.sastContainer.resolvedIssues = [];
const updatedIssue = {
...dockerNewIssues[0],
...mockFindings[0],
foo: 'bar',
};
......@@ -756,9 +530,9 @@ describe('security reports mutations', () => {
it('updates issue in the resolved issues list', () => {
stateCopy.sastContainer.newIssues = [];
stateCopy.sastContainer.resolvedIssues = dockerNewIssues;
stateCopy.sastContainer.resolvedIssues = mockFindings;
const updatedIssue = {
...dockerNewIssues[0],
...mockFindings[0],
foo: 'bar',
};
......@@ -770,10 +544,10 @@ describe('security reports mutations', () => {
describe('UPDATE_DAST_ISSUE', () => {
it('updates issue in the new issues list', () => {
stateCopy.dast.newIssues = parsedDastNewIssues;
stateCopy.dast.newIssues = mockFindings;
stateCopy.dast.resolvedIssues = [];
const updatedIssue = {
...parsedDastNewIssues[0],
...mockFindings[0],
foo: 'bar',
};
......@@ -784,9 +558,9 @@ describe('security reports mutations', () => {
it('updates issue in the resolved issues list', () => {
stateCopy.dast.newIssues = [];
stateCopy.dast.resolvedIssues = parsedDastNewIssues;
stateCopy.dast.resolvedIssues = mockFindings;
const updatedIssue = {
...parsedDastNewIssues[0],
...mockFindings[0],
foo: 'bar',
};
......
import sha1 from 'sha1';
import {
findIssueIndex,
findMatchingRemediations,
parseSastIssues,
parseDependencyScanningIssues,
getDastSites,
parseDastIssues,
getUnapprovedVulnerabilities,
groupedTextBuilder,
statusIcon,
countIssues,
......@@ -14,31 +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 {
formatContainerScanningDescription,
formatContainerScanningMessage,
formatContainerScanningSolution,
parseContainerScanningSeverity,
parseSastContainer,
} from 'ee/vue_shared/security_reports/store/utils/container_scanning';
import { SEVERITY_LEVELS } from 'ee/security_dashboard/store/constants';
import {
oldSastIssues,
sastIssues,
sastIssuesMajor2,
sastFeedbacks,
dependencyScanningIssuesOld,
dependencyScanningIssues,
dependencyScanningIssuesMajor2,
dependencyScanningFeedbacks,
dockerReport,
containerScanningFeedbacks,
dast,
multiSitesDast,
dastFeedbacks,
parsedMultiSitesDast,
parsedDast,
} from '../mock_data';
describe('security reports utils', () => {
describe('findIssueIndex', () => {
......@@ -69,311 +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('parseSastIssues', () => {
it('should parse the received issues with old JSON format', () => {
const parsed = parseSastIssues(oldSastIssues, [], 'path')[0];
expect(parsed.title).toEqual(sastIssues[0].message);
expect(parsed.path).toEqual(sastIssues[0].location.file);
expect(parsed.location.start_line).toEqual(sastIssues[0].location.start_line);
expect(parsed.location.end_line).toBeUndefined();
expect(parsed.urlPath).toEqual('path/Gemfile.lock#L5');
expect(parsed.project_fingerprint).toEqual(sha1(sastIssues[0].cve));
});
it('should parse the received issues with new JSON format', () => {
const parsed = parseSastIssues(sastIssues, [], 'path')[0];
expect(parsed.title).toEqual(sastIssues[0].message);
expect(parsed.path).toEqual(sastIssues[0].location.file);
expect(parsed.location.start_line).toEqual(sastIssues[0].location.start_line);
expect(parsed.location.end_line).toEqual(sastIssues[0].location.end_line);
expect(parsed.urlPath).toEqual('path/Gemfile.lock#L5-10');
expect(parsed.project_fingerprint).toEqual(sha1(sastIssues[0].cve));
});
it('should parse the received issues with new JSON format (2.0)', () => {
const raw = sastIssues[0];
const parsed = parseSastIssues(sastIssuesMajor2, [], 'path')[0];
expect(parsed.title).toEqual(raw.message);
expect(parsed.path).toEqual(raw.location.file);
expect(parsed.location.start_line).toEqual(raw.location.start_line);
expect(parsed.location.end_line).toEqual(raw.location.end_line);
expect(parsed.urlPath).toEqual('path/Gemfile.lock#L5-10');
expect(parsed.project_fingerprint).toEqual(sha1(raw.cve));
});
it('generate correct path to file when there is no line', () => {
const parsed = parseSastIssues(sastIssues, [], 'path')[1];
expect(parsed.urlPath).toEqual('path/Gemfile.lock');
});
it('includes vulnerability feedbacks', () => {
const parsed = parseSastIssues(sastIssues, sastFeedbacks, 'path')[0];
expect(parsed.hasIssue).toEqual(true);
expect(parsed.isDismissed).toEqual(true);
expect(parsed.dismissalFeedback).toEqual(sastFeedbacks[0]);
expect(parsed.issue_feedback).toEqual(sastFeedbacks[1]);
});
});
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('container scanning utils', () => {
describe('formatContainerScanningSolution', () => {
it('should return false if there is no data', () => {
expect(formatContainerScanningSolution({})).toBe(null);
});
it('should return the correct sentence', () => {
expect(formatContainerScanningSolution({ fixedby: 'v9000' })).toBe('Upgrade to v9000.');
expect(
formatContainerScanningSolution({ fixedby: 'v9000', featurename: 'Dependency' }),
).toBe('Upgrade Dependency to v9000.');
expect(
formatContainerScanningSolution({
fixedby: 'v9000',
featurename: 'Dependency',
featureversion: '1.0-beta',
}),
).toBe('Upgrade Dependency from 1.0-beta to v9000.');
});
});
describe('formatContainerScanningMessage', () => {
it('should return concatenated message if vulnerability and featurename are provided', () => {
expect(
formatContainerScanningMessage({ vulnerability: 'CVE-124', featurename: 'grep' }),
).toBe('CVE-124 in grep');
});
it('should return vulnerability if only that is provided', () => {
expect(formatContainerScanningMessage({ vulnerability: 'Foo' })).toBe('Foo');
});
});
describe('formatContainerScanningDescription', () => {
it('should return description', () => {
expect(formatContainerScanningDescription({ description: 'Foobar' })).toBe('Foobar');
});
it('should build description from available fields', () => {
const featurename = 'Dependency';
const featureversion = '1.0';
const namespace = 'debian:8';
const vulnerability = 'CVE-123';
expect(
formatContainerScanningDescription({
featurename,
featureversion,
namespace,
vulnerability,
}),
).toBe('Dependency:1.0 is affected by CVE-123.');
expect(formatContainerScanningDescription({ featurename, namespace, vulnerability })).toBe(
'Dependency is affected by CVE-123.',
);
expect(formatContainerScanningDescription({ namespace, vulnerability })).toBe(
'debian:8 is affected by CVE-123.',
);
});
});
describe('parseContainerScanningSeverity', () => {
it('should return `Critical` for `Defcon1`', () => {
expect(parseContainerScanningSeverity('Defcon1')).toBe(SEVERITY_LEVELS.critical);
});
it('should return `Low` for `Negligible`', () => {
expect(parseContainerScanningSeverity('Negligible')).toBe('Low');
});
it('should not touch other severities', () => {
expect(parseContainerScanningSeverity('oxofrmbl')).toBe('oxofrmbl');
expect(parseContainerScanningSeverity('Medium')).toBe('Medium');
expect(parseContainerScanningSeverity('High')).toBe('High');
});
});
});
describe('parseSastContainer', () => {
it('parses sast container issues', () => {
const parsed = parseSastContainer(dockerReport.vulnerabilities)[0];
const issue = dockerReport.vulnerabilities[0];
expect(parsed.title).toEqual(issue.vulnerability);
expect(parsed.identifiers).toEqual([
{
type: 'CVE',
name: issue.vulnerability,
value: issue.vulnerability,
url: `https://cve.mitre.org/cgi-bin/cvename.cgi?name=${issue.vulnerability}`,
},
]);
expect(parsed.project_fingerprint).toEqual(sha1(issue.vulnerability));
});
it('includes vulnerability feedbacks', () => {
const parsed = parseSastContainer(
dockerReport.vulnerabilities,
containerScanningFeedbacks,
)[0];
expect(parsed.hasIssue).toEqual(true);
expect(parsed.isDismissed).toEqual(true);
expect(parsed.dismissalFeedback).toEqual(containerScanningFeedbacks[0]);
expect(parsed.issue_feedback).toEqual(containerScanningFeedbacks[1]);
});
});
describe('getDastSites', () => {
it.each([{}, 'site', 1, undefined])('wraps non-array argument %p into an array', arg => {
expect(getDastSites(arg)).toEqual([arg]);
});
it("returns argument if it's an array", () => {
const sites = [];
expect(getDastSites(sites)).toEqual(sites);
});
});
describe('parseDastIssues', () => {
it.each`
description | report
${'multi-sites dast report'} | ${multiSitesDast}
${'legacy dast report'} | ${dast}
`('includes vulnerability feedbacks in $description', ({ report }) => {
const parsed = parseDastIssues(report.site, dastFeedbacks)[0];
expect(parsed.hasIssue).toEqual(true);
expect(parsed.isDismissed).toEqual(true);
expect(parsed.dismissalFeedback).toEqual(dastFeedbacks[0]);
expect(parsed.issue_feedback).toEqual(dastFeedbacks[1]);
});
it('parses dast report', () => {
expect(parseDastIssues(multiSitesDast.site)).toEqual(parsedMultiSitesDast);
});
it('parses legacy dast report', () => {
expect(parseDastIssues(dast.site)).toEqual(parsedDast);
});
});
describe('filterByKey', () => {
it('filters the array with the provided key', () => {
const array1 = [{ id: '1234' }, { id: 'abg543' }, { id: '214swfA' }];
......@@ -412,19 +75,6 @@ describe('security reports utils', () => {
});
});
describe('getUnapprovedVulnerabilities', () => {
it('return unapproved vulnerabilities', () => {
const unapproved = getUnapprovedVulnerabilities(
dockerReport.vulnerabilities,
dockerReport.unapproved,
);
expect(unapproved.length).toEqual(dockerReport.unapproved.length);
expect(unapproved[0].vulnerability).toEqual(dockerReport.unapproved[0]);
expect(unapproved[1].vulnerability).toEqual(dockerReport.unapproved[1]);
});
});
describe('textBuilder', () => {
describe('with only the head', () => {
const paths = { head: 'foo' };
......
......@@ -4,20 +4,9 @@ import * as mockData from '../../../frontend/vue_shared/security_reports/mock_da
// https://gitlab.com/gitlab-org/gitlab/merge_requests/10466#note_156218753
export const {
containerScanningFeedbacks,
dast,
dastBase,
dastFeedbacks,
dependencyScanningFeedbacks,
dockerBaseReport,
dockerReport,
dockerReportParsed,
parsedDast,
sastFeedbacks,
sastIssues,
sastIssuesBase,
sastParsedIssues,
mockFindings,
sastDiffSuccessMock,
dastDiffSuccessMock,
containerScanningDiffSuccessMock,
......
......@@ -22014,9 +22014,6 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
msgstr ""
msgid "ciReport|%{namespace} is affected by %{vulnerability}."
msgstr ""
msgid "ciReport|%{remainingPackagesCount} more"
msgstr ""
......@@ -22075,9 +22072,6 @@ msgstr ""
msgid "ciReport|%{reportType}: Loading resulted in an error"
msgstr ""
msgid "ciReport|%{vulnerability} in %{featurename}"
msgstr ""
msgid "ciReport|(errors when loading results)"
msgstr ""
......@@ -22234,15 +22228,6 @@ msgstr ""
msgid "ciReport|There was an error reverting the dismissal. Please try again."
msgstr ""
msgid "ciReport|Upgrade %{name} from %{version} to %{fixed}."
msgstr ""
msgid "ciReport|Upgrade %{name} to %{fixed}."
msgstr ""
msgid "ciReport|Upgrade to %{fixed}."
msgstr ""
msgid "ciReport|Used by %{packagesString}"
msgid_plural "ciReport|Used by %{packagesString}, and %{lastPackage}"
msgstr[0] ""
......
......@@ -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