diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section_new.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section_new.vue
new file mode 100644
index 0000000000000000000000000000000000000000..79e776fe7066976e4c865cb1d21587f85c80db23
--- /dev/null
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section_new.vue
@@ -0,0 +1,48 @@
+<script>
+import { REQUIRE_APPROVAL_TYPE } from '../lib';
+import ApproverAction from './approver_action.vue';
+import BotCommentAction from './bot_comment_action.vue';
+
+export default {
+  name: 'ActionSection',
+  components: {
+    ApproverAction,
+    BotCommentAction,
+  },
+  props: {
+    errors: {
+      type: Array,
+      required: false,
+      default: () => [],
+    },
+    initAction: {
+      type: Object,
+      required: true,
+    },
+    existingApprovers: {
+      type: Object,
+      required: true,
+    },
+  },
+  computed: {
+    isApproverAction() {
+      return this.initAction.type === REQUIRE_APPROVAL_TYPE;
+    },
+  },
+};
+</script>
+
+<template>
+  <approver-action
+    v-if="isApproverAction"
+    class="gl-mb-4"
+    :init-action="initAction"
+    :errors="errors.action"
+    :existing-approvers="existingApprovers"
+    @error="$emit('error')"
+    @updateApprovers="$emit('updateApprovers', $event)"
+    @changed="$emit('changed', $event)"
+    @remove="$emit('remove')"
+  />
+  <bot-comment-action v-else class="gl-mb-4" :init-action="initAction" @remove="$emit('remove')" />
+</template>
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/approver_action.vue
similarity index 96%
rename from ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section.vue
rename to ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/approver_action.vue
index b447a44f4d0e547037e905df019d4e12012721dd..2a1b5781696ab439ff49f13dbc64ab8952f756d2 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_section.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/approver_action.vue
@@ -10,12 +10,13 @@ import {
   actionHasType,
 } from '../lib/actions';
 import SectionLayout from '../../section_layout.vue';
-import ActionApprovers from './action_approvers.vue';
+import ApproverSelectionWrapper from './approver_selection_wrapper.vue';
 
 export default {
+  name: 'ApproverAction',
   components: {
     GlAlert,
-    ActionApprovers,
+    ApproverSelectionWrapper,
     SectionLayout,
   },
   inject: ['namespaceId'],
@@ -137,7 +138,7 @@ export default {
     </gl-alert>
     <section-layout content-classes="gl-py-5 gl-pr-5 gl-bg-white" @remove="$emit('remove')">
       <template #content>
-        <action-approvers
+        <approver-selection-wrapper
           v-for="({ id, type }, i) in approverTypeTracker"
           :key="id"
           :approver-index="i"
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_approvers.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/approver_selection_wrapper.vue
similarity index 100%
rename from ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/action_approvers.vue
rename to ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/approver_selection_wrapper.vue
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/bot_comment_action.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/bot_comment_action.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9d5e6d9ff0709fd804168d3abb6793490f90a033
--- /dev/null
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/action/bot_comment_action.vue
@@ -0,0 +1,18 @@
+<script>
+import SectionLayout from '../../section_layout.vue';
+import { BOT_COMMENT_TYPE } from '../lib';
+
+export default {
+  name: 'BotCommentAction',
+  components: {
+    SectionLayout,
+  },
+  BOT_COMMENT_TYPE,
+};
+</script>
+
+<template>
+  <section-layout @remove="$emit('remove')">
+    <template #content>{{ $options.BOT_COMMENT_TYPE }}</template>
+  </section-layout>
+</template>
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/editor_component.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/editor_component.vue
index 049d821511c8f7703e87c377da76ff52cb4c9c7d..ec74a22a3d73a4a414eb47ea91c9058c70a31f67 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/editor_component.vue
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/editor_component.vue
@@ -4,6 +4,7 @@ import { isEmpty } from 'lodash';
 import { GlAlert, GlEmptyState, GlButton } from '@gitlab/ui';
 import { joinPaths, visitUrl, setUrlFragment } from '~/lib/utils/url_utility';
 import { __, s__ } from '~/locale';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
 import { isGroup, isProject } from 'ee/security_orchestration/components/utils';
 import {
   ADD_ACTION_LABEL,
@@ -22,7 +23,8 @@ import EditorLayout from '../editor_layout.vue';
 import { assignSecurityPolicyProject, modifyPolicy } from '../utils';
 import DimDisableContainer from '../dim_disable_container.vue';
 import SettingsSection from './settings/settings_section.vue';
-import ActionSection from './action/action_section.vue';
+import ActionSection from './action/action_section_new.vue';
+import ApproverAction from './action/approver_action.vue';
 import RuleSection from './rule/rule_section.vue';
 
 import {
@@ -75,6 +77,7 @@ export default {
   },
   components: {
     ActionSection,
+    ApproverAction,
     DimDisableContainer,
     GlAlert,
     GlButton,
@@ -83,6 +86,7 @@ export default {
     RuleSection,
     SettingsSection,
   },
+  mixins: [glFeatureFlagsMixin()],
   inject: [
     'disableScanPolicyUpdate',
     'policyEditorEmptyStateSvgPath',
@@ -138,6 +142,9 @@ export default {
     disableUpdate() {
       return !this.hasParsingError && this.hasEmptyActions && this.hasEmptySettings;
     },
+    isProject() {
+      return isProject(this.namespaceType);
+    },
     settings() {
       return buildSettingsList({
         settings: this.policy.approval_settings,
@@ -198,6 +205,9 @@ export default {
         description: this.$options.i18n.settingWarningDescription,
       };
     },
+    showBotCommentAction() {
+      return this.isProject && this.glFeatures.approvalPolicyDisableBotComment;
+    },
   },
   watch: {
     invalidBranches(branches) {
@@ -216,9 +226,10 @@ export default {
       this.$set(this.policy, 'actions', [buildApprovalAction()]);
       this.updateYamlEditorValue(this.policy);
     },
-    removeAction() {
+    removeAction(index) {
       const { actions, ...newPolicy } = this.policy;
-      this.policy = newPolicy;
+      actions.splice(index, 1);
+      this.policy = { ...newPolicy, ...(actions.length ? { actions } : {}) };
       this.updateYamlEditorValue(this.policy);
       this.updatePolicyApprovers({});
     },
@@ -340,7 +351,7 @@ export default {
       if (this.isActiveRuleMode) {
         this.hasParsingError = this.invalidForRuleMode();
 
-        if (!this.hasEmptyRules && isProject(this.namespaceType) && this.rulesHaveBranches) {
+        if (!this.hasEmptyRules && this.isProject && this.rulesHaveBranches) {
           this.invalidBranches = await getInvalidBranches({
             branches: this.allBranches,
             projectId: this.namespaceId,
@@ -430,21 +441,37 @@ export default {
         </template>
 
         <div v-if="Boolean(policy.actions)">
-          <action-section
-            v-for="(action, index) in policy.actions"
-            :key="action.id"
-            :data-testid="`action-${index}`"
-            class="gl-mb-4"
-            :init-action="action"
-            :errors="errors.action"
-            :existing-approvers="existingApprovers"
-            @error="handleParsingError"
-            @updateApprovers="updatePolicyApprovers"
-            @changed="updateAction(index, $event)"
-            @remove="removeAction"
-          />
+          <div v-if="showBotCommentAction">
+            <action-section
+              v-for="(action, index) in policy.actions"
+              :key="action.id"
+              :data-testid="`action-${index}`"
+              class="gl-mb-4"
+              :init-action="action"
+              :errors="errors.action"
+              :existing-approvers="existingApprovers"
+              @error="handleParsingError"
+              @updateApprovers="updatePolicyApprovers"
+              @changed="updateAction(index, $event)"
+              @remove="removeAction(index)"
+            />
+          </div>
+          <div v-else>
+            <approver-action
+              v-for="(action, index) in policy.actions"
+              :key="action.id"
+              :data-testid="`action-${index}`"
+              class="gl-mb-4"
+              :init-action="action"
+              :errors="errors.action"
+              :existing-approvers="existingApprovers"
+              @error="handleParsingError"
+              @updateApprovers="updatePolicyApprovers"
+              @changed="updateAction(index, $event)"
+              @remove="removeAction(index)"
+            />
+          </div>
         </div>
-
         <div v-else class="gl-bg-gray-10 gl-rounded-base gl-p-5 gl-mb-5">
           <gl-button variant="link" data-testid="add-action" icon="plus" @click="addAction">
             {{ $options.i18n.ADD_ACTION_LABEL }}
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/actions.js b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/actions.js
index 8fb8bae933a522f19a770f105315052de5b285b9..12585f321aa887b8daf556abb82057b44199aa5c 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/actions.js
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/actions.js
@@ -108,6 +108,10 @@ export const MULTIPLE_APPROVER_TYPES_HUMANIZED_TEMPLATE = s__('SecurityOrchestra
 
 export const DEFAULT_APPROVER_DROPDOWN_TEXT = s__('SecurityOrchestration|Choose approver type');
 
+export const REQUIRE_APPROVAL_TYPE = 'require_approval';
+
+export const BOT_COMMENT_TYPE = 'send_bot_message';
+
 export const buildApprovalAction = () => {
-  return { type: 'require_approval', approvals_required: 1, id: uniqueId('action_') };
+  return { type: REQUIRE_APPROVAL_TYPE, approvals_required: 1, id: uniqueId('action_') };
 };
diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/index.js b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/index.js
index 8005819ff2963fb4a5822f3bf892596ee7879eae..fb52ed7cdd3e6e760a5d58427a663031227c994d 100644
--- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/index.js
+++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/lib/index.js
@@ -1,12 +1,7 @@
 export { createPolicyObject, fromYaml } from './from_yaml';
 export { policyToYaml } from './to_yaml';
 export * from './rules';
-export {
-  approversOutOfSync,
-  APPROVER_TYPE_DICT,
-  APPROVER_TYPE_LIST_ITEMS,
-  buildApprovalAction,
-} from './actions';
+export * from './actions';
 export * from './settings';
 export * from './vulnerability_states';
 export * from './filters';
diff --git a/ee/app/controllers/projects/security/policies_controller.rb b/ee/app/controllers/projects/security/policies_controller.rb
index aa96b95dde73e02ec1aeac271ded5be73106df8a..41b96e50844d0bd59f19e5a3e890b9d0df249b2b 100644
--- a/ee/app/controllers/projects/security/policies_controller.rb
+++ b/ee/app/controllers/projects/security/policies_controller.rb
@@ -15,6 +15,7 @@ class PoliciesController < Projects::ApplicationController
         push_frontend_feature_flag(:compliance_pipeline_in_policies, project)
         push_frontend_feature_flag(:pipeline_execution_policy_type, project.group) if project.group
         push_frontend_feature_flag(:security_policies_breaking_changes, project)
+        push_frontend_feature_flag(:approval_policy_disable_bot_comment, project)
       end
 
       feature_category :security_policy_management
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_new_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_new_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..12fafa6d249ce7c1f1c74558e09771bb00b4ce97
--- /dev/null
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_new_spec.js
@@ -0,0 +1,71 @@
+import { shallowMount } from '@vue/test-utils';
+import ActionSection from 'ee/security_orchestration/components/policy_editor/scan_result/action/action_section_new.vue';
+import ApproverAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/approver_action.vue';
+import BotCommentAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/bot_comment_action.vue';
+import {
+  BOT_COMMENT_TYPE,
+  REQUIRE_APPROVAL_TYPE,
+} from 'ee/security_orchestration/components/policy_editor/scan_result/lib';
+
+describe('ActionSection', () => {
+  let wrapper;
+
+  const defaultProps = {
+    initAction: { type: REQUIRE_APPROVAL_TYPE },
+    existingApprovers: {},
+  };
+  const factory = ({ props = {} } = {}) => {
+    wrapper = shallowMount(ActionSection, {
+      propsData: {
+        ...defaultProps,
+        ...props,
+      },
+    });
+  };
+
+  const findApproverAction = () => wrapper.findComponent(ApproverAction);
+  const findBotCommentAction = () => wrapper.findComponent(BotCommentAction);
+
+  describe('Approval Action', () => {
+    beforeEach(() => {
+      factory();
+    });
+
+    it('renders an approver action for that type of action', () => {
+      expect(findApproverAction().exists()).toBe(true);
+      expect(findBotCommentAction().exists()).toBe(false);
+    });
+
+    describe('events', () => {
+      it('passes through the "error" event', () => {
+        findApproverAction().vm.$emit('error');
+        expect(wrapper.emitted('error')).toEqual([[]]);
+      });
+
+      it('passes through the "update-approvers" event', () => {
+        const event = 'event';
+        findApproverAction().vm.$emit('updateApprovers', event);
+        expect(wrapper.emitted('updateApprovers')).toEqual([[event]]);
+      });
+
+      it('passes through the "changed" event', () => {
+        const event = 'event';
+        findApproverAction().vm.$emit('changed', event);
+        expect(wrapper.emitted('changed')).toEqual([[event]]);
+      });
+
+      it('passes through the "remove" event', () => {
+        findApproverAction().vm.$emit('remove');
+        expect(wrapper.emitted('remove')).toEqual([[]]);
+      });
+    });
+  });
+
+  describe('Bot Comment Action', () => {
+    it('renders a bot comment action for that type of action', () => {
+      factory({ props: { initAction: { type: BOT_COMMENT_TYPE } } });
+      expect(findBotCommentAction().exists()).toBe(true);
+      expect(findApproverAction().exists()).toBe(false);
+    });
+  });
+});
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/approver_action_spec.js
similarity index 90%
rename from ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_spec.js
rename to ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/approver_action_spec.js
index 3d6c614e3d64d6b82bcee6c27bcfb80ef7acc831..e7d220d2cadcb6506531d13ef8e8819757448963 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_section_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/approver_action_spec.js
@@ -2,12 +2,12 @@ import { nextTick } from 'vue';
 import { GlAlert } from '@gitlab/ui';
 import { shallowMount } from '@vue/test-utils';
 import { GROUP_TYPE, USER_TYPE, ROLE_TYPE } from 'ee/security_orchestration/constants';
-import ActionSection from 'ee/security_orchestration/components/policy_editor/scan_result/action/action_section.vue';
-import ActionApprovers from 'ee/security_orchestration/components/policy_editor/scan_result/action/action_approvers.vue';
+import ApproverAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/approver_action.vue';
+import ApproverSelectionWrapper from 'ee/security_orchestration/components/policy_editor/scan_result/action/approver_selection_wrapper.vue';
 import { APPROVER_TYPE_LIST_ITEMS } from 'ee/security_orchestration/components/policy_editor/scan_result/lib/actions';
 import SectionLayout from 'ee/security_orchestration/components/policy_editor/section_layout.vue';
 
-describe('ActionSection', () => {
+describe('ApproverAction', () => {
   let wrapper;
 
   const APPROVERS_IDS = [1, 2, 3];
@@ -59,7 +59,7 @@ describe('ActionSection', () => {
   };
 
   const createWrapper = (propsData = {}) => {
-    wrapper = shallowMount(ActionSection, {
+    wrapper = shallowMount(ApproverAction, {
       propsData: {
         initAction: DEFAULT_ACTION,
         existingApprovers: {},
@@ -71,8 +71,8 @@ describe('ActionSection', () => {
     });
   };
 
-  const findActionApprover = () => wrapper.findComponent(ActionApprovers);
-  const findAllActionApprovers = () => wrapper.findAllComponents(ActionApprovers);
+  const findActionApprover = () => wrapper.findComponent(ApproverSelectionWrapper);
+  const findAllApproverSelectionWrapper = () => wrapper.findAllComponents(ApproverSelectionWrapper);
   const findAllAlerts = () => wrapper.findAllComponents(GlAlert);
   const findSectionLayout = () => wrapper.findComponent(SectionLayout);
 
@@ -97,9 +97,9 @@ describe('ActionSection', () => {
     });
 
     it('creates a new approver on "addApproverType"', async () => {
-      expect(findAllActionApprovers()).toHaveLength(1);
+      expect(findAllApproverSelectionWrapper()).toHaveLength(1);
       await emit('addApproverType');
-      expect(findAllActionApprovers()).toHaveLength(2);
+      expect(findAllApproverSelectionWrapper()).toHaveLength(2);
     });
 
     it('does not render alert', () => {
@@ -237,7 +237,7 @@ describe('ActionSection', () => {
         APPROVER_TYPE_LIST_ITEMS.filter((t) => t.value !== USER_TYPE),
       );
       await emit('addApproverType');
-      findAllActionApprovers().at(0).vm.$emit('removeApproverType', USER_TYPE);
+      findAllApproverSelectionWrapper().at(0).vm.$emit('removeApproverType', USER_TYPE);
       await nextTick();
       expect(findActionApprover().props('availableTypes')).toEqual(
         expect.arrayContaining(APPROVER_TYPE_LIST_ITEMS),
@@ -281,7 +281,7 @@ describe('ActionSection', () => {
     });
 
     it('renders the user select when there are existing user approvers', () => {
-      expect(findAllActionApprovers()).toHaveLength(1);
+      expect(findAllApproverSelectionWrapper()).toHaveLength(1);
       expect(findActionApprover().props('approverType')).toBe(USER_TYPE);
     });
   });
@@ -295,7 +295,7 @@ describe('ActionSection', () => {
     });
 
     it('renders the group select when there are existing group approvers', () => {
-      expect(findAllActionApprovers()).toHaveLength(1);
+      expect(findAllApproverSelectionWrapper()).toHaveLength(1);
       expect(findActionApprover().props('approverType')).toBe(GROUP_TYPE);
     });
   });
@@ -309,9 +309,9 @@ describe('ActionSection', () => {
     });
 
     it('renders the user select with only the user approvers', () => {
-      expect(findAllActionApprovers()).toHaveLength(2);
-      expect(findAllActionApprovers().at(0).props('approverType')).toBe(GROUP_TYPE);
-      expect(findAllActionApprovers().at(1).props('approverType')).toBe(USER_TYPE);
+      expect(findAllApproverSelectionWrapper()).toHaveLength(2);
+      expect(findAllApproverSelectionWrapper().at(0).props('approverType')).toBe(GROUP_TYPE);
+      expect(findAllApproverSelectionWrapper().at(1).props('approverType')).toBe(USER_TYPE);
     });
   });
 
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_approvers_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/approver_selection_wrapper_spec.js
similarity index 96%
rename from ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_approvers_spec.js
rename to ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/approver_selection_wrapper_spec.js
index 36f722d328fd76b1f23c958781328a545d1cf9cb..4ae4f179b3708c4828c7c57a9ec7534e8f882a08 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/action_approvers_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/approver_selection_wrapper_spec.js
@@ -3,7 +3,7 @@ import { GlForm, GlFormInput, GlCollapsibleListbox, GlSprintf } from '@gitlab/ui
 import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 import SectionLayout from 'ee/security_orchestration/components/policy_editor/section_layout.vue';
 import { GROUP_TYPE, USER_TYPE } from 'ee/security_orchestration/constants';
-import ActionApprovers from 'ee/security_orchestration/components/policy_editor/scan_result/action/action_approvers.vue';
+import ApproverSelectionWrapper from 'ee/security_orchestration/components/policy_editor/scan_result/action/approver_selection_wrapper.vue';
 import GroupSelect from 'ee/security_orchestration/components/policy_editor/scan_result/action/group_select.vue';
 import UserSelect from 'ee/security_orchestration/components/policy_editor/scan_result/action/user_select.vue';
 import {
@@ -18,11 +18,11 @@ const DEFAULT_ACTION = {
   type: 'require_approval',
 };
 
-describe('ActionApprovers', () => {
+describe('ApproverSelectionWrapper', () => {
   let wrapper;
 
   const factory = ({ propsData = {}, stubs = {} } = {}) => {
-    wrapper = shallowMountExtended(ActionApprovers, {
+    wrapper = shallowMountExtended(ApproverSelectionWrapper, {
       propsData: {
         availableTypes: APPROVER_TYPE_LIST_ITEMS,
         approverIndex: 0,
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/bot_comment_action_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/bot_comment_action_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..18e02b635536ff565ece09502e48fd32c21ee969
--- /dev/null
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/action/bot_comment_action_spec.js
@@ -0,0 +1,18 @@
+import { shallowMount } from '@vue/test-utils';
+import SectionLayout from 'ee/security_orchestration/components/policy_editor/section_layout.vue';
+import BotCommentAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/bot_comment_action.vue';
+
+describe('BotCommentAction', () => {
+  let wrapper;
+
+  const factory = () => {
+    wrapper = shallowMount(BotCommentAction);
+  };
+
+  const findSectionLayout = () => wrapper.findComponent(SectionLayout);
+
+  it('renders', () => {
+    factory();
+    expect(findSectionLayout().exists()).toBe(true);
+  });
+});
diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/editor_component_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/editor_component_spec.js
index 95f2f20a9d67da3b3f62459cd81097a7d4733b14..6e26ad7a47d50babef4bb00611fec1b18228fe4f 100644
--- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/editor_component_spec.js
+++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_result/editor_component_spec.js
@@ -22,6 +22,7 @@ import {
   mockDefaultBranchesScanResultObject,
   mockDeprecatedScanResultManifest,
   mockDeprecatedScanResultObject,
+  mockBotCommentScanResultObject,
 } from 'ee_jest/security_orchestration/mocks/mock_scan_result_policy_data';
 import {
   unsupportedManifest,
@@ -47,7 +48,8 @@ import {
   PARSING_ERROR_MESSAGE,
 } from 'ee/security_orchestration/components/policy_editor/constants';
 import DimDisableContainer from 'ee/security_orchestration/components/policy_editor/dim_disable_container.vue';
-import ActionSection from 'ee/security_orchestration/components/policy_editor/scan_result/action/action_section.vue';
+import ActionSection from 'ee/security_orchestration/components/policy_editor/scan_result/action/action_section_new.vue';
+import ApproverAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/approver_action.vue';
 import RuleSection from 'ee/security_orchestration/components/policy_editor/scan_result/rule/rule_section.vue';
 
 jest.mock('lodash/uniqueId');
@@ -137,6 +139,8 @@ describe('EditorComponent', () => {
   const findPolicyEditorLayout = () => wrapper.findComponent(EditorLayout);
   const findActionSection = () => wrapper.findComponent(ActionSection);
   const findAllActionSections = () => wrapper.findAllComponents(ActionSection);
+  const findApproverAction = () => wrapper.findComponent(ApproverAction);
+  const findAllApproverActions = () => wrapper.findAllComponents(ApproverAction);
   const findAddActionButton = () => wrapper.findByTestId('add-action');
   const findAddRuleButton = () => wrapper.findByTestId('add-rule');
   const findAllDisabledComponents = () => wrapper.findAllComponents(DimDisableContainer);
@@ -195,12 +199,6 @@ describe('EditorComponent', () => {
       expect(findAddRuleButton().exists()).toBe(true);
     });
 
-    it('displays the initial action', () => {
-      factory();
-      expect(findAllActionSections()).toHaveLength(1);
-      expect(findActionSection().props('existingApprovers')).toEqual(scanResultPolicyApprovers);
-    });
-
     describe('when a user is not an owner of the project', () => {
       it('displays the empty state with the appropriate properties', () => {
         factory({ provide: { disableScanPolicyUpdate: true } });
@@ -221,7 +219,7 @@ describe('EditorComponent', () => {
           mockDefaultBranchesScanResultManifest,
         );
         expect(findAllRuleSections()).toHaveLength(1);
-        expect(findAllActionSections()).toHaveLength(1);
+        expect(findAllApproverActions()).toHaveLength(1);
       });
 
       it('displays a scan result policy', () => {
@@ -231,7 +229,7 @@ describe('EditorComponent', () => {
           mockDeprecatedScanResultManifest,
         );
         expect(findAllRuleSections()).toHaveLength(1);
-        expect(findAllActionSections()).toHaveLength(1);
+        expect(findAllApproverActions()).toHaveLength(1);
       });
     });
   });
@@ -392,17 +390,27 @@ describe('EditorComponent', () => {
       });
     });
 
-    describe('action section', () => {
+    describe('action section  when the "approvalPolicyDisableBotComment" feature is off', () => {
+      describe('rendering', () => {
+        it('displays the approver action when the "approvalPolicyDisableBotComment" feature is off', () => {
+          factory();
+          expect(findAllApproverActions()).toHaveLength(1);
+          expect(findApproverAction().props('existingApprovers')).toEqual(
+            scanResultPolicyApprovers,
+          );
+        });
+      });
+
       describe('add', () => {
         it('hides the add button when actions exist', () => {
           factory();
-          expect(findActionSection().exists()).toBe(true);
+          expect(findApproverAction().exists()).toBe(true);
           expect(findAddActionButton().exists()).toBe(false);
         });
 
         it('shows the add button when actions do not exist', () => {
           factoryWithExistingPolicy({ hasActions: false });
-          expect(findActionSection().exists()).toBe(false);
+          expect(findApproverAction().exists()).toBe(false);
           expect(findAddActionButton().exists()).toBe(true);
         });
       });
@@ -410,6 +418,120 @@ describe('EditorComponent', () => {
       describe('remove', () => {
         it('removes the initial action', async () => {
           factory();
+          expect(findApproverAction().exists()).toBe(true);
+          expect(findPolicyEditorLayout().props('policy')).toHaveProperty('actions');
+          await findApproverAction().vm.$emit('remove');
+          expect(findApproverAction().exists()).toBe(false);
+          expect(findPolicyEditorLayout().props('policy')).not.toHaveProperty('actions');
+        });
+
+        it('removes the action approvers when the action is removed', async () => {
+          factory();
+          await findApproverAction().vm.$emit(
+            'changed',
+            mockDefaultBranchesScanResultObject.actions[0],
+          );
+          await findApproverAction().vm.$emit('remove');
+          await findAddActionButton().vm.$emit('click');
+          expect(findPolicyEditorLayout().props('policy').actions).toEqual([
+            {
+              approvals_required: 1,
+              type: 'require_approval',
+              id: 'action_0',
+            },
+          ]);
+          expect(findApproverAction().props('existingApprovers')).toEqual({});
+        });
+      });
+
+      describe('update', () => {
+        beforeEach(() => {
+          factory();
+        });
+
+        it('updates policy action when edited', async () => {
+          const UPDATED_ACTION = { type: 'required_approval', group_approvers_ids: [1] };
+          await findApproverAction().vm.$emit('changed', UPDATED_ACTION);
+
+          expect(findApproverAction().props('initAction')).toEqual(UPDATED_ACTION);
+        });
+
+        it('updates the policy approvers', async () => {
+          const newApprover = ['owner'];
+
+          await findApproverAction().vm.$emit('updateApprovers', {
+            ...scanResultPolicyApprovers,
+            role: newApprover,
+          });
+
+          expect(findApproverAction().props('existingApprovers')).toMatchObject({
+            role: newApprover,
+          });
+        });
+
+        it('creates an error when the action section emits one', async () => {
+          await findApproverAction().vm.$emit('error');
+          verifiesParsingError();
+        });
+      });
+    });
+
+    describe('action section  when the "approvalPolicyDisableBotComment" feature is on', () => {
+      describe('rendering', () => {
+        afterAll(() => {
+          uniqueId.mockRestore();
+        });
+
+        it('displays the action section on the project-level when the "approvalPolicyDisableBotComment" feature is on', () => {
+          factory({
+            glFeatures: { approvalPolicyDisableBotComment: true },
+            provide: { namespaceType: NAMESPACE_TYPES.PROJECT },
+          });
+          expect(findActionSection().exists()).toBe(true);
+          expect(findApproverAction().exists()).toBe(false);
+        });
+
+        it('displays the approver action on the group-level when the "approvalPolicyDisableBotComment" feature is on', () => {
+          factory({
+            glFeatures: { approvalPolicyDisableBotComment: true },
+            provide: { namespaceType: NAMESPACE_TYPES.GROUP },
+          });
+          expect(findActionSection().exists()).toBe(false);
+          expect(findApproverAction().exists()).toBe(true);
+        });
+
+        it('displays multiple action sections', () => {
+          uniqueId
+            .mockImplementationOnce(jest.fn((prefix) => `${prefix}0`))
+            .mockImplementationOnce(jest.fn((prefix) => `${prefix}1`));
+          factoryWithExistingPolicy({
+            glFeatures: { approvalPolicyDisableBotComment: true },
+            policy: mockBotCommentScanResultObject,
+          });
+          expect(findAllActionSections()).toHaveLength(2);
+        });
+      });
+
+      describe('add', () => {
+        it('hides the add button when actions exist', () => {
+          factory({ glFeatures: { approvalPolicyDisableBotComment: true } });
+          expect(findActionSection().exists()).toBe(true);
+          expect(findAddActionButton().exists()).toBe(false);
+        });
+
+        it('shows the add button when actions do not exist', () => {
+          factoryWithExistingPolicy({
+            hasActions: false,
+            glFeatures: { approvalPolicyDisableBotComment: true },
+          });
+          expect(findActionSection().exists()).toBe(false);
+          expect(findAddActionButton().exists()).toBe(true);
+        });
+      });
+
+      describe('remove', () => {
+        it('removes the initial action', async () => {
+          factory({ glFeatures: { approvalPolicyDisableBotComment: true } });
           expect(findActionSection().exists()).toBe(true);
           expect(findPolicyEditorLayout().props('policy')).toHaveProperty('actions');
           await findActionSection().vm.$emit('remove');
@@ -418,7 +540,7 @@ describe('EditorComponent', () => {
         });
 
         it('removes the action approvers when the action is removed', async () => {
-          factory();
+          factory({ glFeatures: { approvalPolicyDisableBotComment: true } });
           await findActionSection().vm.$emit(
             'changed',
             mockDefaultBranchesScanResultObject.actions[0],
@@ -438,7 +560,7 @@ describe('EditorComponent', () => {
 
       describe('update', () => {
         beforeEach(() => {
-          factory();
+          factory({ glFeatures: { approvalPolicyDisableBotComment: true } });
         });
 
         it('updates policy action when edited', async () => {
@@ -534,7 +656,7 @@ describe('EditorComponent', () => {
           await findPolicyEditorLayout().vm.$emit('save-policy');
           await waitForPromises();
 
-          expect(findActionSection().props('errors')).toEqual(error.cause);
+          expect(findApproverAction().props('errors')).toEqual(error.cause);
           expect(wrapper.emitted('error')).toStrictEqual([['']]);
         });
 
@@ -545,7 +667,7 @@ describe('EditorComponent', () => {
           await findPolicyEditorLayout().vm.$emit('save-policy');
           await waitForPromises();
 
-          expect(findActionSection().props('errors')).toEqual([]);
+          expect(findApproverAction().props('errors')).toEqual([]);
           expect(wrapper.emitted('error')).toStrictEqual([[''], [error.message]]);
         });
 
@@ -556,7 +678,7 @@ describe('EditorComponent', () => {
           await findPolicyEditorLayout().vm.$emit('save-policy');
           await waitForPromises();
 
-          expect(findActionSection().props('errors')).toEqual([]);
+          expect(findApproverAction().props('errors')).toEqual([]);
           expect(wrapper.emitted('error')).toStrictEqual([[''], [error.message]]);
         });
 
@@ -567,7 +689,7 @@ describe('EditorComponent', () => {
           await findPolicyEditorLayout().vm.$emit('save-policy');
           await waitForPromises();
 
-          expect(findActionSection().props('errors')).toEqual([approverCause]);
+          expect(findApproverAction().props('errors')).toEqual([approverCause]);
           expect(wrapper.emitted('error')).toStrictEqual([[''], ['There was an error']]);
         });
       });
@@ -581,7 +703,7 @@ describe('EditorComponent', () => {
           await findPolicyEditorLayout().vm.$emit('save-policy');
           await waitForPromises();
 
-          expect(findActionSection().props('errors')).toEqual([]);
+          expect(findApproverAction().props('errors')).toEqual([]);
           expect(wrapper.emitted('error')).toStrictEqual([[''], [error.message]]);
         });
       });
@@ -823,8 +945,7 @@ describe('EditorComponent', () => {
       describe('displays the danger alert when there are no actions and no settings', () => {
         beforeEach(() => {
           factoryWithExistingPolicy({
-            hasActions: false,
-            policy: { approval_settings: { [BLOCK_BRANCH_MODIFICATION]: false } },
+            policy: { actions: [], approval_settings: { [BLOCK_BRANCH_MODIFICATION]: false } },
           });
         });
 
diff --git a/ee/spec/frontend/security_orchestration/mocks/mock_scan_result_policy_data.js b/ee/spec/frontend/security_orchestration/mocks/mock_scan_result_policy_data.js
index 3a85d93a8cc37e8dadc827c3ccdd70327c65b5c1..316f1d1c5d7b7e2a0bd31f7b1dbf8b897492cc01 100644
--- a/ee/spec/frontend/security_orchestration/mocks/mock_scan_result_policy_data.js
+++ b/ee/spec/frontend/security_orchestration/mocks/mock_scan_result_policy_data.js
@@ -58,6 +58,23 @@ export const mockDefaultBranchesScanResultObject = {
   ],
 };
 
+export const mockBotCommentScanResultObject = {
+  type: 'approval_policy',
+  name: 'Add bot comment',
+  description: '',
+  enabled: true,
+  rules: [],
+  actions: [
+    {
+      type: 'require_approval',
+      approvals_required: 1,
+    },
+    {
+      type: 'send_bot_comment',
+    },
+  ],
+};
+
 export const mockDeprecatedScanResultManifest = `type: scan_result_policy
 name: critical vulnerability CS approvals
 description: This policy enforces critical vulnerability CS approvals
diff --git a/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/actions_spec.js b/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/actions_spec.js
index 1ca2aec30d475c2e926366cac07df369a263633f..87016941fe51b1b69bd67f1d320bec2978be7b78 100644
--- a/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/actions_spec.js
+++ b/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/actions_spec.js
@@ -1,7 +1,7 @@
 import { mountExtended } from 'helpers/vue_test_utils_helper';
 import * as urlUtils from '~/lib/utils/url_utility';
 import App from 'ee/security_orchestration/components/policy_editor/app.vue';
-import ActionSection from 'ee/security_orchestration/components/policy_editor/scan_result/action/action_section.vue';
+import ApproverAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/approver_action.vue';
 import GroupSelect from 'ee/security_orchestration/components/policy_editor/scan_result/action/group_select.vue';
 import RoleSelect from 'ee/security_orchestration/components/policy_editor/scan_result/action/role_select.vue';
 import UserSelect from 'ee/security_orchestration/components/policy_editor/scan_result/action/user_select.vue';
@@ -52,7 +52,7 @@ describe('Scan result policy actions', () => {
 
   const findApprovalsInput = () => wrapper.findByTestId('approvals-required-input');
   const findAvailableTypeListBox = () => wrapper.findByTestId('available-types');
-  const findActionSection = () => wrapper.findComponent(ActionSection);
+  const findApproverAction = () => wrapper.findComponent(ApproverAction);
   const findGroupSelect = () => wrapper.findComponent(GroupSelect);
   const findRoleSelect = () => wrapper.findComponent(RoleSelect);
   const findUserSelect = () => wrapper.findComponent(UserSelect);
@@ -63,7 +63,7 @@ describe('Scan result policy actions', () => {
     });
 
     it('should render action section', () => {
-      expect(findActionSection().exists()).toBe(true);
+      expect(findApproverAction().exists()).toBe(true);
       expect(findYamlPreview(wrapper).text()).toContain(
         'actions:\n  - type: require_approval\n    approvals_required: 1',
       );
@@ -83,9 +83,9 @@ describe('Scan result policy actions', () => {
       const DEVELOPER = 'developer';
 
       const verifyRuleMode = () => {
-        expect(findActionSection().exists()).toBe(true);
+        expect(findApproverAction().exists()).toBe(true);
         expect(findRoleSelect().exists()).toBe(true);
-        expect(findActionSection().props('initAction').role_approvers).toEqual([DEVELOPER]);
+        expect(findApproverAction().props('initAction').role_approvers).toEqual([DEVELOPER]);
       };
 
       await findAvailableTypeListBox().vm.$emit('select', ROLE_TYPE);
@@ -103,9 +103,9 @@ describe('Scan result policy actions', () => {
 
     it('selects user approvers', async () => {
       const verifyRuleMode = () => {
-        expect(findActionSection().exists()).toBe(true);
+        expect(findApproverAction().exists()).toBe(true);
         expect(findUserSelect().exists()).toBe(true);
-        expect(findActionSection().props('initAction').user_approvers_ids).toEqual([USER.id]);
+        expect(findApproverAction().props('initAction').user_approvers_ids).toEqual([USER.id]);
       };
 
       await findAvailableTypeListBox().vm.$emit('select', USER_TYPE);
@@ -123,9 +123,9 @@ describe('Scan result policy actions', () => {
 
     it('selects group approvers', async () => {
       const verifyRuleMode = () => {
-        expect(findActionSection().exists()).toBe(true);
+        expect(findApproverAction().exists()).toBe(true);
         expect(findGroupSelect().exists()).toBe(true);
-        expect(findActionSection().props('initAction').group_approvers_ids).toEqual([GROUP.id]);
+        expect(findApproverAction().props('initAction').group_approvers_ids).toEqual([GROUP.id]);
       };
 
       await findAvailableTypeListBox().vm.$emit('select', GROUP_TYPE);
diff --git a/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/scan_result_spec.js b/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/scan_result_spec.js
index b930bc137bc768c6207f9fa447557e9700b2e30c..64a8da364de682a30e7c7ea1feff3f1bf988e52b 100644
--- a/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/scan_result_spec.js
+++ b/ee/spec/frontend_integration/security_orchestration/policy_editor/scan_result/scan_result_spec.js
@@ -3,7 +3,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
 import App from 'ee/security_orchestration/components/policy_editor/app.vue';
 import SettingsSection from 'ee/security_orchestration/components/policy_editor/scan_result/settings/settings_section.vue';
 import { DEFAULT_ASSIGNED_POLICY_PROJECT } from 'ee/security_orchestration/constants';
-import ActionSection from 'ee/security_orchestration/components/policy_editor/scan_result/action/action_section.vue';
+import ApproverAction from 'ee/security_orchestration/components/policy_editor/scan_result/action/approver_action.vue';
 import RuleSection from 'ee/security_orchestration/components/policy_editor/scan_result/rule/rule_section.vue';
 import { DEFAULT_PROVIDE } from '../mocks/mocks';
 
@@ -31,7 +31,7 @@ describe('Policy Editor', () => {
     wrapper.findByTestId('select-policy-approval_policy');
   const findYamlPreview = () => wrapper.findByTestId('rule-editor-preview');
   const findEmptyState = () => wrapper.findComponent(GlEmptyState);
-  const findActionSection = () => wrapper.findComponent(ActionSection);
+  const findApproverAction = () => wrapper.findComponent(ApproverAction);
   const findRuleSection = () => wrapper.findComponent(RuleSection);
   const findSettingsSection = () => wrapper.findComponent(SettingsSection);
 
@@ -47,7 +47,7 @@ describe('Policy Editor', () => {
   describe('rendering', () => {
     it('renders the page correctly', () => {
       expect(findEmptyState().exists()).toBe(false);
-      expect(findActionSection().exists()).toBe(true);
+      expect(findApproverAction().exists()).toBe(true);
       expect(findRuleSection().exists()).toBe(true);
       expect(findSettingsSection().exists()).toBe(true);
       expect(findYamlPreview().exists()).toBe(true);