Commit 788e009d authored by Vitaly Slobodin's avatar Vitaly Slobodin

Merge branch '230581-license-compliance-disable-inline-editing' into 'master'

Disable inline editing of license compliance approval

See merge request gitlab-org/gitlab!43470
parents e7650bc4 7dfae341
...@@ -37,10 +37,7 @@ compliance report will be shown properly. ...@@ -37,10 +37,7 @@ compliance report will be shown properly.
![License Compliance Widget](img/license_compliance_v13_0.png) ![License Compliance Widget](img/license_compliance_v13_0.png)
If you are a project or group Maintainer, you can click on a license to be given You can click on a license to see more information.
the choice to allow it or deny it.
![License approval decision](img/license_compliance_decision_v13_0.png)
When GitLab detects a **Denied** license, you can view it in the [license list](#license-list). When GitLab detects a **Denied** license, you can view it in the [license list](#license-list).
......
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import { GlLink } from '@gitlab/ui';
import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants'; import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants';
import LicensePackages from './license_packages.vue'; import LicensePackages from './license_packages.vue';
export default { export default {
name: 'LicenseIssueBody', name: 'LicenseIssueBody',
components: { LicensePackages }, components: { LicensePackages, GlLink },
props: { props: {
issue: { issue: {
type: Object, type: Object,
...@@ -19,15 +20,7 @@ export default { ...@@ -19,15 +20,7 @@ export default {
<template> <template>
<div class="report-block-info license-item"> <div class="report-block-info license-item">
<button <gl-link :href="issue.url" target="_blank">{{ issue.name }}</gl-link>
class="btn-blank btn-link gl-mr-2"
type="button"
data-toggle="modal"
data-target="#modal-set-license-approval"
@click="setLicenseInModal(issue)"
>
{{ issue.name }}
</button>
<license-packages :packages="issue.packages" class="text-secondary" /> <license-packages :packages="issue.packages" class="text-secondary" />
</div> </div>
</template> </template>
<script>
import { mapActions, mapState } from 'vuex';
import { GlLink } from '@gitlab/ui';
import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants';
import { s__ } from '~/locale';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import LicensePackages from './license_packages.vue';
import { LICENSE_APPROVAL_STATUS } from '../constants';
export default {
name: 'LicenseSetApprovalStatusModal',
components: { GlLink, LicensePackages, GlModal: DeprecatedModal2 },
computed: {
...mapState(LICENSE_MANAGEMENT, ['currentLicenseInModal', 'canManageLicenses']),
headerTitleText() {
if (!this.canManageLicenses) {
return s__('LicenseCompliance|License details');
}
return s__('LicenseCompliance|License review');
},
canApprove() {
return (
this.canManageLicenses &&
this.currentLicenseInModal &&
this.currentLicenseInModal.approvalStatus !== LICENSE_APPROVAL_STATUS.ALLOWED
);
},
canBlacklist() {
return (
this.canManageLicenses &&
this.currentLicenseInModal &&
this.currentLicenseInModal.approvalStatus !== LICENSE_APPROVAL_STATUS.DENIED
);
},
},
methods: {
...mapActions(LICENSE_MANAGEMENT, ['resetLicenseInModal', 'allowLicense', 'denyLicense']),
},
};
</script>
<template>
<gl-modal
id="modal-set-license-approval"
:header-title-text="headerTitleText"
modal-size="lg"
data-qa-selector="license_management_modal"
@cancel="resetLicenseInModal"
>
<slot v-if="currentLicenseInModal">
<div class="row gl-mt-3 gl-mb-3 js-license-name">
<label class="col-sm-3 text-right font-weight-bold">
{{ s__('LicenseCompliance|License') }}:
</label>
<div class="col-sm-9 text-secondary">{{ currentLicenseInModal.name }}</div>
</div>
<div v-if="currentLicenseInModal.url" class="row gl-mt-3 gl-mb-3 js-license-url">
<label class="col-sm-3 text-right font-weight-bold">
{{ s__('LicenseCompliance|URL') }}:
</label>
<div class="col-sm-9 text-secondary">
<gl-link :href="currentLicenseInModal.url" target="_blank" rel="nofollow">{{
currentLicenseInModal.url
}}</gl-link>
</div>
</div>
<div class="row gl-mt-3 gl-mb-3 js-license-packages">
<label class="col-sm-3 text-right font-weight-bold">
{{ s__('LicenseCompliance|Packages') }}:
</label>
<license-packages
:packages="currentLicenseInModal.packages"
class="col-sm-9 text-secondary"
/>
</div>
</slot>
<template slot="footer">
<button
type="button"
class="btn js-modal-cancel-action"
data-dismiss="modal"
@click="resetLicenseInModal"
>
{{ s__('Modal|Cancel') }}
</button>
<button
v-if="canBlacklist"
class="btn btn-remove btn-inverted js-modal-secondary-action"
data-dismiss="modal"
data-qa-selector="deny_license_button"
@click="denyLicense(currentLicenseInModal)"
>
{{ s__('LicenseCompliance|Deny') }}
</button>
<button
v-if="canApprove"
type="button"
class="btn btn-success js-modal-primary-action"
data-dismiss="modal"
data-qa-selector="approve_license_button"
@click="allowLicense(currentLicenseInModal)"
>
{{ s__('LicenseCompliance|Allow') }}
</button>
</template>
</gl-modal>
</template>
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import { GlLink, GlIcon } from '@gitlab/ui'; import { GlLink, GlIcon } from '@gitlab/ui';
import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin'; import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin';
import SetLicenseApprovalModal from 'ee/vue_shared/license_compliance/components/set_approval_status_modal.vue';
import { componentNames } from 'ee/reports/components/issue_body'; import { componentNames } from 'ee/reports/components/issue_body';
import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants'; import { LICENSE_MANAGEMENT } from 'ee/vue_shared/license_compliance/store/constants';
import ReportItem from '~/reports/components/report_item.vue'; import ReportItem from '~/reports/components/report_item.vue';
...@@ -20,7 +19,6 @@ export default { ...@@ -20,7 +19,6 @@ export default {
GlLink, GlLink,
ReportItem, ReportItem,
ReportSection, ReportSection,
SetLicenseApprovalModal,
SmartVirtualList, SmartVirtualList,
GlIcon, GlIcon,
}, },
...@@ -121,7 +119,6 @@ export default { ...@@ -121,7 +119,6 @@ export default {
</script> </script>
<template> <template>
<div> <div>
<set-license-approval-modal />
<report-section <report-section
:status="licenseReportStatus" :status="licenseReportStatus"
:loading-text="licenseSummaryText" :loading-text="licenseSummaryText"
...@@ -185,6 +182,7 @@ export default { ...@@ -185,6 +182,7 @@ export default {
:class="{ 'gl-mr-3': fullReportPath }" :class="{ 'gl-mr-3': fullReportPath }"
:href="licenseManagementSettingsPath" :href="licenseManagementSettingsPath"
class="btn btn-default btn-sm js-manage-licenses" class="btn btn-default btn-sm js-manage-licenses"
data-qa-selector="manage_licenses_button"
> >
{{ s__('ciReport|Manage licenses') }} {{ s__('ciReport|Manage licenses') }}
</a> </a>
......
---
title: Removes ability to change license status through MR and Pipeline pages
merge_request: 43470
author:
type: changed
...@@ -51,6 +51,7 @@ exports[`License Report MR Widget report section should render correctly 1`] = ` ...@@ -51,6 +51,7 @@ exports[`License Report MR Widget report section should render correctly 1`] = `
> >
<a <a
class="btn btn-default btn-sm js-manage-licenses gl-mr-3" class="btn btn-default btn-sm js-manage-licenses gl-mr-3"
data-qa-selector="manage_licenses_button"
href="http://test.host/lm_settings" href="http://test.host/lm_settings"
> >
......
...@@ -21,25 +21,13 @@ describe('LicenseIssueBody', () => { ...@@ -21,25 +21,13 @@ describe('LicenseIssueBody', () => {
vm.$destroy(); vm.$destroy();
}); });
describe('interaction', () => {
it('clicking the button triggers openModal with the current license', () => {
const linkEl = vm.$el.querySelector('.license-item > .btn-link');
expect(store.state.licenseManagement.currentLicenseInModal).toBe(null);
linkEl.click();
expect(store.state.licenseManagement.currentLicenseInModal).toBe(issue);
});
});
describe('template', () => { describe('template', () => {
it('renders component container element with class `license-item`', () => { it('renders component container element with class `license-item`', () => {
expect(vm.$el.classList.contains('license-item')).toBe(true); expect(vm.$el.classList.contains('license-item')).toBe(true);
}); });
it('renders button to open modal', () => { it('renders link to view license', () => {
const linkEl = vm.$el.querySelector('.license-item > .btn-link'); const linkEl = vm.$el.querySelector('.license-item > a');
expect(linkEl).not.toBeNull(); expect(linkEl).not.toBeNull();
expect(linkEl.innerText.trim()).toBe(issue.name); expect(linkEl.innerText.trim()).toBe(issue.name);
......
...@@ -333,12 +333,6 @@ describe('License Report MR Widget', () => { ...@@ -333,12 +333,6 @@ describe('License Report MR Widget', () => {
}); });
}); });
it('should render set approval modal', () => {
mountComponent();
expect(wrapper.find('#modal-set-license-approval')).not.toBeNull();
});
it('should init store after mount', () => { it('should init store after mount', () => {
const actions = { const actions = {
setAPISettings: jest.fn(), setAPISettings: jest.fn(),
......
...@@ -15964,9 +15964,6 @@ msgstr "" ...@@ -15964,9 +15964,6 @@ msgstr ""
msgid "LicenseCompliance|Learn more about %{linkStart}License Approvals%{linkEnd}" msgid "LicenseCompliance|Learn more about %{linkStart}License Approvals%{linkEnd}"
msgstr "" msgstr ""
msgid "LicenseCompliance|License"
msgstr ""
msgid "LicenseCompliance|License Approvals" msgid "LicenseCompliance|License Approvals"
msgstr "" msgstr ""
...@@ -16006,18 +16003,9 @@ msgstr "" ...@@ -16006,18 +16003,9 @@ msgstr ""
msgid "LicenseCompliance|License Compliance detected no new licenses" msgid "LicenseCompliance|License Compliance detected no new licenses"
msgstr "" msgstr ""
msgid "LicenseCompliance|License details"
msgstr ""
msgid "LicenseCompliance|License name" msgid "LicenseCompliance|License name"
msgstr "" msgstr ""
msgid "LicenseCompliance|License review"
msgstr ""
msgid "LicenseCompliance|Packages"
msgstr ""
msgid "LicenseCompliance|Remove license" msgid "LicenseCompliance|Remove license"
msgstr "" msgstr ""
...@@ -16033,9 +16021,6 @@ msgstr "" ...@@ -16033,9 +16021,6 @@ msgstr ""
msgid "LicenseCompliance|This license already exists in this project." msgid "LicenseCompliance|This license already exists in this project."
msgstr "" msgstr ""
msgid "LicenseCompliance|URL"
msgstr ""
msgid "LicenseCompliance|You are about to remove the license, %{name}, from this project." msgid "LicenseCompliance|You are about to remove the license, %{name}, from this project."
msgstr "" msgstr ""
......
...@@ -9,23 +9,25 @@ ...@@ -9,23 +9,25 @@
{ {
"id": "MIT", "id": "MIT",
"name": "MIT License", "name": "MIT License",
"url": "https://opensource.org/licenses/MIT" "url": "http://opensource.org/licenses/mit-license"
} }
], ],
"dependencies": [ "dependencies": [
{ {
"name": "actioncable", "name": "test_dependency",
"version": "6.0.3.3", "version": "0.1.0",
"package_manager": "bundler", "package_manager": "bundler",
"path": "Gemfile.lock", "path": "Gemfile.lock",
"licenses": ["MIT"] "licenses": ["Apache-2.0"]
}, },
{ {
"name": "test_package", "name": "actioncable",
"version": "0.1.0", "version": "1.2",
"url": "http://rubyonrails.org",
"package_manager": "bundler", "package_manager": "bundler",
"path": "Gemfile.lock", "description": "WebSocket framework for Rails.",
"licenses": ["Apache-2.0"] "path": ".",
"licenses": ["MIT"]
} }
] ]
} }
...@@ -19,14 +19,9 @@ module QA ...@@ -19,14 +19,9 @@ module QA
element :icon_status, ':data-qa-selector="`status_${status}_icon`" ' # rubocop:disable QA/ElementWithPattern element :icon_status, ':data-qa-selector="`status_${status}_icon`" ' # rubocop:disable QA/ElementWithPattern
end end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/components/set_approval_status_modal.vue' do
element :license_management_modal
element :approve_license_button
element :deny_license_button
end
view 'ee/app/assets/javascripts/vue_shared/license_compliance/mr_widget_license_report.vue' do view 'ee/app/assets/javascripts/vue_shared/license_compliance/mr_widget_license_report.vue' do
element :license_report_widget element :license_report_widget
element :manage_licenses_button
end end
end end
end end
...@@ -50,20 +45,14 @@ module QA ...@@ -50,20 +45,14 @@ module QA
wait_for_animated_element(:license_management_modal) wait_for_animated_element(:license_management_modal)
end end
def approve_license(name) def click_manage_licenses_button
wait_until(reload: true) do previous_page = page.current_url
click_license(name) within_element(:license_report_widget) do
has_element?(:approve_license_button, wait: 1) click_element :manage_licenses_button
end
click_element(:approve_license_button)
end end
wait_until(max_duration: 15, reload: false) do
def deny_license(name) page.current_url != previous_page
wait_until(reload: true) do
click_license(name)
has_element?(:deny_license_button, wait: 1)
end end
click_element(:deny_license_button)
end end
end end
end end
......
...@@ -114,16 +114,6 @@ module QA ...@@ -114,16 +114,6 @@ module QA
end end
end end
def approve_license_with_mr(name)
expand_license_report unless license_report_expanded?
approve_license(name)
end
def deny_license_with_mr(name)
expand_license_report unless license_report_expanded?
deny_license(name)
end
def expand_vulnerability_report def expand_vulnerability_report
within_element :vulnerability_report_grouped do within_element :vulnerability_report_grouped do
click_element :expand_report_button unless has_content? 'Collapse' click_element :expand_report_button unless has_content? 'Collapse'
......
...@@ -28,7 +28,7 @@ module QA ...@@ -28,7 +28,7 @@ module QA
def approve_license(license) def approve_license(license)
click_element :license_add_button click_element :license_add_button
expand_select_list expand_select_list
search_and_select license search_and_select_exact license
click_element :approved_license_radio click_element :approved_license_radio
click_element :add_license_submit_button click_element :add_license_submit_button
...@@ -36,6 +36,7 @@ module QA ...@@ -36,6 +36,7 @@ module QA
end end
def has_approved_license?(name) def has_approved_license?(name)
has_element?(:admin_license_compliance_row, text: name)
within_element(:admin_license_compliance_row, text: name) do within_element(:admin_license_compliance_row, text: name) do
has_element?(:status_success_icon) has_element?(:status_success_icon)
end end
...@@ -44,7 +45,7 @@ module QA ...@@ -44,7 +45,7 @@ module QA
def deny_license(license) def deny_license(license)
click_element :license_add_button click_element :license_add_button
expand_select_list expand_select_list
search_and_select license search_and_select_exact license
click_element :blacklisted_license_radio click_element :blacklisted_license_radio
click_element :add_license_submit_button click_element :add_license_submit_button
...@@ -52,6 +53,7 @@ module QA ...@@ -52,6 +53,7 @@ module QA
end end
def has_denied_license?(name) def has_denied_license?(name)
has_element?(:admin_license_compliance_row, text: name)
within_element(:admin_license_compliance_row, text: name) do within_element(:admin_license_compliance_row, text: name) do
has_element?(:status_failed_icon) has_element?(:status_failed_icon)
end end
......
...@@ -38,6 +38,16 @@ module QA ...@@ -38,6 +38,16 @@ module QA
select_item(item_text) select_item(item_text)
end end
def search_and_select_exact(item_text)
QA::Runtime::Logger.info "Searching and selecting: #{item_text}"
search_item(item_text)
raise QA::Page::Base::ElementNotFound, %Q(Couldn't find option named "#{item_text}") unless has_item?(item_text)
find('.select2-result-label', text: item_text, exact_text: true).click
end
def expand_select_list def expand_select_list
find('span.select2-arrow').click find('span.select2-arrow').click
end end
......
...@@ -26,6 +26,10 @@ module QA ...@@ -26,6 +26,10 @@ module QA
element :child_pipeline element :child_pipeline
end end
view 'app/assets/javascripts/reports/components/report_section.vue' do
element :expand_report_button
end
view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do view 'app/assets/javascripts/vue_shared/components/ci_icon.vue' do
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
end end
...@@ -78,6 +82,12 @@ module QA ...@@ -78,6 +82,12 @@ module QA
end end
end end
def expand_license_report
within_element(:license_report_widget) do
click_element(:expand_report_button)
end
end
def click_on_first_job def click_on_first_job
first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click
end end
......
...@@ -71,7 +71,6 @@ module QA ...@@ -71,7 +71,6 @@ module QA
end end
describe 'License Compliance pipeline reports' do describe 'License Compliance pipeline reports' do
let(:number_of_licenses_in_fixture) { 2 }
let(:executor) {"qa-runner-#{Time.now.to_i}"} let(:executor) {"qa-runner-#{Time.now.to_i}"}
after do after do
...@@ -101,29 +100,29 @@ module QA ...@@ -101,29 +100,29 @@ module QA
.new(__dir__) .new(__dir__)
.join('../../../../../ee/fixtures/secure_premade_reports') .join('../../../../../ee/fixtures/secure_premade_reports')
project_push.commit_message = 'Create Secure compatible application to serve premade reports' project_push.commit_message = 'Create Secure compatible application to serve premade reports'
end.project.visit! end
@project.visit!
Page::Project::Menu.perform(&:click_ci_cd_pipelines) Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:wait_for_latest_pipeline_success) Page::Project::Pipeline::Index.perform(&:wait_for_latest_pipeline_success)
Page::Project::Menu.perform(&:click_on_license_compliance)
end end
it 'can approve and deny licenses in the pipeline', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/965' do it 'can approve and deny licenses in the pipeline', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/965' do
Flow::Pipeline.visit_latest_pipeline EE::Page::Project::Secure::LicenseCompliance.perform do |license_compliance|
license_compliance.open_tab
license_compliance.approve_license approved_license_name
license_compliance.deny_license denied_license_name
end
@project.visit!
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline| Page::Project::Pipeline::Show.perform do |pipeline|
pipeline.click_on_licenses pipeline.click_on_licenses
expect(pipeline).to have_approved_license approved_license_name
expect(pipeline).to have_license_count_of number_of_licenses_in_fixture expect(pipeline).to have_denied_license denied_license_name
pipeline.approve_license(approved_license_name)
pipeline.deny_license(denied_license_name)
end
Page::Project::Menu.perform(&:click_on_license_compliance)
EE::Page::Project::Secure::LicenseCompliance.perform do |license_compliance|
license_compliance.open_tab
expect(license_compliance).to have_approved_license approved_license_name
expect(license_compliance).to have_denied_license denied_license_name
end end
end end
end end
......
...@@ -103,11 +103,21 @@ module QA ...@@ -103,11 +103,21 @@ module QA
@merge_request.visit! @merge_request.visit!
Page::MergeRequest::Show.perform do |show| Page::MergeRequest::Show.perform do |show|
show.approve_license_with_mr(approved_license_name)
show.deny_license_with_mr(denied_license_name)
show.wait_for_license_compliance_report show.wait_for_license_compliance_report
show.click_manage_licenses_button
end
EE::Page::Project::Secure::LicenseCompliance.perform do |license_compliance|
license_compliance.open_tab
license_compliance.approve_license approved_license_name
license_compliance.deny_license denied_license_name
end
@merge_request.visit!
Page::MergeRequest::Show.perform do |show|
show.wait_for_license_compliance_report
show.expand_license_report
expect(show).to have_approved_license approved_license_name expect(show).to have_approved_license approved_license_name
expect(show).to have_denied_license denied_license_name expect(show).to have_denied_license denied_license_name
end end
......
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