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),
};
});
......@@ -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 = {
......
......@@ -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