Commit f6f4d8b4 authored by Paul Gascou-Vaillancourt's avatar Paul Gascou-Vaillancourt Committed by Nicolò Maria Mezzopera

Create auto-fix user callout

Created the auto-fix user callout that shows up in the project security
dashboard (unless previously dismissed).
parent a4f227d0
<script>
import { GlBanner } from '@gitlab/ui';
export default {
name: 'AutoFixUserCallout',
components: {
GlBanner,
},
props: {
helpPagePath: {
type: String,
required: true,
},
},
};
</script>
<template>
<gl-banner
:title="s__('AutoRemediation|Introducing GitLab auto-fix')"
:button-text="__('Learn more')"
:button-link="helpPagePath"
variant="introduction"
v-on="$listeners"
>
<p>
{{
s__(
"AutoRemediation|If you're using dependency and/or container scanning, and auto-fix is enabled, auto-fix automatically creates merge requests with fixes to vulnerabilities.",
)
}}
</p>
</gl-banner>
</template>
<script>
import Cookies from 'js-cookie';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import AutoFixUserCallout from './auto_fix_user_callout.vue';
import ProjectVulnerabilitiesApp from './project_vulnerabilities.vue';
import ReportsNotConfigured from './empty_states/reports_not_configured.vue';
import SecurityDashboardLayout from './security_dashboard_layout.vue';
......@@ -10,6 +13,7 @@ export const BANNER_COOKIE_KEY = 'hide_vulnerabilities_introduction_banner';
export default {
components: {
AutoFixUserCallout,
ProjectVulnerabilitiesApp,
ReportsNotConfigured,
SecurityDashboardLayout,
......@@ -17,6 +21,7 @@ export default {
CsvExportButton,
Filters,
},
mixins: [glFeatureFlagsMixin()],
props: {
securityDashboardHelpPath: {
type: String,
......@@ -39,15 +44,22 @@ export default {
},
},
data() {
const shoudShowAutoFixUserCallout =
this.glFeatures.securityAutoFix && !Cookies.get('auto_fix_user_callout_dismissed');
return {
filters: {},
shoudShowAutoFixUserCallout,
};
},
inject: ['dashboardDocumentation'],
inject: ['dashboardDocumentation', 'autoFixDocumentation'],
methods: {
handleFilterChange(filters) {
this.filters = filters;
},
handleAutoFixUserCalloutClose() {
Cookies.set('auto_fix_user_callout_dismissed', 'true');
this.shoudShowAutoFixUserCallout = false;
},
},
};
</script>
......@@ -55,6 +67,11 @@ export default {
<template>
<div>
<template v-if="hasVulnerabilities">
<auto-fix-user-callout
v-if="shoudShowAutoFixUserCallout"
:help-page-path="autoFixDocumentation"
@close="handleAutoFixUserCalloutClose"
/>
<security-dashboard-layout>
<template #header>
<div class="mt-4 d-flex">
......
......@@ -42,6 +42,7 @@ export default (el, dashboardType) => {
if (dashboardType === DASHBOARD_TYPES.PROJECT) {
component = FirstClassProjectSecurityDashboard;
props.projectFullPath = el.dataset.projectFullPath;
provide.autoFixDocumentation = el.dataset.autoFixDocumentation;
} else if (dashboardType === DASHBOARD_TYPES.GROUP) {
component = FirstClassGroupSecurityDashboard;
props.groupFullPath = el.dataset.groupFullPath;
......
......@@ -6,6 +6,10 @@ module Projects
include SecurityDashboardsPermissions
alias_method :vulnerable, :project
before_action only: [:index] do
push_frontend_feature_flag(:security_auto_fix, project, default_enabled: false)
end
end
end
end
......@@ -231,7 +231,8 @@ module EE
dashboard_documentation: help_page_path('user/application_security/security_dashboard/index'),
not_enabled_scanners_help_path: help_page_path('user/application_security/index', anchor: 'quick-start'),
no_pipeline_run_scanners_help_path: new_project_pipeline_path(project),
security_dashboard_help_path: help_page_path('user/application_security/security_dashboard/index')
security_dashboard_help_path: help_page_path('user/application_security/security_dashboard/index'),
auto_fix_documentation: help_page_path('user/application_security/index', anchor: 'auto-fix-merge-requests')
}.merge!(security_dashboard_pipeline_data(project))
end
end
......
import { shallowMount } from '@vue/test-utils';
import { GlBanner } from '@gitlab/ui';
import AutoFixUserCallout from 'ee/security_dashboard/components/auto_fix_user_callout.vue';
describe('AutoFixUserCallout', () => {
let wrapper;
const helpPagePath = '/help/page/path';
const createWrapper = () => {
wrapper = shallowMount(AutoFixUserCallout, {
propsData: {
helpPagePath,
},
});
};
it('renders properly', () => {
createWrapper();
expect(wrapper.find(GlBanner).exists()).toBe(true);
expect(wrapper.find(GlBanner).props()).toMatchObject({
title: 'Introducing GitLab auto-fix',
buttonText: 'Learn more',
buttonLink: helpPagePath,
});
expect(wrapper.text()).toContain(
"If you're using dependency and/or container scanning, and auto-fix is enabled, auto-fix automatically creates merge requests with fixes to vulnerabilities.",
);
});
});
import { shallowMount } from '@vue/test-utils';
import { GlBanner } from '@gitlab/ui';
import Cookies from 'js-cookie';
import FirstClassProjectSecurityDashboard from 'ee/security_dashboard/components/first_class_project_security_dashboard.vue';
import AutoFixUserCallout from 'ee/security_dashboard/components/auto_fix_user_callout.vue';
import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue';
import SecurityDashboardLayout from 'ee/security_dashboard/components/security_dashboard_layout.vue';
import ProjectVulnerabilitiesApp from 'ee/security_dashboard/components/project_vulnerabilities.vue';
......@@ -18,7 +20,11 @@ const props = {
const provide = {
dashboardDocumentation: '/help/docs',
autoFixDocumentation: '/auto/fix/documentation',
emptyStateSvgPath: '/svgs/empty/svg',
glFeatures: {
securityAutoFix: true,
},
};
const filters = { foo: 'bar' };
......@@ -31,6 +37,7 @@ describe('First class Project Security Dashboard component', () => {
const findVulnerabilityCountList = () => wrapper.find(VulnerabilityCountList);
const findUnconfiguredState = () => wrapper.find(ReportsNotConfigured);
const findCsvExportButton = () => wrapper.find(CsvExportButton);
const findAutoFixUserCallout = () => wrapper.find(AutoFixUserCallout);
const createComponent = options => {
wrapper = shallowMount(FirstClassProjectSecurityDashboard, {
......@@ -90,6 +97,61 @@ describe('First class Project Security Dashboard component', () => {
});
});
describe('auto-fix user callout', () => {
describe('feature flag disabled', () => {
beforeEach(() => {
createComponent({
props: { hasVulnerabilities: true },
provide: {
...provide,
glFeatures: {
securityAutoFix: false,
},
},
});
});
it('does not show user callout', () => {
expect(findAutoFixUserCallout().exists()).toBe(false);
});
});
describe('cookie not set', () => {
beforeEach(() => {
jest.spyOn(Cookies, 'set');
createComponent({
props: { hasVulnerabilities: true },
});
});
it('shows user callout by default', () => {
expect(findAutoFixUserCallout().exists()).toBe(true);
});
it('when dismissed, hides the user callout and sets the cookie', async () => {
await findAutoFixUserCallout().vm.$emit('close');
expect(findAutoFixUserCallout().exists()).toBe(false);
expect(Cookies.set).toHaveBeenCalledWith('auto_fix_user_callout_dismissed', 'true');
});
});
describe('cookie set', () => {
beforeEach(() => {
jest.doMock('js-cookie', () => ({
get: jest.fn().mockReturnValue(true),
}));
createComponent({
props: { hasVulnerabilities: true },
});
});
it('does not show user callout', () => {
expect(findAutoFixUserCallout().exists()).toBe(false);
});
});
});
describe('with filter data', () => {
beforeEach(() => {
createComponent({
......
......@@ -154,7 +154,8 @@ RSpec.describe ProjectsHelper do
dashboard_documentation: '/help/user/application_security/security_dashboard/index',
security_dashboard_help_path: '/help/user/application_security/security_dashboard/index',
not_enabled_scanners_help_path: help_page_path('user/application_security/index', anchor: 'quick-start'),
no_pipeline_run_scanners_help_path: "/#{project.full_path}/-/pipelines/new"
no_pipeline_run_scanners_help_path: "/#{project.full_path}/-/pipelines/new",
auto_fix_documentation: help_page_path('user/application_security/index', anchor: 'auto-fix-merge-requests')
}
end
......
......@@ -3813,6 +3813,12 @@ msgstr ""
msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found. %{more_information_link}"
msgstr ""
msgid "AutoRemediation|If you're using dependency and/or container scanning, and auto-fix is enabled, auto-fix automatically creates merge requests with fixes to vulnerabilities."
msgstr ""
msgid "AutoRemediation|Introducing GitLab auto-fix"
msgstr ""
msgid "Autocomplete"
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment