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:
authorGitLab Bot <gitlab-bot@gitlab.com>2024-01-11 03:08:09 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2024-01-11 03:08:09 +0300
commita18ca85c05efe431c3a1faf6c9f4257638b73493 (patch)
treeab088ce168ac378f8224c821f33f500b28369df5
parent853e0ceb61507ce55521776c84bc77b4e802c66e (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.eslintrc.yml2
-rw-r--r--.gitlab/ci/reports.gitlab-ci.yml19
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml13
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.checksum8
-rw-r--r--Gemfile.lock14
-rw-r--r--app/controllers/groups_controller.rb3
-rw-r--r--app/controllers/projects/gcp/artifact_registry/docker_images_controller.rb2
-rw-r--r--app/models/namespace.rb3
-rw-r--r--app/services/google_cloud_platform/artifact_registry/list_docker_images_service.rb46
-rw-r--r--app/services/groups/update_service.rb24
-rw-r--r--app/services/integrations/google_cloud_platform/artifact_registry/list_docker_images_service.rb48
-rw-r--r--app/views/admin/application_settings/appearances/_form.html.haml105
-rw-r--r--app/views/groups/settings/_permissions.html.haml8
-rw-r--r--config/feature_flags/beta/group_hierarchy_optimization.yml9
-rw-r--r--data/deprecations/16-8-deprecate-license-list.yml16
-rw-r--r--doc/api/graphql/reference/index.md12
-rw-r--r--doc/update/deprecations.md19
-rw-r--r--doc/user/application_security/policies/scan-execution-policies.md3
-rw-r--r--doc/user/packages/maven_repository/index.md29
-rw-r--r--doc/user/packages/workflows/build_packages.md45
-rw-r--r--doc/user/project/import/github.md17
-rw-r--r--locale/gitlab.pot80
-rw-r--r--package.json2
-rw-r--r--spec/features/groups/settings/user_enables_namespace_hierarchy_cache_spec.rb58
-rw-r--r--spec/requests/projects/gcp/artifact_registry/docker_images_controller_spec.rb4
-rw-r--r--spec/services/google_cloud_platform/artifact_registry/list_docker_images_service_spec.rb (renamed from spec/services/integrations/google_cloud_platform/artifact_registry/list_docker_images_service_spec.rb)2
-rw-r--r--spec/services/groups/update_service_spec.rb54
-rw-r--r--yarn.lock126
29 files changed, 594 insertions, 181 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml
index 595f4fc7b9a..1c6b5a939d2 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -144,6 +144,8 @@ rules:
- error
- escape:
methods: 'sanitize'
+ # This rule will be enabled later.
+ unicorn/no-array-callback-reference: off
overrides:
- files:
- '{,ee/,jh/}spec/frontend*/**/*'
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml
index db4de65feea..c9432394e1c 100644
--- a/.gitlab/ci/reports.gitlab-ci.yml
+++ b/.gitlab/ci/reports.gitlab-ci.yml
@@ -138,3 +138,22 @@ xray_scan:
# this line saves xray_scan job output in raw form for inspection for testing purposes
paths:
- "$OUTPUT_DIR/*/*.json"
+
+pajamas_adoption:
+ extends:
+ - .default-retry
+ - .reports:rules:pajamas_adoption
+ allow_failure: true
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/frontend/pajamas-adoption-scanner:latest
+ stage: lint
+ needs: []
+ script:
+ - EE_APP=$(test -d ee/app/ && echo 'ee/app/' || true)
+ - scan_gitlab_code_quality app/ $EE_APP
+ artifacts:
+ name: pajamas-adoption
+ paths:
+ - gl-code-quality-report.json
+ - pas-findings.json
+ reports:
+ codequality: gl-code-quality-report.json
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 4ced188b932..28d077a3d5d 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -2674,6 +2674,19 @@
when: manual
- when: never
+.reports:rules:pajamas_adoption:
+ rules:
+ - <<: *if-not-ee
+ when: never
+ - <<: *if-jh
+ when: never
+ - <<: *if-merge-request-labels-pipeline-expedite
+ when: never
+ - <<: *if-merge-request
+ changes:
+ - '{,ee/}app/**/*.{js,vue,rb,haml}'
+ - <<: *if-default-refs
+
################
# Review rules #
################
diff --git a/Gemfile b/Gemfile
index 74b8291f541..e274a5c9e27 100644
--- a/Gemfile
+++ b/Gemfile
@@ -203,9 +203,9 @@ gem 'seed-fu', '~> 2.3.7' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'elasticsearch-model', '~> 7.2' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'elasticsearch-rails', '~> 7.2', require: 'elasticsearch/rails/instrumentation' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'elasticsearch-api', '7.13.3' # rubocop:todo Gemfile/MissingFeatureCategory
-gem 'aws-sdk-core', '~> 3.190.0' # rubocop:todo Gemfile/MissingFeatureCategory
+gem 'aws-sdk-core', '~> 3.190.1' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'aws-sdk-cloudformation', '~> 1' # rubocop:todo Gemfile/MissingFeatureCategory
-gem 'aws-sdk-s3', '~> 1.141.0' # rubocop:todo Gemfile/MissingFeatureCategory
+gem 'aws-sdk-s3', '~> 1.142.0' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'faraday_middleware-aws-sigv4', '~>0.3.0' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'typhoeus', '~> 1.4.0' # Used with Elasticsearch to support http keep-alive connections # rubocop:todo Gemfile/MissingFeatureCategory
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 1e0c8b60a46..10ffeac0d26 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -35,11 +35,11 @@
{"name":"awesome_print","version":"1.9.2","platform":"ruby","checksum":"e99b32b704acff16d768b3468680793ced40bfdc4537eb07e06a4be11133786e"},
{"name":"awrence","version":"1.2.1","platform":"ruby","checksum":"dd1d214c12a91f449d1ef81d7ee3babc2816944e450752e7522c65521872483e"},
{"name":"aws-eventstream","version":"1.3.0","platform":"ruby","checksum":"f1434cc03ab2248756eb02cfa45e900e59a061d7fbdc4a9fd82a5dd23d796d3f"},
-{"name":"aws-partitions","version":"1.761.0","platform":"ruby","checksum":"291e444e1edfc92c5521a6dbdd1236ccc3f122b3520163b2be6ec5b6ef350ef2"},
+{"name":"aws-partitions","version":"1.877.0","platform":"ruby","checksum":"9552ed7bbd3700ed1eeb0121c160ceaf64fa5dbaff5a1ff5fe6fd8481ecd9cfd"},
{"name":"aws-sdk-cloudformation","version":"1.41.0","platform":"ruby","checksum":"31e47539719734413671edf9b1a31f8673fbf9688549f50c41affabbcb1c6b26"},
-{"name":"aws-sdk-core","version":"3.190.0","platform":"ruby","checksum":"a3455fb3fc1691dd5331282ff16cb0b2ef136a5b63ed68b77e9fda447ea7cfa6"},
-{"name":"aws-sdk-kms","version":"1.64.0","platform":"ruby","checksum":"40de596c95047bfc6e1aacea24f3df6241aa716b6f7ce08ac4c5f7e3120395ad"},
-{"name":"aws-sdk-s3","version":"1.141.0","platform":"ruby","checksum":"cadb88497af6736e86a4a1fc8eb42333fb27ae85901686334252c50862bdd02e"},
+{"name":"aws-sdk-core","version":"3.190.1","platform":"ruby","checksum":"b02aa7981f955c6021405c89b66e99061b99e2edc4f5b48c0f3dc742dd53daaa"},
+{"name":"aws-sdk-kms","version":"1.76.0","platform":"ruby","checksum":"e7f75013cba9ba357144f66bbc600631c192e2cda9dd572794be239654e2cf49"},
+{"name":"aws-sdk-s3","version":"1.142.0","platform":"ruby","checksum":"79cd888eca66fd2ef3ae8b74d76173a2eccbeff6a1bba62a60b7c7dadc8dd7e9"},
{"name":"aws-sigv4","version":"1.8.0","platform":"ruby","checksum":"84dd99768b91b93b63d1d8e53ee837cfd06ab402812772a7899a78f9f9117cbc"},
{"name":"axe-core-api","version":"4.6.0","platform":"ruby","checksum":"1b0ddec3353f108dc10363baf2282f43a5ff7f13d4e25f99071294e78f8a6c62"},
{"name":"axe-core-rspec","version":"4.6.0","platform":"ruby","checksum":"11c25bc9dd388c137ba4e5e63d64d20092bf22c884d8ffc829a22acfbacd747f"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 47f05f0cb39..6520598664b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -297,19 +297,19 @@ GEM
awesome_print (1.9.2)
awrence (1.2.1)
aws-eventstream (1.3.0)
- aws-partitions (1.761.0)
+ aws-partitions (1.877.0)
aws-sdk-cloudformation (1.41.0)
aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.1)
- aws-sdk-core (3.190.0)
+ aws-sdk-core (3.190.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1)
- aws-sdk-kms (1.64.0)
- aws-sdk-core (~> 3, >= 3.165.0)
+ aws-sdk-kms (1.76.0)
+ aws-sdk-core (~> 3, >= 3.188.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.141.0)
+ aws-sdk-s3 (1.142.0)
aws-sdk-core (~> 3, >= 3.189.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.8)
@@ -1817,8 +1817,8 @@ DEPENDENCIES
autoprefixer-rails (= 10.2.5.1)
awesome_print
aws-sdk-cloudformation (~> 1)
- aws-sdk-core (~> 3.190.0)
- aws-sdk-s3 (~> 1.141.0)
+ aws-sdk-core (~> 3.190.1)
+ aws-sdk-s3 (~> 1.142.0)
axe-core-rspec
babosa (~> 2.0)
base32 (~> 0.3.0)
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 5b9b3b7de11..b151793ad8b 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -305,7 +305,8 @@ class GroupsController < Groups::ApplicationController
:prevent_sharing_groups_outside_hierarchy,
:setup_for_company,
:jobs_to_be_done,
- :crm_enabled
+ :crm_enabled,
+ :enable_namespace_descendants_cache
] + [group_feature_attributes: group_feature_attributes]
end
diff --git a/app/controllers/projects/gcp/artifact_registry/docker_images_controller.rb b/app/controllers/projects/gcp/artifact_registry/docker_images_controller.rb
index cd492e93d14..60adbbe6e5d 100644
--- a/app/controllers/projects/gcp/artifact_registry/docker_images_controller.rb
+++ b/app/controllers/projects/gcp/artifact_registry/docker_images_controller.rb
@@ -25,7 +25,7 @@ module Projects
private
def service
- ::Integrations::GoogleCloudPlatform::ArtifactRegistry::ListDockerImagesService.new(
+ ::GoogleCloudPlatform::ArtifactRegistry::ListDockerImagesService.new(
project: @project,
current_user: current_user,
params: {
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 07a9d49ab1e..cc60a64bc9c 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -56,6 +56,9 @@ class Namespace < ApplicationRecord
has_one :namespace_ldap_settings, inverse_of: :namespace, class_name: 'Namespaces::LdapSetting', autosave: true
+ has_one :namespace_descendants, class_name: 'Namespaces::Descendants'
+ accepts_nested_attributes_for :namespace_descendants, allow_destroy: true
+
has_many :runner_namespaces, inverse_of: :namespace, class_name: 'Ci::RunnerNamespace'
has_many :runners, through: :runner_namespaces, source: :runner, class_name: 'Ci::Runner'
has_many :pending_builds, class_name: 'Ci::PendingBuild'
diff --git a/app/services/google_cloud_platform/artifact_registry/list_docker_images_service.rb b/app/services/google_cloud_platform/artifact_registry/list_docker_images_service.rb
new file mode 100644
index 00000000000..c9afa8609f9
--- /dev/null
+++ b/app/services/google_cloud_platform/artifact_registry/list_docker_images_service.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module GoogleCloudPlatform
+ module ArtifactRegistry
+ class ListDockerImagesService < BaseProjectService
+ def execute(page_token: nil)
+ return ServiceResponse.error(message: "Access denied") unless allowed?
+
+ ServiceResponse.success(payload: client.list_docker_images(page_token: page_token))
+ end
+
+ private
+
+ def allowed?
+ can?(current_user, :read_container_image, project)
+ end
+
+ def client
+ ::Integrations::GoogleCloudPlatform::ArtifactRegistry::Client.new(
+ project: project,
+ user: current_user,
+ gcp_project_id: gcp_project_id,
+ gcp_location: gcp_location,
+ gcp_repository: gcp_repository,
+ gcp_wlif: gcp_wlif
+ )
+ end
+
+ def gcp_project_id
+ params[:gcp_project_id]
+ end
+
+ def gcp_location
+ params[:gcp_location]
+ end
+
+ def gcp_repository
+ params[:gcp_repository]
+ end
+
+ def gcp_wlif
+ params[:gcp_wlif]
+ end
+ end
+ end
+end
diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb
index d91e09d212a..a6ef8c8743b 100644
--- a/app/services/groups/update_service.rb
+++ b/app/services/groups/update_service.rb
@@ -29,6 +29,8 @@ module Groups
handle_namespace_settings
+ handle_hierarchy_cache_update
+
group.assign_attributes(params)
begin
@@ -46,6 +48,28 @@ module Groups
private
+ def handle_hierarchy_cache_update
+ return unless params.key?(:enable_namespace_descendants_cache)
+
+ enabled = Gitlab::Utils.to_boolean(params.delete(:enable_namespace_descendants_cache))
+
+ return unless Feature.enabled?(:group_hierarchy_optimization, group, type: :beta)
+
+ if enabled
+ return if group.namespace_descendants
+
+ params[:namespace_descendants_attributes] = {
+ traversal_ids: group.traversal_ids,
+ all_project_ids: [],
+ self_and_descendant_group_ids: []
+ }
+ else
+ return unless group.namespace_descendants
+
+ params[:namespace_descendants_attributes] = { id: group.id, _destroy: true }
+ end
+ end
+
def valid_path_change?
return true unless group.packages_feature_enabled?
return true if params[:path].blank?
diff --git a/app/services/integrations/google_cloud_platform/artifact_registry/list_docker_images_service.rb b/app/services/integrations/google_cloud_platform/artifact_registry/list_docker_images_service.rb
deleted file mode 100644
index 82bf9a41ae7..00000000000
--- a/app/services/integrations/google_cloud_platform/artifact_registry/list_docker_images_service.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-module Integrations
- module GoogleCloudPlatform
- module ArtifactRegistry
- class ListDockerImagesService < BaseProjectService
- def execute(page_token: nil)
- return ServiceResponse.error(message: "Access denied") unless allowed?
-
- ServiceResponse.success(payload: client.list_docker_images(page_token: page_token))
- end
-
- private
-
- def allowed?
- can?(current_user, :read_container_image, project)
- end
-
- def client
- ::Integrations::GoogleCloudPlatform::ArtifactRegistry::Client.new(
- project: project,
- user: current_user,
- gcp_project_id: gcp_project_id,
- gcp_location: gcp_location,
- gcp_repository: gcp_repository,
- gcp_wlif: gcp_wlif
- )
- end
-
- def gcp_project_id
- params[:gcp_project_id]
- end
-
- def gcp_location
- params[:gcp_location]
- end
-
- def gcp_repository
- params[:gcp_repository]
- end
-
- def gcp_wlif
- params[:gcp_wlif]
- end
- end
- end
- end
-end
diff --git a/app/views/admin/application_settings/appearances/_form.html.haml b/app/views/admin/application_settings/appearances/_form.html.haml
index 672af002e5e..e8bf25b8da6 100644
--- a/app/views/admin/application_settings/appearances/_form.html.haml
+++ b/app/views/admin/application_settings/appearances/_form.html.haml
@@ -6,6 +6,28 @@
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
+ %h4.gl-my-0 Favicon
+
+ .form-group
+ = f.label :favicon, _('Favicon'), class: 'col-form-label gl-pt-0'
+ %p
+ - if @appearance.favicon?
+ = image_tag @appearance.favicon_path, class: 'appearance-light-logo-preview'
+ - if @appearance.persisted?
+ %br
+ = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: favicon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Favicon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove favicon') } }) do
+ = _('Remove favicon')
+ %hr
+ = f.hidden_field :favicon_cache
+ = f.file_field :favicon, class: '', accept: 'image/*'
+ .form-text.text-muted
+ = _("Maximum file size is 1 MB. Image size must be 32 x 32 pixels. Allowed image formats are %{favicon_extension_allowlist}.") % { favicon_extension_allowlist: favicon_extension_allowlist }
+ %br
+ = _("Images with incorrect dimensions are not resized automatically, and may result in unexpected behavior.")
+
+ .settings-section
+ .settings-sticky-header
+ .settings-sticky-header-inner
%h4.gl-my-0= _('Navigation bar')
.form-group
@@ -26,54 +48,29 @@
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
- %h4.gl-my-0 Favicon
+ %h4.gl-my-0= _('New project pages')
.form-group
- = f.label :favicon, _('Favicon'), class: 'col-form-label gl-pt-0'
+ = f.label :new_project_guidelines, class: 'col-form-label'
%p
- - if @appearance.favicon?
- = image_tag @appearance.favicon_path, class: 'appearance-light-logo-preview'
- - if @appearance.persisted?
- %br
- = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: favicon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Favicon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove favicon') } }) do
- = _('Remove favicon')
- %hr
- = f.hidden_field :favicon_cache
- = f.file_field :favicon, class: '', accept: 'image/*'
+ = f.text_area :new_project_guidelines, class: "form-control gl-form-input", rows: 10
.form-text.text-muted
- = _("Maximum file size is 1 MB. Image size must be 32 x 32 pixels. Allowed image formats are %{favicon_extension_allowlist}.") % { favicon_extension_allowlist: favicon_extension_allowlist }
- %br
- = _("Images with incorrect dimensions are not resized automatically, and may result in unexpected behavior.")
-
- = render partial: 'admin/application_settings/appearances/system_header_footer_form', locals: { form: f }
+ = parsed_with_gfm
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
- %h4.gl-my-0= _('Sign in/Sign up pages')
+ %h4.gl-my-0= _('Profile image guidelines')
+
+ %p.gl-text-secondary
+ = _('These guidelines for public avatars are displayed on the user settings page.')
.form-group
- = f.label :title, class: 'col-form-label'
- = f.text_field :title, class: "form-control gl-form-input"
- .form-group
- = f.label :description, class: 'col-form-label'
- = f.text_area :description, class: "form-control gl-form-input", rows: 10
- .form-text.text-muted
- = parsed_with_gfm
- .form-group
- = f.label :logo, class: 'col-form-label gl-pt-0'
+ = f.label :profile_image_guidelines, class: 'col-form-label'
%p
- - if @appearance.logo?
- = image_tag @appearance.logo_path, class: 'appearance-logo-preview'
- - if @appearance.persisted?
- %br
- = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: logo_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove logo') } }) do
- = _('Remove logo')
- %hr
- = f.hidden_field :logo_cache
- = f.file_field :logo, class: "", accept: 'image/*'
+ = f.text_area :profile_image_guidelines, class: "form-control gl-form-input", rows: 10
.form-text.text-muted
- = _('Maximum file size is 1 MB. Pages are optimized for a 128x128 px logo.')
+ = parsed_with_gfm
.settings-section
.settings-sticky-header
@@ -109,26 +106,32 @@
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
- %h4.gl-my-0= _('New project pages')
+ %h4.gl-my-0= _('Sign in/Sign up pages')
.form-group
- = f.label :new_project_guidelines, class: 'col-form-label'
- %p
- = f.text_area :new_project_guidelines, class: "form-control gl-form-input", rows: 10
- .form-text.text-muted
- = parsed_with_gfm
-
- .settings-section
- .settings-sticky-header
- .settings-sticky-header-inner
- %h4.gl-my-0= _('Profile image guideline')
-
+ = f.label :title, class: 'col-form-label'
+ = f.text_field :title, class: "form-control gl-form-input"
.form-group
- = f.label :profile_image_guidelines, class: 'col-form-label'
+ = f.label :description, class: 'col-form-label'
+ = f.text_area :description, class: "form-control gl-form-input", rows: 10
+ .form-text.text-muted
+ = parsed_with_gfm
+ .form-group
+ = f.label :logo, class: 'col-form-label gl-pt-0'
%p
- = f.text_area :profile_image_guidelines, class: "form-control gl-form-input", rows: 10
+ - if @appearance.logo?
+ = image_tag @appearance.logo_path, class: 'appearance-logo-preview'
+ - if @appearance.persisted?
+ %br
+ = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: logo_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove logo') } }) do
+ = _('Remove logo')
+ %hr
+ = f.hidden_field :logo_cache
+ = f.file_field :logo, class: "", accept: 'image/*'
.form-text.text-muted
- = parsed_with_gfm
+ = _('Maximum file size is 1 MB. Pages are optimized for a 128x128 px logo.')
+
+ = render partial: 'admin/application_settings/appearances/system_header_footer_form', locals: { form: f }
- if @appearance.persisted? || @appearance.updated_at
.settings-section
diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml
index 375e5afea62..fae0c41b683 100644
--- a/app/views/groups/settings/_permissions.html.haml
+++ b/app/views/groups/settings/_permissions.html.haml
@@ -58,4 +58,12 @@
checkbox_options: { checked: @group.crm_enabled? },
help_text: s_('GroupSettings|Organizations and contacts can be created and associated with issues.')
+ - if Feature.enabled?(:group_hierarchy_optimization, @group, type: :beta)
+ %h5= _('Performance')
+ .form-group.gl-mb-3
+ = f.gitlab_ui_checkbox_component :enable_namespace_descendants_cache,
+ s_('GroupSettings|Enable caching of hierarchical objects (subgroups and projects) to improve the performance of group-level features within a large group.'),
+ checkbox_options: { checked: @group.namespace_descendants.present? },
+ help_text: s_('GroupSettings|Building the cache is asynchronous, happens in a background job. The cache invalidation is synchronous with strong consistency guarantees.')
+
= f.submit _('Save changes'), pajamas_button: true, class: 'gl-mt-3 js-dirty-submit', data: { testid: 'save-permissions-changes-button' }
diff --git a/config/feature_flags/beta/group_hierarchy_optimization.yml b/config/feature_flags/beta/group_hierarchy_optimization.yml
new file mode 100644
index 00000000000..194f450aefe
--- /dev/null
+++ b/config/feature_flags/beta/group_hierarchy_optimization.yml
@@ -0,0 +1,9 @@
+---
+name: group_hierarchy_optimization
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/433478
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141214
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/437604
+milestone: '16.8'
+group: group::optimize
+type: beta
+default_enabled: false
diff --git a/data/deprecations/16-8-deprecate-license-list.yml b/data/deprecations/16-8-deprecate-license-list.yml
new file mode 100644
index 00000000000..a5955c60361
--- /dev/null
+++ b/data/deprecations/16-8-deprecate-license-list.yml
@@ -0,0 +1,16 @@
+- title: "License List is deprecated"
+ removal_milestone: "17.0"
+ announcement_milestone: "16.8"
+ breaking_change: true
+ reporter: abellucci
+ stage: govern
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/436100
+ body: | # (required) Don't change this line.
+ Today in GitLab you can see a list of all of the licenses your project and the components that
+ use that license on the License List. As of 16.8, the License List
+ is deprecated and scheduled to be removed in 17.0 as a breaking change.
+ With the release of the [Group Dependency List](https://docs.gitlab.com/ee/user/application_security/dependency_list/)
+ and the ability to filter by license on the project and group Dependency List, you can now
+ access all of the licenses your project or group is using on the Dependency List.
+ tiers: [Gold, Ultimate]
+ documentation_url: https://docs.gitlab.com/ee/user/compliance/license_list.html
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 0e6c0620aa2..02dde734f9a 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -1019,7 +1019,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="queryvulnerabilitieshasremediations"></a>`hasRemediations` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have remediations. |
| <a id="queryvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
| <a id="queryvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
-| <a id="queryvulnerabilitiesowasptop10"></a>`owaspTop10` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
+| <a id="queryvulnerabilitiesowasptopten"></a>`owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
| <a id="queryvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| <a id="queryvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
| <a id="queryvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. |
@@ -20310,7 +20310,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupvulnerabilitieshasremediations"></a>`hasRemediations` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have remediations. |
| <a id="groupvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
| <a id="groupvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
-| <a id="groupvulnerabilitiesowasptop10"></a>`owaspTop10` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
+| <a id="groupvulnerabilitiesowasptopten"></a>`owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
| <a id="groupvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| <a id="groupvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
| <a id="groupvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. |
@@ -20366,7 +20366,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| <a id="groupvulnerabilityseveritiescounthasremediations"></a>`hasRemediations` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have remediations. |
| <a id="groupvulnerabilityseveritiescounthasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have a resolution. |
| <a id="groupvulnerabilityseveritiescountimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
-| <a id="groupvulnerabilityseveritiescountowasptop10"></a>`owaspTop10` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
+| <a id="groupvulnerabilityseveritiescountowasptopten"></a>`owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
| <a id="groupvulnerabilityseveritiescountprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| <a id="groupvulnerabilityseveritiescountreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
| <a id="groupvulnerabilityseveritiescountscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by scanner. |
@@ -20943,7 +20943,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| <a id="instancesecuritydashboardvulnerabilityseveritiescounthasremediations"></a>`hasRemediations` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have remediations. |
| <a id="instancesecuritydashboardvulnerabilityseveritiescounthasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have a resolution. |
| <a id="instancesecuritydashboardvulnerabilityseveritiescountimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
-| <a id="instancesecuritydashboardvulnerabilityseveritiescountowasptop10"></a>`owaspTop10` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
+| <a id="instancesecuritydashboardvulnerabilityseveritiescountowasptopten"></a>`owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
| <a id="instancesecuritydashboardvulnerabilityseveritiescountprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| <a id="instancesecuritydashboardvulnerabilityseveritiescountreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
| <a id="instancesecuritydashboardvulnerabilityseveritiescountscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by scanner. |
@@ -25732,7 +25732,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectvulnerabilitieshasremediations"></a>`hasRemediations` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have remediations. |
| <a id="projectvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
| <a id="projectvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
-| <a id="projectvulnerabilitiesowasptop10"></a>`owaspTop10` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
+| <a id="projectvulnerabilitiesowasptopten"></a>`owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
| <a id="projectvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| <a id="projectvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
| <a id="projectvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. |
@@ -25775,7 +25775,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| <a id="projectvulnerabilityseveritiescounthasremediations"></a>`hasRemediations` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have remediations. |
| <a id="projectvulnerabilityseveritiescounthasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have a resolution. |
| <a id="projectvulnerabilityseveritiescountimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
-| <a id="projectvulnerabilityseveritiescountowasptop10"></a>`owaspTop10` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
+| <a id="projectvulnerabilityseveritiescountowasptopten"></a>`owaspTopTen` | [`[VulnerabilityOwaspTop10!]`](#vulnerabilityowasptop10) | Filter vulnerabilities by OWASP Top 10 category. |
| <a id="projectvulnerabilityseveritiescountprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
| <a id="projectvulnerabilityseveritiescountreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
| <a id="projectvulnerabilityseveritiescountscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by scanner. |
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 0b939cb60b5..c980e1c160f 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -846,6 +846,25 @@ The table below lists the deprecated metrics and their respective replacements.
<div class="deprecation breaking-change" data-milestone="17.0">
+### License List is deprecated
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">16.8</span>
+- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/436100).
+</div>
+
+Today in GitLab you can see a list of all of the licenses your project and the components that
+use that license on the License List. As of 16.8, the License List
+is deprecated and scheduled to be removed in 17.0 as a breaking change.
+With the release of the [Group Dependency List](https://docs.gitlab.com/ee/user/application_security/dependency_list/)
+and the ability to filter by license on the project and group Dependency List, you can now
+access all of the licenses your project or group is using on the Dependency List.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="17.0">
+
### License Scanning support for sbt 1.0.X
<div class="deprecation-notes">
diff --git a/doc/user/application_security/policies/scan-execution-policies.md b/doc/user/application_security/policies/scan-execution-policies.md
index 767a2207c15..58d9c0b44f1 100644
--- a/doc/user/application_security/policies/scan-execution-policies.md
+++ b/doc/user/application_security/policies/scan-execution-policies.md
@@ -289,7 +289,6 @@ In this example:
- For every pipeline executed on branches that match the `release/*` wildcard (for example, branch
`release/v1.2.1`)
- DAST scans run with `Scanner Profile A` and `Site Profile B`.
- - A `test job` is injected into the `test` stage of the pipeline, printing `Hello World`.
- DAST and secret detection scans run every 10 minutes. The DAST scan runs with `Scanner Profile C`
and `Site Profile D`.
- Secret detection, container scanning, and SAST scans run for every pipeline executed on the `main`
@@ -399,6 +398,8 @@ scan_execution_policy:
- echo "Hello World"
```
+In this example a `test job` is injected into the `test` stage of the pipeline, printing `Hello World`.
+
### Security policy scopes
> The `policy_scope` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135398) in GitLab 16.7 [with a flag](../../../administration/feature_flags.md) named `security_policies_policy_scope`. Disabled by default.
diff --git a/doc/user/packages/maven_repository/index.md b/doc/user/packages/maven_repository/index.md
index e571c01f6b8..bd5311276c6 100644
--- a/doc/user/packages/maven_repository/index.md
+++ b/doc/user/packages/maven_repository/index.md
@@ -452,6 +452,35 @@ gradle publish
Go to your project's **Packages and registries** page and view the published packages.
+:::TabTitle `sbt`
+
+Configure the `publishTo` setting in your `build.sbt` file:
+
+```scala
+publishTo := Some("gitlab" at "<endpoint url>")
+```
+
+Ensure the credentials are referenced correctly. See the [`sbt` documentation](https://www.scala-sbt.org/1.x/docs/Publishing.html#Credentials) for more information.
+
+To publish a package using `sbt`:
+
+```shell
+sbt publish
+```
+
+If the deploy is successful, the build success message is displayed:
+
+```shell
+[success] Total time: 1 s, completed Jan 28, 2020 12:08:57 PM
+```
+
+Check the success message to ensure the package was published to the
+correct location:
+
+```shell
+[info] published my-project_2.12 to https://gitlab.example.com/api/v4/projects/PROJECT_ID/packages/maven/com/mycompany/my-project_2.12/0.1.1-SNAPSHOT/my-project_2.12-0.1.1-SNAPSHOT.pom
+```
+
::EndTabs
## Install a package
diff --git a/doc/user/packages/workflows/build_packages.md b/doc/user/packages/workflows/build_packages.md
index 59508b3e9e2..9d8db546566 100644
--- a/doc/user/packages/workflows/build_packages.md
+++ b/doc/user/packages/workflows/build_packages.md
@@ -276,6 +276,51 @@ OS: Windows 10 10.0 amd64
1. Enter a project name or press <kbd>Enter</kbd> to use the directory name as project name.
+## sbt
+
+### Install sbt
+
+Install sbt to create new sbt projects.
+
+To install sbt for your development environment:
+
+1. Follow the instructions at [scala-sbt.org](https://www.scala-sbt.org/1.x/docs/Setup.html).
+
+1. From your terminal, verify you can use sbt:
+
+ ```shell
+ sbt --version
+ ```
+
+The output is similar to:
+
+```plaintext
+[warn] Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? (default: r)
+sbt script version: 1.9.8
+```
+
+### Create a Scala project
+
+1. Open your terminal and create a directory to store the project.
+1. From the new directory, initialize a new project:
+
+ ```shell
+ sbt new scala/scala-seed.g8
+ ```
+
+ The output is:
+
+ ```plaintext
+ Minimum Scala build.
+
+ name [My Something Project]: hello
+
+ Template applied in ./hello
+ ```
+
+1. Enter a project name or press <kbd>Enter</kbd> to use the directory name as project name.
+1. Open the `build.sbt` file and edit it as described in the [sbt documentation](https://www.scala-sbt.org/1.x/docs/Publishing.html) to publish your project to the package registry.
+
## npm
### Install npm
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index 87467cbc56c..b861fe9d154 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -480,6 +480,23 @@ repository to be imported manually. Administrators can manually import the repos
project.create_import_state if project.import_state.blank?
# Set state to start
project.import_state.force_start
+
+ # Optional: If your import had certain optional stages selected or a timeout strategy
+ # set, you can reset them here. Below is an example.
+ # The params follow the format documented in the API:
+ # https://docs.gitlab.com/ee/api/import.html#import-repository-from-github
+ Gitlab::GithubImport::Settings
+ .new(project)
+ .write(
+ timeout_strategy: "optimistic",
+ optional_stages: {
+ single_endpoint_issue_events_import: true,
+ single_endpoint_notes_import: true,
+ attachments_import: true,
+ collaborators_import: true
+ }
+ )
+
# Trigger import from second step
Gitlab::GithubImport::Stage::ImportRepositoryWorker.perform_async(project.id)
```
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a01fed3b7b4..70425f7ff1a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -23573,6 +23573,9 @@ msgstr ""
msgid "GroupSettings|Be careful. Changing a group's parent can have unintended side effects. %{learn_more_link_start}Learn more.%{learn_more_link_end}"
msgstr ""
+msgid "GroupSettings|Building the cache is asynchronous, happens in a background job. The cache invalidation is synchronous with strong consistency guarantees."
+msgstr ""
+
msgid "GroupSettings|Cannot update the path because there are projects under this group that contain Docker images in their Container Registry. Please remove the images from your projects first and try again."
msgstr ""
@@ -23615,6 +23618,9 @@ msgstr ""
msgid "GroupSettings|Email notifications are disabled"
msgstr ""
+msgid "GroupSettings|Enable caching of hierarchical objects (subgroups and projects) to improve the performance of group-level features within a large group."
+msgstr ""
+
msgid "GroupSettings|Enable overview background aggregation for Value Streams Dashboard"
msgstr ""
@@ -33318,6 +33324,12 @@ msgstr ""
msgid "OKRs|An update is due on: %{update_due_date}"
msgstr ""
+msgid "OWASP Top 10 2017"
+msgstr ""
+
+msgid "OWASP Top 10 2021"
+msgstr ""
+
msgid "Object does not exist on the server or you don't have permissions to access it"
msgstr ""
@@ -34255,6 +34267,66 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owasp|A10:2017 Insufficient Logging & Monitoring"
+msgstr ""
+
+msgid "Owasp|A10:2021 Server-Side Request Forgery"
+msgstr ""
+
+msgid "Owasp|A1:2017 Injection"
+msgstr ""
+
+msgid "Owasp|A1:2021 Broken Access Control"
+msgstr ""
+
+msgid "Owasp|A2:2017 Broken Authentication"
+msgstr ""
+
+msgid "Owasp|A2:2021 Cryptographic Failures"
+msgstr ""
+
+msgid "Owasp|A3:2017 Sensitive Data Exposure"
+msgstr ""
+
+msgid "Owasp|A3:2021 Injection"
+msgstr ""
+
+msgid "Owasp|A4:2017 XML External Entities (XXE)"
+msgstr ""
+
+msgid "Owasp|A4:2021 Insecure Design"
+msgstr ""
+
+msgid "Owasp|A5:2017 Broken Access Control"
+msgstr ""
+
+msgid "Owasp|A5:2021 Security Misconfiguration"
+msgstr ""
+
+msgid "Owasp|A6:2017 Security Misconfiguration"
+msgstr ""
+
+msgid "Owasp|A6:2021 Vulnerable and Outdated Components"
+msgstr ""
+
+msgid "Owasp|A7:2017 Cross-Site Scripting (XSS)"
+msgstr ""
+
+msgid "Owasp|A7:2021 Identification and Authentication Failures"
+msgstr ""
+
+msgid "Owasp|A8:2017 Insecure Deserialization"
+msgstr ""
+
+msgid "Owasp|A8:2021 Software and Data Integrity Failures"
+msgstr ""
+
+msgid "Owasp|A9:2017 Using Components with Known Vulnerabilities"
+msgstr ""
+
+msgid "Owasp|A9:2021 Security Logging and Monitoring Failures"
+msgstr ""
+
msgid "Owned by %{image_tag}"
msgstr ""
@@ -35130,6 +35202,9 @@ msgstr ""
msgid "Perform common operations on GitLab project"
msgstr ""
+msgid "Performance"
+msgstr ""
+
msgid "Performance optimization"
msgstr ""
@@ -37260,7 +37335,7 @@ msgstr ""
msgid "Profile failed to delete"
msgstr ""
-msgid "Profile image guideline"
+msgid "Profile image guidelines"
msgstr ""
msgid "Profile page:"
@@ -49833,6 +49908,9 @@ msgstr ""
msgid "These existing issues have a similar title. It might be better to comment there instead of creating another similar issue."
msgstr ""
+msgid "These guidelines for public avatars are displayed on the user settings page."
+msgstr ""
+
msgid "These runners are shared across projects in this group."
msgstr ""
diff --git a/package.json b/package.json
index b1bddc3a537..a7b8340890d 100644
--- a/package.json
+++ b/package.json
@@ -231,7 +231,7 @@
"yaml": "^2.0.0-10"
},
"devDependencies": {
- "@gitlab/eslint-plugin": "19.2.0",
+ "@gitlab/eslint-plugin": "19.3.0",
"@gitlab/stylelint-config": "5.0.1",
"@graphql-eslint/eslint-plugin": "3.20.1",
"@originjs/vite-plugin-commonjs": "^1.0.3",
diff --git a/spec/features/groups/settings/user_enables_namespace_hierarchy_cache_spec.rb b/spec/features/groups/settings/user_enables_namespace_hierarchy_cache_spec.rb
new file mode 100644
index 00000000000..4b362a9561d
--- /dev/null
+++ b/spec/features/groups/settings/user_enables_namespace_hierarchy_cache_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Groups > Permission and group features > Enable caching of hierarchical objects', :js, feature_category: :value_stream_management do
+ include ListboxHelpers
+
+ let_it_be_with_reload(:group) { create(:group) }
+ let_it_be(:user) { create(:user).tap { |u| group.add_owner(u) } }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'with the group_hierarchy_optimization feature flag enabled' do
+ before do
+ stub_feature_flags(group_hierarchy_optimization: true)
+ end
+
+ it 'enables the setting' do
+ visit edit_group_path(group)
+
+ page.within('#js-permissions-settings') do
+ check 'group[enable_namespace_descendants_cache]'
+
+ click_on 'Save changes'
+ end
+
+ expect(group.namespace_descendants).to be_present
+ end
+
+ it 'disables the setting' do
+ create(:namespace_descendants, namespace: group)
+
+ visit edit_group_path(group)
+
+ page.within('#js-permissions-settings') do
+ uncheck 'group[enable_namespace_descendants_cache]'
+
+ click_on 'Save changes'
+ end
+
+ expect(group.reload.namespace_descendants).not_to be_present
+ end
+ end
+
+ context 'with the group_hierarchy_optimization feature flag disabled' do
+ before do
+ stub_feature_flags(group_hierarchy_optimization: false)
+ end
+
+ it 'does not render the setting' do
+ visit edit_group_path(group)
+
+ expect(page).not_to have_selector('group[enable_namespace_descendants_cache]')
+ end
+ end
+end
diff --git a/spec/requests/projects/gcp/artifact_registry/docker_images_controller_spec.rb b/spec/requests/projects/gcp/artifact_registry/docker_images_controller_spec.rb
index 8c5bdd1a516..f1c87243516 100644
--- a/spec/requests/projects/gcp/artifact_registry/docker_images_controller_spec.rb
+++ b/spec/requests/projects/gcp/artifact_registry/docker_images_controller_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe Projects::Gcp::ArtifactRegistry::DockerImagesController, feature_
describe '#index' do
let(:service_response) { ServiceResponse.success(payload: dummy_client_payload) }
let(:service_double) do
- instance_double('Integrations::GoogleCloudPlatform::ArtifactRegistry::ListDockerImagesService')
+ instance_double('GoogleCloudPlatform::ArtifactRegistry::ListDockerImagesService')
end
subject(:get_index_page) do
@@ -30,7 +30,7 @@ RSpec.describe Projects::Gcp::ArtifactRegistry::DockerImagesController, feature_
end
before do
- allow_next_instance_of(Integrations::GoogleCloudPlatform::ArtifactRegistry::ListDockerImagesService) do |service|
+ allow_next_instance_of(GoogleCloudPlatform::ArtifactRegistry::ListDockerImagesService) do |service|
allow(service).to receive(:execute).and_return(service_response)
end
end
diff --git a/spec/services/integrations/google_cloud_platform/artifact_registry/list_docker_images_service_spec.rb b/spec/services/google_cloud_platform/artifact_registry/list_docker_images_service_spec.rb
index 3f57add10e3..f19cbaa21cd 100644
--- a/spec/services/integrations/google_cloud_platform/artifact_registry/list_docker_images_service_spec.rb
+++ b/spec/services/google_cloud_platform/artifact_registry/list_docker_images_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Integrations::GoogleCloudPlatform::ArtifactRegistry::ListDockerImagesService, feature_category: :container_registry do
+RSpec.describe GoogleCloudPlatform::ArtifactRegistry::ListDockerImagesService, feature_category: :container_registry do
let_it_be(:project) { create(:project, :private) }
let(:user) { project.owner }
diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb
index 78deb3cf254..f50163041f8 100644
--- a/spec/services/groups/update_service_spec.rb
+++ b/spec/services/groups/update_service_spec.rb
@@ -444,6 +444,60 @@ RSpec.describe Groups::UpdateService, feature_category: :groups_and_projects do
end
end
+ context 'when setting enable_namespace_descendants_cache' do
+ let(:params) { { enable_namespace_descendants_cache: true } }
+
+ subject(:result) { described_class.new(public_group, user, params).execute }
+
+ context 'when the group_hierarchy_optimization feature flag is enabled' do
+ before do
+ stub_feature_flags(group_hierarchy_optimization: true)
+ end
+
+ context 'when enabling the setting' do
+ it 'creates the initial Namespaces::Descendants record' do
+ expect { result }.to change { public_group.reload.namespace_descendants.present? }.from(false).to(true)
+ end
+ end
+
+ context 'when accidentally enabling the setting again' do
+ it 'does nothing' do
+ namespace_descendants = create(:namespace_descendants, namespace: public_group)
+
+ expect { result }.not_to change { namespace_descendants.reload }
+ end
+ end
+
+ context 'when disabling the setting' do
+ before do
+ params[:enable_namespace_descendants_cache] = false
+ end
+
+ it 'removes the Namespaces::Descendants record' do
+ create(:namespace_descendants, namespace: public_group)
+
+ expect { result }.to change { public_group.reload.namespace_descendants }.to(nil)
+ end
+
+ context 'when the Namespaces::Descendants record is missing' do
+ it 'does not raise error' do
+ expect { result }.not_to raise_error
+ end
+ end
+ end
+ end
+
+ context 'when the group_hierarchy_optimization feature flag is disabled' do
+ before do
+ stub_feature_flags(group_hierarchy_optimization: false)
+ end
+
+ it 'does nothing' do
+ expect { result }.not_to change { public_group.reload.namespace_descendants.present? }.from(false)
+ end
+ end
+ end
+
context 'EventStore' do
let(:service) { described_class.new(group, user, **params) }
let(:root_group) { create(:group, path: 'root') }
diff --git a/yarn.lock b/yarn.lock
index 72065067f98..aba17a95e1e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1234,6 +1234,11 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b"
integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==
+"@fastify/busboy@^2.0.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff"
+ integrity sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==
+
"@floating-ui/core@^1.3.1":
version "1.5.3"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.5.3.tgz#b6aa0827708d70971c8679a16cf680a515b8a52a"
@@ -1278,10 +1283,10 @@
core-js "^3.29.1"
mitt "^3.0.1"
-"@gitlab/eslint-plugin@19.2.0":
- version "19.2.0"
- resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-19.2.0.tgz#05f07a873af18c85b5668316409cd39256dc141f"
- integrity sha512-6cTJoBHWZriOknaWwLzIpYKVX4ivCzO3MXKfXm310zHmtt1UK7tmq3JsyaS7Niw6/M19C2csgL+LedRJ88uZ0w==
+"@gitlab/eslint-plugin@19.3.0":
+ version "19.3.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-19.3.0.tgz#146ff28bd3817634261b2705838eeaec415b6ca4"
+ integrity sha512-rWxmLRnJDymlc/AF9/UPQyVnjZeu6bNrhElD9nw0WDndSpWVTPR5RWoEcmmBE4OhG5M7Foe+fVVd3q5zhZU0HQ==
dependencies:
eslint-config-airbnb-base "^15.0.0"
eslint-config-prettier "^6.10.0"
@@ -3590,14 +3595,15 @@ arrify@^1.0.1:
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
-asn1.js@^4.0.0:
- version "4.10.1"
- resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
- integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
+asn1.js@^5.2.0:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
+ integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==
dependencies:
bn.js "^4.0.0"
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
+ safer-buffer "^2.1.0"
assert@^1.1.1:
version "1.4.1"
@@ -3835,11 +3841,16 @@ bluebird@^3.1.1, bluebird@^3.5.5:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
-bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.9:
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9:
version "4.11.9"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
+bn.js@^5.0.0, bn.js@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
+ integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
+
body-parser@1.19.2:
version "1.19.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e"
@@ -3965,26 +3976,28 @@ browserify-des@^1.0.0:
des.js "^1.0.0"
inherits "^2.0.1"
-browserify-rsa@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
- integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=
+browserify-rsa@^4.0.0, browserify-rsa@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d"
+ integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==
dependencies:
- bn.js "^4.1.0"
+ bn.js "^5.0.0"
randombytes "^2.0.1"
browserify-sign@^4.0.0:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
- integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=
- dependencies:
- bn.js "^4.1.1"
- browserify-rsa "^4.0.0"
- create-hash "^1.1.0"
- create-hmac "^1.1.2"
- elliptic "^6.0.0"
- inherits "^2.0.1"
- parse-asn1 "^5.0.0"
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.2.tgz#e78d4b69816d6e3dd1c747e64e9947f9ad79bc7e"
+ integrity sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==
+ dependencies:
+ bn.js "^5.2.1"
+ browserify-rsa "^4.1.0"
+ create-hash "^1.2.0"
+ create-hmac "^1.1.7"
+ elliptic "^6.5.4"
+ inherits "^2.0.4"
+ parse-asn1 "^5.1.6"
+ readable-stream "^3.6.2"
+ safe-buffer "^5.2.1"
browserify-zlib@^0.2.0:
version "0.2.0"
@@ -4673,20 +4686,21 @@ create-ecdh@^4.0.0:
bn.js "^4.1.0"
elliptic "^6.0.0"
-create-hash@^1.1.0, create-hash@^1.1.2:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
- integrity sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=
+create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
+ integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
dependencies:
cipher-base "^1.0.1"
inherits "^2.0.1"
- ripemd160 "^2.0.0"
+ md5.js "^1.3.4"
+ ripemd160 "^2.0.1"
sha.js "^2.4.0"
-create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
- integrity sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=
+create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
+ integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
dependencies:
cipher-base "^1.0.3"
create-hash "^1.1.0"
@@ -5503,9 +5517,9 @@ decode-named-character-reference@^1.0.0:
character-entities "^2.0.0"
decode-uri-component@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
- integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
+ integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
dedent@^0.7.0:
version "0.7.0"
@@ -5807,7 +5821,7 @@ elkjs@^0.8.2:
resolved "https://registry.yarnpkg.com/elkjs/-/elkjs-0.8.2.tgz#c37763c5a3e24e042e318455e0147c912a7c248e"
integrity sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==
-elliptic@^6.0.0:
+elliptic@^6.0.0, elliptic@^6.5.4:
version "6.5.4"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
@@ -10580,16 +10594,16 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
-parse-asn1@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
- integrity sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=
+parse-asn1@^5.0.0, parse-asn1@^5.1.6:
+ version "5.1.6"
+ resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4"
+ integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==
dependencies:
- asn1.js "^4.0.0"
+ asn1.js "^5.2.0"
browserify-aes "^1.0.0"
- create-hash "^1.1.0"
evp_bytestokey "^1.0.0"
pbkdf2 "^3.0.3"
+ safe-buffer "^5.1.1"
parse-json@^5.0.0, parse-json@^5.2.0:
version "5.2.0"
@@ -11360,10 +11374,10 @@ read-pkg@^6.0.0:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
-readable-stream@^3.0.6:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
- integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
+readable-stream@^3.0.6, readable-stream@^3.6.2:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+ integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
@@ -11758,7 +11772,7 @@ safe-regex@^2.1.1:
dependencies:
regexp-tree "~0.1.1"
-"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
+"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -13114,9 +13128,11 @@ undefsafe@^2.0.5:
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
undici@^5.0.0:
- version "5.8.2"
- resolved "https://registry.yarnpkg.com/undici/-/undici-5.8.2.tgz#071fc8a6a5d24db0ad510ad442f607d9b09d5eec"
- integrity sha512-3KLq3pXMS0Y4IELV045fTxqz04Nk9Ms7yfBBHum3yxsTR4XNn+ZCaUbf/mWitgYDAhsplQ0B1G4S5D345lMO3A==
+ version "5.28.2"
+ resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.2.tgz#fea200eac65fc7ecaff80a023d1a0543423b4c91"
+ integrity sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==
+ dependencies:
+ "@fastify/busboy" "^2.0.0"
unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.0"
@@ -13971,9 +13987,9 @@ wildcard@^2.0.0:
integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
word-wrap@~1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
- integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
+ integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
worker-farm@^1.7.0:
version "1.7.0"