diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-13 03:10:17 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-13 03:10:17 +0300 |
commit | dce8d0c6a7fdc7cca4df3b00b11d68000d117e2f (patch) | |
tree | ae6060a584549cfcecced34eea93e2b4fe5c64ed | |
parent | 74cb1a1df361969e97d1a85683c1dfca5ac8cad1 (diff) |
Add latest changes from gitlab-org/gitlab@master
42 files changed, 343 insertions, 228 deletions
@@ -530,7 +530,7 @@ gem 'ssh_data', '~> 1.3' # rubocop:todo Gemfile/MissingFeatureCategory gem 'spamcheck', '~> 1.3.0' # rubocop:todo Gemfile/MissingFeatureCategory # Gitaly GRPC protocol definitions -gem 'gitaly', '~> 16.3.0-rc1' # rubocop:todo Gemfile/MissingFeatureCategory +gem 'gitaly', '~> 16.5.0.pre.rc1' # rubocop:todo Gemfile/MissingFeatureCategory # KAS GRPC protocol definitions gem 'kas-grpc', '~> 0.2.0' # rubocop:todo Gemfile/MissingFeatureCategory diff --git a/Gemfile.checksum b/Gemfile.checksum index 8d7326c7821..8397f016bac 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -203,7 +203,7 @@ {"name":"gettext_i18n_rails","version":"1.11.0","platform":"ruby","checksum":"e19c7e4a256c500f7f38396dca44a282b9838ae278f57c362993a54964b22bbe"}, {"name":"gettext_i18n_rails_js","version":"1.3.0","platform":"ruby","checksum":"5d10afe4be3639bff78c50a56768c20f39aecdabc580c08aa45573911c2bd687"}, {"name":"git","version":"1.18.0","platform":"ruby","checksum":"c9b80462e4565cd3d7a9ba8440c41d2c52244b17b0dad0bfddb46de70630c465"}, -{"name":"gitaly","version":"16.3.0.pre.rc1","platform":"ruby","checksum":"55d9cc414a4f3859588f3770bd88d7c67c0f5454a1178b018b7a6f6913674c43"}, +{"name":"gitaly","version":"16.5.0.pre.rc1","platform":"ruby","checksum":"ed17515ad04d4663a0efc15c8f2887b705f006133e8b10cc9321460eb0a38353"}, {"name":"gitlab","version":"4.19.0","platform":"ruby","checksum":"3f645e3e195dbc24f0834fbf83e8ccfb2056d8e9712b01a640aad418a6949679"}, {"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"}, {"name":"gitlab-dangerfiles","version":"4.1.0","platform":"ruby","checksum":"ecf2262fcc038c1e77f7ea014f5fa8657e02ae37fde5034a2d7f67fd6e804d8d"}, diff --git a/Gemfile.lock b/Gemfile.lock index 51101a25079..77e936d8bc0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -639,7 +639,7 @@ GEM git (1.18.0) addressable (~> 2.8) rchardet (~> 1.8) - gitaly (16.3.0.pre.rc1) + gitaly (16.5.0.pre.rc1) grpc (~> 1.0) gitlab (4.19.0) httparty (~> 0.20) @@ -1816,7 +1816,7 @@ DEPENDENCIES gettext (~> 3.3) gettext_i18n_rails (~> 1.11.0) gettext_i18n_rails_js (~> 1.3) - gitaly (~> 16.3.0.pre.rc1) + gitaly (~> 16.5.0.pre.rc1) gitlab-chronic (~> 0.10.5) gitlab-dangerfiles (~> 4.1.0) gitlab-experiment (~> 0.8.0) diff --git a/app/assets/javascripts/super_sidebar/components/user_menu.vue b/app/assets/javascripts/super_sidebar/components/user_menu.vue index ed6c41e85c6..891e883b6c0 100644 --- a/app/assets/javascripts/super_sidebar/components/user_menu.vue +++ b/app/assets/javascripts/super_sidebar/components/user_menu.vue @@ -12,7 +12,7 @@ import NewNavToggle from '~/nav/components/new_nav_toggle.vue'; import Tracking from '~/tracking'; import PersistentUserCallout from '~/persistent_user_callout'; import { USER_MENU_TRACKING_DEFAULTS, DROPDOWN_Y_OFFSET, IMPERSONATING_OFFSET } from '../constants'; -import UserNameGroup from './user_name_group.vue'; +import UserMenuProfileItem from './user_menu_profile_item.vue'; // Left offset required for the dropdown to be aligned with the super sidebar const DROPDOWN_X_OFFSET_BASE = -211; @@ -40,7 +40,7 @@ export default { GlDisclosureDropdownItem, GlButton, NewNavToggle, - UserNameGroup, + UserMenuProfileItem, }, directives: { SafeHtml, @@ -247,7 +247,10 @@ export default { </gl-button> </template> - <user-name-group :user="data" /> + <gl-disclosure-dropdown-group> + <user-menu-profile-item :user="data" /> + </gl-disclosure-dropdown-group> + <gl-disclosure-dropdown-group bordered> <gl-disclosure-dropdown-item v-if="data.status.can_update" diff --git a/app/assets/javascripts/super_sidebar/components/user_menu_profile_item.vue b/app/assets/javascripts/super_sidebar/components/user_menu_profile_item.vue new file mode 100644 index 00000000000..95255ce3d8e --- /dev/null +++ b/app/assets/javascripts/super_sidebar/components/user_menu_profile_item.vue @@ -0,0 +1,83 @@ +<script> +import { GlBadge, GlDisclosureDropdownItem, GlTooltip } from '@gitlab/ui'; +import SafeHtml from '~/vue_shared/directives/safe_html'; +import { s__ } from '~/locale'; +import { USER_MENU_TRACKING_DEFAULTS } from '../constants'; + +export default { + i18n: { + user: { + busy: s__('UserProfile|Busy'), + }, + }, + components: { + GlBadge, + GlDisclosureDropdownItem, + GlTooltip, + }, + directives: { + SafeHtml, + }, + props: { + user: { + required: true, + type: Object, + }, + }, + computed: { + menuItem() { + const item = { + text: this.user.name, + }; + if (this.user.has_link_to_profile) { + item.href = this.user.link_to_profile; + + item.extraAttrs = { + ...USER_MENU_TRACKING_DEFAULTS, + 'data-track-label': 'user_profile', + 'data-testid': 'user-profile-link', + }; + } + + return item; + }, + }, +}; +</script> + +<template> + <gl-disclosure-dropdown-item :item="menuItem"> + <template #list-item> + <span class="gl-display-flex gl-flex-direction-column"> + <span> + <span class="gl-font-weight-bold"> + {{ user.name }} + </span> + <gl-badge v-if="user.status.busy" size="sm" variant="warning"> + {{ $options.i18n.user.busy }} + </gl-badge> + </span> + + <span class="gl-text-gray-400 gl-word-break-all">@{{ user.username }}</span> + + <span + v-if="user.status.customized" + ref="statusTooltipTarget" + data-testid="user-menu-status" + class="gl-display-flex gl-align-items-baseline gl-mt-2 gl-font-sm" + > + <gl-emoji :data-name="user.status.emoji" class="gl-mr-1" /> + <span v-safe-html="user.status.message_html" class="gl-text-truncate"></span> + <gl-tooltip + v-if="user.status.message_html" + :target="() => $refs.statusTooltipTarget" + boundary="viewport" + placement="bottom" + > + <span v-safe-html="user.status.message_html"></span> + </gl-tooltip> + </span> + </span> + </template> + </gl-disclosure-dropdown-item> +</template> diff --git a/app/assets/javascripts/super_sidebar/components/user_name_group.vue b/app/assets/javascripts/super_sidebar/components/user_name_group.vue deleted file mode 100644 index 29cc340116b..00000000000 --- a/app/assets/javascripts/super_sidebar/components/user_name_group.vue +++ /dev/null @@ -1,91 +0,0 @@ -<script> -import { - GlBadge, - GlDisclosureDropdownGroup, - GlDisclosureDropdownItem, - GlTooltip, -} from '@gitlab/ui'; -import SafeHtml from '~/vue_shared/directives/safe_html'; -import { s__ } from '~/locale'; -import { USER_MENU_TRACKING_DEFAULTS } from '../constants'; - -export default { - i18n: { - user: { - busy: s__('UserProfile|Busy'), - }, - }, - components: { - GlBadge, - GlDisclosureDropdownGroup, - GlDisclosureDropdownItem, - GlTooltip, - }, - directives: { - SafeHtml, - }, - props: { - user: { - required: true, - type: Object, - }, - }, - computed: { - menuItem() { - const item = { - text: this.user.name, - }; - if (this.user.has_link_to_profile) { - item.href = this.user.link_to_profile; - - item.extraAttrs = { - ...USER_MENU_TRACKING_DEFAULTS, - 'data-track-label': 'user_profile', - 'data-testid': 'user-profile-link', - }; - } - - return item; - }, - }, -}; -</script> - -<template> - <gl-disclosure-dropdown-group> - <gl-disclosure-dropdown-item :item="menuItem"> - <template #list-item> - <span class="gl-display-flex gl-flex-direction-column"> - <span> - <span class="gl-font-weight-bold"> - {{ user.name }} - </span> - <gl-badge v-if="user.status.busy" size="sm" variant="warning"> - {{ $options.i18n.user.busy }} - </gl-badge> - </span> - - <span class="gl-text-gray-400 gl-word-break-all">@{{ user.username }}</span> - - <span - v-if="user.status.customized" - ref="statusTooltipTarget" - data-testid="user-menu-status" - class="gl-display-flex gl-align-items-baseline gl-mt-2 gl-font-sm" - > - <gl-emoji :data-name="user.status.emoji" class="gl-mr-1" /> - <span v-safe-html="user.status.message_html" class="gl-text-truncate"></span> - <gl-tooltip - v-if="user.status.message_html" - :target="() => $refs.statusTooltipTarget" - boundary="viewport" - placement="bottom" - > - <span v-safe-html="user.status.message_html"></span> - </gl-tooltip> - </span> - </span> - </template> - </gl-disclosure-dropdown-item> - </gl-disclosure-dropdown-group> -</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue b/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue index c49c1316b1b..619f141144d 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue @@ -83,12 +83,6 @@ export default { return btn.tooltipText; }, - actionButtonQaSelector(btn) { - if (btn.dataQaSelector) { - return btn.dataQaSelector; - } - return 'mr_widget_extension_actions_button'; - }, }, }; </script> @@ -105,7 +99,6 @@ export default { :target="btn.target" :class="[{ 'gl-mr-3': index !== tertiaryButtons.length - 1 }, btn.class]" :data-clipboard-text="btn.dataClipboardText" - :data-qa-selector="actionButtonQaSelector(btn)" :data-method="btn.dataMethod" :icon="btn.icon" :data-testid="btn.testId || 'extension-actions-button'" @@ -159,7 +152,6 @@ export default { :target="btn.target" :class="[{ 'gl-mr-1': index !== tertiaryButtons.length - 1 }, btn.class]" :data-clipboard-text="btn.dataClipboardText" - :data-qa-selector="actionButtonQaSelector(btn)" :data-method="btn.dataMethod" :icon="btn.icon" :data-testid="btn.testId || 'extension-actions-button'" diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue index 6299f0fcbb8..ec72b74daa2 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue @@ -75,7 +75,6 @@ export default { actions.push({ text: this.cancelButtonText, loading: this.isCancellingAutoMerge, - dataQaSelector: 'cancel_auto_merge_button', class: 'js-cancel-auto-merge', testId: 'cancelAutomaticMergeButton', onClick: () => this.cancelAutomaticMerge(), diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue index 4d906f29cb0..4454718a647 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue @@ -67,7 +67,7 @@ export default { actions.push({ text: this.revertLabel, tooltipText: this.revertTitle, - dataQaSelector: 'revert_button', + testId: 'revert-button', onClick: () => this.openRevertModal(), }); } else if (this.mr.revertInForkPath) { @@ -75,7 +75,7 @@ export default { text: this.revertLabel, tooltipText: this.revertTitle, href: this.mr.revertInForkPath, - dataQaSelector: 'revert_button', + testId: 'revert-button', dataMethod: 'post', }); } @@ -84,7 +84,7 @@ export default { actions.push({ text: this.cherryPickLabel, tooltipText: this.cherryPickTitle, - dataQaSelector: 'cherry_pick_button', + testId: 'cherry-pick-button', onClick: () => this.openCherryPickModal(), }); } else if (this.mr.cherryPickInForkPath) { @@ -92,7 +92,7 @@ export default { text: this.cherryPickLabel, tooltipText: this.cherryPickTitle, href: this.mr.cherryPickInForkPath, - dataQaSelector: 'cherry_pick_button', + testId: 'cherry-pick-button', dataMethod: 'post', }); } diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue index 415f58ea8e6..a4afdee4d49 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue @@ -230,7 +230,6 @@ export default { v-if="!rebasingError" class="gl-w-100 gl-md-w-auto gl-flex-grow-1 gl-ml-0! gl-text-body! gl-md-mr-3" data-testid="rebase-message" - data-qa-selector="no_fast_forward_message_content" > <bold-text :message="$options.i18n.rebaseError" /> </span> @@ -247,7 +246,6 @@ export default { :loading="isMakingRequest" variant="confirm" size="small" - data-qa-selector="mr_rebase_button" data-testid="standard-rebase-button" class="gl-align-self-start" @click="tryRebase" diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue index 9da754d01fc..00383418f2d 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue @@ -32,7 +32,7 @@ export default { > <span class="gl-md-mr-3 gl-flex-grow-1 gl-ml-0! gl-text-body!" - data-qa-selector="head_mismatch_content" + data-testid="head-mismatch-content" > <bold-text :message="$options.i18n.I18N_SHA_MISMATCH.warningMessage" /> </span> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue index 97ef96fe382..f1bd5bb25bb 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue @@ -46,7 +46,7 @@ export default { :disabled="isDisabled" name="squash" class="js-squash-checkbox gl-mr-2" - data-qa-selector="squash_checkbox" + data-testid="squash-checkbox" :title="tooltipTitle" @change="(checked) => $emit('input', checked)" > diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/action_buttons.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/action_buttons.vue index 55eeb9d0e63..5b7657f15d9 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/widget/action_buttons.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/action_buttons.vue @@ -80,12 +80,6 @@ export default { return btn.tooltipText; }, - actionButtonQaSelector(btn) { - if (btn.dataQaSelector) { - return btn.dataQaSelector; - } - return 'mr_widget_extension_actions_button'; - }, }, }; </script> @@ -121,7 +115,6 @@ export default { :target="btn.target" :class="[{ 'gl-mr-3': index !== tertiaryButtons.length - 1 }, btn.class]" :data-clipboard-text="btn.dataClipboardText" - :data-qa-selector="actionButtonQaSelector(btn)" :data-method="btn.dataMethod" :icon="btn.icon || btn.iconName" :data-testid="btn.testId || 'extension-actions-button'" diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 175a0b0563f..b55b59fe581 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -576,7 +576,7 @@ export default { </mr-widget-alert-message> </div> - <div class="mr-widget-section" data-qa-selector="mr_widget_content"> + <div class="mr-widget-section" data-testid="mr-widget-content"> <component :is="componentName" :mr="mr" :service="service" /> <ready-to-merge v-if="mr.commitsCount" diff --git a/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue b/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue index 05ce007e615..4ebd8861a67 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue @@ -60,7 +60,7 @@ export default { <template> <gl-disclosure-dropdown - data-qa-selector="apply_suggestion_dropdown" + data-testid="apply-suggestion-dropdown" fluid-width placement="right" size="small" @@ -81,7 +81,7 @@ export default { class="apply-suggestions-input-min-width" :placeholder="defaultCommitMessage" submit-on-enter - data-qa-selector="commit_message_field" + data-testid="commit-message-field" @submit="onApply" /> @@ -93,7 +93,7 @@ export default { class="gl-w-auto! gl-mt-3 gl-align-self-end" category="primary" variant="confirm" - data-qa-selector="commit_with_custom_message_button" + data-testid="commit-with-custom-message-button" @click="onApply" > {{ __('Apply') }} diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index a569b4ea9a7..741bdfd211b 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -281,7 +281,7 @@ export default { :tag-content="lineContent" tracking-property="codeSuggestion" icon="doc-code" - data-qa-selector="suggestion_button" + data-testid="suggestion-button" class="js-suggestion-btn" @click="handleSuggestDismissed" /> @@ -305,7 +305,7 @@ export default { variant="confirm" category="primary" size="small" - data-qa-selector="dismiss_suggestion_popover_button" + data-testid="dismiss-suggestion-popover-button" @click="handleSuggestDismissed" > {{ __('Got it') }} diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue index 8a0ca8ebac1..a822e2a6151 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue @@ -144,13 +144,13 @@ export default { <gl-icon name="question-o" css-classes="link-highlight" /> </a> </div> - <gl-badge v-if="isApplied" variant="success" data-qa-selector="applied_badge"> + <gl-badge v-if="isApplied" variant="success" data-testid="applied-badge"> {{ __('Applied') }} </gl-badge> <div v-else-if="isApplying" class="gl-display-flex gl-align-items-center text-secondary" - data-qa-selector="applying_badge" + data-testid="applying-badge" > <gl-loading-icon size="sm" class="gl-align-items-center gl-justify-content-center gl-mr-3" /> <span>{{ applyingSuggestionsMessage }}</span> @@ -169,7 +169,7 @@ export default { <div v-else-if="!isDisableButton && suggestionsCount > 1"> <gl-button class="btn-inverted js-add-to-batch-btn btn-grouped" - data-qa-selector="add_suggestion_batch_button" + data-testid="add-suggestion-batch-button" :disabled="isDisableButton" size="small" @click="addSuggestionToBatch" diff --git a/app/models/packages/protection/rule.rb b/app/models/packages/protection/rule.rb index bb65be92b90..4e8b47f600c 100644 --- a/app/models/packages/protection/rule.rb +++ b/app/models/packages/protection/rule.rb @@ -4,18 +4,16 @@ module Packages module Protection class Rule < ApplicationRecord enum package_type: Packages::Package.package_types.slice(:npm) + enum push_protected_up_to_access_level: + Gitlab::Access.sym_options_with_owner.slice(:developer, :maintainer, :owner), + _prefix: :push_protected_up_to belongs_to :project, inverse_of: :package_protection_rules validates :package_name_pattern, presence: true, uniqueness: { scope: [:project_id, :package_type] }, length: { maximum: 255 } validates :package_type, presence: true - validates :push_protected_up_to_access_level, presence: true, - inclusion: { in: [ - Gitlab::Access::DEVELOPER, - Gitlab::Access::MAINTAINER, - Gitlab::Access::OWNER - ] } + validates :push_protected_up_to_access_level, presence: true end end end diff --git a/config/feature_flags/development/on_demand_scans_runner_tags.yml b/config/feature_flags/development/prohibited_tag_name_encoding_check.yml index 6141bae2553..98a51b34cc9 100644 --- a/config/feature_flags/development/on_demand_scans_runner_tags.yml +++ b/config/feature_flags/development/prohibited_tag_name_encoding_check.yml @@ -1,8 +1,8 @@ --- -name: on_demand_scans_runner_tags -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103634 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381910 -milestone: '15.7' +name: prohibited_tag_name_encoding_check +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132135 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/426013 +milestone: '16.5' type: development -group: group::dynamic analysis -default_enabled: true +group: group::source code +default_enabled: false diff --git a/db/migrate/20231010101246_change_push_protected_up_to_access_level_to_smallint_in_packages_protection_rules.rb b/db/migrate/20231010101246_change_push_protected_up_to_access_level_to_smallint_in_packages_protection_rules.rb new file mode 100644 index 00000000000..d7228b0a3f1 --- /dev/null +++ b/db/migrate/20231010101246_change_push_protected_up_to_access_level_to_smallint_in_packages_protection_rules.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class ChangePushProtectedUpToAccessLevelToSmallintInPackagesProtectionRules < Gitlab::Database::Migration[2.1] + enable_lock_retries! + + def up + change_column :packages_protection_rules, :push_protected_up_to_access_level, :integer, limit: 2 + end + + def down + change_column :packages_protection_rules, :push_protected_up_to_access_level, :integer + end +end diff --git a/db/schema_migrations/20231010101246 b/db/schema_migrations/20231010101246 new file mode 100644 index 00000000000..1b7622c9bc6 --- /dev/null +++ b/db/schema_migrations/20231010101246 @@ -0,0 +1 @@ +67323d7c15c28b7784bb1021184df4efcc72a38e72e4113a945101c32212a934
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 324888e9173..3d6800cfc55 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -20196,7 +20196,7 @@ CREATE TABLE packages_protection_rules ( project_id bigint NOT NULL, created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, - push_protected_up_to_access_level integer NOT NULL, + push_protected_up_to_access_level smallint NOT NULL, package_type smallint NOT NULL, package_name_pattern text NOT NULL, CONSTRAINT check_d2d75d206d CHECK ((char_length(package_name_pattern) <= 255)) diff --git a/doc/administration/audit_event_streaming/graphql_api.md b/doc/administration/audit_event_streaming/graphql_api.md index 768b1f03bf3..905276a8257 100644 --- a/doc/administration/audit_event_streaming/graphql_api.md +++ b/doc/administration/audit_event_streaming/graphql_api.md @@ -112,8 +112,19 @@ mutation above. ```graphql mutation { - auditEventsStreamingHeadersCreate(input: { destinationId: "gid://gitlab/AuditEvents::ExternalAuditEventDestination/24601", key: "foo", value: "bar" }) { + auditEventsStreamingHeadersCreate(input: { + destinationId: "gid://gitlab/AuditEvents::ExternalAuditEventDestination/1", + key: "foo", + value: "bar", + active: false + }) { errors + header { + id + key + value + active + } } } ``` @@ -146,6 +157,7 @@ query { key value id + active } } eventTypeFilters @@ -500,13 +512,15 @@ mutation { { destinationId: "gid://gitlab/AuditEvents::InstanceExternalAuditEventDestination/42", key: "foo", - value: "bar" + value: "bar", + active: true }) { errors header { id key value + active } } } @@ -538,6 +552,7 @@ query { id key value + active } } eventTypeFilters @@ -590,12 +605,13 @@ by [listing all the custom HTTP headers](#list-streaming-destinations-1) for the ```graphql mutation { - auditEventsStreamingInstanceHeadersUpdate(input: { headerId: "gid://gitlab/AuditEvents::Streaming::InstanceHeader/2", key: "new-key", value: "new-value" }) { + auditEventsStreamingInstanceHeadersUpdate(input: { headerId: "gid://gitlab/AuditEvents::Streaming::InstanceHeader/2", key: "new-key", value: "new-value", active: false }) { errors header { id key value + active } } } diff --git a/doc/user/application_security/dast/proxy-based.md b/doc/user/application_security/dast/proxy-based.md index 86af7d4c5da..230d8ef5ca3 100644 --- a/doc/user/application_security/dast/proxy-based.md +++ b/doc/user/application_security/dast/proxy-based.md @@ -464,7 +464,6 @@ The DAST job does not require the project's repository to be present when runnin > - Auditing for DAST profile management [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217872) in GitLab 14.1. > - Scheduled on-demand DAST scans [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.3 [with a flag](../../../administration/feature_flags.md) named `dast_on_demand_scans_scheduler`. Disabled by default. > - Scheduled on-demand DAST scans [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.5. Feature flag `dast_on_demand_scans_scheduler` removed. -> - Runner tags selection [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345430) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `on_demand_scans_runner_tags. Disabled by default. > - Runner tags selection [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111499) in GitLab 16.3. WARNING: diff --git a/doc/user/project/repository/managing_large_repositories.md b/doc/user/project/repository/managing_large_repositories.md index 83ba0da9865..721150f958b 100644 --- a/doc/user/project/repository/managing_large_repositories.md +++ b/doc/user/project/repository/managing_large_repositories.md @@ -263,12 +263,46 @@ following sections for information on solving: ### Large number of references -A reference in Git (a branch or tag) is used to refer to a commit. If you are -curious, you can go to any `.git` directory and look under the `refs` directory. - -A large number of references can cause performance problems because, with more -references, object walks that Git does are larger for various operations such as -clones, pushes, and housekeeping tasks. +[References in Git](https://git-scm.com/book/en/v2/Git-Internals-Git-References) +are branch and tag names that point to a particular commit. You can use the `git +for-each-ref` command to list all references present in a repository. A large +number of references in a repository can have detrimental impact on the command's +performance. To understand why, we need to understand how Git stores references +and uses them. + +In general, Git stores all references as loose files in the `.git/refs` folder of +the repository. As the number of references grows, the seek time to find a +particular reference in the folder also increases. Therefore, every time Git has +to parse a reference, there is an increased latency due to the added seek time +of the file system. + +To resolve this issue, Git uses [pack-refs](https://git-scm.com/docs/git-pack-refs). In short, instead of storing each +reference in a single file, Git creates a single `.git/packed-refs` file that +contains all the references for that repository. This file reduces storage space +while also increasing performance because seeking within a single file is faster +than seeking a file within a directory. However, creating and updating new references +is still done through loose files and are not added to the `packed-refs` file. To +recreate the `packed-refs` file, run `git pack-refs`. + +Gitaly runs `git pack-refs` during [housekeeping](../../../administration/housekeeping.md#heuristical-housekeeping) +to move loose references into `packed-refs` files. While this is very beneficial +for most repositories, write-heavy repositories still have the problem that: + +- Creating or updating references creates new loose files. +- Deleting references involves modifying the existing `packed-refs` file + altogether to remove the existing reference. + +These problems still cause the same performance issues. + +In addition, fetches and clones from repositories includes the transfer +of missing objects from the server to the client. When there are numerous +references, Git iterates over all references and walks the internal graph +structure for each reference to find the missing objects to transfer to +the client. Iteration and walking are CPU-intensive operations that increase +the latency of these commands. + +In repositories with a lot of activity, this often causes a domino effect because +every operation is slower and each operation stalls subsequent operations. #### Mitigation strategies diff --git a/lib/api/entities/bulk_import.rb b/lib/api/entities/bulk_import.rb index 75989cb4180..18f71048595 100644 --- a/lib/api/entities/bulk_import.rb +++ b/lib/api/entities/bulk_import.rb @@ -10,6 +10,7 @@ module API expose :source_type, documentation: { type: 'string', example: 'gitlab' } expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' } expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' } + expose :has_failures, documentation: { type: 'boolean', example: false } end end end diff --git a/lib/api/entities/bulk_imports/entity.rb b/lib/api/entities/bulk_imports/entity.rb index 176d10b2580..7e9b9973e15 100644 --- a/lib/api/entities/bulk_imports/entity.rb +++ b/lib/api/entities/bulk_imports/entity.rb @@ -24,6 +24,7 @@ module API expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' } expose :failures, using: EntityFailure, documentation: { is_array: true } expose :migrate_projects, documentation: { type: 'boolean', example: true } + expose :has_failures, documentation: { type: 'boolean', example: false } end end end diff --git a/lib/gitlab/checks/tag_check.rb b/lib/gitlab/checks/tag_check.rb index 4505bcb5411..d5addab74b8 100644 --- a/lib/gitlab/checks/tag_check.rb +++ b/lib/gitlab/checks/tag_check.rb @@ -11,7 +11,8 @@ module Gitlab delete_protected_tag_non_web: 'You can only delete protected tags using the web interface.', create_protected_tag: 'You are not allowed to create this tag as it is protected.', default_branch_collision: 'You cannot use default branch name to create a tag', - prohibited_tag_name: 'You cannot create a tag with a prohibited pattern.' + prohibited_tag_name: 'You cannot create a tag with a prohibited pattern.', + prohibited_tag_name_encoding: 'Tag names must be valid when converted to UTF-8 encoding' }.freeze LOG_MESSAGES = { @@ -46,6 +47,16 @@ module Gitlab if tag_name.start_with?("refs/tags/") # rubocop: disable Style/GuardClause raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name] end + + # rubocop: disable Style/GuardClause + # rubocop: disable Style/SoleNestedConditional + if Feature.enabled?(:prohibited_tag_name_encoding_check, project) + unless Gitlab::EncodingHelper.force_encode_utf8(tag_name).valid_encoding? + raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name_encoding] + end + end + # rubocop: enable Style/SoleNestedConditional + # rubocop: enable Style/GuardClause end def protected_tag_checks diff --git a/lib/gitlab/encoding_helper.rb b/lib/gitlab/encoding_helper.rb index 99240f2ad48..b080cb197d4 100644 --- a/lib/gitlab/encoding_helper.rb +++ b/lib/gitlab/encoding_helper.rb @@ -152,8 +152,6 @@ module Gitlab message.delete_prefix(BOM_UTF8) end - private - def force_encode_utf8(message) raise ArgumentError unless message.respond_to?(:force_encoding) return message if message.encoding == Encoding::UTF_8 && message.valid_encoding? @@ -163,6 +161,8 @@ module Gitlab message.force_encoding("UTF-8") end + private + # Escapes \x80 - \xFF characters not supported by UTF-8 def escape_chars(char) bytes = char.bytes diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index 98d00664854..2413166e120 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -21,7 +21,7 @@ module QA element :edit_profile_link end - view 'app/assets/javascripts/super_sidebar/components/user_name_group.vue' do + view 'app/assets/javascripts/super_sidebar/components/user_menu_profile_item.vue' do element 'user-profile-link' end diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb index 3782ae0c9d0..a51c65a18c6 100644 --- a/qa/qa/page/merge_request/show.rb +++ b/qa/qa/page/merge_request/show.rb @@ -71,13 +71,13 @@ module QA end view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue' do - element :cherry_pick_button - element :revert_button + element 'cherry-pick-button' + element 'revert-button' end view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue' do - element :mr_rebase_button - element :no_fast_forward_message_content + element 'standard-rebase-button' + element 'rebase-message' end view 'app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue' do @@ -88,33 +88,33 @@ module QA end view 'app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue' do - element :head_mismatch_content + element 'head-mismatch-content' end view 'app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue' do - element :squash_checkbox + element 'squash-checkbox' end view 'app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue' do - element :mr_widget_content + element 'mr-widget-content' element 'pipeline-container' end view 'app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue' do - element :apply_suggestion_dropdown - element :commit_message_field - element :commit_with_custom_message_button + element 'apply-suggestion-dropdown' + element 'commit-message-field' + element 'commit-with-custom-message-button' end view 'app/assets/javascripts/vue_shared/components/markdown/header.vue' do - element :suggestion_button - element :dismiss_suggestion_popover_button + element 'suggestion-button' + element 'dismiss-suggestion-popover-button' end view 'app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue' do - element :add_suggestion_batch_button - element :applied_badge - element :applying_badge + element 'add-suggestion-batch-button' + element 'applied-badge' + element 'applying-badge' end view 'app/views/projects/merge_requests/_description.html.haml' do @@ -132,10 +132,6 @@ module QA element 'diffs-tab', required: true end - view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue' do - element :cancel_auto_merge_button - end - view 'app/views/shared/_broadcast_message.html.haml' do element 'broadcast-notification-container' element 'close-button' @@ -195,7 +191,9 @@ module QA all_elements('left-line-number', minimum: 1).first.hover click_element('left-comment-button') - click_element(:dismiss_suggestion_popover_button) if has_element?(:dismiss_suggestion_popover_button, wait: 1) + + click_element('dismiss-suggestion-popover-button') if has_element?('dismiss-suggestion-popover-button', + wait: 1) fill_element('reply-field', text) end @@ -227,7 +225,7 @@ module QA end def fast_forward_not_possible? - has_element?(:no_fast_forward_message_content) + has_element?('rebase-message') end def has_file?(file_name) @@ -290,15 +288,15 @@ module QA def mark_to_squash # Refresh page if commit arrived after loading the MR page wait_until(reload: true, message: 'Wait for MR to be unblocked') do - has_no_element?(:head_mismatch_content, wait: 1) + has_no_element?('head-mismatch-content', wait: 1) end # The squash checkbox is enabled via JS wait_until(reload: false) do - !find_element(:squash_checkbox, visible: false).disabled? + !find_element('squash-checkbox', visible: false).disabled? end - check_element(:squash_checkbox, true) + check_element('squash-checkbox', true) end def merge! @@ -338,7 +336,7 @@ module QA # Waits up 10 seconds and returns false if the Revert button is not enabled def revertible? - has_element?(:revert_button, disabled: false, wait: 10) + has_element?('revert-button', disabled: false, wait: 10) end # Waits up 60 seconds and raises an error if unable to merge. @@ -357,7 +355,7 @@ module QA break true unless find_element('merge-button').disabled? # If the widget shows "Merge blocked: new changes were just added" we can refresh the page and check again - next false if has_element?(:head_mismatch_content, wait: 1) + next false if has_element?('head-mismatch-content', wait: 1) # Stop waiting if we're in a transient test. By this point we're in an unexpected state and should let the # test fail so we can investigate. If we're not in a transient test we keep trying until we reach timeout. @@ -372,15 +370,15 @@ module QA def rebase! # The rebase button is disabled on load wait_until do - has_element?(:mr_rebase_button) + has_element?('standard-rebase-button') end # The rebase button is enabled via JS wait_until(reload: false) do - !find_element(:mr_rebase_button).disabled? + !find_element('standard-rebase-button').disabled? end - click_element(:mr_rebase_button) + click_element('standard-rebase-button') end def merge_immediately! @@ -448,7 +446,7 @@ module QA def add_suggestion_to_diff(suggestion, line) find("a[data-linenumber='#{line}']").hover click_element('left-comment-button') - click_element(:suggestion_button) + click_element('suggestion-button') initial_content = find_element('reply-field').value fill_element('reply-field', '') fill_element('reply-field', initial_content.gsub(/(```suggestion:-0\+0\n).*(\n```)/, "\\1#{suggestion}\\2")) @@ -457,24 +455,24 @@ module QA end def apply_suggestion_with_message(message) - all_elements(:apply_suggestion_dropdown, minimum: 1).first.click - fill_element(:commit_message_field, message) - click_element(:commit_with_custom_message_button) + all_elements('apply-suggestion-dropdown', minimum: 1).first.click + fill_element('commit-message-field', message) + click_element('commit-with-custom-message-button') end def add_suggestion_to_batch - all_elements(:add_suggestion_batch_button, minimum: 1).first.click + all_elements('add-suggestion-batch-button', minimum: 1).first.click end def has_suggestions_applied?(count = 1) wait_until(reload: false) do - has_no_element?(:applying_badge) + has_no_element?('applying-badge') end - all_elements(:applied_badge, count: count) + all_elements('applied-badge', count: count) end def cherry_pick! - click_element(:cherry_pick_button, Page::Component::CommitModal) + click_element('cherry-pick-button', Page::Component::CommitModal) click_element(:submit_commit_button) end @@ -482,13 +480,13 @@ module QA # reload page when the revert modal occasionally doesn't appear in ee:large-setup job # https://gitlab.com/gitlab-org/gitlab/-/issues/386623 (transient issue) retry_on_exception(reload: true) do - click_element(:revert_button, Page::Component::CommitModal) + click_element('revert-button', Page::Component::CommitModal) end click_element(:submit_commit_button) end def mr_widget_text - find_element(:mr_widget_content).text + find_element('mr-widget-content').text end def has_fork_icon? diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb index 17c83a32d52..27969759adf 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_project_artifacts/user_can_bulk_delete_artifacts_spec.rb @@ -23,7 +23,7 @@ module QA after do Parallel.each((0..(total_runners_count - 1)), in_threads: 3) do |i| - runners[i].remove_via_api! + runners[i]&.remove_via_api! end end @@ -46,7 +46,7 @@ module QA def launch_runners Parallel.each((1..total_runners_count), in_threads: 3) do |i| - runners << create(:project_runner, project: project, name: "executor-#{i}", tags: [executor]) + runners << create(:project_runner, project: project, name: "#{executor}-#{i}", tags: [executor]) end end diff --git a/spec/factories/packages/protection/rules.rb b/spec/factories/packages/protection/rules.rb index 3038fb847e7..f65a9d3e64d 100644 --- a/spec/factories/packages/protection/rules.rb +++ b/spec/factories/packages/protection/rules.rb @@ -5,6 +5,6 @@ FactoryBot.define do project package_name_pattern { '@my_scope/my_package' } package_type { :npm } - push_protected_up_to_access_level { Gitlab::Access::DEVELOPER } + push_protected_up_to_access_level { :developer } end end diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js index 961ea27f0f4..9b5e812c021 100644 --- a/spec/frontend/design_management/pages/index_spec.js +++ b/spec/frontend/design_management/pages/index_spec.js @@ -191,7 +191,7 @@ describe('Design management index page', () => { [moveDesignMutation, moveDesignHandler], ]; - fakeApollo = createMockApollo(requestHandlers, {}, { addTypename: true }); + fakeApollo = createMockApollo(requestHandlers, {}); wrapper = shallowMountExtended(Index, { apolloProvider: fakeApollo, router, diff --git a/spec/frontend/super_sidebar/components/user_name_group_spec.js b/spec/frontend/super_sidebar/components/user_menu_profile_item_spec.js index a31ad93d143..9cf55154a59 100644 --- a/spec/frontend/super_sidebar/components/user_name_group_spec.js +++ b/spec/frontend/super_sidebar/components/user_menu_profile_item_spec.js @@ -1,12 +1,11 @@ -import { GlDisclosureDropdownGroup, GlDisclosureDropdownItem, GlTooltip } from '@gitlab/ui'; +import { GlDisclosureDropdownItem, GlTooltip } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import UserNameGroup from '~/super_sidebar/components/user_name_group.vue'; +import UserMenuProfileItem from '~/super_sidebar/components/user_menu_profile_item.vue'; import { userMenuMockData, userMenuMockStatus } from '../mock_data'; -describe('UserNameGroup component', () => { +describe('UserMenuProfileItem component', () => { let wrapper; - const findGlDisclosureDropdownGroup = () => wrapper.findComponent(GlDisclosureDropdownGroup); const findGlDisclosureDropdownItem = () => wrapper.findComponent(GlDisclosureDropdownItem); const findGlTooltip = () => wrapper.findComponent(GlTooltip); const findUserStatus = () => wrapper.findByTestId('user-menu-status'); @@ -14,7 +13,7 @@ describe('UserNameGroup component', () => { const GlEmoji = { template: '<img/>' }; const createWrapper = (userDataChanges = {}) => { - wrapper = shallowMountExtended(UserNameGroup, { + wrapper = shallowMountExtended(UserMenuProfileItem, { propsData: { user: { ...userMenuMockData, @@ -32,10 +31,6 @@ describe('UserNameGroup component', () => { createWrapper(); }); - it('renders the menu item in a separate group', () => { - expect(findGlDisclosureDropdownGroup().exists()).toBe(true); - }); - it('renders menu item', () => { expect(findGlDisclosureDropdownItem().exists()).toBe(true); }); diff --git a/spec/frontend/super_sidebar/components/user_menu_spec.js b/spec/frontend/super_sidebar/components/user_menu_spec.js index d41a414f69e..79a31492f3f 100644 --- a/spec/frontend/super_sidebar/components/user_menu_spec.js +++ b/spec/frontend/super_sidebar/components/user_menu_spec.js @@ -2,7 +2,7 @@ import { GlAvatar, GlDisclosureDropdown } from '@gitlab/ui'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import { stubComponent } from 'helpers/stub_component'; import UserMenu from '~/super_sidebar/components/user_menu.vue'; -import UserNameGroup from '~/super_sidebar/components/user_name_group.vue'; +import UserMenuProfileItem from '~/super_sidebar/components/user_menu_profile_item.vue'; import NewNavToggle from '~/nav/components/new_nav_toggle.vue'; import invalidUrl from '~/lib/utils/invalid_url'; import { mockTracking } from 'helpers/tracking_helper'; @@ -86,9 +86,9 @@ describe('UserMenu component', () => { describe('User Menu Group', () => { it('renders and passes data to it', () => { createWrapper(); - const userNameGroup = wrapper.findComponent(UserNameGroup); - expect(userNameGroup.exists()).toBe(true); - expect(userNameGroup.props('user')).toEqual(userMenuMockData); + const userMenuProfileItem = wrapper.findComponent(UserMenuProfileItem); + expect(userMenuProfileItem.exists()).toBe(true); + expect(userMenuProfileItem.props('user')).toEqual(userMenuMockData); }); }); diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js index 111fb5d8458..0b88b3ff5b4 100644 --- a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js +++ b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js @@ -54,7 +54,6 @@ describe('WorkItemLinks', () => { [issueDetailsQuery, issueDetailsQueryHandler], ], resolvers, - { addTypename: true }, ); wrapper = shallowMountExtended(WorkItemLinks, { diff --git a/spec/lib/api/entities/bulk_import_spec.rb b/spec/lib/api/entities/bulk_import_spec.rb index 2db6862b079..cfa293463ad 100644 --- a/spec/lib/api/entities/bulk_import_spec.rb +++ b/spec/lib/api/entities/bulk_import_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe API::Entities::BulkImport do +RSpec.describe API::Entities::BulkImport, feature_category: :importers do let_it_be(:import) { create(:bulk_import) } subject { described_class.new(import).as_json } @@ -13,7 +13,8 @@ RSpec.describe API::Entities::BulkImport do :status, :source_type, :created_at, - :updated_at + :updated_at, + :has_failures ) end end diff --git a/spec/lib/api/entities/bulk_imports/entity_spec.rb b/spec/lib/api/entities/bulk_imports/entity_spec.rb index ba8a2ddffcb..791cd3a20e2 100644 --- a/spec/lib/api/entities/bulk_imports/entity_spec.rb +++ b/spec/lib/api/entities/bulk_imports/entity_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe API::Entities::BulkImports::Entity do +RSpec.describe API::Entities::BulkImports::Entity, feature_category: :importers do let_it_be(:entity) { create(:bulk_import_entity) } subject { described_class.new(entity).as_json } @@ -22,7 +22,8 @@ RSpec.describe API::Entities::BulkImports::Entity do :created_at, :updated_at, :failures, - :migrate_projects + :migrate_projects, + :has_failures ) end end diff --git a/spec/lib/gitlab/checks/tag_check_spec.rb b/spec/lib/gitlab/checks/tag_check_spec.rb index 60d3eb4bfb3..b5aafde006f 100644 --- a/spec/lib/gitlab/checks/tag_check_spec.rb +++ b/spec/lib/gitlab/checks/tag_check_spec.rb @@ -41,6 +41,36 @@ RSpec.describe Gitlab::Checks::TagCheck, feature_category: :source_code_manageme expect { subject.validate! }.not_to raise_error end end + + it "prohibits tag names that include characters incompatible with UTF-8" do + allow(subject).to receive(:tag_name).and_return("v6.0.0-\xCE.BETA") + + expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, "Tag names must be valid when converted to UTF-8 encoding") + end + + it "doesn't prohibit UTF-8 compatible characters" do + allow(subject).to receive(:tag_name).and_return("v6.0.0-Ü.BETA") + + expect { subject.validate! }.not_to raise_error + end + + context "when prohibited_tag_name_encoding_check feature flag is disabled" do + before do + stub_feature_flags(prohibited_tag_name_encoding_check: false) + end + + it "doesn't prohibit tag names that include characters incompatible with UTF-8" do + allow(subject).to receive(:tag_name).and_return("v6.0.0-\xCE.BETA") + + expect { subject.validate! }.not_to raise_error + end + + it "doesn't prohibit UTF-8 compatible characters" do + allow(subject).to receive(:tag_name).and_return("v6.0.0-Ü.BETA") + + expect { subject.validate! }.not_to raise_error + end + end end context 'with protected tag' do diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb index bc72d1a67d6..1b7c11dfef6 100644 --- a/spec/lib/gitlab/encoding_helper_spec.rb +++ b/spec/lib/gitlab/encoding_helper_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -RSpec.describe Gitlab::EncodingHelper do +RSpec.describe Gitlab::EncodingHelper, feature_category: :shared do using RSpec::Parameterized::TableSyntax let(:ext_class) { Class.new { extend Gitlab::EncodingHelper } } @@ -291,4 +291,39 @@ RSpec.describe Gitlab::EncodingHelper do expect(described_class.strip_bom("BOM at the end\xEF\xBB\xBF")).to eq("BOM at the end\xEF\xBB\xBF") end end + + # This cop's alternative to .dup doesn't work in this context for some reason. + # rubocop: disable Performance/UnfreezeString + describe "#force_encode_utf8" do + let(:stringish) do + Class.new(String) do + undef :force_encoding + end + end + + it "raises an ArgumentError if the argument can't force encoding" do + expect { described_class.force_encode_utf8(stringish.new("foo")) }.to raise_error(ArgumentError) + end + + it "returns the message if already UTF-8 and valid encoding" do + string = "føø".dup + + expect(string).not_to receive(:force_encoding).and_call_original + expect(described_class.force_encode_utf8(string)).to eq("føø") + end + + it "forcibly encodes a string to UTF-8" do + string = "føø".dup.force_encoding("ISO-8859-1") + + expect(string).to receive(:force_encoding).with("UTF-8").and_call_original + expect(described_class.force_encode_utf8(string)).to eq("føø") + end + + it "forcibly encodes a frozen string to UTF-8" do + string = "bår".dup.force_encoding("ISO-8859-1").freeze + + expect(described_class.force_encode_utf8(string)).to eq("bår") + end + end + # rubocop: enable Performance/UnfreezeString end diff --git a/spec/models/packages/protection/rule_spec.rb b/spec/models/packages/protection/rule_spec.rb index b368687e6d8..d59c374b442 100644 --- a/spec/models/packages/protection/rule_spec.rb +++ b/spec/models/packages/protection/rule_spec.rb @@ -10,9 +10,19 @@ RSpec.describe Packages::Protection::Rule, type: :model, feature_category: :pack end describe 'enums' do - describe '#package_type' do - it { is_expected.to define_enum_for(:package_type).with_values(npm: Packages::Package.package_types[:npm]) } - end + it { is_expected.to define_enum_for(:package_type).with_values(npm: Packages::Package.package_types[:npm]) } + + it { + is_expected.to( + define_enum_for(:push_protected_up_to_access_level) + .with_values( + developer: Gitlab::Access::DEVELOPER, + maintainer: Gitlab::Access::MAINTAINER, + owner: Gitlab::Access::OWNER + ) + .with_prefix(:push_protected_up_to) + ) + } end describe 'validations' do @@ -30,11 +40,6 @@ RSpec.describe Packages::Protection::Rule, type: :model, feature_category: :pack describe '#push_protected_up_to_access_level' do it { is_expected.to validate_presence_of(:push_protected_up_to_access_level) } - - it { - is_expected.to validate_inclusion_of(:push_protected_up_to_access_level).in_array([Gitlab::Access::DEVELOPER, - Gitlab::Access::MAINTAINER, Gitlab::Access::OWNER]) - } end end end |