Skip to content
代码片段 群组 项目
未验证 提交 32f964ed 编辑于 作者: Savas Vedova's avatar Savas Vedova 提交者: GitLab
浏览文件

Merge branch '482900-display-badge-on-ai-resolvable-items-within-the-mr-report' into 'master'

Resolve "Display badge on AI-resolvable items within the MR report"

See merge request https://gitlab.com/gitlab-org/gitlab/-/merge_requests/168242



Merged-by: default avatarSavas Vedova <svedova@gitlab.com>
Approved-by: default avatarSamantha Ming <sming@gitlab.com>
Approved-by: default avatarSavas Vedova <svedova@gitlab.com>
Co-authored-by: default avatarDave Pisek <dpisek@gitlab.com>
No related branches found
No related tags found
无相关合并请求
<script> <script>
import { GlBadge, GlButton } from '@gitlab/ui'; import { GlBadge, GlButton, GlIcon } from '@gitlab/ui';
import { SEVERITY_LEVELS } from 'ee/security_dashboard/store/constants'; import { SEVERITY_LEVELS } from 'ee/security_dashboard/store/constants';
import MrWidget from '~/vue_merge_request_widget/components/widget/widget.vue'; import MrWidget from '~/vue_merge_request_widget/components/widget/widget.vue';
import MrWidgetRow from '~/vue_merge_request_widget/components/widget/widget_content_row.vue'; import MrWidgetRow from '~/vue_merge_request_widget/components/widget/widget_content_row.vue';
...@@ -7,6 +7,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -7,6 +7,7 @@ import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import SummaryHighlights from 'ee/vue_shared/security_reports/components/summary_highlights.vue'; import SummaryHighlights from 'ee/vue_shared/security_reports/components/summary_highlights.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import glAbilitiesMixin from '~/vue_shared/mixins/gl_abilities_mixin';
import { EXTENSION_ICONS } from '~/vue_merge_request_widget/constants'; import { EXTENSION_ICONS } from '~/vue_merge_request_widget/constants';
import { capitalizeFirstCharacter, convertToCamelCase } from '~/lib/utils/text_utility'; import { capitalizeFirstCharacter, convertToCamelCase } from '~/lib/utils/text_utility';
import { helpPagePath } from '~/helpers/help_page_helper'; import { helpPagePath } from '~/helpers/help_page_helper';
...@@ -28,10 +29,11 @@ export default { ...@@ -28,10 +29,11 @@ export default {
SecurityTrainingPromoWidget, SecurityTrainingPromoWidget,
GlBadge, GlBadge,
GlButton, GlButton,
GlIcon,
DynamicScroller, DynamicScroller,
DynamicScrollerItem, DynamicScrollerItem,
}, },
mixins: [glFeatureFlagMixin()], mixins: [glAbilitiesMixin(), glFeatureFlagMixin()],
i18n, i18n,
props: { props: {
mr: { mr: {
...@@ -317,6 +319,14 @@ export default { ...@@ -317,6 +319,14 @@ export default {
clearModalData() { clearModalData() {
this.modalData = null; this.modalData = null;
}, },
isAiResolvable(vuln) {
return (
vuln.ai_resolution_enabled &&
this.glFeatures.resolveVulnerabilityInMr &&
this.glAbilities.resolveVulnerabilityWithAi
);
},
}, },
SEVERITY_LEVELS, SEVERITY_LEVELS,
widgetHelpPopover: { widgetHelpPopover: {
...@@ -452,6 +462,14 @@ export default { ...@@ -452,6 +462,14 @@ export default {
<gl-badge v-if="isDismissed(vuln)" class="gl-ml-3">{{ <gl-badge v-if="isDismissed(vuln)" class="gl-ml-3">{{
$options.i18n.dismissed $options.i18n.dismissed
}}</gl-badge> }}</gl-badge>
<gl-badge
v-if="isAiResolvable(vuln)"
variant="info"
class="gl-ml-3"
data-testid="ai-resolvable-badge"
>
<gl-icon :size="12" name="tanuki-ai" />
</gl-badge>
</template> </template>
</mr-widget-row> </mr-widget-row>
</dynamic-scroller-item> </dynamic-scroller-item>
......
...@@ -275,6 +275,84 @@ describe('MR Widget Security Reports', () => { ...@@ -275,6 +275,84 @@ describe('MR Widget Security Reports', () => {
expect(findDismissedBadge().text()).toBe('Dismissed'); expect(findDismissedBadge().text()).toBe('Dismissed');
}); });
it.each`
resolveVulnerabilityWithAi | aiResolutionEnabled | shouldShowAiBadge
${true} | ${true} | ${true}
${false} | ${true} | ${false}
${true} | ${false} | ${false}
`(
'with the resolveVulnerabilityWithAi ability set to "$resolveVulnerabilityWithAi" and the vulnerability has ai_resolution_enabled set to "$aiResolutionEnabled" it should show the AI-Badge: "$shouldShowAiBadge"',
async ({ resolveVulnerabilityWithAi, aiResolutionEnabled, shouldShowAiBadge }) => {
await createComponentAndExpandWidget({
mockDataFn: () =>
mockWithData({
findings: {
sast: {
added: [
{
uuid: '1',
severity: 'critical',
name: 'Password leak',
state: 'dismissed',
ai_resolution_enabled: aiResolutionEnabled,
},
],
},
},
}),
provide: {
glAbilities: {
resolveVulnerabilityWithAi,
},
glFeatures: {
resolveVulnerabilityInMr: true,
},
},
});
expect(wrapper.findByTestId('ai-resolvable-badge').exists()).toBe(shouldShowAiBadge);
},
);
it.each`
resolveVulnerabilityWithAi | aiResolutionEnabled
${true} | ${true}
${false} | ${true}
${true} | ${false}
`(
'with the "resolveVulnerabilityInMr" feature flag set to "false" it should never show the AI-Badge',
async ({ resolveVulnerabilityWithAi, aiResolutionEnabled }) => {
await createComponentAndExpandWidget({
mockDataFn: () =>
mockWithData({
findings: {
sast: {
added: [
{
uuid: '1',
severity: 'critical',
name: 'Password leak',
state: 'dismissed',
ai_resolution_enabled: aiResolutionEnabled,
},
],
},
},
}),
provide: {
glAbilities: {
resolveVulnerabilityWithAi,
},
glFeatures: {
resolveVulnerabilityInMr: false,
},
},
});
expect(wrapper.findByTestId('ai-resolvable-badge').exists()).toBe(false);
},
);
it('should mount the widget component', async () => { it('should mount the widget component', async () => {
await createComponentWithData(); await createComponentWithData();
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册