Commit de28bba6 authored by Mark Florian's avatar Mark Florian

Merge branch '284677-api-fuzzing-empty-body' into 'master'

Update API Fuzzing Vuln info to show empty body message

See merge request gitlab-org/gitlab!50731
parents b8b2fdb1 ca1ebef6
...@@ -9,3 +9,4 @@ export const SEVERITY_TOOLTIP_TITLE_MAP = { ...@@ -9,3 +9,4 @@ export const SEVERITY_TOOLTIP_TITLE_MAP = {
}; };
export const VULNERABILITY_MODAL_ID = 'modal-mrwidget-security-issue'; export const VULNERABILITY_MODAL_ID = 'modal-mrwidget-security-issue';
export const EMPTY_BODY_MESSAGE = '<Message body is not provided>';
import { EMPTY_BODY_MESSAGE } from './constants';
export const bodyWithFallBack = (body) => body || EMPTY_BODY_MESSAGE;
...@@ -7,6 +7,7 @@ import SeverityBadge from './severity_badge.vue'; ...@@ -7,6 +7,7 @@ import SeverityBadge from './severity_badge.vue';
import getFileLocation from '../store/utils/get_file_location'; import getFileLocation from '../store/utils/get_file_location';
import VulnerabilityDetail from './vulnerability_detail.vue'; import VulnerabilityDetail from './vulnerability_detail.vue';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import { bodyWithFallBack } from './helpers';
export default { export default {
name: 'VulnerabilityDetails', name: 'VulnerabilityDetails',
...@@ -140,7 +141,7 @@ export default { ...@@ -140,7 +141,7 @@ export default {
const headerLines = this.getHeadersAsCodeBlockLines(headers); const headerLines = this.getHeadersAsCodeBlockLines(headers);
return statusCode && reasonPhrase && headerLines return statusCode && reasonPhrase && headerLines
? [`${statusCode} ${reasonPhrase}\n`, headerLines, '\n\n', body].join('') ? [`${statusCode} ${reasonPhrase}\n`, headerLines, '\n\n', bodyWithFallBack(body)].join('')
: ''; : '';
}, },
constructRequest(request) { constructRequest(request) {
...@@ -148,7 +149,7 @@ export default { ...@@ -148,7 +149,7 @@ export default {
const headerLines = this.getHeadersAsCodeBlockLines(headers); const headerLines = this.getHeadersAsCodeBlockLines(headers);
return method && url && headerLines return method && url && headerLines
? [`${method} ${url}\n`, headerLines, '\n\n', body].join('') ? [`${method} ${url}\n`, headerLines, '\n\n', bodyWithFallBack(body)].join('')
: ''; : '';
}, },
}, },
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { GlLink, GlSprintf, GlTooltipDirective, GlIcon } from '@gitlab/ui'; import { GlLink, GlSprintf, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { SUPPORTING_MESSAGE_TYPES } from 'ee/vulnerabilities/constants'; import { SUPPORTING_MESSAGE_TYPES } from 'ee/vulnerabilities/constants';
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 { bodyWithFallBack } from 'ee/vue_shared/security_reports/components/helpers';
import CodeBlock from '~/vue_shared/components/code_block.vue'; import CodeBlock from '~/vue_shared/components/code_block.vue';
import { __ } from '~/locale'; import { __ } from '~/locale';
import DetailItem from './detail_item.vue'; import DetailItem from './detail_item.vue';
...@@ -147,7 +148,7 @@ export default { ...@@ -147,7 +148,7 @@ export default {
const headerLines = this.getHeadersAsCodeBlockLines(headers); const headerLines = this.getHeadersAsCodeBlockLines(headers);
return statusCode && reasonPhrase && headerLines return statusCode && reasonPhrase && headerLines
? [`${statusCode} ${reasonPhrase}\n`, headerLines, '\n\n', body].join('') ? [`${statusCode} ${reasonPhrase}\n`, headerLines, '\n\n', bodyWithFallBack(body)].join('')
: ''; : '';
}, },
constructRequest(request) { constructRequest(request) {
...@@ -155,7 +156,7 @@ export default { ...@@ -155,7 +156,7 @@ export default {
const headerLines = this.getHeadersAsCodeBlockLines(headers); const headerLines = this.getHeadersAsCodeBlockLines(headers);
return method && url && headerLines return method && url && headerLines
? [`${method} ${url}\n`, headerLines, '\n\n', body].join('') ? [`${method} ${url}\n`, headerLines, '\n\n', bodyWithFallBack(body)].join('')
: ''; : '';
}, },
}, },
......
---
title: API Fuzzing Request/Responses show empty body message
merge_request: 50731
author:
type: changed
...@@ -5,6 +5,7 @@ import { SUPPORTING_MESSAGE_TYPES } from 'ee/vulnerabilities/constants'; ...@@ -5,6 +5,7 @@ import { SUPPORTING_MESSAGE_TYPES } from 'ee/vulnerabilities/constants';
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/vue_shared/security_reports/components/vulnerability_details.vue'; import VulnerabilityDetails from 'ee/vue_shared/security_reports/components/vulnerability_details.vue';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { EMPTY_BODY_MESSAGE } from 'ee/vue_shared/security_reports/components/constants';
import CodeBlock from '~/vue_shared/components/code_block.vue'; import CodeBlock from '~/vue_shared/components/code_block.vue';
import { mockFindings } from '../mock_data'; import { mockFindings } from '../mock_data';
...@@ -40,6 +41,8 @@ describe('VulnerabilityDetails component', () => { ...@@ -40,6 +41,8 @@ describe('VulnerabilityDetails component', () => {
const findCrashType = () => wrapper.find({ ref: 'crashType' }); const findCrashType = () => wrapper.find({ ref: 'crashType' });
const findStacktraceSnippet = () => wrapper.find({ ref: 'stacktraceSnippet' }); const findStacktraceSnippet = () => wrapper.find({ ref: 'stacktraceSnippet' });
const USER_NOT_FOUND_MESSAGE = '{"message":"User not found."}';
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
...@@ -170,7 +173,10 @@ describe('VulnerabilityDetails component', () => { ...@@ -170,7 +173,10 @@ describe('VulnerabilityDetails component', () => {
}); });
}); });
describe('with request information', () => { describe.each([
['', EMPTY_BODY_MESSAGE],
[USER_NOT_FOUND_MESSAGE, USER_NOT_FOUND_MESSAGE],
])('with request information and body set to: %s', (body, renderedBody) => {
let vulnerability; let vulnerability;
beforeEach(() => { beforeEach(() => {
...@@ -182,6 +188,7 @@ describe('VulnerabilityDetails component', () => { ...@@ -182,6 +188,7 @@ describe('VulnerabilityDetails component', () => {
{ name: 'key1', value: 'value1' }, { name: 'key1', value: 'value1' },
{ name: 'key2', value: 'value2' }, { name: 'key2', value: 'value2' },
], ],
body,
}, },
}); });
componentFactory(vulnerability); componentFactory(vulnerability);
...@@ -197,6 +204,7 @@ describe('VulnerabilityDetails component', () => { ...@@ -197,6 +204,7 @@ describe('VulnerabilityDetails component', () => {
expect(findRequest().text()).toContain(method); expect(findRequest().text()).toContain(method);
expect(findRequest().text()).toContain(url); expect(findRequest().text()).toContain(url);
expect(findRequest().text()).toContain('key1: value1\nkey2: value2'); expect(findRequest().text()).toContain('key1: value1\nkey2: value2');
expect(findRequest().text()).toContain(renderedBody);
}); });
it('limits the code-blocks maximum height', () => { it('limits the code-blocks maximum height', () => {
...@@ -225,7 +233,10 @@ describe('VulnerabilityDetails component', () => { ...@@ -225,7 +233,10 @@ describe('VulnerabilityDetails component', () => {
}); });
}); });
describe('with response information', () => { describe.each([
['', EMPTY_BODY_MESSAGE],
[USER_NOT_FOUND_MESSAGE, USER_NOT_FOUND_MESSAGE],
])('with response information and body set to: %s', (body, renderedBody) => {
let vulnerability; let vulnerability;
beforeEach(() => { beforeEach(() => {
...@@ -237,6 +248,7 @@ describe('VulnerabilityDetails component', () => { ...@@ -237,6 +248,7 @@ describe('VulnerabilityDetails component', () => {
{ name: 'key1', value: 'value1' }, { name: 'key1', value: 'value1' },
{ name: 'key2', value: 'value2' }, { name: 'key2', value: 'value2' },
], ],
body,
}, },
}); });
componentFactory(vulnerability); componentFactory(vulnerability);
...@@ -253,6 +265,7 @@ describe('VulnerabilityDetails component', () => { ...@@ -253,6 +265,7 @@ describe('VulnerabilityDetails component', () => {
expect(response.is(CodeBlock)).toBe(true); expect(response.is(CodeBlock)).toBe(true);
expect(response.text()).toContain(reason_phrase); expect(response.text()).toContain(reason_phrase);
expect(response.text()).toContain('key1: value1\nkey2: value2'); expect(response.text()).toContain('key1: value1\nkey2: value2');
expect(response.text()).toContain(renderedBody);
}); });
}); });
...@@ -267,7 +280,10 @@ describe('VulnerabilityDetails component', () => { ...@@ -267,7 +280,10 @@ describe('VulnerabilityDetails component', () => {
}); });
}); });
describe('with recorded response information', () => { describe.each([
['', EMPTY_BODY_MESSAGE],
[USER_NOT_FOUND_MESSAGE, USER_NOT_FOUND_MESSAGE],
])('with recorded response information and body set to: %s', (body, renderedBody) => {
let vulnerability; let vulnerability;
beforeEach(() => { beforeEach(() => {
...@@ -282,6 +298,7 @@ describe('VulnerabilityDetails component', () => { ...@@ -282,6 +298,7 @@ describe('VulnerabilityDetails component', () => {
{ name: 'key1', value: 'value1' }, { name: 'key1', value: 'value1' },
{ name: 'key2', value: 'value2' }, { name: 'key2', value: 'value2' },
], ],
body,
}, },
}, },
], ],
...@@ -289,17 +306,18 @@ describe('VulnerabilityDetails component', () => { ...@@ -289,17 +306,18 @@ describe('VulnerabilityDetails component', () => {
componentFactory(vulnerability); componentFactory(vulnerability);
}); });
it('renders the response status code', () => { it('renders the recorded response status code', () => {
expect(findRecordedResponse().text()).toContain('200'); expect(findRecordedResponse().text()).toContain('200');
}); });
it('renders a code block containing the response', () => { it('renders a code block containing the recorded response', () => {
const { reason_phrase } = vulnerability.supporting_messages[0].response; const { reason_phrase } = vulnerability.supporting_messages[0].response;
const response = findRecordedResponse(); const response = findRecordedResponse();
expect(response.is(CodeBlock)).toBe(true); expect(response.is(CodeBlock)).toBe(true);
expect(response.text()).toContain(reason_phrase); expect(response.text()).toContain(reason_phrase);
expect(response.text()).toContain('key1: value1\nkey2: value2'); expect(response.text()).toContain('key1: value1\nkey2: value2');
expect(response.text()).toContain(renderedBody);
}); });
}); });
......
...@@ -235,18 +235,38 @@ describe('Vulnerability Details', () => { ...@@ -235,18 +235,38 @@ describe('Vulnerability Details', () => {
isCode: true, isCode: true,
}; };
const EXPECT_REQUEST_WITHOUT_BODY = {
label: 'Sent request:',
content:
'GET http://www.gitlab.com\nName1: Value1\nName2: Value2\n\n<Message body is not provided>',
isCode: true,
};
const EXPECT_RESPONSE = { const EXPECT_RESPONSE = {
label: 'Actual response:', label: 'Actual response:',
content: '500 INTERNAL SERVER ERROR\nName1: Value1\nName2: Value2\n\n[{"user_id":1,}]', content: '500 INTERNAL SERVER ERROR\nName1: Value1\nName2: Value2\n\n[{"user_id":1,}]',
isCode: true, isCode: true,
}; };
const EXPECT_RESPONSE_WITHOUT_BODY = {
label: 'Actual response:',
content:
'500 INTERNAL SERVER ERROR\nName1: Value1\nName2: Value2\n\n<Message body is not provided>',
isCode: true,
};
const EXPECT_RECORDED_RESPONSE = { const EXPECT_RECORDED_RESPONSE = {
label: 'Unmodified response:', label: 'Unmodified response:',
content: '200 OK\nName1: Value1\nName2: Value2\n\n[{"user_id":1,}]', content: '200 OK\nName1: Value1\nName2: Value2\n\n[{"user_id":1,}]',
isCode: true, isCode: true,
}; };
const EXPECT_RECORDED_RESPONSE_WITHOUT_BODY = {
label: 'Unmodified response:',
content: '200 OK\nName1: Value1\nName2: Value2\n\n<Message body is not provided>',
isCode: true,
};
const getTextContent = (el) => el.textContent.trim(); const getTextContent = (el) => el.textContent.trim();
const getLabel = (el) => getTextContent(getByTestId(el, 'label')); const getLabel = (el) => getTextContent(getByTestId(el, 'label'));
const getContent = (el) => getTextContent(getByTestId(el, 'value')); const getContent = (el) => getTextContent(getByTestId(el, 'value'));
...@@ -273,6 +293,7 @@ describe('Vulnerability Details', () => { ...@@ -273,6 +293,7 @@ describe('Vulnerability Details', () => {
${{ method: 'GET', url: 'http://www.gitlab.com' }} | ${null} ${{ method: 'GET', url: 'http://www.gitlab.com' }} | ${null}
${{ method: 'GET', url: 'http://www.gitlab.com', body: '[{"user_id":1,}]' }} | ${null} ${{ method: 'GET', url: 'http://www.gitlab.com', body: '[{"user_id":1,}]' }} | ${null}
${{ headers: TEST_HEADERS, method: 'GET', url: 'http://www.gitlab.com', body: '[{"user_id":1,}]' }} | ${[EXPECT_REQUEST]} ${{ headers: TEST_HEADERS, method: 'GET', url: 'http://www.gitlab.com', body: '[{"user_id":1,}]' }} | ${[EXPECT_REQUEST]}
${{ headers: TEST_HEADERS, method: 'GET', url: 'http://www.gitlab.com', body: '' }} | ${[EXPECT_REQUEST_WITHOUT_BODY]}
`('shows request data for $request', ({ request, expectedData }) => { `('shows request data for $request', ({ request, expectedData }) => {
createWrapper({ request }); createWrapper({ request });
expect(getSectionData('request')).toEqual(expectedData); expect(getSectionData('request')).toEqual(expectedData);
...@@ -286,6 +307,7 @@ describe('Vulnerability Details', () => { ...@@ -286,6 +307,7 @@ describe('Vulnerability Details', () => {
${{ headers: TEST_HEADERS, body: '[{"user_id":1,}]' }} | ${null} ${{ headers: TEST_HEADERS, body: '[{"user_id":1,}]' }} | ${null}
${{ headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '500' }} | ${null} ${{ headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '500' }} | ${null}
${{ headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '500', reasonPhrase: 'INTERNAL SERVER ERROR' }} | ${[EXPECT_RESPONSE]} ${{ headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '500', reasonPhrase: 'INTERNAL SERVER ERROR' }} | ${[EXPECT_RESPONSE]}
${{ headers: TEST_HEADERS, body: '', statusCode: '500', reasonPhrase: 'INTERNAL SERVER ERROR' }} | ${[EXPECT_RESPONSE_WITHOUT_BODY]}
`('shows response data for $response', ({ response, expectedData }) => { `('shows response data for $response', ({ response, expectedData }) => {
createWrapper({ response }); createWrapper({ response });
expect(getSectionData('response')).toEqual(expectedData); expect(getSectionData('response')).toEqual(expectedData);
...@@ -302,6 +324,7 @@ describe('Vulnerability Details', () => { ...@@ -302,6 +324,7 @@ describe('Vulnerability Details', () => {
${[{}, { response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', status_code: '200' } }]} | ${null} ${[{}, { response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', status_code: '200' } }]} | ${null}
${[{}, { response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', status_code: '200', reason_phrase: 'OK' } }]} | ${null} ${[{}, { response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', status_code: '200', reason_phrase: 'OK' } }]} | ${null}
${[{}, { name: SUPPORTING_MESSAGE_TYPES.RECORDED, response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '200', reasonPhrase: 'OK' } }]} | ${[EXPECT_RECORDED_RESPONSE]} ${[{}, { name: SUPPORTING_MESSAGE_TYPES.RECORDED, response: { headers: TEST_HEADERS, body: '[{"user_id":1,}]', statusCode: '200', reasonPhrase: 'OK' } }]} | ${[EXPECT_RECORDED_RESPONSE]}
${[{}, { name: SUPPORTING_MESSAGE_TYPES.RECORDED, response: { headers: TEST_HEADERS, body: '', statusCode: '200', reasonPhrase: 'OK' } }]} | ${[EXPECT_RECORDED_RESPONSE_WITHOUT_BODY]}
`('shows response data for $supporting_messages', ({ supportingMessages, expectedData }) => { `('shows response data for $supporting_messages', ({ supportingMessages, expectedData }) => {
createWrapper({ supportingMessages }); createWrapper({ supportingMessages });
expect(getSectionData('recorded-response')).toEqual(expectedData); expect(getSectionData('recorded-response')).toEqual(expectedData);
......
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