Commit c7e8da7c authored by Sam Beckham's avatar Sam Beckham Committed by Phil Hughes

Adds in a URL field for DAST reports modal data

- Adds it to the dashboard
- Adds it to the MR widget
parent 64d6c3ab
import Vue from 'vue'; import Vue from 'vue';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
import getFileLocation from 'ee/vue_shared/security_reports/store/utils/get_file_location';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { DAYS } from './constants'; import { DAYS } from './constants';
import { isSameVulnerability } from './utils'; import { isSameVulnerability } from './utils';
...@@ -99,6 +100,7 @@ export default { ...@@ -99,6 +100,7 @@ export default {
operating_system: namespace, operating_system: namespace,
class: className, class: className,
} = location; } = location;
const fileLocation = getFileLocation(location);
let lineSuffix = ''; let lineSuffix = '';
...@@ -113,6 +115,8 @@ export default { ...@@ -113,6 +115,8 @@ export default {
Vue.set(state.modal.data.file, 'value', file ? `${file}${lineSuffix}` : null); Vue.set(state.modal.data.file, 'value', file ? `${file}${lineSuffix}` : null);
Vue.set(state.modal.data.image, 'value', image); Vue.set(state.modal.data.image, 'value', image);
Vue.set(state.modal.data.namespace, 'value', namespace); Vue.set(state.modal.data.namespace, 'value', namespace);
Vue.set(state.modal.data.url, 'value', fileLocation);
Vue.set(state.modal.data.url, 'url', fileLocation);
} }
Vue.set(state.modal.data.severity, 'value', vulnerability.severity); Vue.set(state.modal.data.severity, 'value', vulnerability.severity);
......
import { s__ } from '~/locale'; import { __, s__ } from '~/locale';
export default () => ({ export default () => ({
isLoadingVulnerabilities: true, isLoadingVulnerabilities: true,
...@@ -25,6 +25,7 @@ export default () => ({ ...@@ -25,6 +25,7 @@ export default () => ({
text: s__('Vulnerability|Project'), text: s__('Vulnerability|Project'),
isLink: true, isLink: true,
}, },
url: { text: __('URL'), isLink: true },
file: { text: s__('Vulnerability|File') }, file: { text: s__('Vulnerability|File') },
identifiers: { text: s__('Vulnerability|Identifiers') }, identifiers: { text: s__('Vulnerability|Identifiers') },
severity: { text: s__('Vulnerability|Severity') }, severity: { text: s__('Vulnerability|Severity') },
......
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
parseDiff, parseDiff,
} from './utils'; } from './utils';
import filterByKey from './utils/filter_by_key'; import filterByKey from './utils/filter_by_key';
import getFileLocation from './utils/get_file_location';
import { parseSastContainer } from './utils/container_scanning'; import { parseSastContainer } from './utils/container_scanning';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
...@@ -269,6 +270,7 @@ export default { ...@@ -269,6 +270,7 @@ export default {
[types.SET_ISSUE_MODAL_DATA](state, payload) { [types.SET_ISSUE_MODAL_DATA](state, payload) {
const { issue, status } = payload; const { issue, status } = payload;
const fileLocation = getFileLocation(issue.location);
Vue.set(state.modal, 'title', issue.title); Vue.set(state.modal, 'title', issue.title);
Vue.set(state.modal.data.description, 'value', issue.description); Vue.set(state.modal.data.description, 'value', issue.description);
...@@ -278,6 +280,8 @@ export default { ...@@ -278,6 +280,8 @@ export default {
Vue.set(state.modal.data.methodName, 'value', issue.location && issue.location.method); Vue.set(state.modal.data.methodName, 'value', issue.location && issue.location.method);
Vue.set(state.modal.data.image, 'value', issue.location && issue.location.image); Vue.set(state.modal.data.image, 'value', issue.location && issue.location.image);
Vue.set(state.modal.data.namespace, 'value', issue.location && issue.location.operating_system); Vue.set(state.modal.data.namespace, 'value', issue.location && issue.location.operating_system);
Vue.set(state.modal.data.url, 'value', fileLocation);
Vue.set(state.modal.data.url, 'url', fileLocation);
if (issue.identifiers && issue.identifiers.length > 0) { if (issue.identifiers && issue.identifiers.length > 0) {
Vue.set(state.modal.data.identifiers, 'value', issue.identifiers); Vue.set(state.modal.data.identifiers, 'value', issue.identifiers);
......
import { s__ } from '~/locale'; import { __, s__ } from '~/locale';
export default () => ({ export default () => ({
blobPath: { blobPath: {
...@@ -68,6 +68,12 @@ export default () => ({ ...@@ -68,6 +68,12 @@ export default () => ({
text: s__('ciReport|Description'), text: s__('ciReport|Description'),
isLink: false, isLink: false,
}, },
url: {
value: null,
url: null,
text: __('URL'),
isLink: true,
},
file: { file: {
value: null, value: null,
url: null, url: null,
......
/**
* Parses the location object on a vulnerability to get a url
* @param {Object} location
* @returns {(String|null)} The parsed url or null if unparsable
*/
const getFileLocation = (location = {}) => {
const { hostname, path } = location;
if (typeof hostname !== 'string' || typeof path !== 'string') {
return null;
}
return `${hostname}${path}`;
};
export default getFileLocation;
---
title: Adds in a URL field for DAST reports modal data
merge_request: 20162
author:
type: changed
...@@ -369,6 +369,9 @@ describe('security reports mutations', () => { ...@@ -369,6 +369,9 @@ describe('security reports mutations', () => {
expect(stateCopy.modal.isCreatingNewIssue).toEqual(false); expect(stateCopy.modal.isCreatingNewIssue).toEqual(false);
expect(stateCopy.modal.isDismissingVulnerability).toEqual(false); expect(stateCopy.modal.isDismissingVulnerability).toEqual(false);
expect(stateCopy.modal.data.url.value).toEqual(null);
expect(stateCopy.modal.data.url.url).toEqual(null);
expect(stateCopy.modal.title).toEqual(null); expect(stateCopy.modal.title).toEqual(null);
expect(stateCopy.modal.learnMoreUrl).toEqual(null); expect(stateCopy.modal.learnMoreUrl).toEqual(null);
expect(stateCopy.modal.error).toEqual(null); expect(stateCopy.modal.error).toEqual(null);
...@@ -391,6 +394,8 @@ describe('security reports mutations', () => { ...@@ -391,6 +394,8 @@ describe('security reports mutations', () => {
method: 'do_something', method: 'do_something',
image: 'https://example.org/docker/example:v1.2.3', image: 'https://example.org/docker/example:v1.2.3',
operating_system: 'debian:8', operating_system: 'debian:8',
hostname: 'https://gitlab.com',
path: '/user6',
}, },
links: [ links: [
{ {
...@@ -431,6 +436,12 @@ describe('security reports mutations', () => { ...@@ -431,6 +436,12 @@ describe('security reports mutations', () => {
expect(stateCopy.modal.data.confidence.value).toEqual(issue.confidence); expect(stateCopy.modal.data.confidence.value).toEqual(issue.confidence);
expect(stateCopy.modal.data.links.value).toEqual(issue.links); expect(stateCopy.modal.data.links.value).toEqual(issue.links);
expect(stateCopy.modal.data.instances.value).toEqual(issue.instances); expect(stateCopy.modal.data.instances.value).toEqual(issue.instances);
expect(stateCopy.modal.data.url.value).toEqual(
`${issue.location.hostname}${issue.location.path}`,
);
expect(stateCopy.modal.data.url.url).toEqual(
`${issue.location.hostname}${issue.location.path}`,
);
expect(stateCopy.modal.vulnerability).toEqual(issue); expect(stateCopy.modal.vulnerability).toEqual(issue);
expect(stateCopy.modal.isResolved).toEqual(true); expect(stateCopy.modal.isResolved).toEqual(true);
}); });
......
...@@ -13,6 +13,7 @@ import { ...@@ -13,6 +13,7 @@ import {
groupedReportText, groupedReportText,
} from 'ee/vue_shared/security_reports/store/utils'; } from 'ee/vue_shared/security_reports/store/utils';
import filterByKey from 'ee/vue_shared/security_reports/store/utils/filter_by_key'; 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 { import {
formatContainerScanningDescription, formatContainerScanningDescription,
formatContainerScanningMessage, formatContainerScanningMessage,
...@@ -382,6 +383,35 @@ describe('security reports utils', () => { ...@@ -382,6 +383,35 @@ describe('security reports utils', () => {
}); });
}); });
describe('getFileLocation', () => {
const hostname = 'https://hostna.me';
const path = '/deeply/nested/route';
it('should return the correct location when passed both a hostname and a path', () => {
const result = getFileLocation({ hostname, path });
expect(result).toEqual(`${hostname}${path}`);
});
it('should return null if the hostname is not present', () => {
const result = getFileLocation({ path });
expect(result).toBeNull();
});
it('should return null if the path is not present', () => {
const result = getFileLocation({ hostname });
expect(result).toBeNull();
});
it('should return null if the argument is undefined', () => {
const result = getFileLocation(undefined);
expect(result).toBeNull();
});
});
describe('getUnapprovedVulnerabilities', () => { describe('getUnapprovedVulnerabilities', () => {
it('return unapproved vulnerabilities', () => { it('return unapproved vulnerabilities', () => {
const unapproved = getUnapprovedVulnerabilities( const unapproved = getUnapprovedVulnerabilities(
......
...@@ -41,7 +41,9 @@ ...@@ -41,7 +41,9 @@
"start_line": 29, "start_line": 29,
"end_line": 29, "end_line": 29,
"class": "com.gitlab.security_products.tests.App", "class": "com.gitlab.security_products.tests.App",
"method": "insecureCypher" "method": "insecureCypher",
"hostname": "https://gitlab.com",
"path": "/user6"
}, },
"links": [ "links": [
{ {
......
...@@ -275,6 +275,15 @@ describe('vulnerabilities module mutations', () => { ...@@ -275,6 +275,15 @@ describe('vulnerabilities module mutations', () => {
it('should set the modal vulnerability', () => { it('should set the modal vulnerability', () => {
expect(state.modal.vulnerability).toEqual(vulnerability); expect(state.modal.vulnerability).toEqual(vulnerability);
}); });
it('should set the modal URL', () => {
const { url } = state.modal.data;
const { hostname, path } = vulnerability.location;
const expected = `${hostname}${path}`;
expect(url.value).toEqual(expected);
expect(url.url).toEqual(expected);
});
}); });
describe('with irregular data', () => { describe('with irregular data', () => {
......
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