Commit 58b82adb authored by Mark Florian's avatar Mark Florian Committed by Olena Horal-Koretska

Show CE security MR widget for non-Ultimate users

This makes the CE security MR widget visible for Starter and Premium
users, and also Free tier users on `.com`.

Addresses https://gitlab.com/gitlab-org/gitlab/-/issues/273205, part of
https://gitlab.com/groups/gitlab-org/-/epics/4394.
parent f1bdac24
...@@ -129,7 +129,7 @@ class MergeRequestWidgetEntity < Grape::Entity ...@@ -129,7 +129,7 @@ class MergeRequestWidgetEntity < Grape::Entity
end end
expose :security_reports_docs_path do |merge_request| expose :security_reports_docs_path do |merge_request|
help_page_path('user/application_security/sast/index.md', anchor: 'reports-json-format') help_page_path('user/application_security/index.md', anchor: 'viewing-security-scan-information-in-merge-requests')
end end
private private
......
...@@ -123,6 +123,24 @@ latest versions of the scanning tools without having to do anything. There are s ...@@ -123,6 +123,24 @@ latest versions of the scanning tools without having to do anything. There are s
with this approach, however, and there is a with this approach, however, and there is a
[plan to resolve them](https://gitlab.com/gitlab-org/gitlab/-/issues/9725). [plan to resolve them](https://gitlab.com/gitlab-org/gitlab/-/issues/9725).
## Viewing security scan information in merge requests **(CORE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4393) in GitLab Core 13.5.
> - Made [available in all tiers](https://gitlab.com/gitlab-org/gitlab/-/issues/273205) in 13.6.
> - It's [deployed behind a feature flag](../feature_flags.md), enabled by default.
> - It's enabled on GitLab.com.
> - It can be enabled or disabled for a single project.
> - It's recommended for production use.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-the-basic-security-widget). **(CORE ONLY)**
CAUTION: **Warning:**
This feature might not be available to you. Check the **version history** note above for details.
Merge requests which have run security scans let you know that the generated
reports are available to download.
![Security widget](img/security_widget_v13_6.png)
## Interacting with the vulnerabilities ## Interacting with the vulnerabilities
> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.8. > Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.8.
...@@ -594,3 +612,28 @@ Analyzer results are displayed in the [job logs](../../ci/pipelines/#expand-and- ...@@ -594,3 +612,28 @@ Analyzer results are displayed in the [job logs](../../ci/pipelines/#expand-and-
[Merge Request widget](sast/index.md#overview) [Merge Request widget](sast/index.md#overview)
or [Security Dashboard](security_dashboard/index.md). or [Security Dashboard](security_dashboard/index.md).
There is [an open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/235772) in which changes to this behavior are being discussed. There is [an open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/235772) in which changes to this behavior are being discussed.
### Enable or disable the basic security widget **(CORE ONLY)**
The basic security widget is under development but ready for production use.
It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../feature_flags.md)
can opt to disable it.
To enable it:
```ruby
# For the instance
Feature.enable(:core_security_mr_widget)
# For a single project
Feature.enable(:core_security_mr_widget, Project.find(<project id>))
```
To disable it:
```ruby
# For the instance
Feature.disable(:core_security_mr_widget)
# For a single project
Feature.disable(:core_security_mr_widget, Project.find(<project id>))
```
<script> <script>
import GroupedSecurityReportsApp from 'ee/vue_shared/security_reports/grouped_security_reports_app.vue';
import GroupedMetricsReportsApp from 'ee/vue_shared/metrics_reports/grouped_metrics_reports_app.vue'; import GroupedMetricsReportsApp from 'ee/vue_shared/metrics_reports/grouped_metrics_reports_app.vue';
import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin'; import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin';
import { componentNames } from 'ee/reports/components/issue_body'; import { componentNames } from 'ee/reports/components/issue_body';
...@@ -22,7 +21,8 @@ export default { ...@@ -22,7 +21,8 @@ export default {
MrWidgetGeoSecondaryNode, MrWidgetGeoSecondaryNode,
MrWidgetPolicyViolation, MrWidgetPolicyViolation,
BlockingMergeRequestsReport, BlockingMergeRequestsReport,
GroupedSecurityReportsApp, GroupedSecurityReportsApp: () =>
import('ee/vue_shared/security_reports/grouped_security_reports_app.vue'),
GroupedMetricsReportsApp, GroupedMetricsReportsApp,
ReportSection, ReportSection,
}, },
...@@ -88,9 +88,13 @@ export default { ...@@ -88,9 +88,13 @@ export default {
return Boolean(loadPerformance.head_path && loadPerformance.base_path); return Boolean(loadPerformance.head_path && loadPerformance.base_path);
}, },
shouldRenderSecurityReport() { shouldRenderBaseSecurityReport() {
return !this.mr.canReadVulnerabilities && this.shouldRenderSecurityReport;
},
shouldRenderExtendedSecurityReport() {
const { enabledReports } = this.mr; const { enabledReports } = this.mr;
return ( return (
this.mr.canReadVulnerabilities &&
enabledReports && enabledReports &&
this.$options.securityReportTypes.some(reportType => enabledReports[reportType]) this.$options.securityReportTypes.some(reportType => enabledReports[reportType])
); );
...@@ -306,8 +310,15 @@ export default { ...@@ -306,8 +310,15 @@ export default {
:endpoint="mr.metricsReportsPath" :endpoint="mr.metricsReportsPath"
class="js-metrics-reports-container" class="js-metrics-reports-container"
/> />
<security-reports-app
v-if="shouldRenderBaseSecurityReport"
:pipeline-id="mr.pipeline.id"
:project-id="mr.targetProjectId"
:security-reports-docs-path="mr.securityReportsDocsPath"
/>
<grouped-security-reports-app <grouped-security-reports-app
v-if="shouldRenderSecurityReport" v-else-if="shouldRenderExtendedSecurityReport"
:head-blob-path="mr.headBlobPath" :head-blob-path="mr.headBlobPath"
:source-branch="mr.sourceBranch" :source-branch="mr.sourceBranch"
:target-branch="mr.targetBranch" :target-branch="mr.targetBranch"
......
...@@ -13,6 +13,7 @@ export default class MergeRequestStore extends CEMergeRequestStore { ...@@ -13,6 +13,7 @@ export default class MergeRequestStore extends CEMergeRequestStore {
this.coverageFuzzingHelp = data.coverage_fuzzing_help_path; this.coverageFuzzingHelp = data.coverage_fuzzing_help_path;
this.secretScanningHelp = data.secret_scanning_help_path; this.secretScanningHelp = data.secret_scanning_help_path;
this.dependencyScanningHelp = data.dependency_scanning_help_path; this.dependencyScanningHelp = data.dependency_scanning_help_path;
this.canReadVulnerabilities = data.can_read_vulnerabilities;
this.vulnerabilityFeedbackPath = data.vulnerability_feedback_path; this.vulnerabilityFeedbackPath = data.vulnerability_feedback_path;
this.canReadVulnerabilityFeedback = data.can_read_vulnerability_feedback; this.canReadVulnerabilityFeedback = data.can_read_vulnerability_feedback;
this.vulnerabilityFeedbackHelpPath = data.vulnerability_feedback_help_path; this.vulnerabilityFeedbackHelpPath = data.vulnerability_feedback_help_path;
......
...@@ -65,6 +65,10 @@ module EE ...@@ -65,6 +65,10 @@ module EE
merge_request.head_pipeline.iid merge_request.head_pipeline.iid
end end
expose :can_read_vulnerabilities do |merge_request|
can?(current_user, :read_vulnerability, merge_request.project)
end
expose :can_read_vulnerability_feedback do |merge_request| expose :can_read_vulnerability_feedback do |merge_request|
can?(current_user, :read_vulnerability_feedback, merge_request.project) can?(current_user, :read_vulnerability_feedback, merge_request.project)
end end
......
---
title: Show basic security scan information in merge requests for non-Ultimate users
merge_request: 46458
author:
type: added
...@@ -2,6 +2,7 @@ import mockData, { mockStore } from 'jest/vue_mr_widget/mock_data'; ...@@ -2,6 +2,7 @@ import mockData, { mockStore } from 'jest/vue_mr_widget/mock_data';
export default { export default {
...mockData, ...mockData,
can_read_vulnerabilities: true,
vulnerability_feedback_help_path: '/help/user/application_security/index', vulnerability_feedback_help_path: '/help/user/application_security/index',
enabled_reports: { enabled_reports: {
sast: false, sast: false,
...@@ -126,3 +127,14 @@ export const codequalityParsedIssues = [ ...@@ -126,3 +127,14 @@ export const codequalityParsedIssues = [
]; ];
export { mockStore }; export { mockStore };
// TODO: Remove as part of https://gitlab.com/gitlab-org/gitlab/-/issues/249544
export const pipelineJobs = [
{
artifacts: [
{
file_type: 'sast',
},
],
},
];
...@@ -246,6 +246,28 @@ RSpec.describe MergeRequestWidgetEntity do ...@@ -246,6 +246,28 @@ RSpec.describe MergeRequestWidgetEntity do
expect(subject.as_json).to include(:create_vulnerability_feedback_dismissal_path) expect(subject.as_json).to include(:create_vulnerability_feedback_dismissal_path)
end end
describe '#can_read_vulnerabilities' do
context 'when security dashboard feature is available' do
before do
stub_licensed_features(security_dashboard: true)
end
it 'is set to true' do
expect(subject.as_json[:can_read_vulnerabilities]).to eq(true)
end
end
context 'when security dashboard feature is not available' do
before do
stub_licensed_features(security_dashboard: false)
end
it 'is set to false' do
expect(subject.as_json[:can_read_vulnerabilities]).to eq(false)
end
end
end
describe '#can_read_vulnerability_feedback' do describe '#can_read_vulnerability_feedback' do
context 'when user has permissions to read vulnerability feedback' do context 'when user has permissions to read vulnerability feedback' do
before do before do
......
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