Commit 3d949510 authored by Dheeraj Joshi's avatar Dheeraj Joshi Committed by Kushal Pandya

Add DAST modal for pipeline view

This adds a new modal to show scanned resources
by DAST job in the pipeline view
parent a2a272b0
<script>
import { GlButton, GlCard, GlCollapse, GlCollapseToggleDirective, GlSprintf } from '@gitlab/ui';
import {
GlButton,
GlCard,
GlCollapse,
GlCollapseToggleDirective,
GlSprintf,
GlModalDirective,
} from '@gitlab/ui';
import { __ } from '~/locale';
import AccessorUtilities from '~/lib/utils/accessor';
import { getFormattedSummary } from '../helpers';
import { COLLAPSE_SECURITY_REPORTS_SUMMARY_LOCAL_STORAGE_KEY as LOCAL_STORAGE_KEY } from '../constants';
import Modal from 'ee/vue_shared/security_reports/components/dast_modal.vue';
export default {
name: 'SecurityReportsSummary',
......@@ -12,9 +20,11 @@ export default {
GlCard,
GlCollapse,
GlSprintf,
Modal,
},
directives: {
collapseToggle: GlCollapseToggleDirective,
GlModal: GlModalDirective,
},
props: {
summary: {
......@@ -54,6 +64,14 @@ export default {
this.isVisible = !shouldHideSummaryDetails;
}
},
methods: {
hasScannedResources(scanSummary) {
return scanSummary.scannedResources?.nodes?.length > 0;
},
downloadLink(scanSummary) {
return scanSummary.scannedResourcesCsvPath || '';
},
},
};
</script>
......@@ -86,9 +104,33 @@ export default {
"
/>
<template v-if="scanSummary.scannedResourcesCount !== undefined">
(<gl-sprintf
:message="n__('%d URL scanned', '%d URLs scanned', scanSummary.scannedResourcesCount)"
/>)
<gl-button
v-if="hasScannedResources(scanSummary)"
v-gl-modal.dastUrl
variant="link"
data-testid="modal-button"
>
(<gl-sprintf
:message="
n__('%d URL scanned', '%d URLs scanned', scanSummary.scannedResourcesCount)
"
/>)
</gl-button>
<template v-else>
(<gl-sprintf
:message="
n__('%d URL scanned', '%d URLs scanned', scanSummary.scannedResourcesCount)
"
/>)
</template>
<modal
v-if="hasScannedResources(scanSummary)"
:scanned-urls="scanSummary.scannedResources.nodes"
:scanned-resources-count="scanSummary.scannedResourcesCount"
:download-link="downloadLink(scanSummary)"
/>
</template>
</div>
</div>
......
......@@ -5,6 +5,13 @@ query($fullPath: ID!, $pipelineIid: ID!) {
dast {
vulnerabilitiesCount
scannedResourcesCount
scannedResourcesCsvPath
scannedResources {
nodes {
requestMethod
url
}
}
}
sast {
vulnerabilitiesCount
......
......@@ -12,6 +12,7 @@ module EE
def security
if pipeline.expose_security_dashboard?
push_frontend_feature_flag(:pipelines_security_report_summary, default_enabled: false)
render_show
else
redirect_to pipeline_path(pipeline)
......
---
title: Implement DAST Modal for Pipeline View
merge_request: 38267
author:
type: added
......@@ -4,6 +4,7 @@ import { trimText } from 'helpers/text_helper';
import AccessorUtilities from '~/lib/utils/accessor';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import SecurityReportsSummary from 'ee/security_dashboard/components/security_reports_summary.vue';
import Modal from 'ee/vue_shared/security_reports/components/dast_modal.vue';
describe('Security reports summary component', () => {
useLocalStorageSpy();
......@@ -19,12 +20,14 @@ describe('Security reports summary component', () => {
stubs: {
GlSprintf,
GlCard: { template: '<div><slot name="header" /><slot /></div>' },
Modal,
},
...options,
});
};
const findToggleButton = () => wrapper.find('[data-testid="collapse-button"]');
const findModalButton = () => wrapper.find('[data-testid="modal-button"]');
beforeEach(() => {
jest.spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').mockReturnValue(true);
......@@ -52,6 +55,7 @@ describe('Security reports summary component', () => {
});
expect(trimText(wrapper.text())).toContain(string);
expect(findModalButton().exists()).toBe(false);
});
it.each`
......@@ -154,4 +158,54 @@ describe('Security reports summary component', () => {
expect(findToggleButton().exists()).toBe(false);
});
});
describe('with scanned resources', () => {
const glModalDirective = jest.fn();
const dastProps = {
vulnerabilitiesCount: 10,
scannedResourcesCount: 149,
scannedResources: {
nodes: [
{
requestMethod: 'GET',
url: 'https://weburl',
},
],
},
};
beforeEach(() => {
createWrapper({
directives: {
glModal: {
bind(el, { modifiers }) {
glModalDirective(modifiers);
},
},
},
propsData: {
summary: { dast: dastProps },
},
});
});
it('should have the modal with id dastUrl', () => {
const modal = wrapper.find(Modal);
expect(modal.exists()).toBe(true);
expect(modal.attributes('modalid')).toBe('dastUrl');
});
it('should contain a link with Scanned URLs count', () => {
expect(findModalButton().exists()).toBe(true);
expect(findModalButton().text()).toContain(
`(${dastProps.scannedResourcesCount} URLs scanned)`,
);
});
it('should link it to the given modal', () => {
expect(glModalDirective).toHaveBeenCalledWith({ dastUrl: true });
});
});
});
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