Commit 22cb9cd3 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch...

Merge branch '217368-dast-vulnerabilities-show-more-information-about-the-request-standalone-page' into 'master'

Add request/response to standalone vulnerability page

See merge request gitlab-org/gitlab!34811
parents 2fdae334 fadaf922
...@@ -19,10 +19,10 @@ export default { ...@@ -19,10 +19,10 @@ export default {
<li :data-testid="valueName"> <li :data-testid="valueName">
<gl-sprintf :message="sprintfMessage"> <gl-sprintf :message="sprintfMessage">
<template #label="{ content }"> <template #label="{ content }">
<strong>{{ content }}</strong> <strong data-testid="label">{{ content }}</strong>
</template> </template>
<template #[valueName]> <template #[valueName]>
<slot></slot> <span data-testid="value"><slot></slot></span>
</template> </template>
</gl-sprintf> </gl-sprintf>
</li> </li>
......
<script> <script>
import { GlLink, GlSprintf } from '@gitlab/ui'; import { GlLink, GlSprintf } from '@gitlab/ui';
import CodeBlock from '~/vue_shared/components/code_block.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue'; import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import { __ } from '~/locale';
import DetailItem from './detail_item.vue'; import DetailItem from './detail_item.vue';
export default { export default {
name: 'VulnerabilityDetails', name: 'VulnerabilityDetails',
components: { GlLink, SeverityBadge, DetailItem, GlSprintf }, components: { CodeBlock, GlLink, SeverityBadge, DetailItem, GlSprintf },
props: { props: {
vulnerability: { vulnerability: {
type: Object, type: Object,
...@@ -48,6 +50,49 @@ export default { ...@@ -48,6 +50,49 @@ export default {
properties: {}, properties: {},
}; };
}, },
requestData() {
const { request: { method, url, headers = [] } = {} } = this.vulnerability;
return [
{
label: __('%{labelStart}Method:%{labelEnd} %{method}'),
content: method,
},
{
label: __('%{labelStart}URL:%{labelEnd} %{url}'),
content: url,
},
{
label: __('%{labelStart}Headers:%{labelEnd} %{headers}'),
content: this.getHeadersAsCodeBlockLines(headers),
isCode: true,
},
].filter(x => x.content);
},
responseData() {
const {
response: { status_code: statusCode, reason_phrase: reasonPhrase, headers = [] } = {},
} = this.vulnerability;
return [
{
label: __('%{labelStart}Status:%{labelEnd} %{status}'),
content: statusCode && reasonPhrase ? `${statusCode} ${reasonPhrase}` : '',
},
{
label: __('%{labelStart}Headers:%{labelEnd} %{headers}'),
content: this.getHeadersAsCodeBlockLines(headers),
isCode: true,
},
].filter(x => x.content);
},
},
methods: {
getHeadersAsCodeBlockLines(headers) {
return Array.isArray(headers)
? headers.map(({ name, value }) => `${name}: ${value}`).join('\n')
: '';
},
}, },
}; };
</script> </script>
...@@ -156,5 +201,37 @@ export default { ...@@ -156,5 +201,37 @@ export default {
</li> </li>
</ul> </ul>
</template> </template>
<section v-if="requestData.length" data-testid="request">
<h3>{{ s__('Vulnerability|Request') }}</h3>
<ul>
<detail-item
v-for="{ label, isCode, content } in requestData"
:key="label"
:sprintf-message="label"
>
<code-block v-if="isCode" class="mt-1" :code="content" max-height="225px" />
<template v-else>
{{ content }}
</template>
</detail-item>
</ul>
</section>
<section v-if="responseData.length" data-testid="response">
<h3>{{ s__('Vulnerability|Response') }}</h3>
<ul>
<detail-item
v-for="{ label, isCode, content } in responseData"
:key="label"
:sprintf-message="label"
>
<code-block v-if="isCode" class="mt-1" :code="content" max-height="225px" />
<template v-else>
{{ content }}
</template>
</detail-item>
</ul>
</section>
</div> </div>
</template> </template>
...@@ -53,7 +53,9 @@ module VulnerabilitiesHelper ...@@ -53,7 +53,9 @@ module VulnerabilitiesHelper
:remediations, :remediations,
:evidence, :evidence,
:scanner, :scanner,
:solution :solution,
:request,
:response
) )
if data[:location]['file'] if data[:location]['file']
......
---
title: Add request/response to standalone vulnerability page
merge_request: 34811
author:
type: added
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { getAllByRole, getByTestId } from '@testing-library/dom';
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue'; import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import VulnerabilityDetails from 'ee/vulnerabilities/components/details.vue'; import VulnerabilityDetails from 'ee/vulnerabilities/components/details.vue';
...@@ -169,4 +170,56 @@ describe('Vulnerability Details', () => { ...@@ -169,4 +170,56 @@ describe('Vulnerability Details', () => {
expect(link().attributes('href')).toBe('//link'); expect(link().attributes('href')).toBe('//link');
}); });
}); });
describe('http data', () => {
const TEST_HEADERS = [{ name: 'Name1', value: 'Value1' }, { name: 'Name2', value: 'Value2' }];
const TEST_URL = 'http://foo.bar/test';
const EXPECT_HEADERS = {
label: 'Headers:',
content: 'Name1: Value1\nName2: Value2',
isCode: true,
};
const getTextContent = el => el.textContent.trim();
const getLabel = el => getTextContent(getByTestId(el, 'label'));
const getContent = el => getTextContent(getByTestId(el, 'value'));
const getSectionData = testId => {
const section = getById(testId).element;
if (!section) {
return null;
}
return getAllByRole(section, 'listitem').map(li => ({
label: getLabel(li),
content: getContent(li),
...(li.querySelector('code') ? { isCode: true } : {}),
}));
};
it.each`
request | expectedData
${{}} | ${null}
${{ headers: TEST_HEADERS }} | ${[EXPECT_HEADERS]}
${{ headers: TEST_HEADERS, method: 'GET' }} | ${[{ label: 'Method:', content: 'GET' }, EXPECT_HEADERS]}
${{ headers: TEST_HEADERS, method: 'GET', url: TEST_URL }} | ${[{ label: 'Method:', content: 'GET' }, { label: 'URL:', content: TEST_URL }, EXPECT_HEADERS]}
${{ url: TEST_URL }} | ${[{ label: 'URL:', content: TEST_URL }]}
${{ method: 'GET' }} | ${[{ label: 'Method:', content: 'GET' }]}
`('shows request data for $request', ({ request, expectedData }) => {
createWrapper({ request });
expect(getSectionData('request')).toEqual(expectedData);
});
it.each`
response | expectedData
${{}} | ${null}
${{ headers: TEST_HEADERS }} | ${[EXPECT_HEADERS]}
${{ headers: TEST_HEADERS, status_code: 200 }} | ${[EXPECT_HEADERS]}
${{ headers: TEST_HEADERS, status_code: 200, reason_phrase: 'OK' }} | ${[{ label: 'Status:', content: '200 OK' }, EXPECT_HEADERS]}
${{ status_code: 400, reason_phrase: 'Something bad' }} | ${[{ label: 'Status:', content: '400 Something bad' }]}
`('shows response data for $response', ({ response, expectedData }) => {
createWrapper({ response });
expect(getSectionData('response')).toEqual(expectedData);
});
});
}); });
...@@ -115,7 +115,9 @@ RSpec.describe VulnerabilitiesHelper do ...@@ -115,7 +115,9 @@ RSpec.describe VulnerabilitiesHelper do
remediations: finding.remediations, remediations: finding.remediations,
solution: kind_of(String), solution: kind_of(String),
evidence: kind_of(String), evidence: kind_of(String),
scanner: kind_of(Grape::Entity::Exposure::NestingExposure::OutputBuilder) scanner: kind_of(Grape::Entity::Exposure::NestingExposure::OutputBuilder),
request: kind_of(Grape::Entity::Exposure::NestingExposure::OutputBuilder),
response: kind_of(Grape::Entity::Exposure::NestingExposure::OutputBuilder)
) )
expect(subject[:location]['blob_path']).to match(kind_of(String)) expect(subject[:location]['blob_path']).to match(kind_of(String))
......
...@@ -409,6 +409,9 @@ msgstr "" ...@@ -409,6 +409,9 @@ msgstr ""
msgid "%{labelStart}File:%{labelEnd} %{file}" msgid "%{labelStart}File:%{labelEnd} %{file}"
msgstr "" msgstr ""
msgid "%{labelStart}Headers:%{labelEnd} %{headers}"
msgstr ""
msgid "%{labelStart}Image:%{labelEnd} %{image}" msgid "%{labelStart}Image:%{labelEnd} %{image}"
msgstr "" msgstr ""
...@@ -427,6 +430,12 @@ msgstr "" ...@@ -427,6 +430,12 @@ msgstr ""
msgid "%{labelStart}Severity:%{labelEnd} %{severity}" msgid "%{labelStart}Severity:%{labelEnd} %{severity}"
msgstr "" msgstr ""
msgid "%{labelStart}Status:%{labelEnd} %{status}"
msgstr ""
msgid "%{labelStart}URL:%{labelEnd} %{url}"
msgstr ""
msgid "%{label_for_message} unavailable" msgid "%{label_for_message} unavailable"
msgstr "" msgstr ""
...@@ -25683,6 +25692,12 @@ msgstr "" ...@@ -25683,6 +25692,12 @@ msgstr ""
msgid "Vulnerability|Project" msgid "Vulnerability|Project"
msgstr "" msgstr ""
msgid "Vulnerability|Request"
msgstr ""
msgid "Vulnerability|Response"
msgstr ""
msgid "Vulnerability|Scanner" msgid "Vulnerability|Scanner"
msgstr "" msgstr ""
......
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