diff --git a/app/models/vulnerability.rb b/app/models/vulnerability.rb
index c8f9e75a3895f416c7b1006ecbea59798534c2e0..3e307ae77a049a4ac2ee8524aa1922841373488b 100644
--- a/app/models/vulnerability.rb
+++ b/app/models/vulnerability.rb
@@ -3,12 +3,6 @@
 # Placeholder class for model that is implemented in EE
 class Vulnerability < ApplicationRecord
   include EachBatch
-  include IgnorableColumns
-
-  ignore_column %i[due_date due_date_sourcing_milestone_id epic_id milestone_id
-    last_edited_at last_edited_by_id start_date start_date_sourcing_milestone_id updated_by_id],
-    remove_with: '16.9',
-    remove_after: '2024-01-19'
 
   alias_attribute :vulnerability_id, :id
 
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 5e3425a20eb314bae87b0585e1c5850572ffaa7c..ea26d9baf921e4cd1b96c47b43154570581bbd75 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -369,6 +369,7 @@ module.exports = {
           {
             loader: 'worker-loader',
             options: {
+              publicPath: './',
               filename: '[name].[contenthash:8].worker.js',
             },
           },
diff --git a/db/docs/cluster_agents.yml b/db/docs/cluster_agents.yml
index 237d8d23bfd7bfdac0bf27478e84d7acd2d50413..1c8417613cf727ca0a2e8cbea1037dc9742f6e5f 100644
--- a/db/docs/cluster_agents.yml
+++ b/db/docs/cluster_agents.yml
@@ -7,4 +7,12 @@ feature_categories:
 description: Represents a GitLab Agent for Kubernetes installed in a Kubernetes cluster
 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33228
 milestone: '13.3'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+  project_id: projects
diff --git a/db/docs/cluster_enabled_grants.yml b/db/docs/cluster_enabled_grants.yml
index 59f896f198dfab3c0c0569da6fd737f8c9df43cb..7c89d5626087b0c940c91f7a77996702a1cf369c 100644
--- a/db/docs/cluster_enabled_grants.yml
+++ b/db/docs/cluster_enabled_grants.yml
@@ -4,7 +4,10 @@ classes:
 - Clusters::ClusterEnabledGrant
 feature_categories:
 - deployment_management
-description: Persists information about namespaces which got an extended life for certificate based clusters
+description: Persists information about namespaces which got an extended life for
+  certificate based clusters
 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87149
 milestone: '15.1'
 gitlab_schema: gitlab_main_cell
+sharding_key:
+  namespace_id: namespaces
diff --git a/db/docs/cluster_groups.yml b/db/docs/cluster_groups.yml
index 70c11431acfc0090adae672abb60b8ccbcd265c1..ddc157644199ef9605d8146de8662959e602abb7 100644
--- a/db/docs/cluster_groups.yml
+++ b/db/docs/cluster_groups.yml
@@ -7,4 +7,12 @@ feature_categories:
 description: "(Deprecated) Join table between 'clusters' and 'namespaces'"
 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/0e15eec86d83cbdfefe17966bf5c02e4d419a34d
 milestone: '11.5'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+  group_id: namespaces
diff --git a/db/docs/cluster_projects.yml b/db/docs/cluster_projects.yml
index 152b60ea87bcdf0f10fc4bd8c24618cce57ca6f0..1313e5938d440f939b15c5a082415ed943fbc6d6 100644
--- a/db/docs/cluster_projects.yml
+++ b/db/docs/cluster_projects.yml
@@ -7,4 +7,12 @@ feature_categories:
 description: "(Deprecated) Join table between 'clusters' and 'projects'"
 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/d0cff7f5855f91b5479f9fdaa39d8d95ec691a9e
 milestone: '10.2'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+  project_id: projects
diff --git a/doc/api/import.md b/doc/api/import.md
index 3bb3417e212e26ce447a90f39515a2de96f381e8..e378958077a580963268b2dae56af5bd9158d144 100644
--- a/doc/api/import.md
+++ b/doc/api/import.md
@@ -210,11 +210,6 @@ curl --request POST \
 }'
 ```
 
-## Automate group and project import **(PREMIUM ALL)**
-
-For information on automating user, group, and project import API calls, see
-[Automate group and project import](../user/project/import/index.md#automate-group-and-project-import).
-
 ## Related topics
 
 - [Group migration by direct transfer API](bulk_imports.md).
diff --git a/doc/api/project_import_export.md b/doc/api/project_import_export.md
index 974694e0808facd06d3bab454305313f55103d1d..1cf276b4f602b7abf501e22210483b97e5bc214f 100644
--- a/doc/api/project_import_export.md
+++ b/doc/api/project_import_export.md
@@ -11,6 +11,12 @@ Use the project import and export API to import and export projects using file t
 Before using the project import and export API, you might want to use the
 [group import and export API](group_import_export.md).
 
+After using the project import and export API, you might want to use the
+[Project-level CI/CD variables API](project_level_variables.md).
+
+You must still migrate your [Container Registry](../user/packages/container_registry/index.md)
+over a series of Docker pulls and pushes. Re-run any CI/CD pipelines to retrieve any build artifacts.
+
 ## Prerequisites
 
 For prerequisites for project import and export API, see:
diff --git a/doc/subscriptions/gitlab_dedicated/index.md b/doc/subscriptions/gitlab_dedicated/index.md
index 0cf604f620f0ea5cf1807dbe7dee211f0a1a04ba..e6a6aace3b4ea484321843e6ab005f63418be264 100644
--- a/doc/subscriptions/gitlab_dedicated/index.md
+++ b/doc/subscriptions/gitlab_dedicated/index.md
@@ -111,11 +111,10 @@ With GitLab Dedicated, you must [install the GitLab Runner application](https://
 To help you migrate your data to GitLab Dedicated, you can choose from the following options:
 
 1. When migrating from another GitLab instance, you can either:
-    - Use the UI, including [group import](../../user/group/import/index.md) and [project import](../../user/project/settings/import_export.md).
+    - Use the UI, by using [direct transfer](../../user/group/import/index.md) to import groups and projects.
     - Use APIs, including the [group import API](../../api/group_import_export.md) and [project import API](../../api/project_import_export.md).
-    - Note: Import functionality behind a feature flag (such as `bulk_import_project`) is not supported in GitLab Dedicated.
 1. When migrating from third-party services, you can use [the GitLab importers](../../user/project/import/index.md#supported-import-sources).
-1. You can perform a fully-automated migration through the [Congregate Automation Tool](../../user/project/import/index.md#automate-group-and-project-import), which supports migrating from existing GitLab instances as well as third-party services.
+1. You can also engage [Professional Services](../../user/project/import/index.md#migrate-by-engaging-professional-services).
 
 ## Features that are not available
 
diff --git a/doc/update/package/index.md b/doc/update/package/index.md
index 662590e7f783c7e94412cfd4ec89021b1223c1c3..45cce799cb0e5cbab3bcd2e5685fe4b8bc50b4bc 100644
--- a/doc/update/package/index.md
+++ b/doc/update/package/index.md
@@ -141,21 +141,27 @@ or upgrade command:
 
    ```shell
    # Ubuntu/Debian
-   sudo apt install gitlab-ee=<version>
+   sudo apt install gitlab-ee=<version>-ee.0
 
    # RHEL/CentOS 7 and Amazon Linux 2
-   yum install gitlab-ee-<version>
+   sudo yum install gitlab-ee-<version>-ee.0.el7
 
-   # RHEL/Almalinux 8/9 and Amazon Linux 2023
-   dnf install gitlab-ee-<version>
+   # RHEL/Almalinux 8/9
+   sudo dnf install gitlab-ee-<version>-ee.0.el8
 
-   # SUSE
-   zypper install gitlab-ee=<version>
+   # Amazon Linux 2023
+   sudo dnf install gitlab-ee-<version>-ee.0.amazon2023
+
+   # OpenSUSE Leap 15.5
+   sudo zypper install gitlab-ee=<version>-ee.sles15
+
+   # SUSE Enterprise Server 12.2/12.5
+   sudo zypper install gitlab-ee=<version>-ee.0.sles12
    ```
 
 NOTE:
-For the GitLab Community Edition, replace `gitlab-ee` with
-`gitlab-ce`.
+For the GitLab Community Edition, replace `ee` with
+`ce`.
 
 ## Upgrade using a manually-downloaded package
 
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index 14c802124221d37cee2645639d134aa5fd1cee88..ffa04c6b916132f4fe525c23c964b52031b01a8d 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -243,18 +243,6 @@ which GitLab you use:
 - GitLab self-managed: no import sources are enabled by default and must be
   [enabled](../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources).
 
-| Import source                                                                                       | GitLab.com default     | GitLab self-managed default |
-|:----------------------------------------------------------------------------------------------------|:-----------------------|:----------------------------|
-| [Bitbucket Cloud](../project/import/bitbucket.md)                                                   | **{check-circle}** Yes | **{dotted-circle}** No      |
-| [Bitbucket Server](../project/import/bitbucket_server.md)                                           | **{check-circle}** Yes | **{dotted-circle}** No      |
-| [FogBugz](../project/import/fogbugz.md)                                                             | **{check-circle}** Yes | **{dotted-circle}** No      |
-| [Gitea](../project/import/gitea.md)                                                                 | **{check-circle}** Yes | **{dotted-circle}** No      |
-| [GitLab by direct transfer](../group/import/index.md)                                               | **{check-circle}** Yes | **{dotted-circle}** No      |
-| [GitLab using file exports](../project/settings/import_export.md)                                   | **{check-circle}** Yes | **{dotted-circle}** No      |
-| [GitHub](../project/import/github.md)                                                               | **{check-circle}** Yes | **{dotted-circle}** No      |
-| [Manifest file](../project/import/manifest.md)                                                      | **{check-circle}** Yes | **{dotted-circle}** No      |
-| [Repository by URL](../project/import/repo_by_url.md)                                               | **{check-circle}** Yes | **{dotted-circle}** No      |
-
 ## IP range
 
 GitLab.com uses the IP ranges `34.74.90.64/28` and `34.74.226.0/24` for traffic from its Web/API
diff --git a/doc/user/group/import/index.md b/doc/user/group/import/index.md
index 42a3ce32e8981b8354e386d6d3a0d9cbc4b0ecd5..be9b8f40f97f43d827aa9acf0a803356f8088d93 100644
--- a/doc/user/group/import/index.md
+++ b/doc/user/group/import/index.md
@@ -60,6 +60,8 @@ groups are in the same GitLab instance. Transferring groups is a faster and more
 ## Known issues
 
 - Because of [issue 406685](https://gitlab.com/gitlab-org/gitlab/-/issues/406685), files with a file name longer than 255 characters are not migrated.
+- In GitLab 16.1 and earlier, you should **not** use direct transfer with
+  [scheduled scan execution policies](../../../user/application_security/policies/scan-execution-policies.md).
 - For a list of other known issues, see [epic 6629](https://gitlab.com/groups/gitlab-org/-/epics/6629).
 
 ## Estimating migration duration
@@ -535,8 +537,3 @@ Distributing projects in different groups helps to avoid timeouts. If several la
 1. Start separate migrations each group and subgroup.
 
 The GitLab UI can only migrate top-level groups. Using the API, you can also migrate subgroups.
-
-## Automate group and project import **(PREMIUM ALL)**
-
-For information on automating user, group, and project import API calls, see
-[Automate group and project import](../../project/import/index.md#automate-group-and-project-import).
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 36e1ae1e0c8e4ee46151bee9ffc32a8a9d3e2c38..5ac6041d09ea7a42bc6b18bb7c3e7613b57beea6 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -476,7 +476,7 @@ To work around the issue, give these users the Guest role or higher to any proje
 - Customize permissions on [protected branches](project/protected_branches.md)
 - [LDAP user permissions](group/access_and_permissions.md#manage-group-memberships-via-ldap)
 - [Value stream analytics permissions](group/value_stream_analytics/index.md#access-permissions-for-value-stream-analytics)
-- [Project aliases](../user/project/import/index.md#project-aliases)
+- [Project aliases](../user/project/working_with_projects.md#project-aliases)
 - [Auditor users](../administration/auditor_users.md)
 - [Confidential issues](project/issues/confidential_issues.md)
 - [Container registry permissions](packages/container_registry/index.md#container-registry-visibility-permissions)
diff --git a/doc/user/project/import/bitbucket_server.md b/doc/user/project/import/bitbucket_server.md
index 572e0edcb90284c12767c9e371744f070b7b58a5..94b0285c54818d480f7f9de2ca3f6fce25b1a397 100644
--- a/doc/user/project/import/bitbucket_server.md
+++ b/doc/user/project/import/bitbucket_server.md
@@ -145,7 +145,3 @@ for Bitbucket Cloud.
 If the project import completes but LFS objects can't be downloaded or cloned, you may be using a
 password or personal access token containing special characters. For more information, see
 [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/337769).
-
-## Related topics
-
-- [Automate group and project import](index.md#automate-group-and-project-import)
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index 0a539d40605aa1efae83dfed9757b4233153f518..1aeece2de4da0b0cd27085cd37b842249c9c18cc 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -448,11 +448,6 @@ LoadModule ssl_module lib/httpd/modules/mod_ssl.so
 </VirtualHost>
 ```
 
-## Automate group and project import **(PREMIUM ALL)**
-
-For information on automating user, group, and project import API calls, see
-[Automate group and project import](index.md#automate-group-and-project-import).
-
 ## Troubleshooting
 
 ### Manually continue a previously failed import process
diff --git a/doc/user/project/import/gitlab_com.md b/doc/user/project/import/gitlab_com.md
index 135b51bf81a620d414427b6abe29f065fd7b53d9..32d5eef0d603da629a8f00fcaeebf49e55a58cf8 100644
--- a/doc/user/project/import/gitlab_com.md
+++ b/doc/user/project/import/gitlab_com.md
@@ -13,5 +13,4 @@ and removed in GitLab 16.0. To import GitLab projects from GitLab.com to a self-
 
 ## Related topics
 
-- [Automate group and project import](index.md#automate-group-and-project-import)
 - [Export a project](../settings/import_export.md#export-a-project-and-its-data)
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index 8c9ba4087990886846698d66f49fd962a8dabc79..cebf5a93f81c8069db266874e14e465538b2cae8 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -14,10 +14,12 @@ To bring existing projects to GitLab, or copy GitLab groups and projects to a di
 
 ## Migrate from GitLab to GitLab by using direct transfer
 
-The best way to migrate GitLab groups and projects between GitLab instances, or in the same GitLab instance, is
+The best way to copy GitLab groups and projects between GitLab instances, or in the same GitLab instance, is
 [by using direct transfer](../../group/import/index.md).
 
-You can also migrate GitLab projects by using a GitLab file export, which is a supported import source.
+Another option is to move GitLab groups using [group transfer](../../group/manage.md#transfer-a-group).
+
+You can also copy GitLab projects by using a GitLab file export, which is a supported import source.
 
 ## Supported import sources
 
@@ -39,28 +41,10 @@ GitLab can import projects from these supported import sources.
 | [Gitea](gitea.md)                             | Import Gitea projects. |
 | [GitHub](github.md)                           | Import from either GitHub.com or GitHub Enterprise. |
 | [GitLab export](../settings/import_export.md) | Migrate projects one by one by using a GitLab export file. |
-| [Manifest file](manifest.md)                 | Upload a manifest file. |
+| [Manifest file](manifest.md)                  | Upload a manifest file. |
 | [Repository by URL](repo_by_url.md)           | Provide a Git repository URL to create a new project from. |
 
-## Other import sources
-
-You can also read information on importing from these other import sources:
-
-- [ClearCase](clearcase.md)
-- [Concurrent Versions System (CVS)](cvs.md)
-- [Jira (issues only)](jira.md)
-- [Perforce Helix](perforce.md)
-- [Team Foundation Version Control (TFVC)](tfvc.md)
-
-### Import repositories from Subversion
-
-GitLab can not automatically migrate Subversion repositories to Git. Converting Subversion repositories to Git can be
-difficult, but several tools exist including:
-
-- [`git svn`](https://git-scm.com/book/en/v2/Git-and-Other-Systems-Migrating-to-Git), for very small and basic repositories.
-- [`reposurgeon`](http://www.catb.org/~esr/reposurgeon/repository-editing.html), for larger and more complex repositories.
-
-## Security
+### Disable unused import sources
 
 Only import projects from sources you trust. If you import a project from an untrusted source,
 an attacker could steal your sensitive data. For example, an imported project
@@ -74,31 +58,23 @@ GitLab self-managed administrators can reduce their attack surface by disabling
 1. Scroll to **Import sources**.
 1. Clear checkboxes for importers that are not required.
 
-In GitLab 16.1 and earlier, you should **not** use direct transfer with [scheduled scan execution policies](../../../user/application_security/policies/scan-execution-policies.md).
-
-## Migrate using the API
-
-To migrate all data from self-managed to GitLab.com, you can leverage the [API](../../../api/rest/index.md).
-Migrate the assets in this order:
-
-1. [Groups](../../../api/groups.md)
-1. [Projects](../../../api/projects.md)
-1. [Project variables](../../../api/project_level_variables.md)
+## Other import sources
 
-You must still migrate your [Container Registry](../../packages/container_registry/index.md)
-over a series of Docker pulls and pushes. Re-run any CI pipelines to retrieve any build artifacts.
+You can also read information on importing from these other import sources:
 
-## Migrate between two self-managed GitLab instances
+- [ClearCase](clearcase.md)
+- [Concurrent Versions System (CVS)](cvs.md)
+- [Jira (issues only)](jira.md)
+- [Perforce Helix](perforce.md)
+- [Team Foundation Version Control (TFVC)](tfvc.md)
 
-To migrate from an existing self-managed GitLab instance to a new self-managed GitLab instance,
-you should [back up](../../../administration/backup_restore/index.md)
-the existing instance and restore it on the new instance. For example, you could use this method to migrate a self-managed instance from an old server to a new server.
+### Import repositories from Subversion
 
-The backups produced don't depend on the operating system running GitLab. You can therefore use
-the restore method to switch between different operating system distributions or versions, as long
-as the same GitLab version [is available for installation](../../../administration/package_information/supported_os.md).
+GitLab can not automatically migrate Subversion repositories to Git. Converting Subversion repositories to Git can be
+difficult, but several tools exist including:
 
-Administrators can use the [Users API](../../../api/users.md) to migrate users.
+- [`git svn`](https://git-scm.com/book/en/v2/Git-and-Other-Systems-Migrating-to-Git), for very small and basic repositories.
+- [`reposurgeon`](http://www.catb.org/~esr/reposurgeon/repository-editing.html), for larger and more complex repositories.
 
 ## View project import history
 
@@ -115,57 +91,23 @@ To view project import history:
 1. Sign in to GitLab.
 1. On the left sidebar, at the top, select **Create new** (**{plus}**) and **New project/repository**.
 1. Select **Import project**.
-1. In the upper-right corner, select **History**.
-1. If there are any errors for a particular import, you can see them by selecting **Details**.
+1. In the upper-right corner, select the **History** link.
+1. If there are any errors for a particular import, select **Details** to see them.
 
 The history also includes projects created from [built-in](../index.md#create-a-project-from-a-built-in-template)
 or [custom](../index.md#create-a-project-from-a-built-in-template)
 templates. GitLab uses [import repository by URL](repo_by_url.md)
 to create a new project from a template.
 
-## LFS authentication
+## Importing projects with LFS objects
 
 When importing a project that contains LFS objects, if the project has an [`.lfsconfig`](https://github.com/git-lfs/git-lfs/blob/main/docs/man/git-lfs-config.adoc)
 file with a URL host (`lfs.url`) different from the repository URL host, LFS files are not downloaded.
 
-## Project aliases **(PREMIUM SELF)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3264) in GitLab 12.1.
-
-GitLab repositories are usually accessed with a namespace and a project name. When migrating
-frequently accessed repositories to GitLab, however, you can use project aliases to access those
-repositories with the original name. Accessing repositories through a project alias reduces the risk
-associated with migrating such repositories.
-
-This feature is only available on Git over SSH. Also, only GitLab administrators can create project
-aliases, and they can only do so through the API. For more information, see the
-[Project Aliases API documentation](../../../api/project_aliases.md).
-
-After an administrator creates an alias for a project, you can use the alias to clone the
-repository. For example, if an administrator creates the alias `gitlab` for the project
-`https://gitlab.com/gitlab-org/gitlab`, you can clone the project with
-`git clone git@gitlab.com:gitlab.git` instead of `git clone git@gitlab.com:gitlab-org/gitlab.git`.
-
-## Automate group and project import **(PREMIUM ALL)**
-
-The GitLab Professional Services team uses [Congregate](https://gitlab.com/gitlab-org/professional-services-automation/tools/migration/congregate)
-to orchestrate user, group, and project import API calls. With Congregate, you can migrate data to
-GitLab from:
-
-- Other GitLab instances
-- GitHub Enterprise
-- GitHub.com
-- Bitbucket Server
-- Bitbucket Data Center
-
-For more information, see:
-
-- Information on paid GitLab [migration services](https://about.gitlab.com/services/migration/).
-- [Quick Start](https://gitlab.com/gitlab-org/professional-services-automation/tools/migration/congregate/-/blob/master/docs/using-congregate.md#quick-start).
-- [Frequently Asked Migration Questions](https://gitlab.com/gitlab-org/professional-services-automation/tools/migration/congregate/-/blob/master/customer/famq.md),
-  including settings that need checking afterwards and other limitations.
+## Migrate by engaging Professional Services
 
-For support, customers must enter into a paid engagement with GitLab Professional Services.
+If you prefer, you can engage GitLab Professional Services to migrate groups and projects to GitLab instead of doing it
+yourself. For more information, see the [Professional Services Full Catalog](https://about.gitlab.com/services/catalog/).
 
 ## Troubleshooting
 
diff --git a/doc/user/project/import/repo_by_url.md b/doc/user/project/import/repo_by_url.md
index 3c5a40b8d27b0b1713063ed136934837d2f3f0f2..92f1a5cbbe76c82eade6744bcbb210814b971273 100644
--- a/doc/user/project/import/repo_by_url.md
+++ b/doc/user/project/import/repo_by_url.md
@@ -30,8 +30,3 @@ If the repository is too large, the import can timeout.
 1. Select **Create project**.
 
 Your newly created project is displayed.
-
-## Automate group and project import **(PREMIUM ALL)**
-
-For information on automating user, group, and project import API calls, see
-[Automate group and project import](index.md#automate-group-and-project-import).
diff --git a/doc/user/project/members/share_project_with_groups.md b/doc/user/project/members/share_project_with_groups.md
index 71b960b15f8b60689c369a75ffad9c17384ca7a3..420e51f580b52dba799750f936f2b2364c65597d 100644
--- a/doc/user/project/members/share_project_with_groups.md
+++ b/doc/user/project/members/share_project_with_groups.md
@@ -10,6 +10,19 @@ When you want a group to have access to your project,
 you can invite [a group](../../group/index.md) to the project.
 The group's direct and inherited members get access to the project, which becomes a *shared project*.
 
+In this case, inherited members are members that are inherited from parent groups into the groups that are shared.
+Only members of the group that is shared get access to the project.
+If you want to give members of a subgroup of the group you are sharing access to the project, you have to share the subgroup.
+
+The following table provides an overview of the group members that get access to a shared project.
+
+| Group member source                                              | Access to shared project          |
+|------------------------------------------------------------------|------------------------|
+| Direct member of the group that is shared                        | **{check-circle}** Yes |
+| Inherited member of the group that is shared                        | **{check-circle}** Yes |
+| Direct member of a subgroup, but not of the group that is shared | **{dotted-circle}** No |
+| Inherited member of a subgroup, but not of the group that is shared | **{dotted-circle}** No |
+
 ## Example
 
 For a project that was created by `Group 1`:
diff --git a/doc/user/project/working_with_projects.md b/doc/user/project/working_with_projects.md
index 7d8305519e471550b443fbf3ceae20aedfa9e67d..4a6684a72a3c64df4b4b038afc0144fdf9f6f30b 100644
--- a/doc/user/project/working_with_projects.md
+++ b/doc/user/project/working_with_projects.md
@@ -311,6 +311,22 @@ Prerequisites:
 1. To use LDAP groups to manage access to a project,
    [add the LDAP-synchronized group as a member](../group/manage.md) to the project.
 
+## Project aliases **(PREMIUM SELF)**
+
+GitLab repositories are usually accessed with a namespace and a project name. When migrating
+frequently accessed repositories to GitLab, however, you can use project aliases to access those
+repositories with the original name. Accessing repositories through a project alias reduces the risk
+associated with migrating such repositories.
+
+This feature is only available on Git over SSH. Also, only GitLab administrators can create project
+aliases, and they can only do so through the API. For more information, see the
+[Project Aliases API documentation](../../api/project_aliases.md).
+
+After an administrator creates an alias for a project, you can use the alias to clone the
+repository. For example, if an administrator creates the alias `gitlab` for the project
+`https://gitlab.com/gitlab-org/gitlab`, you can clone the project with
+`git clone git@gitlab.com:gitlab.git` instead of `git clone git@gitlab.com:gitlab-org/gitlab.git`.
+
 ## Troubleshooting
 
 When working with projects, you might encounter the following issues, or require alternate methods to complete specific tasks.
diff --git a/ee/app/assets/javascripts/usage_quotas/code_suggestions/constants.js b/ee/app/assets/javascripts/usage_quotas/code_suggestions/constants.js
index cfaa61f8af156a5d9d9c929c3728ab6de2441483..2bd4574f6d6094c68f0fbd526d50c080cd47ead2 100644
--- a/ee/app/assets/javascripts/usage_quotas/code_suggestions/constants.js
+++ b/ee/app/assets/javascripts/usage_quotas/code_suggestions/constants.js
@@ -4,7 +4,7 @@ import { thWidthPercent } from '~/lib/utils/table_utility';
 
 export const ADD_ON_CODE_SUGGESTIONS = 'CODE_SUGGESTIONS';
 export const codeSuggestionsLearnMoreLink = `${PROMO_URL}/solutions/code-suggestions/`;
-export const salesLink = `${PROMO_URL}/sales/`;
+export const salesLink = `${PROMO_URL}/solutions/code-suggestions/sales/`;
 
 export const addOnEligibleUserListTableFields = {
   codeSuggestionsAddon: {
diff --git a/ee/app/assets/javascripts/usage_quotas/error_constants.js b/ee/app/assets/javascripts/usage_quotas/error_constants.js
index 8816effef615aec7d938932ad73f9683f7a68bc2..50b46a121fc6a912a7faf7adfc0299fb255927ea 100644
--- a/ee/app/assets/javascripts/usage_quotas/error_constants.js
+++ b/ee/app/assets/javascripts/usage_quotas/error_constants.js
@@ -2,7 +2,7 @@ import { s__ } from '~/locale';
 import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
 import { convertObjectPropsToLowerCase } from '~/lib/utils/common_utils';
 
-const salesLink = `${PROMO_URL}/sales/`;
+const salesLink = `${PROMO_URL}/solutions/code-suggestions/sales/`;
 const supportLink = `${PROMO_URL}/support/`;
 
 const NO_SEATS_AVAILABLE_ERROR = {
diff --git a/spec/scripts/internal_events/cli_spec.rb b/spec/scripts/internal_events/cli_spec.rb
index 571517f005be291482725d6799dd51cb4c317022..54169e0dc2decc232a8cd1cc062c4de55bb29b52 100644
--- a/spec/scripts/internal_events/cli_spec.rb
+++ b/spec/scripts/internal_events/cli_spec.rb
@@ -3,15 +3,14 @@
 require 'fast_spec_helper'
 require 'tty/prompt/test'
 require_relative '../../../scripts/internal_events/cli'
+require_relative '../../support/helpers/wait_helpers'
 
 RSpec.describe Cli, feature_category: :service_ping do
+  include WaitHelpers
+
   let(:prompt) { TTY::Prompt::Test.new }
   let(:files_to_cleanup) { [] }
-
-  let(:example_timeout) { 3 }
-  let(:example_error) { Class.new(Timeout::Error) }
-  let(:interaction_timeout) { 1 }
-  let(:interaction_error) { Class.new(Timeout::Error) }
+  let(:max_wait_time) { 20 }
 
   let(:event1_filepath) { 'config/events/internal_events_cli_used.yml' }
   let(:event1_content) { internal_event_fixture('events/event_with_identifiers.yml') }
@@ -31,19 +30,6 @@
     delete_files(files_to_cleanup)
   end
 
-  around do |example|
-    Timeout.timeout(example_timeout, example_error) { example.run }
-  rescue example_error => e
-    # Override error to include CLI output in error detail
-    raise e.class, timeout_error_message, e.backtrace
-  end
-
-  subject(:execute) do
-    Timeout.timeout(interaction_timeout, interaction_error) { described_class.new(prompt).run }
-  rescue interaction_error
-    # Rescue from timeout so we can make assertions on the CLI output
-  end
-
   # Shared examples used for examples defined in new_events.yml & new_metrics.yml fixtures.
   # Note: Expects CLI to be exited using the 'Exit' option or completing definition flow
   shared_examples 'creates the right defintion files' do |description, test_case = {}|
@@ -51,6 +37,7 @@
     let(:keystrokes) { test_case.dig('inputs', 'keystrokes') || [] }
     let(:input_files) { test_case.dig('inputs', 'files') || [] }
     let(:output_files) { test_case.dig('outputs', 'files') || [] }
+    let(:timeout_error) { 'Internal Events CLI timed out while awaiting completion.' }
 
     # Script execution should stop without a reduced timeout
     let(:interaction_timeout) { example_timeout }
@@ -61,7 +48,7 @@
       queue_cli_inputs(keystrokes)
       expect_file_creation
 
-      execute
+      wait_for_cli_completion
     end
 
     private
@@ -90,6 +77,12 @@ def expect_file_creation
         expect(File).not_to receive(:write)
       end
     end
+
+    def wait_for_cli_completion
+      with_cli_thread do |thread|
+        wait_for(timeout_error, max_wait_time: max_wait_time) { !thread.alive? }
+      end
+    end
   end
 
   context 'when creating new events' do
@@ -138,10 +131,8 @@ def expect_file_creation
           "\n" # Copy & continue
         ])
 
-        execute
-
         # Filter down to "dev" options
-        expect(plain_last_lines(9)).to eq <<~TEXT.chomp
+        expected_output = <<~TEXT.chomp
         ‣ dev:plan:project_management
           dev:plan:product_planning
           dev:plan:knowledge
@@ -152,6 +143,8 @@ def expect_file_creation
           dev:create:editor_extensions
           dev:create:code_creation
         TEXT
+
+        expect_cli_output { plain_last_lines(9) == expected_output }
       end
 
       it 'filters the product group options based on common section & stage' do
@@ -170,16 +163,16 @@ def expect_file_creation
           "\n" # Copy & continue
         ])
 
-        execute
-
         # Filter down to "dev:create" options
-        expect(plain_last_lines(5)).to eq <<~TEXT.chomp
+        expected_output = <<~TEXT.chomp
         ‣ dev:create:source_code
           dev:create:code_review
           dev:create:ide
           dev:create:editor_extensions
           dev:create:code_creation
         TEXT
+
+        expect_cli_output { plain_last_lines(5) == expected_output }
       end
     end
 
@@ -206,10 +199,10 @@ def expect_file_creation
           "2\n" # Modify attributes
         ])
 
-        execute
-
         # Filter down to "dev" options
-        expect(plain_last_lines(50)).to include 'Select one: Which group owns the metric?'
+        expect_cli_output do
+          plain_last_lines(50).include?('Select one: Which group owns the metric?')
+        end
       end
     end
 
@@ -221,13 +214,15 @@ def expect_file_creation
       it 'shows all metrics options' do
         select_event_from_list
 
-        expect(plain_last_lines(5)).to eq <<~TEXT.chomp
+        expected_output = <<~TEXT.chomp
         ‣ Monthly/Weekly count of unique users [who triggered internal_events_cli_used]
           Monthly/Weekly count of unique projects [where internal_events_cli_used occurred]
           Monthly/Weekly count of unique namespaces [where internal_events_cli_used occurred]
           Monthly/Weekly count of [internal_events_cli_used occurrences]
           Total count of [internal_events_cli_used occurrences]
         TEXT
+
+        expect_cli_output { plain_last_lines(5) == expected_output }
       end
 
       context 'with an existing weekly metric' do
@@ -241,7 +236,7 @@ def expect_file_creation
         it 'partially filters metric options' do
           select_event_from_list
 
-          expect(plain_last_lines(6)).to eq <<~TEXT.chomp
+          expected_output = <<~TEXT.chomp
           ‣ Monthly/Weekly count of unique users [who triggered internal_events_cli_used]
             Monthly/Weekly count of unique projects [where internal_events_cli_used occurred]
             Monthly/Weekly count of unique namespaces [where internal_events_cli_used occurred]
@@ -249,6 +244,8 @@ def expect_file_creation
           ✘ Weekly count of [internal_events_cli_used occurrences] (already defined)
             Total count of [internal_events_cli_used occurrences]
           TEXT
+
+          expect_cli_output { plain_last_lines(6) == expected_output }
         end
       end
 
@@ -263,13 +260,15 @@ def expect_file_creation
         it 'filters whole metric options' do
           select_event_from_list
 
-          expect(plain_last_lines(5)).to eq <<~TEXT.chomp
+          expected_output = <<~TEXT.chomp
           ‣ Monthly/Weekly count of unique users [who triggered internal_events_cli_used]
             Monthly/Weekly count of unique projects [where internal_events_cli_used occurred]
             Monthly/Weekly count of unique namespaces [where internal_events_cli_used occurred]
             Monthly/Weekly count of [internal_events_cli_used occurrences]
           ✘ Total count of [internal_events_cli_used occurrences] (already defined)
           TEXT
+
+          expect_cli_output { plain_last_lines(5) == expected_output }
         end
       end
 
@@ -282,8 +281,6 @@ def select_event_from_list
           'internal_events_cli_used', # Filters to this event
           "\n" # Select: config/events/internal_events_cli_used.yml
         ])
-
-        execute
       end
     end
 
@@ -300,15 +297,15 @@ def select_event_from_list
           "\n" # Select: config/events/internal_events_cli_opened.yml
         ])
 
-        execute
-
-        expect(plain_last_lines(5)).to eq <<~TEXT.chomp
+        expected_output = <<~TEXT.chomp
         ✘ Monthly/Weekly count of unique users [who triggered internal_events_cli_opened] (user unavailable)
         ✘ Monthly/Weekly count of unique projects [where internal_events_cli_opened occurred] (project unavailable)
         ✘ Monthly/Weekly count of unique namespaces [where internal_events_cli_opened occurred] (namespace unavailable)
         ‣ Monthly/Weekly count of [internal_events_cli_opened occurrences]
           Total count of [internal_events_cli_opened occurrences]
         TEXT
+
+        expect_cli_output { plain_last_lines(5) == expected_output }
       end
     end
 
@@ -339,10 +336,9 @@ def select_event_from_list
           "\n" # Select: config/events/00_event1.yml
         ])
 
-        execute
+        expected_output = 'Looks like the potential metrics for this event either already exist or are unsupported.'
 
-        expect(plain_last_lines(15)).to include 'Looks like the potential metrics for this event ' \
-                                                'either already exist or are unsupported.'
+        expect_cli_output { plain_last_lines(15).include?(expected_output) }
       end
     end
   end
@@ -410,13 +406,13 @@ def select_event_from_list
           "8\n" # Exit
         ])
 
-        execute
+        expect_cli_output do
+          output = plain_last_lines(100)
 
-        output = plain_last_lines(100)
-
-        expect(output).to include expected_example_prompt
-        expect(output).to include expected_rails_example
-        expect(output).to include expected_rspec_example
+          output.include?(expected_example_prompt) &&
+            output.include?(expected_rails_example) &&
+            output.include?(expected_rspec_example)
+        end
       end
     end
 
@@ -577,17 +573,17 @@ def select_event_from_list
           "8\n" # Exit
         ])
 
-        execute
+        expect_cli_output do
+          output = plain_last_lines(1000)
 
-        output = plain_last_lines(1000)
-
-        expect(output).to include expected_example_prompt
-        expect(output).to include expected_rails_example
-        expect(output).to include expected_rspec_example
-        expect(output).to include expected_vue_example
-        expect(output).to include expected_js_example
-        expect(output).to include expected_vue_template_example
-        expect(output).to include expected_haml_example
+          output.include?(expected_example_prompt) &&
+            output.include?(expected_rails_example) &&
+            output.include?(expected_rspec_example) &&
+            output.include?(expected_vue_example) &&
+            output.include?(expected_js_example) &&
+            output.include?(expected_vue_template_example) &&
+            output.include?(expected_haml_example)
+        end
       end
     end
 
@@ -637,13 +633,13 @@ def select_event_from_list
           "8\n" # Exit
         ])
 
-        execute
-
-        output = plain_last_lines(300)
+        expect_cli_output do
+          output = plain_last_lines(300)
 
-        expect(output).to include expected_example_prompt
-        expect(output).to include expected_event1_example
-        expect(output).to include expected_event2_example
+          output.include?(expected_example_prompt) &&
+            output.include?(expected_event1_example) &&
+            output.include?(expected_event2_example)
+        end
       end
     end
   end
@@ -756,9 +752,9 @@ def select_event_from_list
         "n\n" # No --> Are you trying to track customer usage of a GitLab feature?
       ])
 
-      execute
-
-      expect(plain_last_lines(50)).to include("Oh no! This probably isn't the tool you need!")
+      expect_cli_output do
+        plain_last_lines(50).include?("Oh no! This probably isn't the tool you need!")
+      end
     end
 
     it "handles when product usage can't be tracked with events" do
@@ -768,9 +764,9 @@ def select_event_from_list
         "n\n" # No --> Can usage for the feature be measured by tracking a specific user action?
       ])
 
-      execute
-
-      expect(plain_last_lines(50)).to include("Oh no! This probably isn't the tool you need!")
+      expect_cli_output do
+        plain_last_lines(50).include?("Oh no! This probably isn't the tool you need!")
+      end
     end
 
     it 'handles when user needs to add a new event' do
@@ -782,9 +778,9 @@ def select_event_from_list
         "n\n" # No --> Ready to start?
       ])
 
-      execute
-
-      expect(plain_last_lines(30)).to include("Okay! The next step is adding a new event! (~5 min)")
+      expect_cli_output do
+        plain_last_lines(30).include?("Okay! The next step is adding a new event! (~5 min)")
+      end
     end
 
     it 'handles when user needs to add a new metric' do
@@ -796,9 +792,9 @@ def select_event_from_list
         "n\n" # No --> Ready to start?
       ])
 
-      execute
-
-      expect(plain_last_lines(30)).to include("Amazing! The next step is adding a new metric! (~8 min)")
+      expect_cli_output do
+        plain_last_lines(30).include?("Amazing! The next step is adding a new metric! (~8 min)")
+      end
     end
   end
 
@@ -809,21 +805,6 @@ def queue_cli_inputs(keystrokes)
     prompt.input.rewind
   end
 
-  def timeout_error_message
-    <<~TEXT
-    Awaiting input too long. Entire CLI output:
-
-    #{
-      prompt.output.string.lines
-        .map { |line| "\e[0;37m#{line}\e[0m" } # wrap in white
-        .join('')
-        .gsub("\e[1G", "\e[1G       ") # align to error indent
-    }
-
-
-    TEXT
-  end
-
   def plain_last_lines(size)
     prompt.output.string
       .lines
@@ -873,4 +854,16 @@ def delete_files(files)
   def internal_event_fixture(filepath)
     Rails.root.join('spec', 'fixtures', 'scripts', 'internal_events', filepath)
   end
+
+  def with_cli_thread
+    thread = Thread.new { described_class.new(prompt).run }
+
+    yield thread
+  ensure
+    thread.exit
+  end
+
+  def expect_cli_output(&blk)
+    with_cli_thread { wait_for(blk.source, max_wait_time: max_wait_time, &blk) }
+  end
 end
diff --git a/workhorse/internal/config/config.go b/workhorse/internal/config/config.go
index 562ea05bfd0bba42a2dd6d23e891c78faffa0b48..c3b55c2a6e5a5854e72a953b8fad67f9a2803d34 100644
--- a/workhorse/internal/config/config.go
+++ b/workhorse/internal/config/config.go
@@ -162,6 +162,20 @@ func NewDefaultConfig() *Config {
 	}
 }
 
+func LoadConfigFromFile(file *string) (*Config, error) {
+	tomlData := ""
+
+	if *file != "" {
+		buf, err := os.ReadFile(*file)
+		if err != nil {
+			return nil, fmt.Errorf("file: %v", err)
+		}
+		tomlData = string(buf)
+	}
+
+	return LoadConfig(tomlData)
+}
+
 func LoadConfig(data string) (*Config, error) {
 	cfg := NewDefaultConfig()
 
diff --git a/workhorse/internal/config/config_test.go b/workhorse/internal/config/config_test.go
index d3f000217254afd72841141f79ddab09920c455f..6127a5aae550caf0db2ada6bc54d8f3f3918d1a7 100644
--- a/workhorse/internal/config/config_test.go
+++ b/workhorse/internal/config/config_test.go
@@ -1,6 +1,7 @@
 package config
 
 import (
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -196,3 +197,30 @@ func TestDefaultConfig(t *testing.T) {
 
 	require.Equal(t, uint64(250000), cfg.ImageResizerConfig.MaxFilesize)
 }
+
+func TestLoadConfigFromFile(t *testing.T) {
+	config := `
+[image_resizer]
+max_filesize = 350000
+`
+
+	fileName := createTempFile(t, []byte(config))
+
+	cfg, err := LoadConfigFromFile(&fileName)
+	require.NoError(t, err)
+
+	require.Equal(t, uint64(350000), cfg.ImageResizerConfig.MaxFilesize)
+}
+
+func createTempFile(t *testing.T, contents []byte) string {
+	t.Helper()
+
+	tmpFile, err := os.CreateTemp(t.TempDir(), "config.toml")
+	require.NoError(t, err)
+	defer tmpFile.Close()
+
+	_, err = tmpFile.Write(contents)
+	require.NoError(t, err)
+
+	return tmpFile.Name()
+}
diff --git a/workhorse/main.go b/workhorse/main.go
index 0c470d36e3e30cfd15fdcab57b3c0e3a48af6dfd..4d14d60df92da5fe0934cd3b2ae93c024b45ba37 100644
--- a/workhorse/main.go
+++ b/workhorse/main.go
@@ -138,16 +138,7 @@ func buildConfig(arg0 string, args []string) (*bootConfig, *config.Config, error
 		cfg.CableBackend = cfg.Backend
 	}
 
-	tomlData := ""
-	if *configFile != "" {
-		buf, err := os.ReadFile(*configFile)
-		if err != nil {
-			return nil, nil, fmt.Errorf("configFile: %v", err)
-		}
-		tomlData = string(buf)
-	}
-
-	cfgFromFile, err := config.LoadConfig(tomlData)
+	cfgFromFile, err := config.LoadConfigFromFile(configFile)
 	if err != nil {
 		return nil, nil, fmt.Errorf("configFile: %v", err)
 	}