diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_action.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_action.vue index 4899efe54acf59f6ea7c73e2bf93c9eb6c5a16e7..5a70c82e6e6993b4eb5a830996a0527df5e87a48 100644 --- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_action.vue +++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_action.vue @@ -7,6 +7,7 @@ import { REPORT_TYPE_DEPENDENCY_SCANNING, REPORT_TYPE_CONTAINER_SCANNING, } from '~/vue_shared/security_reports/constants'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { isProject, isGroup } from 'ee/security_orchestration/components/utils'; import SectionLayout from '../../section_layout.vue'; import { ACTION_AND_LABEL, RULE_MODE_SCANNERS } from '../../constants'; @@ -19,8 +20,9 @@ import { POLICY_ACTION_BUILDER_DAST_PROFILES_ERROR_KEY, } from '../constants'; import { buildScannerAction } from '../lib'; -import { CI_VARIABLE, FILTERS } from './scan_filters/constants'; +import { CI_VARIABLE, FILTERS, TEMPLATE } from './scan_filters/constants'; import CiVariablesSelectors from './scan_filters/ci_variables_selectors.vue'; +import TemplateSelector from './scan_filters/template_selector.vue'; import GroupDastProfileSelector from './scan_filters/group_dast_profile_selector.vue'; import ProjectDastProfileSelector from './scan_filters/project_dast_profile_selector.vue'; import RunnerTagsFilter from './scan_filters/runner_tags_filter.vue'; @@ -30,6 +32,7 @@ export default { CI_VARIABLE, FILTERS, SCANNERS: RULE_MODE_SCANNERS, + TEMPLATE, POLICY_ACTION_BUILDER_DAST_PROFILES_ERROR_KEY, POLICY_ACTION_BUILDER_TAGS_ERROR_KEY, components: { @@ -41,7 +44,9 @@ export default { GroupDastProfileSelector, RunnerTagsFilter, ScanFilterSelector, + TemplateSelector, }, + mixins: [glFeatureFlagsMixin()], inject: ['namespacePath', 'namespaceType'], props: { initAction: { @@ -92,6 +97,12 @@ export default { isProject() { return isProject(this.namespaceType); }, + hasTemplateSelector() { + return ( + this.glFeatures.scanExecutionPoliciesWithLatestTemplates || + this.glFeatures.scanExecutionPoliciesWithLatestTemplatesGroup + ); + }, siteProfile() { return this.initAction.site_profile?.trim() ?? ''; }, @@ -114,16 +125,17 @@ export default { isFilterSelected(filter) { return this.filters[filter]; }, - emitCiVariableFilterChanges() { + emitFilterChanges(filter) { const updatedAction = { ...this.initAction }; - delete updatedAction.variables; + if (filter === CI_VARIABLE) delete updatedAction.variables; + if (filter === TEMPLATE) delete updatedAction.template; this.$emit('changed', updatedAction); }, - removeCiFilter() { + removeFilter(filter) { const newFilters = { ...this.filters }; - delete newFilters[CI_VARIABLE]; + delete newFilters[filter]; this.filters = newFilters; - this.emitCiVariableFilterChanges(); + this.emitFilterChanges(filter); }, removeYamlProperty(property) { const updatedAction = { ...this.initAction }; @@ -231,12 +243,19 @@ export default { @error="$emit('parsing-error', $options.POLICY_ACTION_BUILDER_TAGS_ERROR_KEY)" /> + <template-selector + v-if="hasTemplateSelector" + :selected="initAction.template" + @input="triggerChanged" + @remove="removeFilter($options.TEMPLATE)" + /> + <ci-variables-selectors v-if="isCIVariableSelectorSelected" class="gl-bg-white" :scan-type="initAction.scan" :selected="initAction.variables" - @remove="removeCiFilter" + @remove="removeFilter($options.CI_VARIABLE)" @input="triggerChanged" /> diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/constants.js b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/constants.js index b8c04fb91ca95487f82645a54681f6cdc79f0338..c70a78da1ae8cd16e03f9014f2b0c57ca7d821d5 100644 --- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/constants.js +++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/constants.js @@ -2,6 +2,12 @@ import { s__ } from '~/locale'; export const CI_VARIABLE = 'ci_variable'; +export const TEMPLATE = 'template'; + +export const DEFAULT_TEMPLATE = 'default'; + +export const LATEST_TEMPLATE = 'latest'; + export const FILTERS = [ { text: s__('ScanResultPolicy|Customized CI Variables'), diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/template_selector.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/template_selector.vue new file mode 100644 index 0000000000000000000000000000000000000000..8b33bbe51c51b404071476ab9707b589dac27d42 --- /dev/null +++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/template_selector.vue @@ -0,0 +1,86 @@ +<script> +import { GlCollapsibleListbox, GlIcon, GlTooltipDirective as GlTooltip } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import SectionLayout from 'ee/security_orchestration/components/policy_editor/section_layout.vue'; +import { DEFAULT_TEMPLATE, LATEST_TEMPLATE } from './constants'; + +export default { + i18n: { + label: s__('SecurityOrchestration|Security job template'), + defaultTemplateInformation: s__( + 'SecurityOrchestration|CI/CD template edition to be enforced. The default template is stable, but may not have all the features of the latest template.', + ), + latestTemplateInformation: s__( + 'SecurityOrchestration|CI/CD template edition to be enforced. The latest edition may introduce breaking changes.', + ), + }, + components: { + GlCollapsibleListbox, + GlIcon, + SectionLayout, + }, + directives: { + GlTooltip, + }, + props: { + selected: { + type: String, + required: false, + default: DEFAULT_TEMPLATE, + }, + }, + computed: { + availableOptions() { + return [ + { text: s__('SecurityOrchestration|latest'), value: LATEST_TEMPLATE }, + { text: s__('SecurityOrchestration|default'), value: DEFAULT_TEMPLATE }, + ]; + }, + tooltipMessage() { + return this.selected === LATEST_TEMPLATE + ? this.$options.i18n.latestTemplateInformation + : this.$options.i18n.defaultTemplateInformation; + }, + }, + methods: { + toggleValue(value) { + if (value === LATEST_TEMPLATE) { + this.$emit('input', { template: value }); + } else { + this.$emit('remove'); + } + }, + }, +}; +</script> + +<template> + <section-layout + class="gl-w-full gl-bg-white" + content-classes="gl-justify-content-space-between" + :show-remove-button="false" + > + <template #selector> + <label class="gl-mb-0 gl-mr-4" for="policy-template" :title="$options.i18n.label"> + {{ $options.i18n.label }} + </label> + </template> + + <template #content> + <div class="gl-display-flex gl-flex-grow-2 gl-align-items-center"> + <gl-collapsible-listbox + id="policy-template" + :items="availableOptions" + :selected="selected" + @select="toggleValue" + /> + <gl-icon + v-gl-tooltip + name="question-o" + :title="tooltipMessage" + class="gl-text-blue-600 gl-ml-3" + /> + </div> + </template> + </section-layout> +</template> diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml.js b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml.js index bd95ff700c1a4db775a5acb5f5ffb85054a4bbe6..a6d38b3b976d04c6b2944174fd34e06aa537d540 100644 --- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml.js +++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml.js @@ -1,5 +1,9 @@ import { safeLoad } from 'js-yaml'; import { CUSTOM_ACTION_KEY } from 'ee/security_orchestration/components/policy_editor/scan_execution/constants'; +import { + DEFAULT_TEMPLATE, + LATEST_TEMPLATE, +} from 'ee/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/constants'; import { addIdsToPolicy, isValidPolicy, hasInvalidCron } from '../../utils'; import { BRANCH_TYPE_KEY, @@ -22,6 +26,17 @@ const hasInvalidBranchType = (rules) => { ); }; +/** + * Check if any action has invalid template type + * @param {Array} actions + * @returns {Boolean} + */ +const hasInvalidTemplate = (actions = []) => { + return actions.some(({ template }) => { + return (template || template === '') && ![DEFAULT_TEMPLATE, LATEST_TEMPLATE].includes(template); + }); +}; + /** * Checks if rule mode supports the inputted scanner * @param {Object} policy @@ -70,7 +85,15 @@ export const fromYaml = ({ manifest, validateRuleMode = false }) => { 'branch_exceptions', 'id', ]; - const actionsKeys = ['scan', 'site_profile', 'scanner_profile', 'variables', 'tags', 'id']; + const actionsKeys = [ + 'scan', + 'site_profile', + 'scanner_profile', + 'variables', + 'tags', + 'id', + 'template', + ]; if (gon?.features?.compliancePipelineInPolicies) { actionsKeys.push('ci_configuration'); @@ -79,6 +102,7 @@ export const fromYaml = ({ manifest, validateRuleMode = false }) => { return isValidPolicy({ policy, rulesKeys, actionsKeys }) && !hasInvalidCron(policy) && !hasInvalidBranchType(policy.rules) && + !hasInvalidTemplate(policy.actions) && hasRuleModeSupportedScanners(policy) ? policy : { error: true }; diff --git a/ee/app/controllers/groups/security/policies_controller.rb b/ee/app/controllers/groups/security/policies_controller.rb index 6e4dc77ed3b4e206497cce1385f47189c63905ae..8ed86413ef7147096f2ab37c9562d6e58a67b4af 100644 --- a/ee/app/controllers/groups/security/policies_controller.rb +++ b/ee/app/controllers/groups/security/policies_controller.rb @@ -13,6 +13,7 @@ class PoliciesController < Groups::ApplicationController push_frontend_feature_flag(:compliance_pipeline_in_policies, group) push_frontend_feature_flag(:pipeline_execution_policy_type, group) push_frontend_feature_flag(:vulnerability_management_policy_type_group, group) + push_frontend_feature_flag(:scan_execution_policies_with_latest_templates_group, group) end feature_category :security_policy_management diff --git a/ee/app/controllers/projects/security/policies_controller.rb b/ee/app/controllers/projects/security/policies_controller.rb index 442e09207a14c0b3e54d826f97d31c797cbe9137..dc636f4af5914e80f78b0caebf4e77f730e50843 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(:pipeline_execution_policy_type, project.group) if project.group push_frontend_feature_flag(:approval_policy_disable_bot_comment, project) push_frontend_feature_flag(:vulnerability_management_policy_type, project) + push_frontend_feature_flag(:scan_execution_policies_with_latest_templates) end feature_category :security_policy_management diff --git a/ee/config/feature_flags/gitlab_com_derisk/scan_execution_policies_with_latest_templates_group.yml b/ee/config/feature_flags/gitlab_com_derisk/scan_execution_policies_with_latest_templates_group.yml new file mode 100644 index 0000000000000000000000000000000000000000..df6ae8693df2a340d9a11433cc3d83bd3813a6a4 --- /dev/null +++ b/ee/config/feature_flags/gitlab_com_derisk/scan_execution_policies_with_latest_templates_group.yml @@ -0,0 +1,9 @@ +--- +name: scan_execution_policies_with_latest_templates_group +feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415427 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/154468 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/468981 +milestone: '17.2' +group: group::security policies +type: gitlab_com_derisk +default_enabled: false diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/scan_action_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/scan_action_spec.js index a7f174e3dc8214a32594b78b6d2f5c1b519fcc76..b6995c051a756718bfb76cfc690093a38ceecd7b 100644 --- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/scan_action_spec.js +++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/scan_action_spec.js @@ -9,6 +9,7 @@ import groupRunnerTags from 'ee/vue_shared/components/runner_tags_dropdown/graph import GroupDastProfileSelector from 'ee/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/group_dast_profile_selector.vue'; import RunnerTagsFilter from 'ee/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/runner_tags_filter.vue'; import CiVariablesSelectors from 'ee/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/ci_variables_selectors.vue'; +import TemplateSelector from 'ee/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/template_selector.vue'; import ScanFilterSelector from 'ee/security_orchestration/components/policy_editor/scan_filter_selector.vue'; import { buildScannerAction } from 'ee/security_orchestration/components/policy_editor/scan_execution/lib'; import { NAMESPACE_TYPES } from 'ee/security_orchestration/constants'; @@ -26,7 +27,9 @@ import { createMockApolloProvider } from 'ee_jest/security_configuration/dast_pr import { RUNNER_TAG_LIST_MOCK } from 'ee_jest/vue_shared/components/runner_tags_dropdown/mocks/mocks'; import { CI_VARIABLE, + DEFAULT_TEMPLATE, FILTERS, + LATEST_TEMPLATE, } from 'ee/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/constants'; const actionId = 'action_0'; @@ -88,6 +91,7 @@ describe('PolicyActionBuilder', () => { const findActionSeperator = () => wrapper.findByTestId('action-and-label'); const findCiVariablesSelectors = () => wrapper.findComponent(CiVariablesSelectors); + const findTemplateFilter = () => wrapper.findComponent(TemplateSelector); const findSectionLayout = () => wrapper.findAllComponents(SectionLayout).at(1); const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox); const findScanFilterSelector = () => wrapper.findComponent(ScanFilterSelector); @@ -192,10 +196,62 @@ describe('PolicyActionBuilder', () => { }); }); + describe('template filter', () => { + describe('without the feature flag', () => { + it('does not render', () => { + factory(); + expect(findTemplateFilter().exists()).toBe(false); + }); + }); + + describe('with the feature flag', () => { + describe.each([ + 'scanExecutionPoliciesWithLatestTemplates', + 'scanExecutionPoliciesWithLatestTemplatesGroup', + ])('%s feature flag', (featureFlag) => { + it('renders', () => { + factory({ + provide: { glFeatures: { [featureFlag]: true } }, + }); + expect(findTemplateFilter().exists()).toBe(true); + }); + + it('emits "changed" with the updated value when updated', () => { + factory({ + propsData: { + initAction: { + ...DEFAULT_ACTION, + template: LATEST_TEMPLATE, + }, + }, + provide: { glFeatures: { [featureFlag]: true } }, + }); + findTemplateFilter().vm.$emit('input', { template: DEFAULT_TEMPLATE }); + expect(wrapper.emitted('changed')).toEqual([ + [{ ...DEFAULT_ACTION, template: DEFAULT_TEMPLATE }], + ]); + }); + + it('emits "changed" with the updated value when removed', () => { + factory({ + propsData: { + initAction: { + ...DEFAULT_ACTION, + template: LATEST_TEMPLATE, + }, + }, + provide: { glFeatures: { [featureFlag]: true } }, + }); + findTemplateFilter().vm.$emit('remove'); + expect(wrapper.emitted('changed')).toEqual([[{ ...DEFAULT_ACTION }]]); + }); + }); + }); + }); + describe('ci variable filter', () => { it('initially hides ci variable filter', () => { factory(); - expect(findCiVariablesSelectors().exists()).toBe(false); }); diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/template_selector_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/template_selector_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..d756a3133cdf1a3decb3257aa57a32e7ff8c1d84 --- /dev/null +++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/template_selector_spec.js @@ -0,0 +1,71 @@ +import { GlCollapsibleListbox, GlIcon } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import SectionLayout from 'ee/security_orchestration/components/policy_editor/section_layout.vue'; +import TemplateSelector from 'ee/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/template_selector.vue'; +import { + DEFAULT_TEMPLATE, + LATEST_TEMPLATE, +} from 'ee/security_orchestration/components/policy_editor/scan_execution/action/scan_filters/constants'; + +describe('TemplateSelector', () => { + let wrapper; + + const createComponent = (propsData = {}) => { + wrapper = shallowMountExtended(TemplateSelector, { + propsData, + stubs: { + SectionLayout, + }, + }); + }; + + const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox); + const findIcon = () => wrapper.findComponent(GlIcon); + + it('renders default value', () => { + createComponent(); + expect(findDropdown().props('selected')).toBe(DEFAULT_TEMPLATE); + }); + + it('renders help icon for default template', () => { + createComponent(); + expect(findIcon().exists()).toBe(true); + expect(findIcon().attributes('title')).toBe( + 'CI/CD template edition to be enforced. The default template is stable, but may not have all the features of the latest template.', + ); + }); + + it('renders help icon for latest template', () => { + createComponent({ selected: LATEST_TEMPLATE }); + expect(findIcon().exists()).toBe(true); + expect(findIcon().attributes('title')).toBe( + 'CI/CD template edition to be enforced. The latest edition may introduce breaking changes.', + ); + }); + + it('renders selected value', () => { + createComponent({ selected: LATEST_TEMPLATE }); + expect(findDropdown().props('selected')).toBe(LATEST_TEMPLATE); + }); + + it('emits "input" event when "latest" is selected', () => { + createComponent(); + expect(wrapper.emitted('input')).toEqual(undefined); + expect(wrapper.emitted('remove')).toEqual(undefined); + findDropdown().vm.$emit('select', LATEST_TEMPLATE); + expect(wrapper.emitted('input')).toEqual([[{ template: LATEST_TEMPLATE }]]); + expect(wrapper.emitted('remove')).toEqual(undefined); + }); + + it('emits "remove" event when "default" is selected', () => { + createComponent(); + expect(wrapper.emitted('input')).toEqual(undefined); + expect(wrapper.emitted('remove')).toEqual(undefined); + findDropdown().vm.$emit('select', LATEST_TEMPLATE); + expect(wrapper.emitted('input')).toHaveLength(1); + expect(wrapper.emitted('remove')).toEqual(undefined); + findDropdown().vm.$emit('select', DEFAULT_TEMPLATE); + expect(wrapper.emitted('input')).toHaveLength(1); + expect(wrapper.emitted('remove')).toEqual([[]]); + }); +}); diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml_spec.js index 3c39aded1449711a310dd57a437b0d89e9d203fd..419c3c3a7b0b0735ea662471e8acf0e7220983ff 100644 --- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml_spec.js +++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/lib/from_yaml_spec.js @@ -19,6 +19,9 @@ import { mockPolicyScopeScanExecutionObject, mockCodeBlockFilePathScanExecutionManifest, mockCodeBlockFilePathScanExecutionObject, + mockTemplateScanExecutionManifest, + mockTemplateScanExecutionObject, + mockInvalidTemplateScanExecutionManifest, } from 'ee_jest/security_orchestration/mocks/mock_scan_execution_policy_data'; jest.mock('lodash/uniqueId', () => jest.fn((prefix) => `${prefix}0`)); @@ -35,6 +38,8 @@ describe('fromYaml', () => { ${'returns the policy object for project scope'} | ${{ manifest: mockPolicyScopeExecutionManifest, validateRuleMode: true }} | ${mockPolicyScopeScanExecutionObject} | ${{}} ${'returns the policy object for custom code block with file path with enabled ff'} | ${{ manifest: mockCodeBlockFilePathScanExecutionManifest, validateRuleMode: true }} | ${mockCodeBlockFilePathScanExecutionObject} | ${{ compliancePipelineInPolicies: true }} ${'returns the policy object for custom code block with file path with disabled ff'} | ${{ manifest: mockCodeBlockFilePathScanExecutionManifest, validateRuleMode: true }} | ${{ error: true }} | ${{ compliancePipelineInPolicies: false }} + ${'returns the policy object for valid template value'} | ${{ manifest: mockTemplateScanExecutionManifest, validateRuleMode: true }} | ${mockTemplateScanExecutionObject} | ${{ compliancePipelineInPolicies: false }} + ${'returns error object for a policy with invalid template value'} | ${{ manifest: mockInvalidTemplateScanExecutionManifest, validateRuleMode: true }} | ${{ error: true }} | ${{}} `('$title', ({ input, output, features }) => { window.gon = { features }; expect(fromYaml(input)).toStrictEqual(output); diff --git a/ee/spec/frontend/security_orchestration/mocks/mock_scan_execution_policy_data.js b/ee/spec/frontend/security_orchestration/mocks/mock_scan_execution_policy_data.js index 45649fa95571adefd683049811c32baa44cf61cb..d6afc9063e795a3e3d4024d47343b1037f767094 100644 --- a/ee/spec/frontend/security_orchestration/mocks/mock_scan_execution_policy_data.js +++ b/ee/spec/frontend/security_orchestration/mocks/mock_scan_execution_policy_data.js @@ -31,6 +31,22 @@ actions: scanner_profile: required_scanner_profile `; +export const mockDastScanExecutionObject = { + type: 'scan_execution_policy', + name: 'Scheduled Dast/SAST scan', + description: 'This policy enforces pipeline configuration to have a job with DAST scan', + enabled: false, + rules: [{ type: 'pipeline', branches: ['main'], id: ruleId }], + actions: [ + { + scan: 'dast', + site_profile: 'required_site_profile', + scanner_profile: 'required_scanner_profile', + id: actionId, + }, + ], +}; + export const mockBranchExceptionsExecutionManifest = `type: scan_execution_policy name: Branch exceptions description: This policy enforces pipeline configuration to have branch exceptions @@ -48,22 +64,6 @@ actions: scanner_profile: required_scanner_profile `; -export const mockDastScanExecutionObject = { - type: 'scan_execution_policy', - name: 'Scheduled Dast/SAST scan', - description: 'This policy enforces pipeline configuration to have a job with DAST scan', - enabled: false, - rules: [{ type: 'pipeline', branches: ['main'], id: ruleId }], - actions: [ - { - scan: 'dast', - site_profile: 'required_site_profile', - scanner_profile: 'required_scanner_profile', - id: actionId, - }, - ], -}; - export const mockBranchExceptionsScanExecutionObject = { type: 'scan_execution_policy', name: 'Branch exceptions', @@ -282,3 +282,16 @@ export const mockCodeBlockFilePathScanExecutionObject = { }, ], }; + +export const mockTemplateScanExecutionManifest = mockDastScanExecutionManifest.concat( + ` template: default\n`, +); + +export const mockTemplateScanExecutionObject = { + ...mockDastScanExecutionObject, + actions: [{ ...mockDastScanExecutionObject.actions[0], template: 'default' }], +}; + +export const mockInvalidTemplateScanExecutionManifest = mockDastScanExecutionManifest.concat( + ` template: not-valid-value\n`, +); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b0b550eab3166b1ec589b31b905a91bad35ee714..f62d75a9b9d63a865c28fd935fae1521dbf9cd99 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -47709,6 +47709,12 @@ msgstr "" msgid "SecurityOrchestration|Branch: %{boldStart}%{branchName}%{boldEnd} was not found in project: %{boldStart}%{projectName}%{boldEnd}. Edit or remove this entry." msgstr "" +msgid "SecurityOrchestration|CI/CD template edition to be enforced. The default template is stable, but may not have all the features of the latest template." +msgstr "" + +msgid "SecurityOrchestration|CI/CD template edition to be enforced. The latest edition may introduce breaking changes." +msgstr "" + msgid "SecurityOrchestration|Cadence is invalid" msgstr "" @@ -48089,6 +48095,9 @@ msgstr "" msgid "SecurityOrchestration|Security Scan" msgstr "" +msgid "SecurityOrchestration|Security job template" +msgstr "" + msgid "SecurityOrchestration|Security policy overwrites this setting" msgstr "" @@ -48374,6 +48383,9 @@ msgstr "" msgid "SecurityOrchestration|compliance frameworks" msgstr "" +msgid "SecurityOrchestration|default" +msgstr "" + msgid "SecurityOrchestration|except projects" msgstr "" @@ -48389,6 +48401,9 @@ msgstr "" msgid "SecurityOrchestration|have no fix available" msgstr "" +msgid "SecurityOrchestration|latest" +msgstr "" + msgid "SecurityOrchestration|more than %{allowed}" msgstr ""