Commit 2cbdd7ab authored by David O'Regan's avatar David O'Regan

Merge branch...

Merge branch '273423-implement-vulnerability-counts-in-security-mr-widget-for-non-ultimate-users-secret-detection-vuex' into 'master'

Extract and move Secret Detection Vuex module to CE

See merge request gitlab-org/gitlab!47307
parents 5b591e25 b9493ba0
export const FEEDBACK_TYPE_DISMISSAL = 'dismissal';
export const FEEDBACK_TYPE_ISSUE = 'issue';
export const FEEDBACK_TYPE_MERGE_REQUEST = 'merge_request';
import { fetchDiffData } from '../../utils';
import * as types from './mutation_types';
export const setDiffEndpoint = ({ commit }, path) => commit(types.SET_DIFF_ENDPOINT, path);
export const requestDiff = ({ commit }) => commit(types.REQUEST_DIFF);
export const receiveDiffSuccess = ({ commit }, response) =>
commit(types.RECEIVE_DIFF_SUCCESS, response);
export const receiveDiffError = ({ commit }, response) =>
commit(types.RECEIVE_DIFF_ERROR, response);
export const fetchDiff = ({ state, rootState, dispatch }) => {
dispatch('requestDiff');
return fetchDiffData(rootState, state.paths.diffEndpoint, 'secret_detection')
.then(data => {
dispatch('receiveDiffSuccess', data);
})
.catch(() => {
dispatch('receiveDiffError');
});
};
import state from './state';
import mutations from './mutations';
import * as actions from './actions';
export default {
namespaced: true,
state,
mutations,
actions,
};
export const RECEIVE_DIFF_SUCCESS = 'RECEIVE_DIFF_SUCCESS';
export const RECEIVE_DIFF_ERROR = 'RECEIVE_DIFF_ERROR';
export const REQUEST_DIFF = 'REQUEST_DIFF';
export const SET_DIFF_ENDPOINT = 'SET_DIFF_ENDPOINT';
import { parseDiff } from '~/vue_shared/security_reports/store/utils';
import * as types from './mutation_types';
export default {
[types.SET_DIFF_ENDPOINT](state, path) {
state.paths.diffEndpoint = path;
},
[types.REQUEST_DIFF](state) {
state.isLoading = true;
},
[types.RECEIVE_DIFF_SUCCESS](state, { diff, enrichData }) {
const { added, fixed, existing } = parseDiff(diff, enrichData);
const baseReportOutofDate = diff.base_report_out_of_date || false;
const hasBaseReport = Boolean(diff.base_report_created_at);
state.isLoading = false;
state.newIssues = added;
state.resolvedIssues = fixed;
state.allIssues = existing;
state.baseReportOutofDate = baseReportOutofDate;
state.hasBaseReport = hasBaseReport;
},
[types.RECEIVE_DIFF_ERROR](state) {
state.isLoading = false;
state.hasError = true;
},
};
export default () => ({
paths: {
head: null,
base: null,
diffEndpoint: null,
},
isLoading: false,
hasError: false,
newIssues: [],
resolvedIssues: [],
allIssues: [],
baseReportOutofDate: false,
hasBaseReport: false,
});
import pollUntilComplete from '~/lib/utils/poll_until_complete'; import pollUntilComplete from '~/lib/utils/poll_until_complete';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import {
FEEDBACK_TYPE_DISMISSAL,
FEEDBACK_TYPE_ISSUE,
FEEDBACK_TYPE_MERGE_REQUEST,
} from '../constants';
export const fetchDiffData = (state, endpoint, category) => { export const fetchDiffData = (state, endpoint, category) => {
const requests = [pollUntilComplete(endpoint)]; const requests = [pollUntilComplete(endpoint)];
...@@ -24,21 +29,21 @@ export const enrichVulnerabilityWithFeedback = (vulnerability, feedback = []) => ...@@ -24,21 +29,21 @@ export const enrichVulnerabilityWithFeedback = (vulnerability, feedback = []) =>
feedback feedback
.filter(fb => fb.project_fingerprint === vulnerability.project_fingerprint) .filter(fb => fb.project_fingerprint === vulnerability.project_fingerprint)
.reduce((vuln, fb) => { .reduce((vuln, fb) => {
if (fb.feedback_type === 'dismissal') { if (fb.feedback_type === FEEDBACK_TYPE_DISMISSAL) {
return { return {
...vuln, ...vuln,
isDismissed: true, isDismissed: true,
dismissalFeedback: fb, dismissalFeedback: fb,
}; };
} }
if (fb.feedback_type === 'issue' && fb.issue_iid) { if (fb.feedback_type === FEEDBACK_TYPE_ISSUE && fb.issue_iid) {
return { return {
...vuln, ...vuln,
hasIssue: true, hasIssue: true,
issue_feedback: fb, issue_feedback: fb,
}; };
} }
if (fb.feedback_type === 'merge_request' && fb.merge_request_iid) { if (fb.feedback_type === FEEDBACK_TYPE_MERGE_REQUEST && fb.merge_request_iid) {
return { return {
...vuln, ...vuln,
hasMergeRequest: true, hasMergeRequest: true,
......
...@@ -6,6 +6,11 @@ import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; ...@@ -6,6 +6,11 @@ import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { s__, n__, sprintf } from '~/locale'; import { s__, n__, sprintf } from '~/locale';
import { deprecatedCreateFlash as createFlash } from '~/flash'; import { deprecatedCreateFlash as createFlash } from '~/flash';
import toast from '~/vue_shared/plugins/global_toast'; import toast from '~/vue_shared/plugins/global_toast';
import {
FEEDBACK_TYPE_DISMISSAL,
FEEDBACK_TYPE_ISSUE,
FEEDBACK_TYPE_MERGE_REQUEST,
} from '~/vue_shared/security_reports/constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
/** /**
...@@ -83,7 +88,7 @@ export const createIssue = ({ dispatch }, { vulnerability, flashError }) => { ...@@ -83,7 +88,7 @@ export const createIssue = ({ dispatch }, { vulnerability, flashError }) => {
axios axios
.post(vulnerability.create_vulnerability_feedback_issue_path, { .post(vulnerability.create_vulnerability_feedback_issue_path, {
vulnerability_feedback: { vulnerability_feedback: {
feedback_type: 'issue', feedback_type: FEEDBACK_TYPE_ISSUE,
category: vulnerability.report_type, category: vulnerability.report_type,
project_fingerprint: vulnerability.project_fingerprint, project_fingerprint: vulnerability.project_fingerprint,
vulnerability_data: { vulnerability_data: {
...@@ -147,7 +152,7 @@ export const dismissSelectedVulnerabilities = ({ dispatch, state }, { comment } ...@@ -147,7 +152,7 @@ export const dismissSelectedVulnerabilities = ({ dispatch, state }, { comment }
vulnerability_feedback: { vulnerability_feedback: {
category: vulnerability.report_type, category: vulnerability.report_type,
comment, comment,
feedback_type: 'dismissal', feedback_type: FEEDBACK_TYPE_DISMISSAL,
project_fingerprint: vulnerability.project_fingerprint, project_fingerprint: vulnerability.project_fingerprint,
vulnerability_data: { vulnerability_data: {
id: vulnerability.id, id: vulnerability.id,
...@@ -232,7 +237,7 @@ export const dismissVulnerability = ( ...@@ -232,7 +237,7 @@ export const dismissVulnerability = (
vulnerability_feedback: { vulnerability_feedback: {
category: vulnerability.report_type, category: vulnerability.report_type,
comment, comment,
feedback_type: 'dismissal', feedback_type: FEEDBACK_TYPE_DISMISSAL,
pipeline_id: state.pipelineId, pipeline_id: state.pipelineId,
project_fingerprint: vulnerability.project_fingerprint, project_fingerprint: vulnerability.project_fingerprint,
vulnerability_data: { vulnerability_data: {
...@@ -434,7 +439,7 @@ export const createMergeRequest = ({ state, dispatch }, { vulnerability, flashEr ...@@ -434,7 +439,7 @@ export const createMergeRequest = ({ state, dispatch }, { vulnerability, flashEr
axios axios
.post(create_vulnerability_feedback_merge_request_path, { .post(create_vulnerability_feedback_merge_request_path, {
vulnerability_feedback: { vulnerability_feedback: {
feedback_type: 'merge_request', feedback_type: FEEDBACK_TYPE_MERGE_REQUEST,
category: report_type, category: report_type,
project_fingerprint, project_fingerprint,
vulnerability_data: { vulnerability_data: {
......
...@@ -191,7 +191,7 @@ export default { ...@@ -191,7 +191,7 @@ export default {
'dast', 'dast',
'coverageFuzzing', 'coverageFuzzing',
'dependencyScanning', 'dependencyScanning',
'secretScanning', 'secretDetection',
'summaryCounts', 'summaryCounts',
'modal', 'modal',
'isCreatingIssue', 'isCreatingIssue',
...@@ -204,12 +204,10 @@ export default { ...@@ -204,12 +204,10 @@ export default {
'groupedContainerScanningText', 'groupedContainerScanningText',
'groupedDastText', 'groupedDastText',
'groupedDependencyText', 'groupedDependencyText',
'groupedSecretScanningText',
'groupedCoverageFuzzingText', 'groupedCoverageFuzzingText',
'containerScanningStatusIcon', 'containerScanningStatusIcon',
'dastStatusIcon', 'dastStatusIcon',
'dependencyScanningStatusIcon', 'dependencyScanningStatusIcon',
'secretScanningStatusIcon',
'coverageFuzzingStatusIcon', 'coverageFuzzingStatusIcon',
'isBaseSecurityReportOutOfDate', 'isBaseSecurityReportOutOfDate',
'canCreateIssue', 'canCreateIssue',
...@@ -217,6 +215,7 @@ export default { ...@@ -217,6 +215,7 @@ export default {
'canDismissVulnerability', 'canDismissVulnerability',
]), ]),
...mapGetters('sast', ['groupedSastText', 'sastStatusIcon']), ...mapGetters('sast', ['groupedSastText', 'sastStatusIcon']),
...mapGetters('secretDetection', ['groupedSecretDetectionText', 'secretDetectionStatusIcon']),
...mapGetters('pipelineJobs', ['hasFuzzingArtifacts', 'fuzzingJobsWithArtifact']), ...mapGetters('pipelineJobs', ['hasFuzzingArtifacts', 'fuzzingJobsWithArtifact']),
securityTab() { securityTab() {
return `${this.pipelinePath}/security`; return `${this.pipelinePath}/security`;
...@@ -237,7 +236,7 @@ export default { ...@@ -237,7 +236,7 @@ export default {
hasSastReports() { hasSastReports() {
return this.enabledReports.sast; return this.enabledReports.sast;
}, },
hasSecretScanningReports() { hasSecretDetectionReports() {
return this.enabledReports.secretDetection; return this.enabledReports.secretDetection;
}, },
isMRActive() { isMRActive() {
...@@ -258,8 +257,23 @@ export default { ...@@ -258,8 +257,23 @@ export default {
dastDownloadLink() { dastDownloadLink() {
return this.dastSummary?.scannedResourcesCsvPath || ''; return this.dastSummary?.scannedResourcesCsvPath || '';
}, },
coverageFuzzingShowIssues() { hasCoverageFuzzingIssues() {
return this.coverageFuzzing.newIssues || this.coverageFuzzing.resolvedIssues; return this.hasIssuesForReportType('coverageFuzzing');
},
hasSastIssues() {
return this.hasIssuesForReportType('sast');
},
hasDependencyScanningIssues() {
return this.hasIssuesForReportType('dependencyScanning');
},
hasContainerScanningIssues() {
return this.hasIssuesForReportType('containerScanning');
},
hasDastIssues() {
return this.hasIssuesForReportType('dast');
},
hasSecretDetectionIssues() {
return this.hasIssuesForReportType('secretDetection');
}, },
}, },
...@@ -308,10 +322,10 @@ export default { ...@@ -308,10 +322,10 @@ export default {
this.fetchDependencyScanningDiff(); this.fetchDependencyScanningDiff();
} }
const secretScanningDiffEndpoint = gl?.mrWidgetData?.secret_scanning_comparison_path; const secretDetectionDiffEndpoint = gl?.mrWidgetData?.secret_scanning_comparison_path;
if (secretScanningDiffEndpoint && this.hasSecretScanningReports) { if (secretDetectionDiffEndpoint && this.hasSecretDetectionReports) {
this.setSecretScanningDiffEndpoint(secretScanningDiffEndpoint); this.setSecretDetectionDiffEndpoint(secretDetectionDiffEndpoint);
this.fetchSecretScanningDiff(); this.fetchSecretDetectionDiff();
} }
const coverageFuzzingDiffEndpoint = gl?.mrWidgetData?.coverage_fuzzing_comparison_path; const coverageFuzzingDiffEndpoint = gl?.mrWidgetData?.coverage_fuzzing_comparison_path;
...@@ -352,8 +366,6 @@ export default { ...@@ -352,8 +366,6 @@ export default {
'setDependencyScanningDiffEndpoint', 'setDependencyScanningDiffEndpoint',
'fetchDastDiff', 'fetchDastDiff',
'setDastDiffEndpoint', 'setDastDiffEndpoint',
'fetchSecretScanningDiff',
'setSecretScanningDiffEndpoint',
'fetchCoverageFuzzingDiff', 'fetchCoverageFuzzingDiff',
'setCoverageFuzzingDiffEndpoint', 'setCoverageFuzzingDiffEndpoint',
]), ]),
...@@ -361,10 +373,17 @@ export default { ...@@ -361,10 +373,17 @@ export default {
setSastDiffEndpoint: 'setDiffEndpoint', setSastDiffEndpoint: 'setDiffEndpoint',
fetchSastDiff: 'fetchDiff', fetchSastDiff: 'fetchDiff',
}), }),
...mapActions('secretDetection', {
setSecretDetectionDiffEndpoint: 'setDiffEndpoint',
fetchSecretDetectionDiff: 'fetchDiff',
}),
...mapActions('pipelineJobs', ['fetchPipelineJobs', 'setPipelineJobsPath', 'setProjectId']), ...mapActions('pipelineJobs', ['fetchPipelineJobs', 'setPipelineJobsPath', 'setProjectId']),
...mapActions('pipelineJobs', { ...mapActions('pipelineJobs', {
setPipelineJobsId: 'setPipelineId', setPipelineJobsId: 'setPipelineId',
}), }),
hasIssuesForReportType(reportType) {
return Boolean(this[reportType]?.newIssues.length || this[reportType]?.resolvedIssues.length);
},
}, },
summarySlots: ['success', 'error', 'loading'], summarySlots: ['success', 'error', 'loading'],
}; };
...@@ -443,11 +462,10 @@ export default { ...@@ -443,11 +462,10 @@ export default {
</summary-row> </summary-row>
<grouped-issues-list <grouped-issues-list
v-if="sast.newIssues.length || sast.resolvedIssues.length" v-if="hasSastIssues"
:unresolved-issues="sast.newIssues" :unresolved-issues="sast.newIssues"
:resolved-issues="sast.resolvedIssues" :resolved-issues="sast.resolvedIssues"
:component="$options.componentNames.SecurityIssueBody" :component="$options.componentNames.SecurityIssueBody"
class="report-block-group-list"
data-testid="sast-issues-list" data-testid="sast-issues-list"
/> />
</template> </template>
...@@ -465,11 +483,10 @@ export default { ...@@ -465,11 +483,10 @@ export default {
</summary-row> </summary-row>
<grouped-issues-list <grouped-issues-list
v-if="dependencyScanning.newIssues.length || dependencyScanning.resolvedIssues.length" v-if="hasDependencyScanningIssues"
:unresolved-issues="dependencyScanning.newIssues" :unresolved-issues="dependencyScanning.newIssues"
:resolved-issues="dependencyScanning.resolvedIssues" :resolved-issues="dependencyScanning.resolvedIssues"
:component="$options.componentNames.SecurityIssueBody" :component="$options.componentNames.SecurityIssueBody"
class="report-block-group-list"
data-testid="dependency-scanning-issues-list" data-testid="dependency-scanning-issues-list"
/> />
</template> </template>
...@@ -487,11 +504,10 @@ export default { ...@@ -487,11 +504,10 @@ export default {
</summary-row> </summary-row>
<grouped-issues-list <grouped-issues-list
v-if="containerScanning.newIssues.length || containerScanning.resolvedIssues.length" v-if="hasContainerScanningIssues"
:unresolved-issues="containerScanning.newIssues" :unresolved-issues="containerScanning.newIssues"
:resolved-issues="containerScanning.resolvedIssues" :resolved-issues="containerScanning.resolvedIssues"
:component="$options.componentNames.SecurityIssueBody" :component="$options.componentNames.SecurityIssueBody"
class="report-block-group-list"
data-testid="container-scanning-issues-list" data-testid="container-scanning-issues-list"
/> />
</template> </template>
...@@ -522,33 +538,31 @@ export default { ...@@ -522,33 +538,31 @@ export default {
</template> </template>
</summary-row> </summary-row>
<grouped-issues-list <grouped-issues-list
v-if="dast.newIssues.length || dast.resolvedIssues.length" v-if="hasDastIssues"
:unresolved-issues="dast.newIssues" :unresolved-issues="dast.newIssues"
:resolved-issues="dast.resolvedIssues" :resolved-issues="dast.resolvedIssues"
:component="$options.componentNames.SecurityIssueBody" :component="$options.componentNames.SecurityIssueBody"
class="report-block-group-list"
data-testid="dast-issues-list" data-testid="dast-issues-list"
/> />
</template> </template>
<template v-if="hasSecretScanningReports"> <template v-if="hasSecretDetectionReports">
<summary-row <summary-row
:status-icon="secretScanningStatusIcon" :status-icon="secretDetectionStatusIcon"
:popover-options="secretScanningPopover" :popover-options="secretScanningPopover"
class="js-secret-scanning" class="js-secret-scanning"
data-qa-selector="secret_scan_report" data-qa-selector="secret_scan_report"
> >
<template #summary> <template #summary>
<security-summary :message="groupedSecretScanningText" /> <security-summary :message="groupedSecretDetectionText" />
</template> </template>
</summary-row> </summary-row>
<grouped-issues-list <grouped-issues-list
v-if="secretScanning.newIssues.length || secretScanning.resolvedIssues.length" v-if="hasSecretDetectionIssues"
:unresolved-issues="secretScanning.newIssues" :unresolved-issues="secretDetection.newIssues"
:resolved-issues="secretScanning.resolvedIssues" :resolved-issues="secretDetection.resolvedIssues"
:component="$options.componentNames.SecurityIssueBody" :component="$options.componentNames.SecurityIssueBody"
class="report-block-group-list"
data-testid="secret-scanning-issues-list" data-testid="secret-scanning-issues-list"
/> />
</template> </template>
...@@ -571,11 +585,10 @@ export default { ...@@ -571,11 +585,10 @@ export default {
</summary-row> </summary-row>
<grouped-issues-list <grouped-issues-list
v-if="coverageFuzzingShowIssues" v-if="hasCoverageFuzzingIssues"
:unresolved-issues="coverageFuzzing.newIssues" :unresolved-issues="coverageFuzzing.newIssues"
:resolved-issues="coverageFuzzing.resolvedIssues" :resolved-issues="coverageFuzzing.resolvedIssues"
:component="$options.componentNames.SecurityIssueBody" :component="$options.componentNames.SecurityIssueBody"
class="report-block-group-list"
data-testid="coverage-fuzzing-issues-list" data-testid="coverage-fuzzing-issues-list"
/> />
</template> </template>
......
...@@ -6,6 +6,11 @@ import { s__, sprintf } from '~/locale'; ...@@ -6,6 +6,11 @@ import { s__, sprintf } from '~/locale';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
import toast from '~/vue_shared/plugins/global_toast'; import toast from '~/vue_shared/plugins/global_toast';
import { fetchDiffData } from '~/vue_shared/security_reports/store/utils'; import { fetchDiffData } from '~/vue_shared/security_reports/store/utils';
import {
FEEDBACK_TYPE_DISMISSAL,
FEEDBACK_TYPE_ISSUE,
FEEDBACK_TYPE_MERGE_REQUEST,
} from '~/vue_shared/security_reports/constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
/** /**
...@@ -173,36 +178,6 @@ export const fetchCoverageFuzzingDiff = ({ state, dispatch }) => { ...@@ -173,36 +178,6 @@ export const fetchCoverageFuzzingDiff = ({ state, dispatch }) => {
export const updateCoverageFuzzingIssue = ({ commit }, issue) => export const updateCoverageFuzzingIssue = ({ commit }, issue) =>
commit(types.UPDATE_COVERAGE_FUZZING_ISSUE, issue); commit(types.UPDATE_COVERAGE_FUZZING_ISSUE, issue);
/**
* SECRET SCANNING
*/
export const setSecretScanningDiffEndpoint = ({ commit }, path) =>
commit(types.SET_SECRET_SCANNING_DIFF_ENDPOINT, path);
export const requestSecretScanningDiff = ({ commit }) => commit(types.REQUEST_SECRET_SCANNING_DIFF);
export const receiveSecretScanningDiffSuccess = ({ commit }, response) =>
commit(types.RECEIVE_SECRET_SCANNING_DIFF_SUCCESS, response);
export const receiveSecretScanningDiffError = ({ commit }) =>
commit(types.RECEIVE_SECRET_SCANNING_DIFF_ERROR);
export const fetchSecretScanningDiff = ({ state, dispatch }) => {
dispatch('requestSecretScanningDiff');
return fetchDiffData(state, state.secretScanning.paths.diffEndpoint, 'secret_detection')
.then(data => {
dispatch('receiveSecretScanningDiffSuccess', data);
})
.catch(() => {
dispatch('receiveSecretScanningDiffError');
});
};
export const updateSecretScanningIssue = ({ commit }, issue) =>
commit(types.UPDATE_SECRET_SCANNING_ISSUE, issue);
export const openModal = ({ dispatch }, payload) => { export const openModal = ({ dispatch }, payload) => {
dispatch('setModalData', payload); dispatch('setModalData', payload);
...@@ -229,7 +204,7 @@ export const dismissVulnerability = ({ state, dispatch }, comment) => { ...@@ -229,7 +204,7 @@ export const dismissVulnerability = ({ state, dispatch }, comment) => {
vulnerability_feedback: { vulnerability_feedback: {
category: state.modal.vulnerability.category, category: state.modal.vulnerability.category,
comment, comment,
feedback_type: 'dismissal', feedback_type: FEEDBACK_TYPE_DISMISSAL,
pipeline_id: state.pipelineId, pipeline_id: state.pipelineId,
project_fingerprint: state.modal.vulnerability.project_fingerprint, project_fingerprint: state.modal.vulnerability.project_fingerprint,
vulnerability_data: state.modal.vulnerability, vulnerability_data: state.modal.vulnerability,
...@@ -392,7 +367,7 @@ export const createNewIssue = ({ state, dispatch }) => { ...@@ -392,7 +367,7 @@ export const createNewIssue = ({ state, dispatch }) => {
axios axios
.post(state.createVulnerabilityFeedbackIssuePath, { .post(state.createVulnerabilityFeedbackIssuePath, {
vulnerability_feedback: { vulnerability_feedback: {
feedback_type: 'issue', feedback_type: FEEDBACK_TYPE_ISSUE,
category: state.modal.vulnerability.category, category: state.modal.vulnerability.category,
project_fingerprint: state.modal.vulnerability.project_fingerprint, project_fingerprint: state.modal.vulnerability.project_fingerprint,
pipeline_id: state.pipelineId, pipeline_id: state.pipelineId,
...@@ -423,7 +398,7 @@ export const createMergeRequest = ({ state, dispatch }) => { ...@@ -423,7 +398,7 @@ export const createMergeRequest = ({ state, dispatch }) => {
axios axios
.post(state.createVulnerabilityFeedbackMergeRequestPath, { .post(state.createVulnerabilityFeedbackMergeRequestPath, {
vulnerability_feedback: { vulnerability_feedback: {
feedback_type: 'merge_request', feedback_type: FEEDBACK_TYPE_MERGE_REQUEST,
category, category,
project_fingerprint, project_fingerprint,
vulnerability_data: vulnerability, vulnerability_data: vulnerability,
......
...@@ -11,14 +11,6 @@ export const groupedContainerScanningText = ({ containerScanning }) => ...@@ -11,14 +11,6 @@ export const groupedContainerScanningText = ({ containerScanning }) =>
messages.CONTAINER_SCANNING_IS_LOADING, messages.CONTAINER_SCANNING_IS_LOADING,
); );
export const groupedSecretScanningText = ({ secretScanning }) =>
groupedReportText(
secretScanning,
messages.SECRET_SCANNING,
messages.SECRET_SCANNING_HAS_ERROR,
messages.SECRET_SCANNING_IS_LOADING,
);
export const groupedDastText = ({ dast }) => export const groupedDastText = ({ dast }) =>
groupedReportText(dast, messages.DAST, messages.DAST_HAS_ERROR, messages.DAST_IS_LOADING); groupedReportText(dast, messages.DAST, messages.DAST_HAS_ERROR, messages.DAST_IS_LOADING);
...@@ -43,7 +35,7 @@ export const summaryCounts = ({ ...@@ -43,7 +35,7 @@ export const summaryCounts = ({
dast, dast,
dependencyScanning, dependencyScanning,
sast, sast,
secretScanning, secretDetection,
coverageFuzzing, coverageFuzzing,
} = {}) => { } = {}) => {
const allNewVulns = [ const allNewVulns = [
...@@ -51,7 +43,7 @@ export const summaryCounts = ({ ...@@ -51,7 +43,7 @@ export const summaryCounts = ({
...dast.newIssues, ...dast.newIssues,
...dependencyScanning.newIssues, ...dependencyScanning.newIssues,
...sast.newIssues, ...sast.newIssues,
...secretScanning.newIssues, ...secretDetection.newIssues,
...coverageFuzzing.newIssues, ...coverageFuzzing.newIssues,
]; ];
...@@ -114,9 +106,6 @@ export const dependencyScanningStatusIcon = ({ dependencyScanning }) => ...@@ -114,9 +106,6 @@ export const dependencyScanningStatusIcon = ({ dependencyScanning }) =>
dependencyScanning.newIssues.length, dependencyScanning.newIssues.length,
); );
export const secretScanningStatusIcon = ({ secretScanning }) =>
statusIcon(secretScanning.isLoading, secretScanning.hasError, secretScanning.newIssues.length);
export const coverageFuzzingStatusIcon = ({ coverageFuzzing }) => export const coverageFuzzingStatusIcon = ({ coverageFuzzing }) =>
statusIcon(coverageFuzzing.isLoading, coverageFuzzing.hasError, coverageFuzzing.newIssues.length); statusIcon(coverageFuzzing.isLoading, coverageFuzzing.hasError, coverageFuzzing.newIssues.length);
...@@ -125,7 +114,7 @@ export const areReportsLoading = state => ...@@ -125,7 +114,7 @@ export const areReportsLoading = state =>
state.dast.isLoading || state.dast.isLoading ||
state.containerScanning.isLoading || state.containerScanning.isLoading ||
state.dependencyScanning.isLoading || state.dependencyScanning.isLoading ||
state.secretScanning.isLoading || state.secretDetection.isLoading ||
state.coverageFuzzing.isLoading; state.coverageFuzzing.isLoading;
export const areAllReportsLoading = state => export const areAllReportsLoading = state =>
...@@ -133,7 +122,7 @@ export const areAllReportsLoading = state => ...@@ -133,7 +122,7 @@ export const areAllReportsLoading = state =>
state.dast.isLoading && state.dast.isLoading &&
state.containerScanning.isLoading && state.containerScanning.isLoading &&
state.dependencyScanning.isLoading && state.dependencyScanning.isLoading &&
state.secretScanning.isLoading && state.secretDetection.isLoading &&
state.coverageFuzzing.isLoading; state.coverageFuzzing.isLoading;
export const allReportsHaveError = state => export const allReportsHaveError = state =>
...@@ -141,7 +130,7 @@ export const allReportsHaveError = state => ...@@ -141,7 +130,7 @@ export const allReportsHaveError = state =>
state.dast.hasError && state.dast.hasError &&
state.containerScanning.hasError && state.containerScanning.hasError &&
state.dependencyScanning.hasError && state.dependencyScanning.hasError &&
state.secretScanning.hasError && state.secretDetection.hasError &&
state.coverageFuzzing.hasError; state.coverageFuzzing.hasError;
export const anyReportHasError = state => export const anyReportHasError = state =>
...@@ -149,7 +138,7 @@ export const anyReportHasError = state => ...@@ -149,7 +138,7 @@ export const anyReportHasError = state =>
state.dast.hasError || state.dast.hasError ||
state.containerScanning.hasError || state.containerScanning.hasError ||
state.dependencyScanning.hasError || state.dependencyScanning.hasError ||
state.secretScanning.hasError || state.secretDetection.hasError ||
state.coverageFuzzing.hasError; state.coverageFuzzing.hasError;
export const noBaseInAllReports = state => export const noBaseInAllReports = state =>
...@@ -157,7 +146,7 @@ export const noBaseInAllReports = state => ...@@ -157,7 +146,7 @@ export const noBaseInAllReports = state =>
!state.dast.hasBaseReport && !state.dast.hasBaseReport &&
!state.containerScanning.hasBaseReport && !state.containerScanning.hasBaseReport &&
!state.dependencyScanning.hasBaseReport && !state.dependencyScanning.hasBaseReport &&
!state.secretScanning.hasBaseReport && !state.secretDetection.hasBaseReport &&
!state.coverageFuzzing.hasBaseReport; !state.coverageFuzzing.hasBaseReport;
export const anyReportHasIssues = state => export const anyReportHasIssues = state =>
...@@ -165,7 +154,7 @@ export const anyReportHasIssues = state => ...@@ -165,7 +154,7 @@ export const anyReportHasIssues = state =>
state.dast.newIssues.length > 0 || state.dast.newIssues.length > 0 ||
state.containerScanning.newIssues.length > 0 || state.containerScanning.newIssues.length > 0 ||
state.dependencyScanning.newIssues.length > 0 || state.dependencyScanning.newIssues.length > 0 ||
state.secretScanning.newIssues.length > 0 || state.secretDetection.newIssues.length > 0 ||
state.coverageFuzzing.newIssues.length > 0; state.coverageFuzzing.newIssues.length > 0;
export const isBaseSecurityReportOutOfDate = state => export const isBaseSecurityReportOutOfDate = state =>
...@@ -173,7 +162,7 @@ export const isBaseSecurityReportOutOfDate = state => ...@@ -173,7 +162,7 @@ export const isBaseSecurityReportOutOfDate = state =>
state.dast.baseReportOutofDate || state.dast.baseReportOutofDate ||
state.containerScanning.baseReportOutofDate || state.containerScanning.baseReportOutofDate ||
state.dependencyScanning.baseReportOutofDate || state.dependencyScanning.baseReportOutofDate ||
state.secretScanning.baseReportOutofDate || state.secretDetection.baseReportOutofDate ||
state.coverageFuzzing.baseReportOutofDate; state.coverageFuzzing.baseReportOutofDate;
export const canCreateIssue = state => Boolean(state.createVulnerabilityFeedbackIssuePath); export const canCreateIssue = state => Boolean(state.createVulnerabilityFeedbackIssuePath);
......
...@@ -8,6 +8,7 @@ import mutations from './mutations'; ...@@ -8,6 +8,7 @@ import mutations from './mutations';
import state from './state'; import state from './state';
import sast from './modules/sast'; import sast from './modules/sast';
import secretDetection from './modules/secret_detection';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -15,6 +16,7 @@ export default () => ...@@ -15,6 +16,7 @@ export default () =>
new Vuex.Store({ new Vuex.Store({
modules: { modules: {
sast, sast,
secretDetection,
pipelineJobs, pipelineJobs,
}, },
actions, actions,
......
import * as types from './mutation_types'; import * as types from './mutation_types';
const updateIssueActionsMap = { export const updateIssueActionsMap = {
sast: 'sast/updateVulnerability', sast: 'sast/updateVulnerability',
dependency_scanning: 'updateDependencyScanningIssue', dependency_scanning: 'updateDependencyScanningIssue',
container_scanning: 'updateContainerScanningIssue', container_scanning: 'updateContainerScanningIssue',
dast: 'updateDastIssue', dast: 'updateDastIssue',
secret_scanning: 'updateSecretScanningIssue', secret_detection: 'secretDetection/updateVulnerability',
coverage_fuzzing: 'updateCoverageFuzzingIssue', coverage_fuzzing: 'updateCoverageFuzzingIssue',
}; };
......
import messages from '../../messages';
export const { SAST, SAST_HAS_ERROR, SAST_IS_LOADING } = messages;
import { statusIcon, groupedReportText } from '../../utils'; import { statusIcon, groupedReportText } from '../../utils';
import { SAST, SAST_HAS_ERROR, SAST_IS_LOADING } from './constants'; import messages from '../../messages';
export const groupedSastText = state => export const groupedSastText = state =>
groupedReportText(state, SAST, SAST_HAS_ERROR, SAST_IS_LOADING); groupedReportText(state, messages.SAST, messages.SAST_HAS_ERROR, messages.SAST_IS_LOADING);
export const sastStatusIcon = ({ isLoading, hasError, newIssues }) => export const sastStatusIcon = ({ isLoading, hasError, newIssues }) =>
statusIcon(isLoading, hasError, newIssues.length); statusIcon(isLoading, hasError, newIssues.length);
import * as types from './mutation_types';
export * from '~/vue_shared/security_reports/store/modules/secret_detection/actions';
export const updateVulnerability = ({ commit }, vulnerability) =>
commit(types.UPDATE_VULNERABILITY, vulnerability);
import { statusIcon, groupedReportText } from '../../utils';
import messages from '../../messages';
export const groupedSecretDetectionText = state =>
groupedReportText(
state,
messages.SECRET_SCANNING,
messages.SECRET_SCANNING_HAS_ERROR,
messages.SECRET_SCANNING_IS_LOADING,
);
export const secretDetectionStatusIcon = ({ isLoading, hasError, newIssues }) =>
statusIcon(isLoading, hasError, newIssues.length);
import state from './state';
import mutations from './mutations';
import * as getters from './getters';
import * as actions from './actions';
export default {
namespaced: true,
state,
mutations,
getters,
actions,
};
export * from '~/vue_shared/security_reports/store/modules/secret_detection/mutation_types';
export const UPDATE_VULNERABILITY = 'UPDATE_VULNERABILITY';
import ceMutations from '~/vue_shared/security_reports/store/modules/secret_detection/mutations';
import { findIssueIndex } from '../../utils';
import * as types from './mutation_types';
export default {
...ceMutations,
[types.UPDATE_VULNERABILITY](state, issue) {
const newIssuesIndex = findIssueIndex(state.newIssues, issue);
if (newIssuesIndex !== -1) {
state.newIssues.splice(newIssuesIndex, 1, issue);
return;
}
const resolvedIssuesIndex = findIssueIndex(state.resolvedIssues, issue);
if (resolvedIssuesIndex !== -1) {
state.resolvedIssues.splice(resolvedIssuesIndex, 1, issue);
return;
}
const allIssuesIndex = findIssueIndex(state.allIssues, issue);
if (allIssuesIndex !== -1) {
state.allIssues.splice(allIssuesIndex, 1, issue);
}
},
};
export { default } from '~/vue_shared/security_reports/store/modules/secret_detection/state';
...@@ -30,12 +30,6 @@ export const REQUEST_DEPENDENCY_SCANNING_DIFF = 'REQUEST_DEPENDENCY_SCANNING_DIF ...@@ -30,12 +30,6 @@ export const REQUEST_DEPENDENCY_SCANNING_DIFF = 'REQUEST_DEPENDENCY_SCANNING_DIF
export const RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS = 'RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS'; export const RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS = 'RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS';
export const RECEIVE_DEPENDENCY_SCANNING_DIFF_ERROR = 'RECEIVE_DEPENDENCY_SCANNING_DIFF_ERROR'; export const RECEIVE_DEPENDENCY_SCANNING_DIFF_ERROR = 'RECEIVE_DEPENDENCY_SCANNING_DIFF_ERROR';
// SECRET SCANNING
export const SET_SECRET_SCANNING_DIFF_ENDPOINT = 'SET_SECRET_SCANNING_DIFF_ENDPOINT';
export const REQUEST_SECRET_SCANNING_DIFF = 'REQUEST_SECRET_SCANNING_DIFF';
export const RECEIVE_SECRET_SCANNING_DIFF_SUCCESS = 'RECEIVE_SECRET_SCANNING_DIFF_SUCCESS';
export const RECEIVE_SECRET_SCANNING_DIFF_ERROR = 'RECEIVE_SECRET_SCANNING_DIFF_ERROR';
// COVERAGE FUZZING // COVERAGE FUZZING
export const SET_COVERAGE_FUZZING_DIFF_ENDPOINT = 'SET_COVERAGE_FUZZING_DIFF_ENDPOINT'; export const SET_COVERAGE_FUZZING_DIFF_ENDPOINT = 'SET_COVERAGE_FUZZING_DIFF_ENDPOINT';
export const REQUEST_COVERAGE_FUZZING_DIFF = 'REQUEST_COVERAGE_FUZZING_DIFF'; export const REQUEST_COVERAGE_FUZZING_DIFF = 'REQUEST_COVERAGE_FUZZING_DIFF';
...@@ -69,7 +63,6 @@ export const HIDE_DISMISSAL_DELETE_BUTTONS = 'HIDE_DISMISSAL_DELETE_BUTTONS'; ...@@ -69,7 +63,6 @@ export const HIDE_DISMISSAL_DELETE_BUTTONS = 'HIDE_DISMISSAL_DELETE_BUTTONS';
export const UPDATE_DEPENDENCY_SCANNING_ISSUE = 'UPDATE_DEPENDENCY_SCANNING_ISSUE'; export const UPDATE_DEPENDENCY_SCANNING_ISSUE = 'UPDATE_DEPENDENCY_SCANNING_ISSUE';
export const UPDATE_CONTAINER_SCANNING_ISSUE = 'UPDATE_CONTAINER_SCANNING_ISSUE'; export const UPDATE_CONTAINER_SCANNING_ISSUE = 'UPDATE_CONTAINER_SCANNING_ISSUE';
export const UPDATE_DAST_ISSUE = 'UPDATE_DAST_ISSUE'; export const UPDATE_DAST_ISSUE = 'UPDATE_DAST_ISSUE';
export const UPDATE_SECRET_SCANNING_ISSUE = 'UPDATE_SECRET_SCANNING_ISSUE';
export const UPDATE_COVERAGE_FUZZING_ISSUE = 'UPDATE_COVERAGE_FUZZING_ISSUE'; export const UPDATE_COVERAGE_FUZZING_ISSUE = 'UPDATE_COVERAGE_FUZZING_ISSUE';
export const OPEN_DISMISSAL_COMMENT_BOX = 'OPEN_DISMISSAL_COMMENT_BOX '; export const OPEN_DISMISSAL_COMMENT_BOX = 'OPEN_DISMISSAL_COMMENT_BOX ';
......
...@@ -160,33 +160,6 @@ export default { ...@@ -160,33 +160,6 @@ export default {
Vue.set(state.dependencyScanning, 'hasError', true); Vue.set(state.dependencyScanning, 'hasError', true);
}, },
// SECRET SCANNING
[types.SET_SECRET_SCANNING_DIFF_ENDPOINT](state, path) {
Vue.set(state.secretScanning.paths, 'diffEndpoint', path);
},
[types.REQUEST_SECRET_SCANNING_DIFF](state) {
Vue.set(state.secretScanning, 'isLoading', true);
},
[types.RECEIVE_SECRET_SCANNING_DIFF_SUCCESS](state, { diff, enrichData }) {
const { added, fixed, existing } = parseDiff(diff, enrichData);
const baseReportOutofDate = diff.base_report_out_of_date || false;
const hasBaseReport = Boolean(diff.base_report_created_at);
Vue.set(state.secretScanning, 'isLoading', false);
Vue.set(state.secretScanning, 'newIssues', added);
Vue.set(state.secretScanning, 'resolvedIssues', fixed);
Vue.set(state.secretScanning, 'allIssues', existing);
Vue.set(state.secretScanning, 'baseReportOutofDate', baseReportOutofDate);
Vue.set(state.secretScanning, 'hasBaseReport', hasBaseReport);
},
[types.RECEIVE_SECRET_SCANNING_DIFF_ERROR](state) {
Vue.set(state.secretScanning, 'isLoading', false);
Vue.set(state.secretScanning, 'hasError', true);
},
[types.SET_ISSUE_MODAL_DATA](state, payload) { [types.SET_ISSUE_MODAL_DATA](state, payload) {
const { issue, status } = payload; const { issue, status } = payload;
...@@ -298,26 +271,6 @@ export default { ...@@ -298,26 +271,6 @@ export default {
} }
}, },
[types.UPDATE_SECRET_SCANNING_ISSUE](state, issue) {
// Find issue in the correct list and update it
const newIssuesIndex = findIssueIndex(state.secretScanning.newIssues, issue);
if (newIssuesIndex !== -1) {
state.secretScanning.newIssues.splice(newIssuesIndex, 1, issue);
return;
}
const resolvedIssuesIndex = findIssueIndex(state.secretScanning.resolvedIssues, issue);
if (resolvedIssuesIndex !== -1) {
state.secretScanning.resolvedIssues.splice(resolvedIssuesIndex, 1, issue);
}
const allIssuesIndex = findIssueIndex(state.secretScanning.allIssues, issue);
if (allIssuesIndex !== -1) {
state.secretScanning.allIssues.splice(allIssuesIndex, 1, issue);
}
},
[types.REQUEST_CREATE_ISSUE](state) { [types.REQUEST_CREATE_ISSUE](state) {
state.isCreatingIssue = true; state.isCreatingIssue = true;
// reset error in case previous state was error // reset error in case previous state was error
......
...@@ -76,22 +76,6 @@ export default () => ({ ...@@ -76,22 +76,6 @@ export default () => ({
baseReportOutofDate: false, baseReportOutofDate: false,
hasBaseReport: false, hasBaseReport: false,
}, },
secretScanning: {
paths: {
head: null,
base: null,
diffEndpoint: null,
},
isLoading: false,
hasError: false,
newIssues: [],
resolvedIssues: [],
allIssues: [],
baseReportOutofDate: false,
hasBaseReport: false,
},
modal: { modal: {
title: null, title: null,
......
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import {
FEEDBACK_TYPE_ISSUE,
FEEDBACK_TYPE_MERGE_REQUEST,
} from '~/vue_shared/security_reports/constants';
export const VULNERABILITY_STATE_OBJECTS = { export const VULNERABILITY_STATE_OBJECTS = {
detected: { detected: {
...@@ -49,8 +53,8 @@ export const HEADER_ACTION_BUTTONS = { ...@@ -49,8 +53,8 @@ export const HEADER_ACTION_BUTTONS = {
}; };
export const FEEDBACK_TYPES = { export const FEEDBACK_TYPES = {
ISSUE: 'issue', ISSUE: FEEDBACK_TYPE_ISSUE,
MERGE_REQUEST: 'merge_request', MERGE_REQUEST: FEEDBACK_TYPE_MERGE_REQUEST,
}; };
export const RELATED_ISSUES_ERRORS = { export const RELATED_ISSUES_ERRORS = {
......
---
title: Fix real-time update of dismissal status of vulnerabilities found by Secret Detection
merge_request: 47307
author:
type: fixed
...@@ -10,7 +10,7 @@ export default { ...@@ -10,7 +10,7 @@ export default {
dast: false, dast: false,
dependency_scanning: false, dependency_scanning: false,
license_management: false, license_management: false,
secret_scanning: false, secret_detection: false,
}, },
}; };
......
...@@ -4,6 +4,7 @@ import GroupedSecurityReportsApp from 'ee/vue_shared/security_reports/grouped_se ...@@ -4,6 +4,7 @@ import GroupedSecurityReportsApp from 'ee/vue_shared/security_reports/grouped_se
import appStore from 'ee/vue_shared/security_reports/store'; import appStore from 'ee/vue_shared/security_reports/store';
import * as types from 'ee/vue_shared/security_reports/store/mutation_types'; import * as types from 'ee/vue_shared/security_reports/store/mutation_types';
import * as sastTypes from 'ee/vue_shared/security_reports/store/modules/sast/mutation_types'; import * as sastTypes from 'ee/vue_shared/security_reports/store/modules/sast/mutation_types';
import * as secretDetectionTypes from 'ee/vue_shared/security_reports/store/modules/secret_detection/mutation_types';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { waitForMutation } from 'helpers/vue_test_utils_helper'; import { waitForMutation } from 'helpers/vue_test_utils_helper';
import { trimText } from 'helpers/text_helper'; import { trimText } from 'helpers/text_helper';
...@@ -29,7 +30,7 @@ const DEPENDENCY_SCANNING_DIFF_ENDPOINT = 'dependency_scanning.json'; ...@@ -29,7 +30,7 @@ const DEPENDENCY_SCANNING_DIFF_ENDPOINT = 'dependency_scanning.json';
const DAST_DIFF_ENDPOINT = 'dast.json'; const DAST_DIFF_ENDPOINT = 'dast.json';
const SAST_DIFF_ENDPOINT = 'sast.json'; const SAST_DIFF_ENDPOINT = 'sast.json';
const PIPELINE_JOBS_ENDPOINT = 'jobs.json'; const PIPELINE_JOBS_ENDPOINT = 'jobs.json';
const SECRET_SCANNING_DIFF_ENDPOINT = 'secret_detection.json'; const SECRET_DETECTION_DIFF_ENDPOINT = 'secret_detection.json';
const COVERAGE_FUZZING_DIFF_ENDPOINT = 'coverage_fuzzing.json'; const COVERAGE_FUZZING_DIFF_ENDPOINT = 'coverage_fuzzing.json';
describe('Grouped security reports app', () => { describe('Grouped security reports app', () => {
...@@ -117,7 +118,7 @@ describe('Grouped security reports app', () => { ...@@ -117,7 +118,7 @@ describe('Grouped security reports app', () => {
gl.mrWidgetData.dependency_scanning_comparison_path = DEPENDENCY_SCANNING_DIFF_ENDPOINT; gl.mrWidgetData.dependency_scanning_comparison_path = DEPENDENCY_SCANNING_DIFF_ENDPOINT;
gl.mrWidgetData.dast_comparison_path = DAST_DIFF_ENDPOINT; gl.mrWidgetData.dast_comparison_path = DAST_DIFF_ENDPOINT;
gl.mrWidgetData.sast_comparison_path = SAST_DIFF_ENDPOINT; gl.mrWidgetData.sast_comparison_path = SAST_DIFF_ENDPOINT;
gl.mrWidgetData.secret_scanning_comparison_path = SECRET_SCANNING_DIFF_ENDPOINT; gl.mrWidgetData.secret_scanning_comparison_path = SECRET_DETECTION_DIFF_ENDPOINT;
gl.mrWidgetData.coverage_fuzzing_comparison_path = COVERAGE_FUZZING_DIFF_ENDPOINT; gl.mrWidgetData.coverage_fuzzing_comparison_path = COVERAGE_FUZZING_DIFF_ENDPOINT;
}); });
...@@ -127,7 +128,7 @@ describe('Grouped security reports app', () => { ...@@ -127,7 +128,7 @@ describe('Grouped security reports app', () => {
mock.onGet(DEPENDENCY_SCANNING_DIFF_ENDPOINT).reply(500); mock.onGet(DEPENDENCY_SCANNING_DIFF_ENDPOINT).reply(500);
mock.onGet(DAST_DIFF_ENDPOINT).reply(500); mock.onGet(DAST_DIFF_ENDPOINT).reply(500);
mock.onGet(SAST_DIFF_ENDPOINT).reply(500); mock.onGet(SAST_DIFF_ENDPOINT).reply(500);
mock.onGet(SECRET_SCANNING_DIFF_ENDPOINT).reply(500); mock.onGet(SECRET_DETECTION_DIFF_ENDPOINT).reply(500);
mock.onGet(COVERAGE_FUZZING_DIFF_ENDPOINT).reply(500); mock.onGet(COVERAGE_FUZZING_DIFF_ENDPOINT).reply(500);
createWrapper(allReportProps); createWrapper(allReportProps);
...@@ -137,7 +138,10 @@ describe('Grouped security reports app', () => { ...@@ -137,7 +138,10 @@ describe('Grouped security reports app', () => {
waitForMutation(wrapper.vm.$store, types.RECEIVE_CONTAINER_SCANNING_DIFF_ERROR), waitForMutation(wrapper.vm.$store, types.RECEIVE_CONTAINER_SCANNING_DIFF_ERROR),
waitForMutation(wrapper.vm.$store, types.RECEIVE_DAST_DIFF_ERROR), waitForMutation(wrapper.vm.$store, types.RECEIVE_DAST_DIFF_ERROR),
waitForMutation(wrapper.vm.$store, types.RECEIVE_DEPENDENCY_SCANNING_DIFF_ERROR), waitForMutation(wrapper.vm.$store, types.RECEIVE_DEPENDENCY_SCANNING_DIFF_ERROR),
waitForMutation(wrapper.vm.$store, types.RECEIVE_SECRET_SCANNING_DIFF_ERROR), waitForMutation(
wrapper.vm.$store,
`secretDetection/${secretDetectionTypes.RECEIVE_DIFF_ERROR}`,
),
waitForMutation(wrapper.vm.$store, types.RECEIVE_COVERAGE_FUZZING_DIFF_ERROR), waitForMutation(wrapper.vm.$store, types.RECEIVE_COVERAGE_FUZZING_DIFF_ERROR),
]); ]);
}); });
...@@ -179,7 +183,7 @@ describe('Grouped security reports app', () => { ...@@ -179,7 +183,7 @@ describe('Grouped security reports app', () => {
mock.onGet(DEPENDENCY_SCANNING_DIFF_ENDPOINT).reply(200, {}); mock.onGet(DEPENDENCY_SCANNING_DIFF_ENDPOINT).reply(200, {});
mock.onGet(DAST_DIFF_ENDPOINT).reply(200, {}); mock.onGet(DAST_DIFF_ENDPOINT).reply(200, {});
mock.onGet(SAST_DIFF_ENDPOINT).reply(200, {}); mock.onGet(SAST_DIFF_ENDPOINT).reply(200, {});
mock.onGet(SECRET_SCANNING_DIFF_ENDPOINT).reply(200, {}); mock.onGet(SECRET_DETECTION_DIFF_ENDPOINT).reply(200, {});
mock.onGet(COVERAGE_FUZZING_DIFF_ENDPOINT).reply(200, {}); mock.onGet(COVERAGE_FUZZING_DIFF_ENDPOINT).reply(200, {});
createWrapper(allReportProps); createWrapper(allReportProps);
...@@ -212,7 +216,7 @@ describe('Grouped security reports app', () => { ...@@ -212,7 +216,7 @@ describe('Grouped security reports app', () => {
mock.onGet(DEPENDENCY_SCANNING_DIFF_ENDPOINT).reply(200, emptyResponse); mock.onGet(DEPENDENCY_SCANNING_DIFF_ENDPOINT).reply(200, emptyResponse);
mock.onGet(DAST_DIFF_ENDPOINT).reply(200, emptyResponse); mock.onGet(DAST_DIFF_ENDPOINT).reply(200, emptyResponse);
mock.onGet(SAST_DIFF_ENDPOINT).reply(200, emptyResponse); mock.onGet(SAST_DIFF_ENDPOINT).reply(200, emptyResponse);
mock.onGet(SECRET_SCANNING_DIFF_ENDPOINT).reply(200, emptyResponse); mock.onGet(SECRET_DETECTION_DIFF_ENDPOINT).reply(200, emptyResponse);
mock.onGet(COVERAGE_FUZZING_DIFF_ENDPOINT).reply(200, emptyResponse); mock.onGet(COVERAGE_FUZZING_DIFF_ENDPOINT).reply(200, emptyResponse);
createWrapper(allReportProps); createWrapper(allReportProps);
...@@ -222,7 +226,10 @@ describe('Grouped security reports app', () => { ...@@ -222,7 +226,10 @@ describe('Grouped security reports app', () => {
waitForMutation(wrapper.vm.$store, types.RECEIVE_DAST_DIFF_SUCCESS), waitForMutation(wrapper.vm.$store, types.RECEIVE_DAST_DIFF_SUCCESS),
waitForMutation(wrapper.vm.$store, types.RECEIVE_CONTAINER_SCANNING_DIFF_SUCCESS), waitForMutation(wrapper.vm.$store, types.RECEIVE_CONTAINER_SCANNING_DIFF_SUCCESS),
waitForMutation(wrapper.vm.$store, types.RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS), waitForMutation(wrapper.vm.$store, types.RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS),
waitForMutation(wrapper.vm.$store, types.RECEIVE_SECRET_SCANNING_DIFF_SUCCESS), waitForMutation(
wrapper.vm.$store,
`secretDetection/${secretDetectionTypes.RECEIVE_DIFF_SUCCESS}`,
),
waitForMutation(wrapper.vm.$store, types.RECEIVE_COVERAGE_FUZZING_DIFF_SUCCESS), waitForMutation(wrapper.vm.$store, types.RECEIVE_COVERAGE_FUZZING_DIFF_SUCCESS),
]); ]);
}); });
...@@ -262,7 +269,7 @@ describe('Grouped security reports app', () => { ...@@ -262,7 +269,7 @@ describe('Grouped security reports app', () => {
mock.onGet(DEPENDENCY_SCANNING_DIFF_ENDPOINT).reply(200, dependencyScanningDiffSuccessMock); mock.onGet(DEPENDENCY_SCANNING_DIFF_ENDPOINT).reply(200, dependencyScanningDiffSuccessMock);
mock.onGet(DAST_DIFF_ENDPOINT).reply(200, dastDiffSuccessMock); mock.onGet(DAST_DIFF_ENDPOINT).reply(200, dastDiffSuccessMock);
mock.onGet(SAST_DIFF_ENDPOINT).reply(200, sastDiffSuccessMock); mock.onGet(SAST_DIFF_ENDPOINT).reply(200, sastDiffSuccessMock);
mock.onGet(SECRET_SCANNING_DIFF_ENDPOINT).reply(200, secretScanningDiffSuccessMock); mock.onGet(SECRET_DETECTION_DIFF_ENDPOINT).reply(200, secretScanningDiffSuccessMock);
mock.onGet(COVERAGE_FUZZING_DIFF_ENDPOINT).reply(200, coverageFuzzingDiffSuccessMock); mock.onGet(COVERAGE_FUZZING_DIFF_ENDPOINT).reply(200, coverageFuzzingDiffSuccessMock);
createWrapper(allReportProps); createWrapper(allReportProps);
...@@ -272,7 +279,10 @@ describe('Grouped security reports app', () => { ...@@ -272,7 +279,10 @@ describe('Grouped security reports app', () => {
waitForMutation(wrapper.vm.$store, types.RECEIVE_DAST_DIFF_SUCCESS), waitForMutation(wrapper.vm.$store, types.RECEIVE_DAST_DIFF_SUCCESS),
waitForMutation(wrapper.vm.$store, types.RECEIVE_CONTAINER_SCANNING_DIFF_SUCCESS), waitForMutation(wrapper.vm.$store, types.RECEIVE_CONTAINER_SCANNING_DIFF_SUCCESS),
waitForMutation(wrapper.vm.$store, types.RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS), waitForMutation(wrapper.vm.$store, types.RECEIVE_DEPENDENCY_SCANNING_DIFF_SUCCESS),
waitForMutation(wrapper.vm.$store, types.RECEIVE_SECRET_SCANNING_DIFF_SUCCESS), waitForMutation(
wrapper.vm.$store,
`secretDetection/${secretDetectionTypes.RECEIVE_DIFF_SUCCESS}`,
),
waitForMutation(wrapper.vm.$store, types.RECEIVE_COVERAGE_FUZZING_DIFF_SUCCESS), waitForMutation(wrapper.vm.$store, types.RECEIVE_COVERAGE_FUZZING_DIFF_SUCCESS),
]); ]);
}); });
...@@ -553,9 +563,9 @@ describe('Grouped security reports app', () => { ...@@ -553,9 +563,9 @@ describe('Grouped security reports app', () => {
describe('secret scanning reports', () => { describe('secret scanning reports', () => {
const initSecretScan = (isEnabled = true) => { const initSecretScan = (isEnabled = true) => {
gl.mrWidgetData = gl.mrWidgetData || {}; gl.mrWidgetData = gl.mrWidgetData || {};
gl.mrWidgetData.secret_scanning_comparison_path = SECRET_SCANNING_DIFF_ENDPOINT; gl.mrWidgetData.secret_scanning_comparison_path = SECRET_DETECTION_DIFF_ENDPOINT;
mock.onGet(SECRET_SCANNING_DIFF_ENDPOINT).reply(200, secretScanningDiffSuccessMock); mock.onGet(SECRET_DETECTION_DIFF_ENDPOINT).reply(200, secretScanningDiffSuccessMock);
createWrapper({ createWrapper({
...props, ...props,
...@@ -564,7 +574,10 @@ describe('Grouped security reports app', () => { ...@@ -564,7 +574,10 @@ describe('Grouped security reports app', () => {
}, },
}); });
return waitForMutation(wrapper.vm.$store, types.RECEIVE_SECRET_SCANNING_DIFF_SUCCESS); return waitForMutation(
wrapper.vm.$store,
`secretDetection/${secretDetectionTypes.RECEIVE_DIFF_SUCCESS}`,
);
}; };
describe('enabled', () => { describe('enabled', () => {
...@@ -576,8 +589,10 @@ describe('Grouped security reports app', () => { ...@@ -576,8 +589,10 @@ describe('Grouped security reports app', () => {
expect(wrapper.find('[data-qa-selector="secret_scan_report"]').exists()).toBe(true); expect(wrapper.find('[data-qa-selector="secret_scan_report"]').exists()).toBe(true);
}); });
it('should set setSecretScanningDiffEndpoint', () => { it('should set diffEndpoint', () => {
expect(wrapper.vm.secretScanning.paths.diffEndpoint).toEqual(SECRET_SCANNING_DIFF_ENDPOINT); expect(wrapper.vm.secretDetection.paths.diffEndpoint).toEqual(
SECRET_DETECTION_DIFF_ENDPOINT,
);
}); });
it('should display the correct numbers of vulnerabilities', () => { it('should display the correct numbers of vulnerabilities', () => {
......
...@@ -277,31 +277,6 @@ export const containerScanningFeedbacks = [ ...@@ -277,31 +277,6 @@ export const containerScanningFeedbacks = [
}, },
]; ];
export const secretScanningFeedbacks = [
{
id: 3,
project_id: 17,
author_id: 1,
issue_iid: null,
pipeline_id: 132,
category: 'secret_detection',
feedback_type: 'dismissal',
branch: 'try_new_secret_scanning',
project_fingerprint: libTiffCveFingerprint2,
},
{
id: 4,
project_id: 17,
author_id: 1,
issue_iid: 123,
pipeline_id: 132,
category: 'secret_detection',
feedback_type: 'issue',
branch: 'try_new_secret_scanning',
project_fingerprint: libTiffCveFingerprint2,
},
];
export const coverageFuzzingFeedbacks = [ export const coverageFuzzingFeedbacks = [
{ {
id: 3, id: 3,
......
...@@ -29,7 +29,6 @@ import { ...@@ -29,7 +29,6 @@ import {
updateDependencyScanningIssue, updateDependencyScanningIssue,
updateContainerScanningIssue, updateContainerScanningIssue,
updateDastIssue, updateDastIssue,
updateSecretScanningIssue,
updateCoverageFuzzingIssue, updateCoverageFuzzingIssue,
addDismissalComment, addDismissalComment,
receiveAddDismissalCommentError, receiveAddDismissalCommentError,
...@@ -53,10 +52,6 @@ import { ...@@ -53,10 +52,6 @@ import {
receiveDastDiffSuccess, receiveDastDiffSuccess,
receiveDastDiffError, receiveDastDiffError,
fetchDastDiff, fetchDastDiff,
setSecretScanningDiffEndpoint,
receiveSecretScanningDiffSuccess,
receiveSecretScanningDiffError,
fetchSecretScanningDiff,
setCoverageFuzzingDiffEndpoint, setCoverageFuzzingDiffEndpoint,
receiveCoverageFuzzingDiffSuccess, receiveCoverageFuzzingDiffSuccess,
receiveCoverageFuzzingDiffError, receiveCoverageFuzzingDiffError,
...@@ -70,7 +65,6 @@ import { ...@@ -70,7 +65,6 @@ import {
dastFeedbacks, dastFeedbacks,
containerScanningFeedbacks, containerScanningFeedbacks,
dependencyScanningFeedbacks, dependencyScanningFeedbacks,
secretScanningFeedbacks,
coverageFuzzingFeedbacks, coverageFuzzingFeedbacks,
} from '../mock_data'; } from '../mock_data';
import toasted from '~/vue_shared/plugins/global_toast'; import toasted from '~/vue_shared/plugins/global_toast';
...@@ -1087,26 +1081,6 @@ describe('security reports actions', () => { ...@@ -1087,26 +1081,6 @@ describe('security reports actions', () => {
}); });
}); });
describe('updateSecretScanningIssue', () => {
it('commits update secret scanning issue', done => {
const payload = { foo: 'bar' };
testAction(
updateSecretScanningIssue,
payload,
mockedState,
[
{
type: types.UPDATE_SECRET_SCANNING_ISSUE,
payload,
},
],
[],
done,
);
});
});
describe('updateDastIssue', () => { describe('updateDastIssue', () => {
it('commits update dast issue', done => { it('commits update dast issue', done => {
const payload = { foo: 'bar' }; const payload = { foo: 'bar' };
...@@ -1709,194 +1683,6 @@ describe('security reports actions', () => { ...@@ -1709,194 +1683,6 @@ describe('security reports actions', () => {
}); });
}); });
describe('setSecretScanningDiffEndpoint', () => {
it('should pass down the endpoint to the mutation', done => {
const payload = '/secret_scanning_endpoint.json';
testAction(
setSecretScanningDiffEndpoint,
payload,
mockedState,
[
{
type: types.SET_SECRET_SCANNING_DIFF_ENDPOINT,
payload,
},
],
[],
done,
);
});
});
describe('receiveSecretScanningDiffSuccess', () => {
it('should pass down the response to the mutation', done => {
const payload = { data: 'Effort yields its own rewards.' };
testAction(
receiveSecretScanningDiffSuccess,
payload,
mockedState,
[
{
type: types.RECEIVE_SECRET_SCANNING_DIFF_SUCCESS,
payload,
},
],
[],
done,
);
});
});
describe('receiveSecretScanningDiffError', () => {
it('should commit secret diff error mutation', done => {
testAction(
receiveSecretScanningDiffError,
undefined,
mockedState,
[
{
type: types.RECEIVE_SECRET_SCANNING_DIFF_ERROR,
},
],
[],
done,
);
});
});
describe('fetchSecretScanningDiff', () => {
const diff = { vulnerabilities: [] };
const endpoint = 'secret_scanning_diff.json';
beforeEach(() => {
mockedState.vulnerabilityFeedbackPath = 'vulnerabilities_feedback';
mockedState.canReadVulnerabilityFeedback = true;
mockedState.secretScanning.paths.diffEndpoint = endpoint;
});
describe('on success', () => {
it('should dispatch `receiveSecretScanningDiffSuccess`', done => {
mock.onGet(endpoint).reply(200, diff);
mock
.onGet('vulnerabilities_feedback', {
params: {
category: 'secret_detection',
},
})
.reply(200, secretScanningFeedbacks);
testAction(
fetchSecretScanningDiff,
null,
mockedState,
[],
[
{
type: 'requestSecretScanningDiff',
},
{
type: 'receiveSecretScanningDiffSuccess',
payload: {
diff,
enrichData: secretScanningFeedbacks,
},
},
],
done,
);
});
});
describe('when diff endpoint responds successfully and fetching vulnerability feedback is not authorized', () => {
beforeEach(() => {
mockedState.canReadVulnerabilityFeedback = false;
mock.onGet(endpoint).reply(200, diff);
});
it('should dispatch `secret_scanning`', done => {
testAction(
fetchSecretScanningDiff,
null,
mockedState,
[],
[
{
type: 'requestSecretScanningDiff',
},
{
type: 'receiveSecretScanningDiffSuccess',
payload: {
diff,
enrichData: [],
},
},
],
done,
);
});
});
describe('when vulnerabilities path errors', () => {
it('should dispatch `receiveSecretScanningError`', done => {
mock.onGet(endpoint).reply(500);
mock
.onGet('vulnerabilities_feedback', {
params: {
category: 'secret_scanning',
},
})
.reply(200, secretScanningFeedbacks);
testAction(
fetchSecretScanningDiff,
null,
mockedState,
[],
[
{
type: 'requestSecretScanningDiff',
},
{
type: 'receiveSecretScanningDiffError',
},
],
done,
);
});
});
describe('when feedback path errors', () => {
it('should dispatch `receiveSecretScanningError`', done => {
mock.onGet(endpoint).reply(200, diff);
mock
.onGet('vulnerabilities_feedback', {
params: {
category: 'secret_scanning',
},
})
.reply(500);
testAction(
fetchSecretScanningDiff,
null,
mockedState,
[],
[
{
type: 'requestSecretScanningDiff',
},
{
type: 'receiveSecretScanningDiffError',
},
],
done,
);
});
});
});
describe('setCoverageFuzzingDiffEndpoint', () => { describe('setCoverageFuzzingDiffEndpoint', () => {
it('should pass down the endpoint to the mutation', done => { it('should pass down the endpoint to the mutation', done => {
const payload = '/coverage_fuzzing_endpoint.json'; const payload = '/coverage_fuzzing_endpoint.json';
......
import createState from 'ee/vue_shared/security_reports/store/state'; import createState from 'ee/vue_shared/security_reports/store/state';
import createSastState from 'ee/vue_shared/security_reports/store/modules/sast/state'; import createSastState from 'ee/vue_shared/security_reports/store/modules/sast/state';
import createSecretScanningState from 'ee/vue_shared/security_reports/store/modules/secret_detection/state';
import { groupedTextBuilder } from 'ee/vue_shared/security_reports/store/utils'; import { groupedTextBuilder } from 'ee/vue_shared/security_reports/store/utils';
import { import {
groupedContainerScanningText, groupedContainerScanningText,
groupedDastText, groupedDastText,
groupedDependencyText, groupedDependencyText,
groupedSecretScanningText,
groupedCoverageFuzzingText, groupedCoverageFuzzingText,
groupedSummaryText, groupedSummaryText,
allReportsHaveError, allReportsHaveError,
...@@ -38,11 +38,11 @@ describe('Security reports getters', () => { ...@@ -38,11 +38,11 @@ describe('Security reports getters', () => {
beforeEach(() => { beforeEach(() => {
state = createState(); state = createState();
state.sast = createSastState(); state.sast = createSastState();
state.secretDetection = createSecretScanningState();
}); });
describe.each` describe.each`
name | scanner | getter name | scanner | getter
${'Secret scanning'} | ${'secretScanning'} | ${groupedSecretScanningText}
${'Dependency scanning'} | ${'dependencyScanning'} | ${groupedDependencyText} ${'Dependency scanning'} | ${'dependencyScanning'} | ${groupedDependencyText}
${'Container scanning'} | ${'containerScanning'} | ${groupedContainerScanningText} ${'Container scanning'} | ${'containerScanning'} | ${groupedContainerScanningText}
${'DAST'} | ${'dast'} | ${groupedDastText} ${'DAST'} | ${'dast'} | ${groupedDastText}
...@@ -220,7 +220,7 @@ describe('Security reports getters', () => { ...@@ -220,7 +220,7 @@ describe('Security reports getters', () => {
state.dast.hasError = true; state.dast.hasError = true;
state.containerScanning.hasError = true; state.containerScanning.hasError = true;
state.dependencyScanning.hasError = true; state.dependencyScanning.hasError = true;
state.secretScanning.hasError = true; state.secretDetection.hasError = true;
state.coverageFuzzing.hasError = true; state.coverageFuzzing.hasError = true;
expect(allReportsHaveError(state)).toEqual(true); expect(allReportsHaveError(state)).toEqual(true);
...@@ -234,7 +234,7 @@ describe('Security reports getters', () => { ...@@ -234,7 +234,7 @@ describe('Security reports getters', () => {
state.dast.hasError = false; state.dast.hasError = false;
state.containerScanning.hasError = true; state.containerScanning.hasError = true;
state.dependencyScanning.hasError = true; state.dependencyScanning.hasError = true;
state.secretScanning.hasError = true; state.secretDetection.hasError = true;
expect(allReportsHaveError(state)).toEqual(false); expect(allReportsHaveError(state)).toEqual(false);
}); });
......
import * as types from 'ee/vue_shared/security_reports/store/mutation_types'; import * as types from 'ee/vue_shared/security_reports/store/mutation_types';
import configureMediator from 'ee/vue_shared/security_reports/store/mediator'; import configureMediator, {
updateIssueActionsMap,
} from 'ee/vue_shared/security_reports/store/mediator';
const mockedStore = { const mockedStore = {
dispatch: jest.fn(), dispatch: jest.fn(),
...@@ -17,18 +19,14 @@ describe('security reports mediator', () => { ...@@ -17,18 +19,14 @@ describe('security reports mediator', () => {
describe(types.RECEIVE_DISMISS_VULNERABILITY_SUCCESS, () => { describe(types.RECEIVE_DISMISS_VULNERABILITY_SUCCESS, () => {
const type = types.RECEIVE_DISMISS_VULNERABILITY_SUCCESS; const type = types.RECEIVE_DISMISS_VULNERABILITY_SUCCESS;
it.each` it.each(Object.entries(updateIssueActionsMap).map(entry => entry.reverse()))(
action | category `should trigger %s on when a %s is updated`,
${'sast/updateVulnerability'} | ${'sast'} (action, category) => {
${'updateDastIssue'} | ${'dast'} const payload = { category };
${'updateDependencyScanningIssue'} | ${'dependency_scanning'} mockedStore.commit({ type, payload });
${'updateContainerScanningIssue'} | ${'container_scanning'}
`(`should trigger $action on when a $category is updated`, data => {
const { action, category } = data;
const payload = { category };
mockedStore.commit({ type, payload });
expect(mockedStore.dispatch).toHaveBeenCalledWith(action, payload); expect(mockedStore.dispatch).toHaveBeenCalledWith(action, payload);
}); },
);
}); });
}); });
import { import messages from 'ee/vue_shared/security_reports/store/messages';
SAST_HAS_ERROR,
SAST_IS_LOADING,
} from 'ee/vue_shared/security_reports/store/modules/sast/constants';
import * as getters from 'ee/vue_shared/security_reports/store/modules/sast/getters'; import * as getters from 'ee/vue_shared/security_reports/store/modules/sast/getters';
const createReport = (config = {}) => ({ const createReport = (config = {}) => ({
...@@ -15,14 +12,14 @@ describe('groupedSastText', () => { ...@@ -15,14 +12,14 @@ describe('groupedSastText', () => {
const sast = createReport({ hasError: true }); const sast = createReport({ hasError: true });
const result = getters.groupedSastText(sast); const result = getters.groupedSastText(sast);
expect(result).toStrictEqual({ message: SAST_HAS_ERROR }); expect(result).toStrictEqual({ message: messages.SAST_HAS_ERROR });
}); });
it("should return the loading message if it's still loading", () => { it("should return the loading message if it's still loading", () => {
const sast = createReport({ isLoading: true }); const sast = createReport({ isLoading: true });
const result = getters.groupedSastText(sast); const result = getters.groupedSastText(sast);
expect(result).toStrictEqual({ message: SAST_IS_LOADING }); expect(result).toStrictEqual({ message: messages.SAST_IS_LOADING });
}); });
it('should call groupedTextBuilder if everything is fine', () => { it('should call groupedTextBuilder if everything is fine', () => {
......
import testAction from 'helpers/vuex_action_helper';
import createState from 'ee/vue_shared/security_reports/store/modules/secret_detection/state';
import * as types from 'ee/vue_shared/security_reports/store/modules/secret_detection/mutation_types';
import * as actions from 'ee/vue_shared/security_reports/store/modules/secret_detection/actions';
const issue = {};
let state;
// See also the corresponding CE specs in
// spec/frontend/vue_shared/security_reports/store/modules/secret_detection/actions_spec.js
describe('EE secret detection report actions', () => {
beforeEach(() => {
state = createState();
});
describe('updateVulnerability', () => {
it(`should commit ${types.UPDATE_VULNERABILITY} with the correct response`, done => {
testAction(
actions.updateVulnerability,
issue,
state,
[
{
type: types.UPDATE_VULNERABILITY,
payload: issue,
},
],
[],
done,
);
});
});
});
import messages from 'ee/vue_shared/security_reports/store/messages';
import * as getters from 'ee/vue_shared/security_reports/store/modules/secret_detection/getters';
const createReport = (config = {}) => ({
paths: [],
newIssues: [],
...config,
});
describe('groupedSecretDetectionText', () => {
it("should return the error message if there's an error", () => {
const report = createReport({ hasError: true });
const result = getters.groupedSecretDetectionText(report);
expect(result).toStrictEqual({ message: messages.SECRET_SCANNING_HAS_ERROR });
});
it("should return the loading message if it's still loading", () => {
const report = createReport({ isLoading: true });
const result = getters.groupedSecretDetectionText(report);
expect(result).toStrictEqual({ message: messages.SECRET_SCANNING_IS_LOADING });
});
it('should call groupedTextBuilder if everything is fine', () => {
const report = createReport();
const result = getters.groupedSecretDetectionText(report);
expect(result).toStrictEqual({
countMessage: '',
critical: 0,
high: 0,
message: 'Secret scanning detected %{totalStart}no%{totalEnd} vulnerabilities.',
other: 0,
status: '',
total: 0,
});
});
});
describe('secretDetectionStatusIcon', () => {
it("should return `loading` when we're still loading", () => {
const report = createReport({ isLoading: true });
const result = getters.secretDetectionStatusIcon(report);
expect(result).toBe('loading');
});
it("should return `warning` when there's an issue", () => {
const report = createReport({ hasError: true });
const result = getters.secretDetectionStatusIcon(report);
expect(result).toBe('warning');
});
it('should return `success` when nothing is wrong', () => {
const report = createReport();
const result = getters.secretDetectionStatusIcon(report);
expect(result).toBe('success');
});
});
import * as types from 'ee/vue_shared/security_reports/store/modules/secret_detection/mutation_types';
import createState from 'ee/vue_shared/security_reports/store/modules/secret_detection/state';
import mutations from 'ee/vue_shared/security_reports/store/modules/secret_detection/mutations';
const createIssue = ({ ...config }) => ({ changed: false, ...config });
// See also the corresponding CE specs in
// spec/frontend/vue_shared/security_reports/store/modules/secret_detection/mutations_spec.js
describe('EE secret detection module mutations', () => {
let state;
beforeEach(() => {
state = createState();
});
describe(types.UPDATE_VULNERABILITY, () => {
let newIssue;
let resolvedIssue;
let allIssue;
beforeEach(() => {
newIssue = createIssue({ project_fingerprint: 'new' });
resolvedIssue = createIssue({ project_fingerprint: 'resolved' });
allIssue = createIssue({ project_fingerprint: 'all' });
state.newIssues.push(newIssue);
state.resolvedIssues.push(resolvedIssue);
state.allIssues.push(allIssue);
});
describe('with a `new` issue', () => {
beforeEach(() => {
mutations[types.UPDATE_VULNERABILITY](state, { ...newIssue, changed: true });
});
it('should update the correct issue', () => {
expect(state.newIssues[0].changed).toBe(true);
});
});
describe('with a `resolved` issue', () => {
beforeEach(() => {
mutations[types.UPDATE_VULNERABILITY](state, { ...resolvedIssue, changed: true });
});
it('should update the correct issue', () => {
expect(state.resolvedIssues[0].changed).toBe(true);
});
});
describe('with an `all` issue', () => {
beforeEach(() => {
mutations[types.UPDATE_VULNERABILITY](state, { ...allIssue, changed: true });
});
it('should update the correct issue', () => {
expect(state.allIssues[0].changed).toBe(true);
});
});
describe('with an invalid issue', () => {
beforeEach(() => {
mutations[types.UPDATE_VULNERABILITY](
state,
createIssue({ project_fingerprint: 'invalid', changed: true }),
);
});
it('should ignore the issue', () => {
expect(state.newIssues[0].changed).toBe(false);
expect(state.resolvedIssues[0].changed).toBe(false);
expect(state.allIssues[0].changed).toBe(false);
});
});
});
});
...@@ -89,14 +89,6 @@ describe('EE sast reports mutations', () => { ...@@ -89,14 +89,6 @@ describe('EE sast reports mutations', () => {
}); });
}); });
describe('REQUEST_SECRET_SCANNING_DIFF', () => {
it('should set secret scanning loading flag to true', () => {
mutations[types.REQUEST_SECRET_SCANNING_DIFF](stateCopy);
expect(stateCopy.secretScanning.isLoading).toEqual(true);
});
});
describe('SET_ISSUE_MODAL_DATA', () => { describe('SET_ISSUE_MODAL_DATA', () => {
it('has default data', () => { it('has default data', () => {
expect(stateCopy.modal.vulnerability.isDismissed).toEqual(false); expect(stateCopy.modal.vulnerability.isDismissed).toEqual(false);
...@@ -486,34 +478,6 @@ describe('EE sast reports mutations', () => { ...@@ -486,34 +478,6 @@ describe('EE sast reports mutations', () => {
}); });
}); });
describe('UPDATE_SECRET_SCANNING_ISSUE', () => {
it('updates issue in the new issues list', () => {
stateCopy.secretScanning.newIssues = mockFindings;
stateCopy.secretScanning.resolvedIssues = [];
const updatedIssue = {
...mockFindings[0],
foo: 'bar',
};
mutations[types.UPDATE_SECRET_SCANNING_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.secretScanning.newIssues[0]).toEqual(updatedIssue);
});
it('updates issue in the resolved issues list', () => {
stateCopy.secretScanning.newIssues = [];
stateCopy.secretScanning.resolvedIssues = mockFindings;
const updatedIssue = {
...mockFindings[0],
foo: 'bar',
};
mutations[types.UPDATE_SECRET_SCANNING_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.secretScanning.resolvedIssues[0]).toEqual(updatedIssue);
});
});
describe('SET_CONTAINER_SCANNING_DIFF_ENDPOINT', () => { describe('SET_CONTAINER_SCANNING_DIFF_ENDPOINT', () => {
const endpoint = 'container_scanning_diff_endpoint.json'; const endpoint = 'container_scanning_diff_endpoint.json';
...@@ -743,72 +707,6 @@ describe('EE sast reports mutations', () => { ...@@ -743,72 +707,6 @@ describe('EE sast reports mutations', () => {
}); });
}); });
describe('SET_SECRET_SCANNING_DIFF_ENDPOINT', () => {
const endpoint = 'secret_scanning_diff_endpoint.json';
beforeEach(() => {
mutations[types.SET_SECRET_SCANNING_DIFF_ENDPOINT](stateCopy, endpoint);
});
it('should set the correct endpoint', () => {
expect(stateCopy.secretScanning.paths.diffEndpoint).toEqual(endpoint);
});
});
describe('RECEIVE_SECRET_SCANNING_DIFF_SUCCESS', () => {
const reports = {
diff: {
added: [
{ name: 'added vuln 1', report_type: 'secret_scanning' },
{ name: 'added vuln 2', report_type: 'secret_scanning' },
],
fixed: [{ name: 'fixed vuln 1', report_type: 'secret_scanning' }],
base_report_out_of_date: true,
},
};
beforeEach(() => {
mutations[types.RECEIVE_SECRET_SCANNING_DIFF_SUCCESS](stateCopy, reports);
});
it('should set isLoading to false', () => {
expect(stateCopy.secretScanning.isLoading).toBe(false);
});
it('should set baseReportOutofDate to true', () => {
expect(stateCopy.secretScanning.baseReportOutofDate).toBe(true);
});
it('should parse and set the added vulnerabilities', () => {
reports.diff.added.forEach((vuln, i) => {
expect(stateCopy.secretScanning.newIssues[i]).toMatchObject({
name: vuln.name,
title: vuln.name,
category: vuln.report_type,
});
});
});
it('should parse and set the fixed vulnerabilities', () => {
reports.diff.fixed.forEach((vuln, i) => {
expect(stateCopy.secretScanning.resolvedIssues[i]).toMatchObject({
name: vuln.name,
title: vuln.name,
category: vuln.report_type,
});
});
});
});
describe('RECEIVE_SECRET_SCANNING_DIFF_ERROR', () => {
it('should set secret scanning loading flag to false and error flag to true', () => {
mutations[types.RECEIVE_SECRET_SCANNING_DIFF_ERROR](stateCopy);
expect(stateCopy.secretScanning.isLoading).toEqual(false);
expect(stateCopy.secretScanning.hasError).toEqual(true);
});
});
describe('SET_COVERAGE_FUZZING_DIFF_ENDPOINT', () => { describe('SET_COVERAGE_FUZZING_DIFF_ENDPOINT', () => {
const endpoint = 'coverage_fuzzing_diff_endpoint.json'; const endpoint = 'coverage_fuzzing_diff_endpoint.json';
......
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import createState from '~/vue_shared/security_reports/store/modules/secret_detection/state';
import * as types from '~/vue_shared/security_reports/store/modules/secret_detection/mutation_types';
import * as actions from '~/vue_shared/security_reports/store/modules/secret_detection/actions';
import axios from '~/lib/utils/axios_utils';
const diffEndpoint = 'diff-endpoint.json';
const blobPath = 'blob-path.json';
const reports = {
base: 'base',
head: 'head',
enrichData: 'enrichData',
diff: 'diff',
};
const error = 'Something went wrong';
const vulnerabilityFeedbackPath = 'vulnerability-feedback-path';
const rootState = { vulnerabilityFeedbackPath, blobPath };
let state;
describe('secret detection report actions', () => {
beforeEach(() => {
state = createState();
});
describe('setDiffEndpoint', () => {
it(`should commit ${types.SET_DIFF_ENDPOINT} with the correct path`, done => {
testAction(
actions.setDiffEndpoint,
diffEndpoint,
state,
[
{
type: types.SET_DIFF_ENDPOINT,
payload: diffEndpoint,
},
],
[],
done,
);
});
});
describe('requestDiff', () => {
it(`should commit ${types.REQUEST_DIFF}`, done => {
testAction(actions.requestDiff, {}, state, [{ type: types.REQUEST_DIFF }], [], done);
});
});
describe('receiveDiffSuccess', () => {
it(`should commit ${types.RECEIVE_DIFF_SUCCESS} with the correct response`, done => {
testAction(
actions.receiveDiffSuccess,
reports,
state,
[
{
type: types.RECEIVE_DIFF_SUCCESS,
payload: reports,
},
],
[],
done,
);
});
});
describe('receiveDiffError', () => {
it(`should commit ${types.RECEIVE_DIFF_ERROR} with the correct response`, done => {
testAction(
actions.receiveDiffError,
error,
state,
[
{
type: types.RECEIVE_DIFF_ERROR,
payload: error,
},
],
[],
done,
);
});
});
describe('fetchDiff', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
state.paths.diffEndpoint = diffEndpoint;
rootState.canReadVulnerabilityFeedback = true;
});
afterEach(() => {
mock.restore();
});
describe('when diff and vulnerability feedback endpoints respond successfully', () => {
beforeEach(() => {
mock
.onGet(diffEndpoint)
.replyOnce(200, reports.diff)
.onGet(vulnerabilityFeedbackPath)
.replyOnce(200, reports.enrichData);
});
it('should dispatch the `receiveDiffSuccess` action', done => {
const { diff, enrichData } = reports;
testAction(
actions.fetchDiff,
{},
{ ...rootState, ...state },
[],
[
{ type: 'requestDiff' },
{
type: 'receiveDiffSuccess',
payload: {
diff,
enrichData,
},
},
],
done,
);
});
});
describe('when diff endpoint responds successfully and fetching vulnerability feedback is not authorized', () => {
beforeEach(() => {
rootState.canReadVulnerabilityFeedback = false;
mock.onGet(diffEndpoint).replyOnce(200, reports.diff);
});
it('should dispatch the `receiveDiffSuccess` action with empty enrich data', done => {
const { diff } = reports;
const enrichData = [];
testAction(
actions.fetchDiff,
{},
{ ...rootState, ...state },
[],
[
{ type: 'requestDiff' },
{
type: 'receiveDiffSuccess',
payload: {
diff,
enrichData,
},
},
],
done,
);
});
});
describe('when the vulnerability feedback endpoint fails', () => {
beforeEach(() => {
mock
.onGet(diffEndpoint)
.replyOnce(200, reports.diff)
.onGet(vulnerabilityFeedbackPath)
.replyOnce(404);
});
it('should dispatch the `receiveDiffError` action', done => {
testAction(
actions.fetchDiff,
{},
{ ...rootState, ...state },
[],
[{ type: 'requestDiff' }, { type: 'receiveDiffError' }],
done,
);
});
});
describe('when the diff endpoint fails', () => {
beforeEach(() => {
mock
.onGet(diffEndpoint)
.replyOnce(404)
.onGet(vulnerabilityFeedbackPath)
.replyOnce(200, reports.enrichData);
});
it('should dispatch the `receiveDiffError` action', done => {
testAction(
actions.fetchDiff,
{},
{ ...rootState, ...state },
[],
[{ type: 'requestDiff' }, { type: 'receiveDiffError' }],
done,
);
});
});
});
});
import * as types from '~/vue_shared/security_reports/store/modules/secret_detection/mutation_types';
import createState from '~/vue_shared/security_reports/store/modules/secret_detection/state';
import mutations from '~/vue_shared/security_reports/store/modules/secret_detection/mutations';
const createIssue = ({ ...config }) => ({ changed: false, ...config });
describe('secret detection module mutations', () => {
const path = 'path';
let state;
beforeEach(() => {
state = createState();
});
describe(types.SET_DIFF_ENDPOINT, () => {
it('should set the secret detection diff endpoint', () => {
mutations[types.SET_DIFF_ENDPOINT](state, path);
expect(state.paths.diffEndpoint).toBe(path);
});
});
describe(types.REQUEST_DIFF, () => {
it('should set the `isLoading` status to `true`', () => {
mutations[types.REQUEST_DIFF](state);
expect(state.isLoading).toBe(true);
});
});
describe(types.RECEIVE_DIFF_SUCCESS, () => {
beforeEach(() => {
const reports = {
diff: {
added: [
createIssue({ cve: 'CVE-1' }),
createIssue({ cve: 'CVE-2' }),
createIssue({ cve: 'CVE-3' }),
],
fixed: [createIssue({ cve: 'CVE-4' }), createIssue({ cve: 'CVE-5' })],
existing: [createIssue({ cve: 'CVE-6' })],
base_report_out_of_date: true,
},
};
state.isLoading = true;
mutations[types.RECEIVE_DIFF_SUCCESS](state, reports);
});
it('should set the `isLoading` status to `false`', () => {
expect(state.isLoading).toBe(false);
});
it('should set the `baseReportOutofDate` status to `true`', () => {
expect(state.baseReportOutofDate).toBe(true);
});
it('should have the relevant `new` issues', () => {
expect(state.newIssues).toHaveLength(3);
});
it('should have the relevant `resolved` issues', () => {
expect(state.resolvedIssues).toHaveLength(2);
});
it('should have the relevant `all` issues', () => {
expect(state.allIssues).toHaveLength(1);
});
});
describe(types.RECEIVE_DIFF_ERROR, () => {
beforeEach(() => {
state.isLoading = true;
mutations[types.RECEIVE_DIFF_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);
});
});
});
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