Disable save policy button based on schema

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

Why are we doing this work

  • a user's yml is being validated against the schema and shows warnings and errors to the user in the editor; those warnings and errors should be used to prevent a user from trying to save the policy as the backend will throw an error anyways

Relevant links

Sample project

error_for_validaton

Non-functional requirements

  • Documentation:
  • Feature flag: Required as this feature could affect the users ability to save a policy
  • Testing:

Implementation plan

DIFF TO GET SCHEMA ERRORS/WARNINGS
commit ad950e8727a7cbbdaa0aa8bcca150cc28555b51b
Author: Alexander Turinske <aturinske@gitlab.com>
Date:   Mon Apr 10 16:08:38 2023 +1200

    Update scan execution policy validation
    
    - use schema to disable save button
    
    Changelog: changed
    
    EE: true

diff --git a/app/assets/javascripts/editor/constants.js b/app/assets/javascripts/editor/constants.js
index 2d50b7e4319c..86c256d38419 100644
--- a/app/assets/javascripts/editor/constants.js
+++ b/app/assets/javascripts/editor/constants.js
@@ -167,3 +167,11 @@ export const EXTENSION_MARKDOWN_BUTTONS = [
   },
 ];
 export const EXTENSION_SOFTWRAP_ID = 'soft-wrap';
+
+// Severities defined in https://microsoft.github.io/monaco-editor/docs.html#enums/MarkerSeverity.html
+export const MARKER_SEVERITY_DICT = {
+  HINT: 1,
+  INFO: 2,
+  WARNING: 4,
+  ERROR: 8,
+};
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_layout.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_layout.vue
index df04a8d45487..ebf676ce4fcc 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_layout.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_layout.vue
@@ -338,6 +338,7 @@ export default {
             :value="yamlEditorValue"
             :read-only="false"
             @input="updateYaml"
+            @schema-markers="$emit('schema-markers', $event)"
           />
         </section>
         <section
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/editor_component.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/editor_component.vue
index 5537a8c84715..54dfc0c25068 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/editor_component.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/editor_component.vue
@@ -5,6 +5,7 @@ import { __, s__ } from '~/locale';
 import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
 import ScanFilterSelector from 'ee/security_orchestration/components/policy_editor/scan_filter_selector.vue';
 import { isGroup } from 'ee/security_orchestration/components/utils';
+import { MARKER_SEVERITY_DICT } from '~/editor/constants';
 import {
   EDITOR_MODE_RULE,
   EDITOR_MODE_YAML,
@@ -174,6 +175,9 @@ export default {
       this.policy = updatedPolicy;
       this.updateYamlEditorValue(this.policy);
     },
+    handleSchemaMarkers(markers) {
+      this.hasParsingError = markers.some((m) => m.severity === MARKER_SEVERITY_DICT.ERROR);
+    },
     handleUpdateProperty(property, value) {
       this.policy[property] = value;
       this.updateYamlEditorValue(this.policy);
@@ -247,6 +251,7 @@ export default {
   <editor-layout
     v-if="!disableScanPolicyUpdate"
     :custom-save-button-text="$options.i18n.createMergeRequest"
+    :disable-update="hasParsingError"
     :has-parsing-error="hasParsingError"
     :is-editing="isEditing"
     :is-removing-policy="isRemovingPolicy"
@@ -257,6 +262,7 @@ export default {
     @remove-policy="handleModifyPolicy($options.SECURITY_POLICY_ACTIONS.REMOVE)"
     @save-policy="handleModifyPolicy()"
     @remove-property="handleRemoveProperty"
+    @schema-markers="handleSchemaMarkers"
     @update-property="handleUpdateProperty"
     @update-yaml="updateYaml"
     @update-editor-mode="changeEditorMode"
diff --git a/ee/app/assets/javascripts/security_orchestration/components/yaml_editor.vue b/ee/app/assets/javascripts/security_orchestration/components/yaml_editor.vue
index 6a2e4bde3f7a..7c37f6341844 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/yaml_editor.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/yaml_editor.vue
@@ -1,4 +1,5 @@
 <script>
+import { editor as monacoEditor } from 'monaco-editor';
 import SourceEditor from '~/vue_shared/components/source_editor.vue';
 import { EDITOR_READY_EVENT } from '~/editor/constants';
 import { SecurityPolicySchemaExtension } from '~/editor/extensions/source_editor_security_policy_schema_ext';
@@ -65,6 +66,11 @@ export default {
           namespaceType: this.namespaceType,
           policyType: this.policyType,
         });
+        instance.onDidChangeModelDecorations(() => {
+          const model = instance.getModel();
+          const markers = monacoEditor.getModelMarkers(model);
+          this.$emit('schema-markers', markers);
+        });
       }
     },
   },

Verification steps

  1. Upload a GitLab Ultimate license
  2. Navigate to a group/project => Security & Compliance => Policies => New policy => Scan Execution
  3. Create an invalid yaml
  4. Verify the Configure with merge request button is disabled
  5. Fix the yaml to make it valid
  6. Verify the Configure with merge request button is enabled
Edited by 🤖 GitLab Bot 🤖