Prevent from creating more than X policies for given type in security policy project
Why are we doing this work
Currently, it is possible to create more than 5 policies for a given type (Scan Result Policies/Scan Execution Policies), and GitLab will ignore them without any feedback for users. With this issue, we would like to change it to appropriately respond when a user tries to enable/create more than 5 policies of a given type.
This limit is applied to policies for a single Security Policy Project only. Inherited policies from the group/sub-group level are not counted to this limit.
when updating existing policy to be enabled will increase the the amount of enabled policies for given type, error message is returned instead
In scope of this issue we would like to:
grey-outNew Policy
button when there are already 5 policies enabled for both types,grey-outScan Result Policy
when there are already 5 policies enabled for this type,grey-outScan Execution Policy
when there are already 5 policies enabled for this type,tooltip is added when a button is greyed-out with explanation why,when creating new or updating existing policy will increase the the amount of enabled policies for given type, error message is returned instead,
What has been implemented
Relevant links
Non-functional requirements
-
Documentation: Make sure the limit is documented in the documentation -
Feature flag: -
Performance: -
Testing:
Implementation plan
Previous Plan
-
Pass container.security_orchestration_policy_configuration.active_scan_execution_policies.length
andcontainer.security_orchestration_policy_configuration.active_scan_result_policies.length
to the frontend.
diff --git a/ee/app/helpers/ee/security_orchestration_helper.rb b/ee/app/helpers/ee/security_orchestration_helper.rb
index b5c8efe89473..67390b089990 100644
--- a/ee/app/helpers/ee/security_orchestration_helper.rb
+++ b/ee/app/helpers/ee/security_orchestration_helper.rb
@@ -43,7 +43,9 @@ def orchestration_policy_data(container, policy_type = nil, policy = nil, approv
software_licenses: SoftwareLicense.all_license_names,
global_group_approvers_enabled: Gitlab::CurrentSettings.security_policy_global_group_approvers_enabled.to_json,
root_namespace_path: container.root_ancestor&.full_path,
- timezones: timezone_data(format: :full).to_json
+ timezones: timezone_data(format: :full).to_json,
+ active_scan_execution_policy_count: container.security_orchestration_policy_configuration.active_scan_execution_policies.length,
+ active_scan_result_policy_count: container.security_orchestration_policy_configuration.active_scan_result_policies.length
}
if container.is_a?(::Project)
-
do something like below -
disable tooltip if the button is not disabled -
add tests
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/policy_type_selector.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/policy_type_selector.vue
index cbef8e4831e6..0e4f360f9af2 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/policy_type_selector.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/policy_type_selector.vue
@@ -1,7 +1,7 @@
<script>
import shieldCheckIllustrationUrl from '@gitlab/svgs/dist/illustrations/secure-sm.svg?url';
import magnifyingGlassIllustrationUrl from '@gitlab/svgs/dist/illustrations/search-sm.svg?url';
-import { GlCard, GlButton } from '@gitlab/ui';
+import { GlCard, GlButton, GlTooltipDirective } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { s__, __ } from '~/locale';
@@ -26,6 +26,9 @@ const i18n = {
scanExecutionPolicyExample: s__(
'SecurityOrchestration|Run a DAST scan with Scan Profile A and Site Profile A when a pipeline run against the main branch.',
),
+ disabledButtonTooltip: s__(
+ 'SecurityOrchestration|The max number of polices have been created for this type',
+ ),
};
export default {
@@ -34,11 +37,25 @@ export default {
GlButton,
},
directives: {
+ GlTooltipDirective,
SafeHtml,
},
mixins: [glFeatureFlagsMixin()],
- inject: ['policiesPath'],
+ inject: [
+ 'maxActiveScanExecutionPoliciesReached',
+ 'maxActiveScanResultPoliciesReached',
+ 'policiesPath',
+ ],
computed: {
+ hasMaxPolicies() {
+ return {
+ [POLICY_TYPE_COMPONENT_OPTIONS.scanExecution.urlParameter]: this
+ .maxActiveScanExecutionPoliciesReached,
+ [POLICY_TYPE_COMPONENT_OPTIONS.scanResult.urlParameter]: this
+ .maxActiveScanResultPoliciesReached,
+ };
+ },
+
policies() {
return [
{
@@ -79,7 +96,7 @@ export default {
body-class="gl-p-6 gl-display-flex gl-flex-grow-1"
>
<div class="gl-mr-6 gl-text-white">
- <img aria-hidden="true" :src="option.imageSrc" />
+ <img :alt="option.title" aria-hidden="true" :src="option.imageSrc" />
</div>
<div class="gl-display-flex gl-flex-direction-column">
<h4 class="gl-mt-0">{{ option.title }}</h4>
@@ -87,12 +104,20 @@ export default {
<h5>{{ $options.i18n.examples }}</h5>
<p class="gl-flex-grow-1">{{ option.example }}</p>
<div>
- <gl-button
- variant="confirm"
- :href="constructUrl(option.urlParameter)"
- :data-testid="`select-policy-${option.urlParameter}`"
- >{{ $options.i18n.selectPolicy }}</gl-button
+ <span
+ v-gl-tooltip
+ :title="$options.i18n.disabledButtonTooltip"
+ :disabled="hasMaxPolicies[option.urlParameter]"
>
+ <gl-button
+ :disabled="hasMaxPolicies[option.urlParameter]"
+ variant="confirm"
+ :href="constructUrl(option.urlParameter)"
+ :data-testid="`select-policy-${option.urlParameter}`"
+ >
+ {{ $options.i18n.selectPolicy }}
+ </gl-button>
+ </span>
</div>
</div>
</gl-card>
diff --git a/ee/app/assets/javascripts/security_orchestration/policy_editor.js b/ee/app/assets/javascripts/security_orchestration/policy_editor.js
index 57734c99f53f..28112f639b3b 100644
--- a/ee/app/assets/javascripts/security_orchestration/policy_editor.js
+++ b/ee/app/assets/javascripts/security_orchestration/policy_editor.js
@@ -11,6 +11,8 @@ export default (el, namespaceType) => {
disableScanPolicyUpdate,
createAgentHelpPath,
globalGroupApproversEnabled,
+ maxActiveScanExecutionPoliciesReached,
+ maxActiveScanResultPoliciesReached,
namespaceId,
namespacePath,
policiesPath,
@@ -63,6 +65,8 @@ export default (el, namespaceType) => {
createAgentHelpPath,
disableScanPolicyUpdate: parseBoolean(disableScanPolicyUpdate),
globalGroupApproversEnabled: parseBoolean(globalGroupApproversEnabled),
+ maxActiveScanExecutionPoliciesReached: parseBoolean(maxActiveScanExecutionPoliciesReached),
+ maxActiveScanResultPoliciesReached: parseBoolean(maxActiveScanResultPoliciesReached),
namespaceId,
namespacePath,
namespaceType,
-
when there are already 5 policies, do not allow a user to enable an existing policy. Return an error that gives guidance on how to move forward or link to docs discussing it -
add a check on push of policy.yml
to ensure that there are no more than X active policies for given type
-
display error
Verification steps
Edited by Martin Čavoj