Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml2
-rw-r--r--.rubocop_todo/layout/array_alignment.yml1
-rw-r--r--.rubocop_todo/rails/file_path.yml1
-rw-r--r--.rubocop_todo/rspec/context_wording.yml1
-rw-r--r--.rubocop_todo/rspec/expect_in_hook.yml1
-rw-r--r--.rubocop_todo/rspec/instance_variable.yml1
-rw-r--r--.rubocop_todo/style/inline_disable_annotation.yml1
-rw-r--r--.ruby-version2
-rw-r--r--app/assets/javascripts/graphql_shared/possible_types.json1
-rw-r--r--app/assets/javascripts/projects/commit_box/info/components/commit_refs.vue2
-rw-r--r--app/assets/javascripts/projects/commit_box/info/components/refs_list.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js2
-rw-r--r--app/models/project_authorizations/changes.rb1
-rw-r--r--app/models/work_items/widget_definition.rb3
-rw-r--r--app/views/projects/commit/_commit_box.html.haml2
-rw-r--r--config/feature_flags/development/use_gitlab_http_v2.yml8
-rw-r--r--config/feature_flags/development/user_approval_rules_removal.yml8
-rw-r--r--config/initializers_before_autoloader/004_zeitwerk.rb1
-rw-r--r--db/docs/batched_background_migrations/backfill_owasp_top_ten_of_vulnerability_reads.yml8
-rw-r--r--db/post_migrate/20231211154654_add_work_items_rolledup_dates_widget.rb49
-rw-r--r--db/post_migrate/20231214111617_queue_backfill_owasp_top_ten_of_vulnerability_reads.rb28
-rw-r--r--db/schema_migrations/202312111546541
-rw-r--r--db/schema_migrations/202312141116171
-rw-r--r--doc/api/graphql/reference/index.md21
-rw-r--r--doc/api/issues.md3
-rw-r--r--doc/ci/caching/index.md2
-rw-r--r--doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md2
-rw-r--r--doc/ci/docker/using_docker_build.md2
-rw-r--r--doc/ci/environments/index.md2
-rw-r--r--doc/ci/index.md2
-rw-r--r--doc/ci/review_apps/index.md2
-rw-r--r--doc/ci/runners/index.md2
-rw-r--r--doc/ci/runners/new_creation_workflow.md8
-rw-r--r--doc/ci/runners/runners_scope.md7
-rw-r--r--doc/ci/variables/index.md2
-rw-r--r--doc/ci/yaml/index.md2
-rw-r--r--doc/development/cicd/configuration.md8
-rw-r--r--doc/development/cicd/pipeline_wizard.md2
-rw-r--r--doc/development/contributing/verify/index.md2
-rw-r--r--doc/development/fe_guide/architecture.md6
-rw-r--r--doc/development/pages/index.md20
-rw-r--r--doc/development/pipelines/index.md4
-rw-r--r--doc/development/pipelines/internals.md2
-rw-r--r--doc/update/index.md4
-rw-r--r--doc/user/group/epics/manage_epics.md41
-rw-r--r--doc/user/project/issues/managing_issues.md33
-rw-r--r--doc/user/project/remote_development/connect_machine.md2
-rw-r--r--doc/user/project/remote_development/index.md2
-rw-r--r--lib/gitlab/background_migration/backfill_owasp_top_ten_of_vulnerability_reads.rb86
-rw-r--r--lib/gitlab/database_importers/work_items/base_type_importer.rb6
-rw-r--r--lib/gitlab/http.rb29
-rw-r--r--lib/gitlab/legacy_http.rb78
-rw-r--r--locale/gitlab.pot5
-rw-r--r--qa/gdk/Dockerfile.gdk1
-rw-r--r--spec/factories/work_items/dates_sources.rb7
-rw-r--r--spec/lib/gitlab/background_migration/backfill_owasp_top_ten_of_vulnerability_reads_spec.rb225
-rw-r--r--spec/lib/gitlab/http_spec.rb36
-rw-r--r--spec/lib/gitlab/legacy_http_spec.rb448
-rw-r--r--spec/migrations/20230807083334_add_linked_items_work_item_widget_spec.rb4
-rw-r--r--spec/migrations/20231211154654_add_work_items_rolledup_dates_widget_spec.rb9
-rw-r--r--spec/migrations/20231214111617_queue_backfill_owasp_top_ten_of_vulnerability_reads_spec.rb26
-rw-r--r--spec/models/application_setting_spec.rb336
-rw-r--r--spec/models/project_authorizations/changes_spec.rb16
-rw-r--r--spec/models/work_items/widget_definition_spec.rb3
-rw-r--r--spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb8
65 files changed, 701 insertions, 938 deletions
diff --git a/.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml b/.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml
index 1939c1feaf6..7f093a7cbc6 100644
--- a/.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml
+++ b/.gitlab/ci/gitlab-com/danger-review.gitlab-ci.yml
@@ -1,6 +1,6 @@
include:
- project: gitlab-org/quality/pipeline-common
- ref: 8.3.1
+ ref: 8.3.2
file:
- /ci/danger-review.yml
diff --git a/.rubocop_todo/layout/array_alignment.yml b/.rubocop_todo/layout/array_alignment.yml
index 9628f297226..dcb2667bc31 100644
--- a/.rubocop_todo/layout/array_alignment.yml
+++ b/.rubocop_todo/layout/array_alignment.yml
@@ -283,7 +283,6 @@ Layout/ArrayAlignment:
- 'spec/lib/gitlab/usage_data/topology_spec.rb'
- 'spec/lib/gitlab/utils/merge_hash_spec.rb'
- 'spec/lib/gitlab/visibility_level_spec.rb'
- - 'spec/models/application_setting_spec.rb'
- 'spec/models/ci/bridge_spec.rb'
- 'spec/models/ci/build_spec.rb'
- 'spec/models/ci/group_spec.rb'
diff --git a/.rubocop_todo/rails/file_path.yml b/.rubocop_todo/rails/file_path.yml
index b7291734253..49d95cfeac3 100644
--- a/.rubocop_todo/rails/file_path.yml
+++ b/.rubocop_todo/rails/file_path.yml
@@ -99,7 +99,6 @@ Rails/FilePath:
- 'spec/lib/gitlab/feature_categories_spec.rb'
- 'spec/lib/gitlab/file_hook_spec.rb'
- 'spec/lib/gitlab/jwt_authenticatable_spec.rb'
- - 'spec/lib/gitlab/legacy_http_spec.rb'
- 'spec/lib/gitlab/mail_room/mail_room_spec.rb'
- 'spec/lib/gitlab/middleware/multipart/handler_spec.rb'
- 'spec/lib/gitlab/multi_destination_logger_spec.rb'
diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml
index fe7e9f045e7..a141ac1e508 100644
--- a/.rubocop_todo/rspec/context_wording.yml
+++ b/.rubocop_todo/rspec/context_wording.yml
@@ -1842,7 +1842,6 @@ RSpec/ContextWording:
- 'spec/lib/gitlab/kubernetes/default_namespace_spec.rb'
- 'spec/lib/gitlab/kubernetes/kube_client_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/client_spec.rb'
- - 'spec/lib/gitlab/legacy_http_spec.rb'
- 'spec/lib/gitlab/lfs/client_spec.rb'
- 'spec/lib/gitlab/lfs_token_spec.rb'
- 'spec/lib/gitlab/lograge/custom_options_spec.rb'
diff --git a/.rubocop_todo/rspec/expect_in_hook.yml b/.rubocop_todo/rspec/expect_in_hook.yml
index a8896eed55d..0fc7ecfde58 100644
--- a/.rubocop_todo/rspec/expect_in_hook.yml
+++ b/.rubocop_todo/rspec/expect_in_hook.yml
@@ -236,7 +236,6 @@ RSpec/ExpectInHook:
- 'spec/lib/gitlab/kas/client_spec.rb'
- 'spec/lib/gitlab/kubernetes/kube_client_spec.rb'
- 'spec/lib/gitlab/kubernetes/kubeconfig/template_spec.rb'
- - 'spec/lib/gitlab/legacy_http_spec.rb'
- 'spec/lib/gitlab/memory/instrumentation_spec.rb'
- 'spec/lib/gitlab/memory/jemalloc_spec.rb'
- 'spec/lib/gitlab/metrics/boot_time_tracker_spec.rb'
diff --git a/.rubocop_todo/rspec/instance_variable.yml b/.rubocop_todo/rspec/instance_variable.yml
index a4d4c2119c0..51290ec9294 100644
--- a/.rubocop_todo/rspec/instance_variable.yml
+++ b/.rubocop_todo/rspec/instance_variable.yml
@@ -96,7 +96,6 @@ RSpec/InstanceVariable:
- 'spec/lib/gitlab/git/repository_spec.rb'
- 'spec/lib/gitlab/import_export/group/tree_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
- - 'spec/lib/gitlab/legacy_http_spec.rb'
- 'spec/lib/gitlab/patch/prependable_spec.rb'
- 'spec/lib/gitlab/popen_spec.rb'
- 'spec/lib/gitlab/project_transfer_spec.rb'
diff --git a/.rubocop_todo/style/inline_disable_annotation.yml b/.rubocop_todo/style/inline_disable_annotation.yml
index 9dbb54954f8..78a34c6cd57 100644
--- a/.rubocop_todo/style/inline_disable_annotation.yml
+++ b/.rubocop_todo/style/inline_disable_annotation.yml
@@ -2560,7 +2560,6 @@ Style/InlineDisableAnnotation:
- 'lib/gitlab/legacy_github_import/importer.rb'
- 'lib/gitlab/legacy_github_import/issuable_formatter.rb'
- 'lib/gitlab/legacy_github_import/user_formatter.rb'
- - 'lib/gitlab/legacy_http.rb'
- 'lib/gitlab/lets_encrypt/client.rb'
- 'lib/gitlab/lfs_token.rb'
- 'lib/gitlab/local_and_remote_storage_migration/base_migrater.rb'
diff --git a/.ruby-version b/.ruby-version
index 0aec50e6ede..be94e6f53db 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.1.4
+3.2.2
diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json
index f266e183662..fe151c2b358 100644
--- a/app/assets/javascripts/graphql_shared/possible_types.json
+++ b/app/assets/javascripts/graphql_shared/possible_types.json
@@ -200,6 +200,7 @@
"WorkItemWidgetNotifications",
"WorkItemWidgetProgress",
"WorkItemWidgetRequirementLegacy",
+ "WorkItemWidgetRolledupDates",
"WorkItemWidgetStartAndDueDate",
"WorkItemWidgetStatus",
"WorkItemWidgetTestReports",
diff --git a/app/assets/javascripts/projects/commit_box/info/components/commit_refs.vue b/app/assets/javascripts/projects/commit_box/info/components/commit_refs.vue
index 25af4cc8082..684ae5343b0 100644
--- a/app/assets/javascripts/projects/commit_box/info/components/commit_refs.vue
+++ b/app/assets/javascripts/projects/commit_box/info/components/commit_refs.vue
@@ -107,7 +107,7 @@ export default {
</script>
<template>
- <div class="gl-ml-7">
+ <div>
<refs-list
v-if="hasBranches"
:has-containing-refs="hasContainingBranches"
diff --git a/app/assets/javascripts/projects/commit_box/info/components/refs_list.vue b/app/assets/javascripts/projects/commit_box/info/components/refs_list.vue
index 8ceab9cb60b..7a926c3f4e6 100644
--- a/app/assets/javascripts/projects/commit_box/info/components/refs_list.vue
+++ b/app/assets/javascripts/projects/commit_box/info/components/refs_list.vue
@@ -1,6 +1,6 @@
<script>
import { GlCollapse, GlBadge, GlButton, GlIcon, GlSkeletonLoader } from '@gitlab/ui';
-import { CONTAINING_COMMIT, FETCH_CONTAINING_REFS_EVENT } from '../constants';
+import { CONTAINING_COMMIT, FETCH_CONTAINING_REFS_EVENT, BRANCHES_REF_TYPE } from '../constants';
export default {
name: 'RefsList',
@@ -55,6 +55,9 @@ export default {
isLoadingRefs() {
return this.isLoading && !this.containingRefs.length;
},
+ refIcon() {
+ return this.refType === BRANCHES_REF_TYPE ? 'branch' : 'tag';
+ },
},
methods: {
toggleCollapse() {
@@ -75,7 +78,8 @@ export default {
</script>
<template>
- <div class="gl-pt-4">
+ <div class="gl-p-5 gl-border-b gl-border-gray-50">
+ <gl-icon :name="refIcon" :size="14" class="gl-ml-2 gl-mr-3" />
<span data-testid="title" class="gl-mr-2">{{ namespace }}</span>
<gl-badge
v-for="ref in tippingRefs"
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
index 5362ceac9ee..6549de96c98 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
@@ -67,6 +67,7 @@ export const TOKEN_TITLE_AUTHOR = __('Author');
export const TOKEN_TITLE_CONFIDENTIAL = __('Confidential');
export const TOKEN_TITLE_CONTACT = s__('Crm|Contact');
export const TOKEN_TITLE_GROUP = __('Group');
+export const TOKEN_TITLE_GROUP_INVITE = __('Group invite');
export const TOKEN_TITLE_LABEL = __('Label');
export const TOKEN_TITLE_PROJECT = __('Project');
export const TOKEN_TITLE_MILESTONE = __('Milestone');
@@ -90,6 +91,7 @@ export const TOKEN_TYPE_AUTHOR = 'author';
export const TOKEN_TYPE_CONFIDENTIAL = 'confidential';
export const TOKEN_TYPE_CONTACT = 'contact';
export const TOKEN_TYPE_GROUP = 'group';
+export const TOKEN_TYPE_GROUP_INVITE = 'group-invite';
export const TOKEN_TYPE_EPIC = 'epic';
// As health status gets reused between issue lists and boards
// this is in the shared constants. Until we have not decoupled the EE filtered search bar
diff --git a/app/models/project_authorizations/changes.rb b/app/models/project_authorizations/changes.rb
index 256207d2cc7..26f5366ad5e 100644
--- a/app/models/project_authorizations/changes.rb
+++ b/app/models/project_authorizations/changes.rb
@@ -160,7 +160,6 @@ module ProjectAuthorizations
end
def publish_removed_event
- return if ::Feature.disabled?(:user_approval_rules_removal)
return if @removed_user_ids.none?
events = @affected_project_ids.flat_map do |project_id|
diff --git a/app/models/work_items/widget_definition.rb b/app/models/work_items/widget_definition.rb
index d187573ff55..2637a7c8185 100644
--- a/app/models/work_items/widget_definition.rb
+++ b/app/models/work_items/widget_definition.rb
@@ -33,7 +33,8 @@ module WorkItems
current_user_todos: 15,
award_emoji: 16,
linked_items: 17,
- color: 18 # EE-only
+ color: 18, # EE-only
+ rolledup_dates: 19 # EE-only
}
def self.available_widgets
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index be0e5a428b4..adaebf90b4b 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -36,7 +36,7 @@
%span.cgray= n_('parent', 'parents', @commit.parents.count)
- @commit.parents.each do |parent|
= link_to parent.short_id, project_commit_path(@project, parent), class: "commit-sha"
- #js-commit-branches-and-tags{ data: { full_path: @project.full_path, commit_sha: @commit.short_id } }
+ #js-commit-branches-and-tags{ data: { full_path: @project.full_path, commit_sha: @commit.short_id } }
.well-segment.merge-request-info
.icon-container
diff --git a/config/feature_flags/development/use_gitlab_http_v2.yml b/config/feature_flags/development/use_gitlab_http_v2.yml
deleted file mode 100644
index 8a840c48a4b..00000000000
--- a/config/feature_flags/development/use_gitlab_http_v2.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: use_gitlab_http_v2
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132742
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/426549
-milestone: '16.5'
-type: development
-group: group::pipeline authoring
-default_enabled: true
diff --git a/config/feature_flags/development/user_approval_rules_removal.yml b/config/feature_flags/development/user_approval_rules_removal.yml
deleted file mode 100644
index 96025a8c163..00000000000
--- a/config/feature_flags/development/user_approval_rules_removal.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: user_approval_rules_removal
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138691
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/434141
-milestone: '16.7'
-type: development
-group: group::code review
-default_enabled: true
diff --git a/config/initializers_before_autoloader/004_zeitwerk.rb b/config/initializers_before_autoloader/004_zeitwerk.rb
index 689da6e390c..2d54ab87dca 100644
--- a/config/initializers_before_autoloader/004_zeitwerk.rb
+++ b/config/initializers_before_autoloader/004_zeitwerk.rb
@@ -35,7 +35,6 @@ Rails.autoloaders.each do |autoloader|
'html_parser' => 'HTMLParser',
'html_gitlab' => 'HTMLGitlab',
'http' => 'HTTP',
- 'legacy_http' => 'LegacyHTTP',
'http_connection_adapter' => 'HTTPConnectionAdapter',
'http_clone_enabled_check' => 'HTTPCloneEnabledCheck',
'hangouts_chat_http_override' => 'HangoutsChatHTTPOverride',
diff --git a/db/docs/batched_background_migrations/backfill_owasp_top_ten_of_vulnerability_reads.yml b/db/docs/batched_background_migrations/backfill_owasp_top_ten_of_vulnerability_reads.yml
new file mode 100644
index 00000000000..16c505faf1f
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_owasp_top_ten_of_vulnerability_reads.yml
@@ -0,0 +1,8 @@
+---
+migration_job_name: BackfillOwaspTopTenOfVulnerabilityReads
+description: Backfills owasp_top_10 column for vulnerability_reads table.
+feature_category: vulnerability_management
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139544
+milestone: '16.8'
+queued_migration_version: 20231214111617
+finalize_after: '2024-1-10'
diff --git a/db/post_migrate/20231211154654_add_work_items_rolledup_dates_widget.rb b/db/post_migrate/20231211154654_add_work_items_rolledup_dates_widget.rb
new file mode 100644
index 00000000000..b45967920fe
--- /dev/null
+++ b/db/post_migrate/20231211154654_add_work_items_rolledup_dates_widget.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class AddWorkItemsRolledupDatesWidget < Gitlab::Database::Migration[2.2]
+ milestone '16.8'
+
+ class WorkItemType < MigrationRecord
+ self.table_name = 'work_item_types'
+ end
+
+ class WidgetDefinition < MigrationRecord
+ self.table_name = 'work_item_widget_definitions'
+ end
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ WIDGET_NAME = 'Rolledup dates'
+ WIDGET_ENUM_VALUE = 19
+ WORK_ITEM_TYPES = ['Epic'].freeze
+
+ def up
+ widgets = WORK_ITEM_TYPES.each_with_object([]) do |type_name, result|
+ type = WorkItemType.find_by_name_and_namespace_id(type_name, nil)
+
+ unless type
+ Gitlab::AppLogger.warn("type #{type_name} is missing, not adding widget")
+
+ next
+ end
+
+ result << {
+ work_item_type_id: type.id,
+ name: WIDGET_NAME,
+ widget_type: WIDGET_ENUM_VALUE
+ }
+ end
+
+ return if widgets.empty?
+
+ WidgetDefinition.upsert_all(
+ widgets,
+ unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
+ )
+ end
+
+ def down
+ WidgetDefinition.where(name: WIDGET_NAME).delete_all
+ end
+end
diff --git a/db/post_migrate/20231214111617_queue_backfill_owasp_top_ten_of_vulnerability_reads.rb b/db/post_migrate/20231214111617_queue_backfill_owasp_top_ten_of_vulnerability_reads.rb
new file mode 100644
index 00000000000..e8b13212df8
--- /dev/null
+++ b/db/post_migrate/20231214111617_queue_backfill_owasp_top_ten_of_vulnerability_reads.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class QueueBackfillOwaspTopTenOfVulnerabilityReads < Gitlab::Database::Migration[2.2]
+ milestone '16.8'
+
+ MIGRATION = "BackfillOwaspTopTenOfVulnerabilityReads"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 10000
+ SUB_BATCH_SIZE = 50
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :vulnerability_reads,
+ :vulnerability_id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :vulnerability_reads, :vulnerability_id, [])
+ end
+end
diff --git a/db/schema_migrations/20231211154654 b/db/schema_migrations/20231211154654
new file mode 100644
index 00000000000..24f56f52ed1
--- /dev/null
+++ b/db/schema_migrations/20231211154654
@@ -0,0 +1 @@
+7c587bfbe8349640c9766d41a3c287bd27d8bc03d7a3f17d9a47c49f31bed2d8 \ No newline at end of file
diff --git a/db/schema_migrations/20231214111617 b/db/schema_migrations/20231214111617
new file mode 100644
index 00000000000..42c574c3f8b
--- /dev/null
+++ b/db/schema_migrations/20231214111617
@@ -0,0 +1 @@
+4acc75ab443f518a7340cea213f5803dee10c39f48d07b8a2e284f71d4c1eedd \ No newline at end of file
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index f4b60ab7b20..aaa1a7c559b 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -5443,6 +5443,7 @@ Input type: `MemberRoleUpdateInput`
| <a id="mutationmemberroleupdatedescription"></a>`description` | [`String`](#string) | Description of the member role. |
| <a id="mutationmemberroleupdateid"></a>`id` | [`MemberRoleID!`](#memberroleid) | ID of the member role to mutate. |
| <a id="mutationmemberroleupdatename"></a>`name` | [`String`](#string) | Name of the member role. |
+| <a id="mutationmemberroleupdatepermissions"></a>`permissions` | [`[MemberRolePermission!]`](#memberrolepermission) | List of all customizable permissions. |
#### Fields
@@ -29233,6 +29234,24 @@ Represents a legacy requirement widget.
| <a id="workitemwidgetrequirementlegacylegacyiid"></a>`legacyIid` **{warning-solid}** | [`Int`](#int) | **Deprecated** in 15.9. Use Work Item IID instead. |
| <a id="workitemwidgetrequirementlegacytype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
+### `WorkItemWidgetRolledupDates`
+
+Represents the rolledup dates widget.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="workitemwidgetrolledupdatesduedate"></a>`dueDate` | [`Date`](#date) | Due date for the work item. |
+| <a id="workitemwidgetrolledupdatesduedateisfixed"></a>`dueDateIsFixed` | [`Boolean`](#boolean) | Indicates if the due date for the work item is fixed. |
+| <a id="workitemwidgetrolledupdatesduedatesourcingmilestone"></a>`dueDateSourcingMilestone` | [`Milestone`](#milestone) | Indicates which milestone sources the rolledup due date. |
+| <a id="workitemwidgetrolledupdatesduedatesourcingworkitem"></a>`dueDateSourcingWorkItem` | [`WorkItem`](#workitem) | Indicates which work_item sources the rolledup due date. |
+| <a id="workitemwidgetrolledupdatesstartdate"></a>`startDate` | [`Date`](#date) | Start date for the work item. |
+| <a id="workitemwidgetrolledupdatesstartdateisfixed"></a>`startDateIsFixed` | [`Boolean`](#boolean) | Indicates if the start date for the work item is fixed. |
+| <a id="workitemwidgetrolledupdatesstartdatesourcingmilestone"></a>`startDateSourcingMilestone` | [`Milestone`](#milestone) | Indicates which milestone sources the rolledup start date. |
+| <a id="workitemwidgetrolledupdatesstartdatesourcingworkitem"></a>`startDateSourcingWorkItem` | [`WorkItem`](#workitem) | Indicates which work_item sources the rolledup start date. |
+| <a id="workitemwidgetrolledupdatestype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
+
### `WorkItemWidgetStartAndDueDate`
Represents a start and due date widget.
@@ -32134,6 +32153,7 @@ Type of a work item widget.
| <a id="workitemwidgettypenotifications"></a>`NOTIFICATIONS` | Notifications widget. |
| <a id="workitemwidgettypeprogress"></a>`PROGRESS` | Progress widget. |
| <a id="workitemwidgettyperequirement_legacy"></a>`REQUIREMENT_LEGACY` | Requirement Legacy widget. |
+| <a id="workitemwidgettyperolledup_dates"></a>`ROLLEDUP_DATES` | Rolledup Dates widget. |
| <a id="workitemwidgettypestart_and_due_date"></a>`START_AND_DUE_DATE` | Start And Due Date widget. |
| <a id="workitemwidgettypestatus"></a>`STATUS` | Status widget. |
| <a id="workitemwidgettypetest_reports"></a>`TEST_REPORTS` | Test Reports widget. |
@@ -33820,6 +33840,7 @@ Implementations:
- [`WorkItemWidgetNotifications`](#workitemwidgetnotifications)
- [`WorkItemWidgetProgress`](#workitemwidgetprogress)
- [`WorkItemWidgetRequirementLegacy`](#workitemwidgetrequirementlegacy)
+- [`WorkItemWidgetRolledupDates`](#workitemwidgetrolledupdates)
- [`WorkItemWidgetStartAndDueDate`](#workitemwidgetstartandduedate)
- [`WorkItemWidgetStatus`](#workitemwidgetstatus)
- [`WorkItemWidgetTestReports`](#workitemwidgettestreports)
diff --git a/doc/api/issues.md b/doc/api/issues.md
index b2c6f0cb739..3c4ad7b6685 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -2020,7 +2020,8 @@ The `assignee` column is deprecated. We now show it as a single-sized array `ass
Promotes an issue to an epic by adding a comment with the `/promote`
[quick action](../user/project/quick_actions.md).
-For more information about promoting issues to epics, see [Manage epics](../user/group/epics/manage_epics.md#promote-an-issue-to-an-epic).
+For more information about promoting issues to epics, see
+[Promote an issue to an epic](../user/project/issues/managing_issues.md#promote-an-issue-to-an-epic).
```plaintext
POST /projects/:id/issues/:issue_iid/notes
diff --git a/doc/ci/caching/index.md b/doc/ci/caching/index.md
index 55f18987490..737b18fb6c2 100644
--- a/doc/ci/caching/index.md
+++ b/doc/ci/caching/index.md
@@ -738,5 +738,5 @@ instance.
To share the cache between concurrent runners, you can either:
- Use the `[runners.docker]` section of the runners' `config.toml` to configure a single mount point on the host that
-is mapped to `/cache` in each container, preventing the runner from creating unique volume names.
+ is mapped to `/cache` in each container, preventing the runner from creating unique volume names.
- Use a distributed cache.
diff --git a/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md b/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md
index b80bbbc5c98..82f92cdc938 100644
--- a/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md
+++ b/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md
@@ -276,7 +276,7 @@ include:
To use DAST on the default branch:
1. Set up a new [service](#create-an-ecs-service). This service will be used to deploy a temporary
-DAST environment.
+ DAST environment.
1. Use the `CI_AWS_ECS_SERVICE` variable to set the name.
1. Set the scope to the `dast-default` environment.
1. Add the following to your `.gitlab-ci.yml` file:
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index beaa2291eea..bc157c7ae08 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -853,7 +853,7 @@ This indicates the GitLab Runner does not have permission to start the
1. Check that `privileged = true` is set in the `config.toml`.
1. Make sure the CI job has the right Runner tags to use these
-privileged runners.
+ privileged runners.
### Error: `cgroups: cgroup mountpoint does not exist: unknown`
diff --git a/doc/ci/environments/index.md b/doc/ci/environments/index.md
index 03c9a152d98..4a6e0118f3b 100644
--- a/doc/ci/environments/index.md
+++ b/doc/ci/environments/index.md
@@ -108,7 +108,7 @@ To create a static environment, in your `.gitlab-ci.yml` file:
1. Define a job in the `deploy` stage.
1. In the job, define the environment `name` and `url`. If an
-environment of that name doesn't exist when the pipeline runs, it is created.
+ environment of that name doesn't exist when the pipeline runs, it is created.
NOTE:
Some characters cannot be used in environment names. For more information about the
diff --git a/doc/ci/index.md b/doc/ci/index.md
index beb7fffeb8a..b74b2e1735b 100644
--- a/doc/ci/index.md
+++ b/doc/ci/index.md
@@ -39,7 +39,7 @@ In the `.gitlab-ci.yml` file, you can define:
- [Create your first `.gitlab-ci.yml` file](quick_start/index.md).
- [View all the possible keywords that you can use in the `.gitlab-ci.yml` file](yaml/index.md).
-the configuration.
+ the configuration.
- Use the [pipeline editor](pipeline_editor/index.md) to edit or [visualize](pipeline_editor/index.md#visualize-ci-configuration)
your CI/CD configuration.
diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md
index 3ff25cc8bab..5854704521b 100644
--- a/doc/ci/review_apps/index.md
+++ b/doc/ci/review_apps/index.md
@@ -108,7 +108,7 @@ The following are example projects that demonstrate review app configuration:
Other examples of review apps:
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-[Cloud Native Development with GitLab](https://www.youtube.com/watch?v=jfIyQEwrocw).
+ [Cloud Native Development with GitLab](https://www.youtube.com/watch?v=jfIyQEwrocw).
- [Review apps for Android](https://about.gitlab.com/blog/2020/05/06/how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io/).
## Route Maps
diff --git a/doc/ci/runners/index.md b/doc/ci/runners/index.md
index 1df93ed8896..bfb30a36be2 100644
--- a/doc/ci/runners/index.md
+++ b/doc/ci/runners/index.md
@@ -33,7 +33,7 @@ When you use SaaS runners:
- The VM is active only for the duration of the job and immediately deleted. This means that any changes that your job makes to the virtual machine will not be available to a subsequent job.
- The virtual machine where your job runs has `sudo` access with no password.
- The storage is shared by the operating system, the image with pre-installed software, and a copy of your cloned repository.
-This means that the available free disk space for your jobs to use is reduced.
+ This means that the available free disk space for your jobs to use is reduced.
NOTE:
Jobs handled by SaaS runners on GitLab.com **time out after 3 hours**, regardless of the timeout configured in a project.
diff --git a/doc/ci/runners/new_creation_workflow.md b/doc/ci/runners/new_creation_workflow.md
index c870a89a77a..12bffb79e33 100644
--- a/doc/ci/runners/new_creation_workflow.md
+++ b/doc/ci/runners/new_creation_workflow.md
@@ -39,7 +39,7 @@ The new runner registration workflow has the following benefits:
- Preserved ownership records for runners, and minimized impact on users.
- The addition of a unique system ID ensures that you can reuse the same authentication token across
-multiple runners. For more information, see [Reusing a GitLab Runner configuration](https://docs.gitlab.com/runner/fleet_scaling/#reusing-a-gitlab-runner-configuration).
+ multiple runners. For more information, see [Reusing a GitLab Runner configuration](https://docs.gitlab.com/runner/fleet_scaling/#reusing-a-gitlab-runner-configuration).
## Estimated time frame for planned changes
@@ -61,7 +61,7 @@ To avoid a broken workflow, you must:
1. [Create a shared runner](runners_scope.md#create-a-shared-runner-with-a-runner-authentication-token) and obtain the authentication token.
1. Replace the registration token in your runner registration workflow with the
-authentication token.
+ authentication token.
## Using registration tokens after GitLab 17.0
@@ -159,7 +159,9 @@ Several runner configuration options cannot be set during runner registration. T
The following configuration options are no longer supported in [`values.yaml`](https://gitlab.com/gitlab-org/charts/gitlab-runner/-/blob/main/values.yaml):
```yaml
-## All these fields are DEPRECATED and the runner WILL FAIL TO START if you specify them
+## All these fields are DEPRECATED and the runner WILL FAIL TO START with GitLab Runner 18.0 and later if you specify them.
+## If a runner authentication token is specified in runnerRegistrationToken, the registration will succeed, however the
+## other values will be ignored.
runnerRegistrationToken: ""
locked: true
tags: ""
diff --git a/doc/ci/runners/runners_scope.md b/doc/ci/runners/runners_scope.md
index 48f6a22e9b3..d6a556ffd9b 100644
--- a/doc/ci/runners/runners_scope.md
+++ b/doc/ci/runners/runners_scope.md
@@ -576,13 +576,16 @@ A runner can have one of the following statuses.
As an administrator, you can view runner statistics to learn about the performance of your runner fleet.
-- The **Median job queued time** value is calculated by sampling the queue duration of the
+The **Median job queued time** value is calculated by sampling the queue duration of the
most recent 100 jobs that were run by Instance runners. Jobs from only the latest 5000
runners are considered.
-- The median is a value that falls into the 50th percentile: half of the jobs
+
+The median is a value that falls into the 50th percentile: half of the jobs
queued for longer than the median value, and half of the jobs queued for less than the
median value.
+To view runner statistics:
+
1. On the left sidebar, at the bottom, select **Admin Area**.
1. Select **CI/CD > Runners**.
1. Select **View metrics**.
diff --git a/doc/ci/variables/index.md b/doc/ci/variables/index.md
index f247d9609fe..86fc813b0cc 100644
--- a/doc/ci/variables/index.md
+++ b/doc/ci/variables/index.md
@@ -967,4 +967,4 @@ As a workaround you can either:
- Use [File-type](#use-file-type-cicd-variables) CI/CD variables for large environment variables where possible.
- If a single large variable is larger than `ARG_MAX`, try using [Secure Files](../secure_files/index.md), or
-bring the file to the job through some other mechanism.
+ bring the file to the job through some other mechanism.
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index 93c38237993..2575c78461e 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -1634,7 +1634,7 @@ use the new cache, instead of rebuilding the dependencies.
**Additional details**:
- The cache `key` is a SHA computed from the most recent commits
-that changed each listed file.
+ that changed each listed file.
If neither file is changed in any commits, the fallback key is `default`.
##### `cache:key:prefix`
diff --git a/doc/development/cicd/configuration.md b/doc/development/cicd/configuration.md
index 903a3d63e8c..60f55174651 100644
--- a/doc/development/cicd/configuration.md
+++ b/doc/development/cicd/configuration.md
@@ -32,13 +32,13 @@ or [`ee/lib/ee/gitlab/ci/config/entry`](https://gitlab.com/gitlab-org/gitlab/-/t
An entry is represented by a class that inherits from;
- `Entry::Node`: for simple keywords.
-(e.g. [`Entry::Stage`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/config/entry/stage.rb))
+ (e.g. [`Entry::Stage`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/config/entry/stage.rb))
- `Entry::Simplifiable`: for keywords that have multiple structures.
-For example, [`Entry::Retry`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/config/entry/retry.rb) can be a simple number or a hash configuration.
+ For example, [`Entry::Retry`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/config/entry/retry.rb) can be a simple number or a hash configuration.
- `Entry::ComposableArray`: for keywords that have a list of single-type sub-elements.
-For example, [`Entry::Includes`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/config/entry/includes.rb) has a list of `Entry::Include` elements.
+ For example, [`Entry::Includes`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/config/entry/includes.rb) has a list of `Entry::Include` elements.
- `Entry::ComposableHash`: for keywords that have single-type sub-elements with user-defined keys.
-For example, [`Entry::Variables`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/config/entry/variables.rb) has a list of `Entry::Variable` elements with user-defined keys.
+ For example, [`Entry::Variables`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/config/entry/variables.rb) has a list of `Entry::Variable` elements with user-defined keys.
### Helper Classes
diff --git a/doc/development/cicd/pipeline_wizard.md b/doc/development/cicd/pipeline_wizard.md
index 0c0c0f3cc45..b534fede6e9 100644
--- a/doc/development/cicd/pipeline_wizard.md
+++ b/doc/development/cicd/pipeline_wizard.md
@@ -138,7 +138,7 @@ is planned to add the ability to create a MR from here.
### Events
- `done` - Emitted after the file has been committed. Use this to redirect the
-user to the pipeline, for example.
+ user to the pipeline, for example.
### Template file location
diff --git a/doc/development/contributing/verify/index.md b/doc/development/contributing/verify/index.md
index dbc48121dff..5f9e2e3acb3 100644
--- a/doc/development/contributing/verify/index.md
+++ b/doc/development/contributing/verify/index.md
@@ -53,7 +53,7 @@ and they serve us and our users well. Some examples of these principles are that
If a job fails and we notify a user that it was successful, it can have severe negative consequences.
- Feedback needs to be available when a user needs it and data cannot disappear unexpectedly when engineers need it.
- It all doesn't matter if the platform is not secure and we
-are leaking credentials or secrets.
+ are leaking credentials or secrets.
- When a user provides a set of preconditions in a form of CI/CD configuration, the result should be deterministic each time a pipeline runs, because otherwise the platform might not be trustworthy.
- If it is fast, simple to use and has a great UX it will serve our users well.
diff --git a/doc/development/fe_guide/architecture.md b/doc/development/fe_guide/architecture.md
index 971c527ef68..75a815925ab 100644
--- a/doc/development/fe_guide/architecture.md
+++ b/doc/development/fe_guide/architecture.md
@@ -24,7 +24,7 @@ This structure allows the group to think through a proposed change, gather feedb
### Design Documents
-When the work ahead may affect more than a single group, stage or potentially an entirement department (for example, all of the Frontend team) then it is likely that there is need for a [Design Document](https://about.gitlab.com/handbook/engineering/architecture/workflow/).
+When the work ahead may affect more than a single group, stage or potentially an entire department (for example, all of the Frontend team) then it is likely that there is need for a [Design Document](https://about.gitlab.com/handbook/engineering/architecture/workflow/).
This is well documented in the handbook, but to touch on it shortly, it is **the best way** to propose large changes and gather the required feedback and support to move forward. These documents are version controlled, keep evolving with time and are a great way to share a complex understanding across the entire organization. They also require a coach, which is a great way to involve someone with a lot of experience with larger changes. This process is shared across all engineering departments and is owned by the CTO.
@@ -57,9 +57,9 @@ Very small changes may have a very broad impact. For example, a change to any ES
For recommending certain code patterns in our documentation, you can write the MR that apply your proposed change, share it broadly with the department and if no strong objections are raised, merge your change. This is more efficient than RFCs because of the bias for action, while also gathering all the feedback necessary for everyone to feel included.
-If you'd like to propose a major change to the technological stack (Vue to React, JavaScript to TypeScript, etc.), start by reaching out on Slack to gauge interest. Always ask yourself whether or not the problems that you see can be fixed from our current tech stack, as we should always try to fix our problems with the tools we already have. Other departments, such as Backend and QA, do not have a clear process to propose technological changes either. That is because these changes would require huge investements from the company and probably cannot be decided without involving high-ranking executives from engineering.
+If you'd like to propose a major change to the technological stack (Vue to React, JavaScript to TypeScript, etc.), start by reaching out on Slack to gauge interest. Always ask yourself whether or not the problems that you see can be fixed from our current tech stack, as we should always try to fix our problems with the tools we already have. Other departments, such as Backend and QA, do not have a clear process to propose technological changes either. That is because these changes would require huge investments from the company and probably cannot be decided without involving high-ranking executives from engineering.
-Instead, consider starting a Design Document that explains the problem and try to solve it with our current tools. Invite contribution from the department and research this thoroughly as there can only be two outcomes. Either the problem **can** be solved with our current tools or it cannot. If it can, this is a huge with for our teams since we've fixed and issue without the need to completly change our stack, and if it cannot, then the Design Document can be the start of the larger conversation around the technological change.
+Instead, consider starting a Design Document that explains the problem and try to solve it with our current tools. Invite contribution from the department and research this thoroughly as there can only be two outcomes. Either the problem **can** be solved with our current tools or it cannot. If it can, this is a huge win for our teams since we've fixed an issue without the need to completely change our stack, and if it cannot, then the Design Document can be the start of the larger conversation around the technological change.
## Widget Architecture
diff --git a/doc/development/pages/index.md b/doc/development/pages/index.md
index f4710c951ed..7bf89789ee0 100644
--- a/doc/development/pages/index.md
+++ b/doc/development/pages/index.md
@@ -22,14 +22,14 @@ subdomain. You can set the GitLab Pages hostname:
As `/etc/hosts` don't support wildcard hostnames, you must configure one entry
for GitLab Pages, and then one entry for each page site:
- ```plaintext
- 127.0.0.1 gdk.test # If you're using GDK
- 127.0.0.1 pages.gdk.test # Pages host
- # Any namespace/group/user needs to be added
- # as a subdomain to the pages host. This is because
- # /etc/hosts doesn't accept wildcards
- 127.0.0.1 root.pages.gdk.test # for the root pages
- ```
+```plaintext
+127.0.0.1 gdk.test # If you're using GDK
+127.0.0.1 pages.gdk.test # Pages host
+# Any namespace/group/user needs to be added
+# as a subdomain to the pages host. This is because
+# /etc/hosts doesn't accept wildcards
+127.0.0.1 root.pages.gdk.test # for the root pages
+```
### With DNS wildcard alternatives
@@ -151,8 +151,8 @@ GitLab Pages access control is disabled by default. To enable it:
1. Create an [Instance-wide OAuth application](../../integration/oauth_provider.md#create-an-instance-wide-application)
with the `api` scope.
1. Set the value of your `redirect-uri` to the `pages-domain` authorization endpoint
-(for example, `http://pages.gdk.test:3010/auth`).
-The `redirect-uri` must not contain any GitLab Pages site domain.
+ (for example, `http://pages.gdk.test:3010/auth`).
+ The `redirect-uri` must not contain any GitLab Pages site domain.
1. Add the auth client configuration:
diff --git a/doc/development/pipelines/index.md b/doc/development/pipelines/index.md
index aebb0f9076d..5ed15213e3e 100644
--- a/doc/development/pipelines/index.md
+++ b/doc/development/pipelines/index.md
@@ -716,9 +716,9 @@ We also run tests with a single database in nightly scheduled pipelines, and in
Single database tests run in two modes:
1. **Single database with one connection**. Where GitLab connects to all the tables using one connection pool.
-This runs through all the jobs that end with `-single-db`
+ This runs through all the jobs that end with `-single-db`
1. **Single database with two connections**. Where GitLab connects to `gitlab_main`, `gitlab_ci` database tables
-using different database connections. This runs through all the jobs that end with `-single-db-ci-connection`.
+ using different database connections. This runs through all the jobs that end with `-single-db-ci-connection`.
If you want to force tests to run with a single database, you can add the `pipeline:run-single-db` label to the merge request.
diff --git a/doc/development/pipelines/internals.md b/doc/development/pipelines/internals.md
index a81eb6f656b..04c1d1f32e8 100644
--- a/doc/development/pipelines/internals.md
+++ b/doc/development/pipelines/internals.md
@@ -445,7 +445,7 @@ projects, only one of the following tags should be added to a job:
- `gitlab-org`: Jobs randomly use privileged and unprivileged runners.
- `gitlab-org-docker`: Jobs must use a privileged runner. If you need [Docker-in-Docker support](../../ci/docker/using_docker_build.md#use-docker-in-docker),
-use `gitlab-org-docker` instead of `gitlab-org`.
+ use `gitlab-org-docker` instead of `gitlab-org`.
The `gitlab-org-docker` tag is added by the `.use-docker-in-docker` job
definition above.
diff --git a/doc/update/index.md b/doc/update/index.md
index 0c43af3b925..2043d26a7db 100644
--- a/doc/update/index.md
+++ b/doc/update/index.md
@@ -88,10 +88,10 @@ As for the artifacts, the GitLab Runner attempts to upload them three times, aft
To address the above two scenarios, it is advised to do the following prior to upgrading:
1. Plan your maintenance.
-1. Pause your runners or block new jobs from starting by adding following to your `/etc/gitlab/gitlab.rb`:
+1. Pause your runners, or block new jobs from starting by adding the following to your `/etc/gitlab/gitlab.rb`:
```ruby
- nginx['custom_gitlab_server_config'] = "location /api/v4/jobs/request {\n deny all;\n return 503;\n}\n"
+ nginx['custom_gitlab_server_config'] = "location ^~ /api/v4/jobs/request {\n deny all;\n return 503;\n}\n"
```
And reconfigure GitLab with:
diff --git a/doc/user/group/epics/manage_epics.md b/doc/user/group/epics/manage_epics.md
index 9cdebdd7d9d..286a1c474da 100644
--- a/doc/user/group/epics/manage_epics.md
+++ b/doc/user/group/epics/manage_epics.md
@@ -11,10 +11,6 @@ to them.
## Create an epic
-> - The New Epic form [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211533) in GitLab 13.2.
-> - In [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/issues/229621) and later, the New Epic button on the Epics list opens the New Epic form.
-> - In [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45948) and later, you can create a new epic from an empty roadmap.
-
Prerequisites:
- You must have at least the Reporter role for the epic's group.
@@ -175,6 +171,9 @@ To do so, either:
- In the upper-right corner, select **epic actions** (**{ellipsis_v}**) and then **Reopen epic**
- Use the `/reopen` [quick action](../../project/quick_actions.md).
+You can also create an epic by
+[promoting an issue](../../project/issues/managing_issues.md#promote-an-issue-to-an-epic).
+
## Go to an epic from an issue
If an issue belongs to an epic, you can go to the parent epic with the
@@ -453,40 +452,6 @@ To move an issue to another epic:
1. Go to the **Child issues and epics** section.
1. Drag issues into the desired parent epic in the visible hierarchy.
-### Promote an issue to an epic
-
-> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/37081) from GitLab Ultimate to GitLab Premium in 12.8.
-
-Prerequisites:
-
-- The project to which the issue belongs must be in a group.
-- You must have at least the Reporter role the project's immediate parent group.
-- You must either:
- - Have at least the Reporter role for the project.
- - Be the author of the issue.
- - Be assigned to the issue.
-
-You can promote an issue to an epic with the `/promote`
-[quick action](../../project/quick_actions.md#issues-merge-requests-and-epics).
-
-NOTE:
-Promoting a confidential issue to an epic makes all information
-related to the issue public as epics are public to group members.
-
-When an issue is promoted to an epic:
-
-- If the issue was confidential, an additional warning is displayed first.
-- An epic is created in the same group as the project of the issue.
-- Subscribers of the issue are notified that the epic was created.
-
-The following issue metadata is copied to the epic:
-
-- Title, description, activity/comment thread.
-- Upvotes and downvotes.
-- Participants.
-- Group labels that the issue already has.
-- Parent epic.
-
### Use an epic template for repeating issues
You can create a spreadsheet template to manage a pattern of consistently repeating issues.
diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md
index ae7afd35af4..b80db3887bf 100644
--- a/doc/user/project/issues/managing_issues.md
+++ b/doc/user/project/issues/managing_issues.md
@@ -367,12 +367,35 @@ Alternatively:
## Promote an issue to an epic **(PREMIUM ALL)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3777) in GitLab 11.6.
-> - Moved from GitLab Ultimate to GitLab Premium in 12.8.
-> - Promoting issues to epics via the UI [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233974) in GitLab 13.6.
-
You can promote an issue to an [epic](../../group/epics/index.md) in the immediate parent group.
+NOTE:
+Promoting a confidential issue to an epic makes all information
+related to the issue public, as epics are public to group members.
+
+When an issue is promoted to an epic:
+
+- If the issue was confidential, an additional warning is displayed first.
+- An epic is created in the same group as the project of the issue.
+- Subscribers of the issue are notified that the epic was created.
+
+The following issue metadata is copied to the epic:
+
+- Title, description, activity, and comment threads.
+- Upvotes and downvotes.
+- Participants.
+- Group labels that the issue had.
+- Parent epic.
+
+Prerequisites:
+
+- The project to which the issue belongs must be in a group.
+- You must have at least the Reporter role the project's immediate parent group.
+- You must either:
+ - Have at least the Reporter role for the project.
+ - Be the author of the issue.
+ - Be assigned to the issue.
+
To promote an issue to an epic:
1. On the left sidebar, select **Search or go to** and find your project.
@@ -382,8 +405,6 @@ To promote an issue to an epic:
Alternatively, you can use the `/promote` [quick action](../quick_actions.md#issues-merge-requests-and-epics).
-Read more about [promoting an issues to epics](../../group/epics/manage_epics.md#promote-an-issue-to-an-epic).
-
## Promote an issue to an incident
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/296787) in GitLab 14.5.
diff --git a/doc/user/project/remote_development/connect_machine.md b/doc/user/project/remote_development/connect_machine.md
index cf46774741c..df2921b184c 100644
--- a/doc/user/project/remote_development/connect_machine.md
+++ b/doc/user/project/remote_development/connect_machine.md
@@ -4,7 +4,7 @@ group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Tutorial: Connect a remote machine to the Web IDE **(FREE ALL BETA)**
+# Tutorial: Connect a remote machine to the Web IDE **(FREE ALL)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95169) in GitLab 15.4 [with a flag](../../../administration/feature_flags.md) named `vscode_web_ide`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/371084) in GitLab 15.7.
diff --git a/doc/user/project/remote_development/index.md b/doc/user/project/remote_development/index.md
index ac8d7102e40..c11d8591745 100644
--- a/doc/user/project/remote_development/index.md
+++ b/doc/user/project/remote_development/index.md
@@ -4,7 +4,7 @@ group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Remote development **(FREE ALL BETA)**
+# Remote development **(FREE ALL)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95169) in GitLab 15.4 [with a flag](../../../administration/feature_flags.md) named `vscode_web_ide`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/371084) in GitLab 15.7.
diff --git a/lib/gitlab/background_migration/backfill_owasp_top_ten_of_vulnerability_reads.rb b/lib/gitlab/background_migration/backfill_owasp_top_ten_of_vulnerability_reads.rb
new file mode 100644
index 00000000000..5d8867a130a
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_owasp_top_ten_of_vulnerability_reads.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Backfills owasp_top_10 column for vulnerability_reads table.
+ class BackfillOwaspTopTenOfVulnerabilityReads < BatchedMigrationJob
+ operation_name :set_owasp_top_10
+ feature_category :vulnerability_management
+
+ OWASP_TOP_10 = {
+ "A1:2017-Injection" => 1,
+ "A1:2017" => 1,
+ "A2:2017-Broken Authentication" => 2,
+ "A2:2017" => 2,
+ "A3:2017-Sensitive Data Exposure" => 3,
+ "A3:2017" => 3,
+ "A4:2017-XML External Entities (XXE)" => 4,
+ "A4:2017" => 4,
+ "A5:2017-Broken Access Control" => 5,
+ "A5:2017" => 5,
+ "A6:2017-Security Misconfiguration" => 6,
+ "A6:2017" => 6,
+ "A7:2017-Cross-Site Scripting (XSS)" => 7,
+ "A7:2017" => 7,
+ "A8:2017-Insecure Deserialization" => 8,
+ "A8:2017" => 8,
+ "A9:2017-Using Components with Known Vulnerabilities" => 9,
+ "A9:2017" => 9,
+ "A10:2017-Insufficient Logging & Monitoring" => 10,
+ "A10:2017" => 10,
+
+ "A1:2021-Broken Access Control" => 11,
+ "A1:2021" => 11,
+ "A2:2021-Cryptographic Failures" => 12,
+ "A2:2021" => 12,
+ "A3:2021-Injection" => 13,
+ "A3:2021" => 13,
+ "A4:2021-Insecure Design" => 14,
+ "A4:2021" => 14,
+ "A5:2021-Security Misconfiguration" => 15,
+ "A5:2021" => 15,
+ "A6:2021-Vulnerable and Outdated Components" => 16,
+ "A6:2021" => 16,
+ "A7:2021-Identification and Authentication Failures" => 17,
+ "A7:2021" => 17,
+ "A8:2021-Software and Data Integrity Failures" => 18,
+ "A8:2021" => 18,
+ "A9:2021-Security Logging and Monitoring Failures" => 19,
+ "A9:2021" => 19,
+ "A10:2021-Server-Side Request Forgery" => 20,
+ "A10:2021" => 20
+ }.with_indifferent_access.freeze
+
+ UPDATE_SQL = <<-SQL.squish
+ UPDATE vulnerability_reads AS vr
+ SET owasp_top_10 =
+ CASE selected_ids.external_id
+ #{OWASP_TOP_10.map { |external_id, value| "WHEN '#{external_id}' THEN #{value}" }.join(' ')}
+ ELSE vr.owasp_top_10
+ END
+ FROM (
+ SELECT vr.id, vi.external_id
+ FROM vulnerability_reads vr
+ INNER JOIN vulnerability_occurrences vo ON vr.vulnerability_id = vo.vulnerability_id
+ INNER JOIN vulnerability_occurrence_identifiers voi ON vo.id = voi.occurrence_id
+ INNER JOIN vulnerability_identifiers vi ON voi.identifier_id = vi.id
+ WHERE LOWER(vi.external_type) = 'owasp'
+ AND vi.external_id IN (?)
+ AND vr.id IN (?)
+ ) AS selected_ids
+ WHERE vr.id = selected_ids.id
+ SQL
+
+ class VulnerabilitiesRead < ::ApplicationRecord
+ self.table_name = 'vulnerability_reads'
+ end
+
+ def perform
+ each_sub_batch do |sub_batch|
+ update_query = VulnerabilitiesRead.sanitize_sql([UPDATE_SQL, OWASP_TOP_10.keys, sub_batch.select(:id)])
+ connection.execute(update_query)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database_importers/work_items/base_type_importer.rb b/lib/gitlab/database_importers/work_items/base_type_importer.rb
index 380c4b8f196..6e6080a0543 100644
--- a/lib/gitlab/database_importers/work_items/base_type_importer.rb
+++ b/lib/gitlab/database_importers/work_items/base_type_importer.rb
@@ -23,7 +23,8 @@ module Gitlab
current_user_todos: 'Current user todos',
award_emoji: 'Award emoji',
linked_items: 'Linked items',
- color: 'Color'
+ color: 'Color',
+ rolledup_dates: 'Rolledup dates'
}.freeze
WIDGETS_FOR_TYPE = {
@@ -128,7 +129,8 @@ module Gitlab
:current_user_todos,
:award_emoji,
:linked_items,
- :color
+ :color,
+ :rolledup_dates
],
ticket: [
:assignees,
diff --git a/lib/gitlab/http.rb b/lib/gitlab/http.rb
index 9c9816e142e..958b415e18f 100644
--- a/lib/gitlab/http.rb
+++ b/lib/gitlab/http.rb
@@ -26,13 +26,6 @@ module Gitlab
}.freeze
DEFAULT_READ_TOTAL_TIMEOUT = 30.seconds
- SILENT_MODE_ALLOWED_METHODS = [
- Net::HTTP::Get,
- Net::HTTP::Head,
- Net::HTTP::Options,
- Net::HTTP::Trace
- ].freeze
-
# We are explicitly assigning these constants because they are used in the codebase.
Error = HTTParty::Error
Response = HTTParty::Response
@@ -42,11 +35,7 @@ module Gitlab
class << self
::Gitlab::HTTP_V2::SUPPORTED_HTTP_METHODS.each do |method|
define_method(method) do |path, options = {}, &block|
- if ::Feature.enabled?(:use_gitlab_http_v2, Feature.current_request)
- ::Gitlab::HTTP_V2.public_send(method, path, http_v2_options(options), &block) # rubocop:disable GitlabSecurity/PublicSend
- else
- ::Gitlab::LegacyHTTP.public_send(method, path, options, &block) # rubocop:disable GitlabSecurity/PublicSend
- end
+ ::Gitlab::HTTP_V2.public_send(method, path, http_v2_options(options), &block) # rubocop:disable GitlabSecurity/PublicSend -- method is validated to make sure it is one of the methods in Gitlab::HTTP_V2::SUPPORTED_HTTP_METHODS
end
end
@@ -59,18 +48,14 @@ module Gitlab
# TODO: This method is subject to be removed
# We have this for now because we explicitly use the `perform_request` method in some places.
def perform_request(http_method, path, options, &block)
- if ::Feature.enabled?(:use_gitlab_http_v2, Feature.current_request)
- method_name = http_method::METHOD.downcase.to_sym
-
- unless ::Gitlab::HTTP_V2::SUPPORTED_HTTP_METHODS.include?(method_name)
- raise ArgumentError, "Unsupported HTTP method: '#{method_name}'."
- end
+ method_name = http_method::METHOD.downcase.to_sym
- # Use `::Gitlab::HTTP_V2.get/post/...` methods
- ::Gitlab::HTTP_V2.public_send(method_name, path, http_v2_options(options), &block) # rubocop:disable GitlabSecurity/PublicSend
- else
- ::Gitlab::LegacyHTTP.perform_request(http_method, path, options, &block)
+ unless ::Gitlab::HTTP_V2::SUPPORTED_HTTP_METHODS.include?(method_name)
+ raise ArgumentError, "Unsupported HTTP method: '#{method_name}'."
end
+
+ # Use `::Gitlab::HTTP_V2.get/post/...` methods
+ ::Gitlab::HTTP_V2.public_send(method_name, path, http_v2_options(options), &block) # rubocop:disable GitlabSecurity/PublicSend -- method is validated to make sure it is one of the methods in Gitlab::HTTP_V2::SUPPORTED_HTTP_METHODS
end
private
diff --git a/lib/gitlab/legacy_http.rb b/lib/gitlab/legacy_http.rb
deleted file mode 100644
index cf6ab80d37f..00000000000
--- a/lib/gitlab/legacy_http.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# frozen_string_literal: true
-
-#
-# IMPORTANT: With the new development of the 'gitlab-http' gem (https://gitlab.com/gitlab-org/gitlab/-/issues/415686),
-# no additional change should be implemented in this class. This class will be removed after migrating all
-# the usages to the new gem.
-#
-
-require_relative 'http_connection_adapter'
-
-module Gitlab
- class LegacyHTTP # rubocop:disable Gitlab/NamespacedClass
- include HTTParty # rubocop:disable Gitlab/HTTParty
-
- class << self
- alias_method :httparty_perform_request, :perform_request
- end
-
- connection_adapter ::Gitlab::HTTPConnectionAdapter
-
- def self.perform_request(http_method, path, options, &block)
- raise_if_blocked_by_silent_mode(http_method)
-
- log_info = options.delete(:extra_log_info)
- options_with_timeouts =
- if !options.has_key?(:timeout)
- options.with_defaults(Gitlab::HTTP::DEFAULT_TIMEOUT_OPTIONS)
- else
- options
- end
-
- return httparty_perform_request(http_method, path, options_with_timeouts, &block) if options[:stream_body]
-
- start_time = nil
- read_total_timeout = options.fetch(:timeout, Gitlab::HTTP::DEFAULT_READ_TOTAL_TIMEOUT)
-
- httparty_perform_request(http_method, path, options_with_timeouts) do |fragment|
- start_time ||= ::Gitlab::Metrics::System.monotonic_time
- elapsed = ::Gitlab::Metrics::System.monotonic_time - start_time
-
- if elapsed > read_total_timeout
- raise Gitlab::HTTP::ReadTotalTimeout, "Request timed out after #{elapsed} seconds"
- end
-
- yield fragment if block
- end
- rescue HTTParty::RedirectionTooDeep
- raise Gitlab::HTTP::RedirectionTooDeep
- rescue *Gitlab::HTTP::HTTP_ERRORS => e
- extra_info = log_info || {}
- extra_info = log_info.call(e, path, options) if log_info.respond_to?(:call)
- Gitlab::ErrorTracking.log_exception(e, extra_info)
- raise e
- end
-
- def self.try_get(path, options = {}, &block)
- self.get(path, options, &block) # rubocop:disable Style/RedundantSelf
- rescue *Gitlab::HTTP::HTTP_ERRORS
- nil
- end
-
- def self.raise_if_blocked_by_silent_mode(http_method)
- return unless blocked_by_silent_mode?(http_method)
-
- ::Gitlab::SilentMode.log_info(
- message: 'Outbound HTTP request blocked',
- outbound_http_request_method: http_method.to_s
- )
-
- raise Gitlab::HTTP::SilentModeBlockedError,
- 'only get, head, options, and trace methods are allowed in silent mode'
- end
-
- def self.blocked_by_silent_mode?(http_method)
- ::Gitlab::SilentMode.enabled? && Gitlab::HTTP::SILENT_MODE_ALLOWED_METHODS.exclude?(http_method)
- end
- end
-end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e4094f7bf8c..121d87af164 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -23148,6 +23148,9 @@ msgstr ""
msgid "Group information"
msgstr ""
+msgid "Group invite"
+msgstr ""
+
msgid "Group jobs by"
msgstr ""
@@ -29934,7 +29937,7 @@ msgstr ""
msgid "MemberRole|can't be changed"
msgstr ""
-msgid "MemberRole|cannot be changed because it is already assigned to a user. Please create a new Member Role instead"
+msgid "MemberRole|cannot be changed. Please create a new Member Role instead."
msgstr ""
msgid "MemberRole|cannot be deleted because it is already assigned to a user. Please disassociate the member role from all users before deletion."
diff --git a/qa/gdk/Dockerfile.gdk b/qa/gdk/Dockerfile.gdk
index f55b10e62d9..62249c1a92f 100644
--- a/qa/gdk/Dockerfile.gdk
+++ b/qa/gdk/Dockerfile.gdk
@@ -98,6 +98,7 @@ RUN set -eux; \
gdk config set gitaly.skip_setup true \
&& gdk config set workhorse.skip_setup true \
&& gdk config set gitlab_shell.skip_setup true \
+ && cp .ruby-version ./gitlab/ \
&& cp .tool-versions ./gitlab/ \
&& make redis/redis.conf all \
&& gdk kill
diff --git a/spec/factories/work_items/dates_sources.rb b/spec/factories/work_items/dates_sources.rb
new file mode 100644
index 00000000000..ea82eceb402
--- /dev/null
+++ b/spec/factories/work_items/dates_sources.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :work_items_dates_source, class: 'WorkItems::DatesSource' do
+ work_item
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/backfill_owasp_top_ten_of_vulnerability_reads_spec.rb b/spec/lib/gitlab/background_migration/backfill_owasp_top_ten_of_vulnerability_reads_spec.rb
new file mode 100644
index 00000000000..1462848845e
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_owasp_top_ten_of_vulnerability_reads_spec.rb
@@ -0,0 +1,225 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillOwaspTopTenOfVulnerabilityReads,
+ feature_category: :vulnerability_management do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:users) { table(:users) }
+ let(:scanners) { table(:vulnerability_scanners) }
+ let(:vulnerabilities) { table(:vulnerabilities) }
+ let(:vulnerability_reads) { table(:vulnerability_reads) }
+ let(:vulnerability_findings) { table(:vulnerability_occurrences) }
+ let(:vulnerability_occurrence_identifiers) { table(:vulnerability_occurrence_identifiers) }
+ let(:vulnerability_identifiers) { table(:vulnerability_identifiers) }
+
+ let(:namespace) { namespaces.create!(name: 'user', path: 'user') }
+ let(:project) { projects.create!(namespace_id: namespace.id, project_namespace_id: namespace.id) }
+ let(:user) { users.create!(username: 'john_doe', email: 'johndoe@gitlab.com', projects_limit: 10) }
+ let(:scanner) { scanners.create!(project_id: project.id, external_id: 'external_id', name: 'Test Scanner') }
+
+ shared_context 'with vulnerability data' do
+ let(:external_id) { '' }
+ let(:external_type) { '' }
+ let(:identifier_name) { '' }
+
+ let(:vulnerability_1) { create_vulnerability(title: 'vulnerability 1') }
+ let(:vulnerability_2) { create_vulnerability(title: 'vulnerability 2') }
+ let(:vulnerability_3) { create_vulnerability(title: 'vulnerability 3') }
+
+ let(:vuln_identifier) do
+ create_identifier(external_id: external_id, external_type: external_type, name: identifier_name)
+ end
+
+ let(:vuln_finding) do
+ create_finding(vulnerability_id: vulnerability_1.id, primary_identifier_id: vuln_identifier.id)
+ end
+
+ let!(:vulnerability_read_1) { create_vulnerability_read(vulnerability_id: vulnerability_1.id) }
+ let!(:vulnerability_read_2) { create_vulnerability_read(vulnerability_id: vulnerability_2.id) }
+ let!(:vulnerability_read_3) { create_vulnerability_read(vulnerability_id: vulnerability_3.id) }
+
+ before do
+ create_vulnerability_occurrence_identifier(occurrence_id: vuln_finding.id, identifier_id: vuln_identifier.id)
+ end
+ end
+
+ describe '#perform' do
+ subject(:perform_migration) do
+ described_class.new(
+ start_id: vulnerability_reads.first.vulnerability_id,
+ end_id: vulnerability_reads.last.vulnerability_id,
+ batch_table: :vulnerability_reads,
+ batch_column: :vulnerability_id,
+ sub_batch_size: vulnerability_reads.count,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
+ end
+
+ context 'with owasp top 10 data' do
+ include_context 'with vulnerability data' do
+ let(:external_id) { 'A1:2017-Injection' }
+ let(:external_type) { 'owasp' }
+ let(:identifier_name) { 'Injection' }
+ end
+
+ it 'updates vulnerability_reads' do
+ expect { perform_migration }.to change { vulnerability_read_1.reload.owasp_top_10 }
+ .from(nil).to(1)
+ .and not_change { vulnerability_read_2.reload.owasp_top_10 }.from(nil)
+ end
+
+ it 'updates vulnerability_reads with correct mapping' do
+ vuln_identifier_2 = create_identifier(external_id: 'A1:2021', external_type: 'owasp', name: 'A1 2021')
+ vuln_identifier_3 = create_identifier
+ vuln_finding_2 = create_finding(vulnerability_id: vulnerability_2.id,
+ primary_identifier_id: vuln_identifier_2.id)
+ vuln_finding_3 = create_finding(vulnerability_id: vulnerability_3.id,
+ primary_identifier_id: vuln_identifier_3.id)
+
+ create_vulnerability_occurrence_identifier(occurrence_id: vuln_finding_2.id,
+ identifier_id: vuln_identifier_2.id)
+ create_vulnerability_occurrence_identifier(occurrence_id: vuln_finding_3.id,
+ identifier_id: vuln_identifier_3.id)
+
+ perform_migration
+
+ expect(vulnerability_read_1.reload.owasp_top_10).to eq(1)
+ expect(vulnerability_read_2.reload.owasp_top_10).to eq(11)
+ expect(vulnerability_read_3.reload.owasp_top_10).to be_nil
+ end
+ end
+
+ context 'with incorrect owasp top 10 data' do
+ include_context 'with vulnerability data'
+
+ shared_examples 'does not update vulnerability_reads' do
+ it do
+ perform_migration
+
+ expect(vulnerability_read_1.reload.owasp_top_10).to be_nil
+ expect(vulnerability_read_2.reload.owasp_top_10).to be_nil
+ expect(vulnerability_read_3.reload.owasp_top_10).to be_nil
+ end
+ end
+
+ context 'with incorrect long format external_id' do
+ let(:external_id) { 'A1:2015-Injection' }
+ let(:external_type) { 'owasp' }
+ let(:identifier_name) { 'Injection' }
+
+ it_behaves_like 'does not update vulnerability_reads'
+ end
+
+ context 'with incorrect short format external_id' do
+ let(:external_id) { 'A1' }
+ let(:external_type) { 'owasp' }
+ let(:identifier_name) { 'Injection' }
+
+ it_behaves_like 'does not update vulnerability_reads'
+ end
+
+ context 'with incorrect external_type' do
+ let(:external_id) { 'A1:2017' }
+ let(:external_type) { 'owasp2017' }
+ let(:identifier_name) { 'Injection' }
+
+ it_behaves_like 'does not update vulnerability_reads'
+ end
+ end
+
+ context 'with no vulnerability identifiers match' do
+ include_context 'with vulnerability data' do
+ let(:external_id) { 'CVE-2018-1234' }
+ let(:external_type) { 'CVE' }
+ let(:identifier_name) { 'CVE-2018-1234' }
+ end
+
+ it 'does not update vulnerability_reads' do
+ perform_migration
+
+ expect(vulnerability_reads.where.not(owasp_top_10: nil).count).to eq(0)
+ end
+ end
+ end
+
+ private
+
+ def create_vulnerability(overrides = {})
+ attrs = {
+ project_id: project.id,
+ author_id: user.id,
+ title: 'test',
+ severity: 1,
+ confidence: 1,
+ report_type: 1
+ }.merge(overrides)
+
+ vulnerabilities.create!(attrs)
+ end
+
+ def create_vulnerability_read(overrides = {})
+ attrs = {
+ project_id: project.id,
+ vulnerability_id: 1,
+ scanner_id: scanner.id,
+ severity: 1,
+ report_type: 1,
+ state: 1,
+ uuid: SecureRandom.uuid
+ }.merge(overrides)
+
+ vulnerability_reads.create!(attrs)
+ end
+
+ def create_finding(overrides = {})
+ attrs = {
+ project_id: project.id,
+ scanner_id: scanner.id,
+ severity: 5, # medium
+ confidence: 2, # unknown,
+ report_type: 99, # generic
+ primary_identifier_id: create_identifier.id,
+ project_fingerprint: SecureRandom.hex(20),
+ location_fingerprint: SecureRandom.hex(20),
+ uuid: SecureRandom.uuid,
+ name: "CVE-2018-1234",
+ raw_metadata: "{}",
+ metadata_version: "test:1.0"
+ }.merge(overrides)
+
+ vulnerability_findings.create!(attrs)
+ end
+
+ def create_identifier(overrides = {})
+ attrs = {
+ project_id: project.id,
+ external_id: "CVE-2018-1234",
+ external_type: "CVE",
+ name: "CVE-2018-1234",
+ fingerprint: SecureRandom.hex(20)
+ }.merge(overrides)
+
+ vulnerability_identifiers.create!(attrs)
+ end
+
+ def create_vulnerability_occurrence_identifier(overrides = {})
+ time = Time.now.utc
+
+ attrs = {
+ created_at: time,
+ updated_at: time,
+ occurrence_id: nil,
+ identifier_id: nil
+ }.merge(overrides)
+
+ vulnerability_occurrence_identifiers.create!(attrs)
+ end
+
+ def checksum(value)
+ sha = Digest::SHA256.hexdigest(value)
+ Gitlab::Database::ShaAttribute.new.serialize(sha)
+ end
+end
diff --git a/spec/lib/gitlab/http_spec.rb b/spec/lib/gitlab/http_spec.rb
index 3fc486a8984..402790616b6 100644
--- a/spec/lib/gitlab/http_spec.rb
+++ b/spec/lib/gitlab/http_spec.rb
@@ -104,40 +104,4 @@ RSpec.describe Gitlab::HTTP, feature_category: :shared do
end
end
end
-
- context 'when the FF use_gitlab_http_v2 is disabled' do
- before do
- stub_feature_flags(use_gitlab_http_v2: false)
- end
-
- describe '.get' do
- it 'calls Gitlab::LegacyHTTP.get with default options' do
- expect(Gitlab::LegacyHTTP).to receive(:get).with('/path', {})
-
- described_class.get('/path')
- end
- end
-
- describe '.try_get' do
- it 'calls .get' do
- expect(described_class).to receive(:get).with('/path', {})
-
- described_class.try_get('/path')
- end
-
- it 'returns nil when .get raises an error' do
- expect(described_class).to receive(:get).and_raise(SocketError)
-
- expect(described_class.try_get('/path')).to be_nil
- end
- end
-
- describe '.perform_request' do
- it 'calls Gitlab::LegacyHTTP.perform_request with default options' do
- expect(Gitlab::LegacyHTTP).to receive(:perform_request).with(Net::HTTP::Get, '/path', {})
-
- described_class.perform_request(Net::HTTP::Get, '/path', {})
- end
- end
- end
end
diff --git a/spec/lib/gitlab/legacy_http_spec.rb b/spec/lib/gitlab/legacy_http_spec.rb
deleted file mode 100644
index 07a30b194b6..00000000000
--- a/spec/lib/gitlab/legacy_http_spec.rb
+++ /dev/null
@@ -1,448 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::LegacyHTTP, feature_category: :shared do
- include StubRequests
-
- let(:default_options) { Gitlab::HTTP::DEFAULT_TIMEOUT_OPTIONS }
-
- context 'when allow_local_requests' do
- it 'sends the request to the correct URI' do
- stub_full_request('https://example.org:8080', ip_address: '8.8.8.8').to_return(status: 200)
-
- described_class.get('https://example.org:8080', allow_local_requests: false)
-
- expect(WebMock).to have_requested(:get, 'https://8.8.8.8:8080').once
- end
- end
-
- context 'when not allow_local_requests' do
- it 'sends the request to the correct URI' do
- stub_full_request('https://example.org:8080')
-
- described_class.get('https://example.org:8080', allow_local_requests: true)
-
- expect(WebMock).to have_requested(:get, 'https://8.8.8.9:8080').once
- end
- end
-
- context 'when reading the response is too slow' do
- before_all do
- # Override Net::HTTP to add a delay between sending each response chunk
- mocked_http = Class.new(Net::HTTP) do
- def request(*)
- super do |response|
- response.instance_eval do
- def read_body(*)
- mock_stream = @body.split(' ')
- mock_stream.each do |fragment|
- sleep 0.002.seconds
-
- yield fragment if block_given?
- end
-
- @body
- end
- end
-
- yield response if block_given?
-
- response
- end
- end
- end
-
- @original_net_http = Net.send(:remove_const, :HTTP)
- @webmock_net_http = WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP)
-
- Net.send(:const_set, :HTTP, mocked_http)
- WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_set(:@webMockNetHTTP, mocked_http)
-
- # Reload Gitlab::NetHttpAdapter
- Gitlab.send(:remove_const, :NetHttpAdapter)
- load "#{Rails.root}/lib/gitlab/net_http_adapter.rb"
- end
-
- before do
- stub_const("Gitlab::HTTP::DEFAULT_READ_TOTAL_TIMEOUT", 0.001.seconds)
-
- WebMock.stub_request(:post, /.*/).to_return do
- { body: "chunk-1 chunk-2", status: 200 }
- end
- end
-
- after(:all) do
- Net.send(:remove_const, :HTTP)
- Net.send(:const_set, :HTTP, @original_net_http)
- WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_set(:@webMockNetHTTP, @webmock_net_http)
-
- # Reload Gitlab::NetHttpAdapter
- Gitlab.send(:remove_const, :NetHttpAdapter)
- load "#{Rails.root}/lib/gitlab/net_http_adapter.rb"
- end
-
- let(:options) { {} }
-
- subject(:request_slow_responder) { described_class.post('http://example.org', **options) }
-
- it 'raises an error' do
- expect { request_slow_responder }.to raise_error(
- Gitlab::HTTP::ReadTotalTimeout, /Request timed out after ?([0-9]*[.])?[0-9]+ seconds/)
- end
-
- context 'and timeout option is greater than DEFAULT_READ_TOTAL_TIMEOUT' do
- let(:options) { { timeout: 10.seconds } }
-
- it 'does not raise an error' do
- expect { request_slow_responder }.not_to raise_error
- end
- end
-
- context 'and stream_body option is truthy' do
- let(:options) { { stream_body: true } }
-
- it 'does not raise an error' do
- expect { request_slow_responder }.not_to raise_error
- end
- end
- end
-
- it 'calls a block' do
- WebMock.stub_request(:post, /.*/)
-
- expect { |b| described_class.post('http://example.org', &b) }.to yield_with_args
- end
-
- describe 'allow_local_requests_from_web_hooks_and_services is' do
- before do
- WebMock.stub_request(:get, /.*/).to_return(status: 200, body: 'Success')
- end
-
- context 'disabled' do
- before do
- allow(Gitlab::CurrentSettings).to receive(:allow_local_requests_from_web_hooks_and_services?).and_return(false)
- end
-
- it 'deny requests to localhost' do
- expect { described_class.get('http://localhost:3003') }.to raise_error(Gitlab::HTTP::BlockedUrlError)
- end
-
- it 'deny requests to private network' do
- expect { described_class.get('http://192.168.1.2:3003') }.to raise_error(Gitlab::HTTP::BlockedUrlError)
- end
-
- context 'if allow_local_requests set to true' do
- it 'override the global value and allow requests to localhost or private network' do
- stub_full_request('http://localhost:3003')
-
- expect { described_class.get('http://localhost:3003', allow_local_requests: true) }.not_to raise_error
- end
- end
- end
-
- context 'enabled' do
- before do
- allow(Gitlab::CurrentSettings).to receive(:allow_local_requests_from_web_hooks_and_services?).and_return(true)
- end
-
- it 'allow requests to localhost' do
- stub_full_request('http://localhost:3003')
-
- expect { described_class.get('http://localhost:3003') }.not_to raise_error
- end
-
- it 'allow requests to private network' do
- expect { described_class.get('http://192.168.1.2:3003') }.not_to raise_error
- end
-
- context 'if allow_local_requests set to false' do
- it 'override the global value and ban requests to localhost or private network' do
- expect { described_class.get('http://localhost:3003', allow_local_requests: false) }.to raise_error(
- Gitlab::HTTP::BlockedUrlError)
- end
- end
- end
- end
-
- describe 'handle redirect loops' do
- before do
- stub_full_request("http://example.org", method: :any).to_raise(
- HTTParty::RedirectionTooDeep.new("Redirection Too Deep"))
- end
-
- it 'handles GET requests' do
- expect { described_class.get('http://example.org') }.to raise_error(Gitlab::HTTP::RedirectionTooDeep)
- end
-
- it 'handles POST requests' do
- expect { described_class.post('http://example.org') }.to raise_error(Gitlab::HTTP::RedirectionTooDeep)
- end
-
- it 'handles PUT requests' do
- expect { described_class.put('http://example.org') }.to raise_error(Gitlab::HTTP::RedirectionTooDeep)
- end
-
- it 'handles DELETE requests' do
- expect { described_class.delete('http://example.org') }.to raise_error(Gitlab::HTTP::RedirectionTooDeep)
- end
-
- it 'handles HEAD requests' do
- expect { described_class.head('http://example.org') }.to raise_error(Gitlab::HTTP::RedirectionTooDeep)
- end
- end
-
- describe 'setting default timeouts' do
- before do
- stub_full_request('http://example.org', method: :any)
- end
-
- context 'when no timeouts are set' do
- it 'sets default open and read and write timeouts' do
- expect(described_class).to receive(:httparty_perform_request).with(
- Net::HTTP::Get, 'http://example.org', default_options
- ).and_call_original
-
- described_class.get('http://example.org')
- end
- end
-
- context 'when :timeout is set' do
- it 'does not set any default timeouts' do
- expect(described_class).to receive(:httparty_perform_request).with(
- Net::HTTP::Get, 'http://example.org', { timeout: 1 }
- ).and_call_original
-
- described_class.get('http://example.org', { timeout: 1 })
- end
- end
-
- context 'when :open_timeout is set' do
- it 'only sets default read and write timeout' do
- expect(described_class).to receive(:httparty_perform_request).with(
- Net::HTTP::Get, 'http://example.org', default_options.merge(open_timeout: 1)
- ).and_call_original
-
- described_class.get('http://example.org', open_timeout: 1)
- end
- end
-
- context 'when :read_timeout is set' do
- it 'only sets default open and write timeout' do
- expect(described_class).to receive(:httparty_perform_request).with(
- Net::HTTP::Get, 'http://example.org', default_options.merge(read_timeout: 1)
- ).and_call_original
-
- described_class.get('http://example.org', read_timeout: 1)
- end
- end
-
- context 'when :write_timeout is set' do
- it 'only sets default open and read timeout' do
- expect(described_class).to receive(:httparty_perform_request).with(
- Net::HTTP::Put, 'http://example.org', default_options.merge(write_timeout: 1)
- ).and_call_original
-
- described_class.put('http://example.org', write_timeout: 1)
- end
- end
- end
-
- describe '.try_get' do
- let(:path) { 'http://example.org' }
-
- let(:extra_log_info_proc) do
- proc do |error, url, options|
- { klass: error.class, url: url, options: options }
- end
- end
-
- let(:request_options) do
- default_options.merge({
- verify: false,
- basic_auth: { username: 'user', password: 'pass' }
- })
- end
-
- Gitlab::HTTP::HTTP_ERRORS.each do |exception_class|
- context "with #{exception_class}" do
- let(:klass) { exception_class }
-
- context 'with path' do
- before do
- expect(described_class).to receive(:httparty_perform_request)
- .with(Net::HTTP::Get, path, default_options)
- .and_raise(klass)
- end
-
- it 'handles requests without extra_log_info' do
- expect(Gitlab::ErrorTracking)
- .to receive(:log_exception)
- .with(instance_of(klass), {})
-
- expect(described_class.try_get(path)).to be_nil
- end
-
- it 'handles requests with extra_log_info as hash' do
- expect(Gitlab::ErrorTracking)
- .to receive(:log_exception)
- .with(instance_of(klass), { a: :b })
-
- expect(described_class.try_get(path, extra_log_info: { a: :b })).to be_nil
- end
-
- it 'handles requests with extra_log_info as proc' do
- expect(Gitlab::ErrorTracking)
- .to receive(:log_exception)
- .with(instance_of(klass), { url: path, klass: klass, options: {} })
-
- expect(described_class.try_get(path, extra_log_info: extra_log_info_proc)).to be_nil
- end
- end
-
- context 'with path and options' do
- before do
- expect(described_class).to receive(:httparty_perform_request)
- .with(Net::HTTP::Get, path, request_options)
- .and_raise(klass)
- end
-
- it 'handles requests without extra_log_info' do
- expect(Gitlab::ErrorTracking)
- .to receive(:log_exception)
- .with(instance_of(klass), {})
-
- expect(described_class.try_get(path, request_options)).to be_nil
- end
-
- it 'handles requests with extra_log_info as hash' do
- expect(Gitlab::ErrorTracking)
- .to receive(:log_exception)
- .with(instance_of(klass), { a: :b })
-
- expect(described_class.try_get(path, **request_options, extra_log_info: { a: :b })).to be_nil
- end
-
- it 'handles requests with extra_log_info as proc' do
- expect(Gitlab::ErrorTracking)
- .to receive(:log_exception)
- .with(instance_of(klass), { klass: klass, url: path, options: request_options })
-
- expect(described_class.try_get(path, **request_options, extra_log_info: extra_log_info_proc)).to be_nil
- end
- end
-
- context 'with path, options, and block' do
- let(:block) do
- proc {}
- end
-
- before do
- expect(described_class).to receive(:httparty_perform_request)
- .with(Net::HTTP::Get, path, request_options, &block)
- .and_raise(klass)
- end
-
- it 'handles requests without extra_log_info' do
- expect(Gitlab::ErrorTracking)
- .to receive(:log_exception)
- .with(instance_of(klass), {})
-
- expect(described_class.try_get(path, request_options, &block)).to be_nil
- end
-
- it 'handles requests with extra_log_info as hash' do
- expect(Gitlab::ErrorTracking)
- .to receive(:log_exception)
- .with(instance_of(klass), { a: :b })
-
- expect(described_class.try_get(path, **request_options, extra_log_info: { a: :b }, &block)).to be_nil
- end
-
- it 'handles requests with extra_log_info as proc' do
- expect(Gitlab::ErrorTracking)
- .to receive(:log_exception)
- .with(instance_of(klass), { klass: klass, url: path, options: request_options })
-
- expect(
- described_class.try_get(path, **request_options, extra_log_info: extra_log_info_proc, &block)
- ).to be_nil
- end
- end
- end
- end
- end
-
- describe 'silent mode', feature_category: :geo_replication do
- before do
- stub_full_request("http://example.org", method: :any)
- stub_application_setting(silent_mode_enabled: silent_mode)
- end
-
- context 'when silent mode is enabled' do
- let(:silent_mode) { true }
-
- it 'allows GET requests' do
- expect { described_class.get('http://example.org') }.not_to raise_error
- end
-
- it 'allows HEAD requests' do
- expect { described_class.head('http://example.org') }.not_to raise_error
- end
-
- it 'allows OPTIONS requests' do
- expect { described_class.options('http://example.org') }.not_to raise_error
- end
-
- it 'blocks POST requests' do
- expect { described_class.post('http://example.org') }.to raise_error(Gitlab::HTTP::SilentModeBlockedError)
- end
-
- it 'blocks PUT requests' do
- expect { described_class.put('http://example.org') }.to raise_error(Gitlab::HTTP::SilentModeBlockedError)
- end
-
- it 'blocks DELETE requests' do
- expect { described_class.delete('http://example.org') }.to raise_error(Gitlab::HTTP::SilentModeBlockedError)
- end
-
- it 'logs blocked requests' do
- expect(::Gitlab::AppJsonLogger).to receive(:info).with(
- message: "Outbound HTTP request blocked",
- outbound_http_request_method: 'Net::HTTP::Post',
- silent_mode_enabled: true
- )
-
- expect { described_class.post('http://example.org') }.to raise_error(Gitlab::HTTP::SilentModeBlockedError)
- end
- end
-
- context 'when silent mode is disabled' do
- let(:silent_mode) { false }
-
- it 'allows GET requests' do
- expect { described_class.get('http://example.org') }.not_to raise_error
- end
-
- it 'allows HEAD requests' do
- expect { described_class.head('http://example.org') }.not_to raise_error
- end
-
- it 'allows OPTIONS requests' do
- expect { described_class.options('http://example.org') }.not_to raise_error
- end
-
- it 'blocks POST requests' do
- expect { described_class.post('http://example.org') }.not_to raise_error
- end
-
- it 'blocks PUT requests' do
- expect { described_class.put('http://example.org') }.not_to raise_error
- end
-
- it 'blocks DELETE requests' do
- expect { described_class.delete('http://example.org') }.not_to raise_error
- end
- end
- end
-end
diff --git a/spec/migrations/20230807083334_add_linked_items_work_item_widget_spec.rb b/spec/migrations/20230807083334_add_linked_items_work_item_widget_spec.rb
index cd6da15403f..7b759182a21 100644
--- a/spec/migrations/20230807083334_add_linked_items_work_item_widget_spec.rb
+++ b/spec/migrations/20230807083334_add_linked_items_work_item_widget_spec.rb
@@ -4,7 +4,5 @@ require 'spec_helper'
require_migration!
RSpec.describe AddLinkedItemsWorkItemWidget, :migration, feature_category: :portfolio_management do
- it_behaves_like 'migration that adds widget to work items definitions', widget_name: 'Linked items' do
- let(:work_item_type_count) { 8 }
- end
+ it_behaves_like 'migration that adds widget to work items definitions', widget_name: 'Linked items'
end
diff --git a/spec/migrations/20231211154654_add_work_items_rolledup_dates_widget_spec.rb b/spec/migrations/20231211154654_add_work_items_rolledup_dates_widget_spec.rb
new file mode 100644
index 00000000000..2c3d20dcc56
--- /dev/null
+++ b/spec/migrations/20231211154654_add_work_items_rolledup_dates_widget_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddWorkItemsRolledupDatesWidget, :migration, feature_category: :team_planning do
+ it_behaves_like 'migration that adds widget to work items definitions',
+ widget_name: 'Rolledup dates'
+end
diff --git a/spec/migrations/20231214111617_queue_backfill_owasp_top_ten_of_vulnerability_reads_spec.rb b/spec/migrations/20231214111617_queue_backfill_owasp_top_ten_of_vulnerability_reads_spec.rb
new file mode 100644
index 00000000000..9ee11715da4
--- /dev/null
+++ b/spec/migrations/20231214111617_queue_backfill_owasp_top_ten_of_vulnerability_reads_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillOwaspTopTenOfVulnerabilityReads, feature_category: :vulnerability_management do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :vulnerability_reads,
+ column_name: :vulnerability_id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 1e70653c628..9b2c14314df 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -102,65 +102,18 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { is_expected.not_to allow_value(nil).for(:protected_paths_for_get_request) }
it { is_expected.to allow_value([]).for(:protected_paths_for_get_request) }
- it { is_expected.to allow_value(3).for(:push_event_hooks_limit) }
- it { is_expected.not_to allow_value('three').for(:push_event_hooks_limit) }
- it { is_expected.not_to allow_value(nil).for(:push_event_hooks_limit) }
-
- it { is_expected.to allow_value(3).for(:push_event_activities_limit) }
- it { is_expected.not_to allow_value('three').for(:push_event_activities_limit) }
- it { is_expected.not_to allow_value(nil).for(:push_event_activities_limit) }
-
- it { is_expected.to validate_numericality_of(:container_registry_delete_tags_service_timeout).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.to validate_numericality_of(:container_registry_cleanup_tags_service_max_list_size).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.to validate_numericality_of(:container_registry_data_repair_detail_worker_max_concurrency).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.to validate_numericality_of(:container_registry_expiration_policies_worker_capacity).only_integer.is_greater_than_or_equal_to(0) }
it { is_expected.to validate_inclusion_of(:container_registry_expiration_policies_caching).in_array([true, false]) }
- it { is_expected.to validate_numericality_of(:container_registry_import_max_tags_count).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.to validate_numericality_of(:container_registry_import_max_retries).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.to validate_numericality_of(:container_registry_import_start_max_retries).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.to validate_numericality_of(:container_registry_import_max_step_duration).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.to validate_numericality_of(:container_registry_pre_import_timeout).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.to validate_numericality_of(:container_registry_import_timeout).only_integer.is_greater_than_or_equal_to(0) }
it { is_expected.to validate_numericality_of(:container_registry_pre_import_tags_rate).is_greater_than_or_equal_to(0) }
- it { is_expected.not_to allow_value(nil).for(:container_registry_data_repair_detail_worker_max_concurrency) }
- it { is_expected.not_to allow_value(nil).for(:container_registry_import_max_tags_count) }
- it { is_expected.not_to allow_value(nil).for(:container_registry_import_max_retries) }
- it { is_expected.not_to allow_value(nil).for(:container_registry_import_start_max_retries) }
- it { is_expected.not_to allow_value(nil).for(:container_registry_import_max_step_duration) }
- it { is_expected.not_to allow_value(nil).for(:container_registry_pre_import_timeout) }
- it { is_expected.not_to allow_value(nil).for(:container_registry_import_timeout) }
it { is_expected.not_to allow_value(nil).for(:container_registry_pre_import_tags_rate) }
it { is_expected.to allow_value(1.5).for(:container_registry_pre_import_tags_rate) }
it { is_expected.to validate_presence_of(:container_registry_import_target_plan) }
it { is_expected.to validate_presence_of(:container_registry_import_created_before) }
- it { is_expected.to validate_numericality_of(:decompress_archive_file_timeout).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.not_to allow_value(nil).for(:decompress_archive_file_timeout) }
-
- it { is_expected.to validate_numericality_of(:dependency_proxy_ttl_group_policy_worker_capacity).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.not_to allow_value(nil).for(:dependency_proxy_ttl_group_policy_worker_capacity) }
-
- it { is_expected.to validate_numericality_of(:packages_cleanup_package_file_worker_capacity).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.not_to allow_value(nil).for(:packages_cleanup_package_file_worker_capacity) }
-
- it { is_expected.to validate_numericality_of(:package_registry_cleanup_policies_worker_capacity).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.not_to allow_value(nil).for(:package_registry_cleanup_policies_worker_capacity) }
-
- it { is_expected.to validate_numericality_of(:snippet_size_limit).only_integer.is_greater_than(0) }
it { is_expected.to validate_numericality_of(:wiki_page_max_content_bytes).only_integer.is_greater_than_or_equal_to(1024) }
it { is_expected.to validate_inclusion_of(:wiki_asciidoc_allow_uri_includes).in_array([true, false]) }
- it { is_expected.to validate_presence_of(:max_artifacts_size) }
- it { is_expected.to validate_numericality_of(:max_artifacts_size).only_integer.is_greater_than(0) }
- it { is_expected.to validate_presence_of(:max_yaml_size_bytes) }
- it { is_expected.to validate_numericality_of(:max_yaml_size_bytes).only_integer.is_greater_than(0) }
- it { is_expected.to validate_presence_of(:max_yaml_depth) }
- it { is_expected.to validate_numericality_of(:max_yaml_depth).only_integer.is_greater_than(0) }
it { is_expected.to validate_presence_of(:max_pages_size) }
- it { is_expected.to validate_presence_of(:max_pages_custom_domains_per_project) }
- it { is_expected.to validate_presence_of(:max_terraform_state_size_bytes) }
- it { is_expected.to validate_numericality_of(:max_terraform_state_size_bytes).only_integer.is_greater_than_or_equal_to(0) }
it { is_expected.to validate_inclusion_of(:user_defaults_to_private_profile).in_array([true, false]) }
@@ -175,40 +128,12 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
.is_less_than(::Gitlab::Pages::MAX_SIZE / 1.megabyte)
end
- it 'ensures max_pages_custom_domains_per_project is an integer greater than 0 (or equal to 0 to indicate unlimited/maximum)' do
- is_expected
- .to validate_numericality_of(:max_pages_custom_domains_per_project)
- .only_integer
- .is_greater_than_or_equal_to(0)
- end
-
- it { is_expected.to validate_presence_of(:jobs_per_stage_page_size) }
- it { is_expected.to validate_numericality_of(:jobs_per_stage_page_size).only_integer.is_greater_than_or_equal_to(0) }
-
it { is_expected.not_to allow_value(7).for(:minimum_password_length) }
it { is_expected.not_to allow_value(129).for(:minimum_password_length) }
it { is_expected.not_to allow_value(nil).for(:minimum_password_length) }
it { is_expected.not_to allow_value('abc').for(:minimum_password_length) }
it { is_expected.to allow_value(10).for(:minimum_password_length) }
- it { is_expected.to allow_value(300).for(:issues_create_limit) }
- it { is_expected.not_to allow_value('three').for(:issues_create_limit) }
- it { is_expected.not_to allow_value(nil).for(:issues_create_limit) }
- it { is_expected.not_to allow_value(10.5).for(:issues_create_limit) }
- it { is_expected.not_to allow_value(-1).for(:issues_create_limit) }
-
- it { is_expected.to allow_value(0).for(:raw_blob_request_limit) }
- it { is_expected.not_to allow_value('abc').for(:raw_blob_request_limit) }
- it { is_expected.not_to allow_value(nil).for(:raw_blob_request_limit) }
- it { is_expected.not_to allow_value(10.5).for(:raw_blob_request_limit) }
- it { is_expected.not_to allow_value(-1).for(:raw_blob_request_limit) }
-
- it { is_expected.to allow_value(0).for(:pipeline_limit_per_project_user_sha) }
- it { is_expected.not_to allow_value('abc').for(:pipeline_limit_per_project_user_sha) }
- it { is_expected.not_to allow_value(nil).for(:pipeline_limit_per_project_user_sha) }
- it { is_expected.not_to allow_value(10.5).for(:pipeline_limit_per_project_user_sha) }
- it { is_expected.not_to allow_value(-1).for(:pipeline_limit_per_project_user_sha) }
-
it { is_expected.not_to allow_value(false).for(:hashed_storage_enabled) }
it { is_expected.to allow_value('default' => 0).for(:repository_storages_weighted) }
@@ -220,15 +145,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { is_expected.not_to allow_value('default' => 101).for(:repository_storages_weighted).with_message("value for 'default' must be between 0 and 100") }
it { is_expected.not_to allow_value('default' => 100, shouldntexist: 50).for(:repository_storages_weighted).with_message("can't include: shouldntexist") }
- %i[notes_create_limit search_rate_limit search_rate_limit_unauthenticated users_get_by_id_limit
- projects_api_rate_limit_unauthenticated gitlab_shell_operation_limit].each do |setting|
- it { is_expected.to allow_value(400).for(setting) }
- it { is_expected.not_to allow_value('two').for(setting) }
- it { is_expected.not_to allow_value(nil).for(setting) }
- it { is_expected.not_to allow_value(5.5).for(setting) }
- it { is_expected.not_to allow_value(-2).for(setting) }
- end
-
def many_usernames(num = 100)
Array.new(num) { |i| "username#{i}" }
end
@@ -281,23 +197,131 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { is_expected.to validate_inclusion_of(:silent_mode_enabled).in_array([true, false]) }
- it { is_expected.to allow_value(0).for(:ci_max_includes) }
- it { is_expected.to allow_value(200).for(:ci_max_includes) }
- it { is_expected.not_to allow_value('abc').for(:ci_max_includes) }
- it { is_expected.not_to allow_value(nil).for(:ci_max_includes) }
- it { is_expected.not_to allow_value(10.5).for(:ci_max_includes) }
- it { is_expected.not_to allow_value(-1).for(:ci_max_includes) }
+ context 'for non-null integer attributes starting from 0' do
+ where(:attribute) do
+ %i[
+ bulk_import_max_download_file_size
+ ci_max_includes
+ ci_max_total_yaml_size_bytes
+ container_registry_cleanup_tags_service_max_list_size
+ container_registry_data_repair_detail_worker_max_concurrency
+ container_registry_delete_tags_service_timeout
+ container_registry_expiration_policies_worker_capacity
+ container_registry_import_max_retries
+ container_registry_import_max_step_duration
+ container_registry_import_max_tags_count
+ container_registry_import_start_max_retries
+ container_registry_import_timeout
+ container_registry_pre_import_timeout
+ decompress_archive_file_timeout
+ dependency_proxy_ttl_group_policy_worker_capacity
+ gitlab_shell_operation_limit
+ inactive_projects_min_size_mb
+ issues_create_limit
+ jobs_per_stage_page_size
+ max_decompressed_archive_size
+ max_export_size
+ max_import_remote_file_size
+ max_import_size
+ max_pages_custom_domains_per_project
+ max_terraform_state_size_bytes
+ package_registry_cleanup_policies_worker_capacity
+ packages_cleanup_package_file_worker_capacity
+ pipeline_limit_per_project_user_sha
+ projects_api_rate_limit_unauthenticated
+ raw_blob_request_limit
+ search_rate_limit
+ search_rate_limit_unauthenticated
+ session_expire_delay
+ sidekiq_job_limiter_compression_threshold_bytes
+ sidekiq_job_limiter_limit_bytes
+ terminal_max_session_time
+ users_get_by_id_limit
+ notes_create_limit
+ ]
+ end
+
+ with_them do
+ it { is_expected.to validate_numericality_of(attribute).only_integer.is_greater_than_or_equal_to(0) }
+ it { is_expected.not_to allow_value(nil).for(attribute) }
+ end
+ end
- it { is_expected.to allow_value(0).for(:ci_max_total_yaml_size_bytes) }
- it { is_expected.to allow_value(200).for(:ci_max_total_yaml_size_bytes) }
- it { is_expected.not_to allow_value('abc').for(:ci_max_total_yaml_size_bytes) }
- it { is_expected.not_to allow_value(nil).for(:ci_max_total_yaml_size_bytes) }
- it { is_expected.not_to allow_value(10.5).for(:ci_max_total_yaml_size_bytes) }
- it { is_expected.not_to allow_value(-1).for(:ci_max_total_yaml_size_bytes) }
+ context 'for non-null numerical attributes starting from 0' do
+ where(:attribute) do
+ %i[
+ push_event_hooks_limit
+ push_event_activities_limit
+ ]
+ end
- it { is_expected.to validate_inclusion_of(:remember_me_enabled).in_array([true, false]) }
+ with_them do
+ it { is_expected.to validate_numericality_of(attribute).is_greater_than_or_equal_to(0) }
+ it { is_expected.not_to allow_value(nil).for(attribute) }
+ end
+ end
+
+ context 'for non-null integer attributes starting from 1' do
+ where(:attribute) do
+ %i[
+ max_attachment_size
+ max_artifacts_size
+ container_registry_token_expire_delay
+ housekeeping_optimize_repository_period
+ bulk_import_concurrent_pipeline_batch_limit
+ snippet_size_limit
+ max_yaml_size_bytes
+ max_yaml_depth
+ namespace_aggregation_schedule_lease_duration_in_seconds
+ throttle_unauthenticated_api_requests_per_period
+ throttle_unauthenticated_api_period_in_seconds
+ throttle_unauthenticated_requests_per_period
+ throttle_unauthenticated_period_in_seconds
+ throttle_unauthenticated_packages_api_requests_per_period
+ throttle_unauthenticated_packages_api_period_in_seconds
+ throttle_unauthenticated_files_api_requests_per_period
+ throttle_unauthenticated_files_api_period_in_seconds
+ throttle_unauthenticated_deprecated_api_requests_per_period
+ throttle_unauthenticated_deprecated_api_period_in_seconds
+ throttle_authenticated_api_requests_per_period
+ throttle_authenticated_api_period_in_seconds
+ throttle_authenticated_git_lfs_requests_per_period
+ throttle_authenticated_git_lfs_period_in_seconds
+ throttle_authenticated_web_requests_per_period
+ throttle_authenticated_web_period_in_seconds
+ throttle_authenticated_packages_api_requests_per_period
+ throttle_authenticated_packages_api_period_in_seconds
+ throttle_authenticated_files_api_requests_per_period
+ throttle_authenticated_files_api_period_in_seconds
+ throttle_authenticated_deprecated_api_requests_per_period
+ throttle_authenticated_deprecated_api_period_in_seconds
+ throttle_protected_paths_requests_per_period
+ throttle_protected_paths_period_in_seconds
+ project_jobs_api_rate_limit
+ ]
+ end
- it { is_expected.to validate_numericality_of(:namespace_aggregation_schedule_lease_duration_in_seconds).only_integer.is_greater_than(0) }
+ with_them do
+ it { is_expected.to validate_numericality_of(attribute).only_integer.is_greater_than(0) }
+ it { is_expected.not_to allow_value(nil).for(attribute) }
+ end
+ end
+
+ context 'for null integer attributes starting from 1' do
+ where(:attribute) do
+ %i[
+ failed_login_attempts_unlock_period_in_minutes
+ external_pipeline_validation_service_timeout
+ max_login_attempts
+ ]
+ end
+
+ with_them do
+ it { is_expected.to validate_numericality_of(attribute).only_integer.is_greater_than(0).allow_nil }
+ end
+ end
+
+ it { is_expected.to validate_inclusion_of(:remember_me_enabled).in_array([true, false]) }
it { is_expected.to validate_inclusion_of(:instance_level_code_suggestions_enabled).in_array([true, false]) }
@@ -587,66 +611,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
end
end
- it { is_expected.to validate_presence_of(:max_attachment_size) }
-
- specify do
- is_expected.to validate_numericality_of(:max_attachment_size)
- .only_integer
- .is_greater_than(0)
- end
-
- it { is_expected.to validate_presence_of(:max_export_size) }
-
- specify do
- is_expected.to validate_numericality_of(:max_export_size)
- .only_integer
- .is_greater_than_or_equal_to(0)
- end
-
- it { is_expected.to validate_presence_of(:max_import_size) }
-
- specify do
- is_expected.to validate_numericality_of(:max_import_size)
- .only_integer
- .is_greater_than_or_equal_to(0)
- end
-
- it { is_expected.to validate_presence_of(:max_import_remote_file_size) }
-
- specify do
- is_expected.to validate_numericality_of(:max_import_remote_file_size)
- .only_integer
- .is_greater_than_or_equal_to(0)
- end
-
- it { is_expected.to validate_presence_of(:bulk_import_max_download_file_size) }
-
- specify do
- is_expected.to validate_numericality_of(:bulk_import_max_download_file_size)
- .only_integer
- .is_greater_than_or_equal_to(0)
- end
-
- it { is_expected.to validate_presence_of(:max_decompressed_archive_size) }
-
- specify do
- is_expected.to validate_numericality_of(:max_decompressed_archive_size)
- .only_integer
- .is_greater_than_or_equal_to(0)
- end
-
- specify do
- is_expected.to validate_numericality_of(:failed_login_attempts_unlock_period_in_minutes)
- .only_integer
- .is_greater_than(0)
- end
-
- specify do
- is_expected.to validate_numericality_of(:max_login_attempts)
- .only_integer
- .is_greater_than(0)
- end
-
specify do
is_expected.to validate_numericality_of(:local_markdown_version)
.only_integer
@@ -880,10 +844,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
end
end
- context 'housekeeping settings' do
- it { is_expected.not_to allow_value(0).for(:housekeeping_optimize_repository_period) }
- end
-
context 'gitaly timeouts' do
it "validates that the default_timeout is lower than the max_request_duration" do
is_expected.to validate_numericality_of(:gitaly_timeout_default)
@@ -1003,8 +963,8 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it 'the credentials are valid when the private key can be read and matches the certificate' do
tls_attributes = [:external_auth_client_key_pass,
- :external_auth_client_key,
- :external_auth_client_cert]
+ :external_auth_client_key,
+ :external_auth_client_cert]
setting.external_auth_client_key = File.read('spec/fixtures/passphrase_x509_certificate_pk.key')
setting.external_auth_client_key_pass = '5iveL!fe'
@@ -1216,43 +1176,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
end
end
- context 'throttle_* settings' do
- where(:throttle_setting) do
- %i[
- throttle_unauthenticated_api_requests_per_period
- throttle_unauthenticated_api_period_in_seconds
- throttle_unauthenticated_requests_per_period
- throttle_unauthenticated_period_in_seconds
- throttle_authenticated_api_requests_per_period
- throttle_authenticated_api_period_in_seconds
- throttle_authenticated_web_requests_per_period
- throttle_authenticated_web_period_in_seconds
- throttle_unauthenticated_packages_api_requests_per_period
- throttle_unauthenticated_packages_api_period_in_seconds
- throttle_authenticated_packages_api_requests_per_period
- throttle_authenticated_packages_api_period_in_seconds
- throttle_unauthenticated_files_api_requests_per_period
- throttle_unauthenticated_files_api_period_in_seconds
- throttle_authenticated_files_api_requests_per_period
- throttle_authenticated_files_api_period_in_seconds
- throttle_unauthenticated_deprecated_api_requests_per_period
- throttle_unauthenticated_deprecated_api_period_in_seconds
- throttle_authenticated_deprecated_api_requests_per_period
- throttle_authenticated_deprecated_api_period_in_seconds
- throttle_authenticated_git_lfs_requests_per_period
- throttle_authenticated_git_lfs_period_in_seconds
- ]
- end
-
- with_them do
- it { is_expected.to allow_value(3).for(throttle_setting) }
- it { is_expected.not_to allow_value(-3).for(throttle_setting) }
- it { is_expected.not_to allow_value(0).for(throttle_setting) }
- it { is_expected.not_to allow_value('three').for(throttle_setting) }
- it { is_expected.not_to allow_value(nil).for(throttle_setting) }
- end
- end
-
context 'sidekiq job limiter settings' do
it 'has the right defaults', :aggregate_failures do
expect(setting.sidekiq_job_limiter_mode).to eq('compress')
@@ -1263,8 +1186,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
end
it { is_expected.to allow_value('track').for(:sidekiq_job_limiter_mode) }
- it { is_expected.to validate_numericality_of(:sidekiq_job_limiter_compression_threshold_bytes).only_integer.is_greater_than_or_equal_to(0) }
- it { is_expected.to validate_numericality_of(:sidekiq_job_limiter_limit_bytes).only_integer.is_greater_than_or_equal_to(0) }
end
context 'prometheus settings' do
@@ -1353,13 +1274,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
.with_message("must be a value between 0 and 1")
end
end
-
- describe 'bulk_import_concurrent_pipeline_batch_limit' do
- it do
- is_expected.to validate_numericality_of(:bulk_import_concurrent_pipeline_batch_limit)
- .is_greater_than(0)
- end
- end
end
context 'restrict creating duplicates' do
@@ -1715,8 +1629,6 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { is_expected.to validate_numericality_of(:inactive_projects_delete_after_months).is_greater_than(0) }
- it { is_expected.to validate_numericality_of(:inactive_projects_min_size_mb).is_greater_than_or_equal_to(0) }
-
it "deletes the redis key used for tracking inactive projects deletion warning emails when setting is updated",
:clean_gitlab_redis_shared_state do
Gitlab::Redis::SharedState.with do |redis|
diff --git a/spec/models/project_authorizations/changes_spec.rb b/spec/models/project_authorizations/changes_spec.rb
index 714144841fb..9c2686e82f6 100644
--- a/spec/models/project_authorizations/changes_spec.rb
+++ b/spec/models/project_authorizations/changes_spec.rb
@@ -74,22 +74,6 @@ RSpec.describe ProjectAuthorizations::Changes, feature_category: :groups_and_pro
apply_project_authorization_changes
end
-
- context 'when feature flag "user_approval_rules_removal" is disabled' do
- before do
- stub_feature_flags(user_approval_rules_removal: false)
- end
-
- it 'does not publish a AuthorizationsRemovedEvent event' do
- expect(::Gitlab::EventStore).not_to(
- receive(:publish_group).with(
- array_including(an_instance_of(::ProjectAuthorizations::AuthorizationsRemovedEvent))
- )
- )
-
- apply_project_authorization_changes
- end
- end
end
shared_examples_for 'publishes AuthorizationsAddedEvent' do
diff --git a/spec/models/work_items/widget_definition_spec.rb b/spec/models/work_items/widget_definition_spec.rb
index b79348986e7..1540ee57ff4 100644
--- a/spec/models/work_items/widget_definition_spec.rb
+++ b/spec/models/work_items/widget_definition_spec.rb
@@ -27,7 +27,8 @@ RSpec.describe WorkItems::WidgetDefinition, feature_category: :team_planning do
::WorkItems::Widgets::Progress,
::WorkItems::Widgets::RequirementLegacy,
::WorkItems::Widgets::TestReports,
- ::WorkItems::Widgets::Color
+ ::WorkItems::Widgets::Color,
+ ::WorkItems::Widgets::RolledupDates
]
end
diff --git a/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb b/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb
index 37c338a7712..aa5c7ffe7be 100644
--- a/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb
+++ b/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb
@@ -3,7 +3,7 @@
RSpec.shared_examples 'migration that adds widget to work items definitions' do |widget_name:|
let(:migration) { described_class.new }
let(:work_item_definitions) { table(:work_item_widget_definitions) }
- let(:work_item_type_count) { 7 }
+ let(:work_item_type_count) { described_class::WORK_ITEM_TYPES.size }
describe '#up' do
it "creates widget definition in all types" do
@@ -14,11 +14,13 @@ RSpec.shared_examples 'migration that adds widget to work items definitions' do
end
it 'logs a warning if the type is missing' do
+ type_name = described_class::WORK_ITEM_TYPES.first
+
allow(described_class::WorkItemType).to receive(:find_by_name_and_namespace_id).and_call_original
allow(described_class::WorkItemType).to receive(:find_by_name_and_namespace_id)
- .with('Issue', nil).and_return(nil)
+ .with(type_name, nil).and_return(nil)
- expect(Gitlab::AppLogger).to receive(:warn).with('type Issue is missing, not adding widget')
+ expect(Gitlab::AppLogger).to receive(:warn).with("type #{type_name} is missing, not adding widget")
migrate!
end
end