From 5c2a27a69b36799e31ba0cc4a57c9b3576f74cad Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 28 May 2025 09:18:20 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- Gemfile | 4 +- Gemfile.lock | 2 +- Gemfile.next.lock | 2 +- .../search/results/components/app.vue | 8 +- ...ci_job_variables_on_partition_id_job_id.rb | 18 +++++ db/schema_migrations/20250527170705 | 1 + doc/administration/get_started.md | 34 ++++----- doc/administration/moderate_users.md | 3 + .../postgresql/replication_and_failover.md | 9 +++ doc/development/database/foreign_keys.md | 13 +++- lib/gitlab/database/schema_helpers.rb | 23 ++++++ spec/db/schema_spec.rb | 3 +- .../search/results/components/app_spec.js | 2 +- .../gitlab/database/schema_helpers_spec.rb | 75 +++++++++++++++++++ 14 files changed, 170 insertions(+), 27 deletions(-) create mode 100644 db/post_migrate/20250527170705_async_remove_idx_ci_job_variables_on_partition_id_job_id.rb create mode 100644 db/schema_migrations/20250527170705 diff --git a/Gemfile b/Gemfile index 704ab2af66d..822b45a8d1b 100644 --- a/Gemfile +++ b/Gemfile @@ -34,9 +34,9 @@ gem 'bootsnap', '~> 1.18.3', require: false, feature_category: :shared # Avoid the precompiled native gems because Omnibus needs to build this to ensure # LD_LIBRARY_PATH is correct: https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/7730 if RUBY_PLATFORM.include?('darwin') - gem 'ffi', '~> 1.17', feature_category: :shared + gem 'ffi', '~> 1.17.2', feature_category: :shared else - gem 'ffi', '~> 1.17', force_ruby_platform: true, feature_category: :shared + gem 'ffi', '~> 1.17.2', force_ruby_platform: true, feature_category: :shared end gem 'openssl', '~> 3.0', feature_category: :shared diff --git a/Gemfile.lock b/Gemfile.lock index b626a8aabb9..28182fa7749 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2139,7 +2139,7 @@ DEPENDENCIES faraday_middleware-aws-sigv4 (~> 1.0.1) fast_blank (~> 1.0.1) ffaker (~> 2.24) - ffi (~> 1.17) + ffi (~> 1.17.2) flipper (~> 0.28.0) flipper-active_record (~> 0.28.0) flipper-active_support_cache_store (~> 0.28.0) diff --git a/Gemfile.next.lock b/Gemfile.next.lock index b626a8aabb9..28182fa7749 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -2139,7 +2139,7 @@ DEPENDENCIES faraday_middleware-aws-sigv4 (~> 1.0.1) fast_blank (~> 1.0.1) ffaker (~> 2.24) - ffi (~> 1.17) + ffi (~> 1.17.2) flipper (~> 0.28.0) flipper-active_record (~> 0.28.0) flipper-active_support_cache_store (~> 0.28.0) diff --git a/app/assets/javascripts/search/results/components/app.vue b/app/assets/javascripts/search/results/components/app.vue index 9ee9240f0a1..e7315124ee6 100644 --- a/app/assets/javascripts/search/results/components/app.vue +++ b/app/assets/javascripts/search/results/components/app.vue @@ -33,6 +33,7 @@ export default { return { hasError: false, blobSearch: {}, + loaded: false, }; }, apollo: { @@ -66,6 +67,7 @@ export default { }, result({ data }) { this.hasError = false; + this.loaded = true; this.blobSearch = data?.blobSearch; this.$store.commit(RECEIVE_NAVIGATION_COUNT, { key: 'blobs', @@ -75,6 +77,7 @@ export default { debounce: 500, error(error) { logError(error); + this.loaded = true; this.hasError = true; }, }, @@ -85,6 +88,9 @@ export default { return this.query?.page ? parseInt(this.query?.page, 10) : 1; }, isLoading() { + if (!this.loaded && !this.$apollo?.queries?.blobSearch?.loading) { + return true; + } return this.$apollo.queries.blobSearch.loading; }, hasResults() { @@ -99,13 +105,13 @@ export default {
- +
diff --git a/db/post_migrate/20250527170705_async_remove_idx_ci_job_variables_on_partition_id_job_id.rb b/db/post_migrate/20250527170705_async_remove_idx_ci_job_variables_on_partition_id_job_id.rb new file mode 100644 index 00000000000..33c7de59935 --- /dev/null +++ b/db/post_migrate/20250527170705_async_remove_idx_ci_job_variables_on_partition_id_job_id.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AsyncRemoveIdxCiJobVariablesOnPartitionIdJobId < Gitlab::Database::Migration[2.3] + milestone '18.1' + + TABLE_NAME = :ci_job_variables + INDEX_NAME = :index_ci_job_variables_on_partition_id_job_id + COLUMNS = [:partition_id, :job_id] + + # TODO: Index to be destroyed synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/544929 + def up + prepare_async_index_removal TABLE_NAME, COLUMNS, name: INDEX_NAME + end + + def down + unprepare_async_index TABLE_NAME, COLUMNS, name: INDEX_NAME + end +end diff --git a/db/schema_migrations/20250527170705 b/db/schema_migrations/20250527170705 new file mode 100644 index 00000000000..6a206c3b8e9 --- /dev/null +++ b/db/schema_migrations/20250527170705 @@ -0,0 +1 @@ +896e1bab1741d053b090890c71e2f5cea31d41e8532ffee8782e41bfce8c8add \ No newline at end of file diff --git a/doc/administration/get_started.md b/doc/administration/get_started.md index 2e31644844d..9cc37f972da 100644 --- a/doc/administration/get_started.md +++ b/doc/administration/get_started.md @@ -20,15 +20,15 @@ and back up GitLab. Authentication is the first step in making your installation secure. -- [Enforce two-factor authentication (2FA) for all users](../security/two_factor_authentication.md). We highly recommended 2FA for GitLab Self-Managed instances. +- [Enforce two-factor authentication (2FA) for all users](../security/two_factor_authentication.md). You should use 2FA for GitLab Self-Managed instances. - Ensure users do the following: - Choose a strong, secure password. If possible, store it in a password management system. - - If it is not configured for everyone, enable [two-factor authentication (2FA)](../user/profile/account/two_factor_authentication.md) for your account. + - If it is not configured for everyone, turn on [two-factor authentication (2FA)](../user/profile/account/two_factor_authentication.md) for your account. This one-time secret code is an additional safeguard that keeps intruders out, even if they have your password. - Add a backup email. If you lose access to your account, the GitLab Support team can help you more quickly. - Save or print your recovery codes. If you can't access your authentication device, you can use these recovery codes to sign in to your GitLab account. - - Add [an SSH key](../user/ssh.md) to your profile. You can generate new recovery codes as needed with SSH. - - Enable [personal access tokens](../user/profile/personal_access_tokens.md). When using 2FA, you can use these tokens to access the GitLab API. + - Add [an SSH key](../user/ssh.md) to your profile. You can generate recovery codes as needed with SSH. + - Create [personal access tokens](../user/profile/personal_access_tokens.md). When you use 2FA, you can use these tokens to access the GitLab API. ## Projects and groups @@ -48,7 +48,7 @@ Get started: - [Add members](../user/group/_index.md#add-users-to-a-group) to the group. - Create a [subgroup](../user/group/subgroups/_index.md#create-a-subgroup). - [Add members](../user/group/subgroups/_index.md#subgroup-membership) to the subgroup. -- Enable [external authorization control](settings/external_authorization.md#configuration). +- Turn on [external authorization control](settings/external_authorization.md#configuration). **More resources** @@ -60,10 +60,10 @@ Get started: ## Import projects -You may need to import projects from external sources like GitHub, Bitbucket, or another instance of GitLab. Many external sources can be imported into GitLab. +You might have to import projects from external sources like GitHub, Bitbucket, or another instance of GitLab. Many external sources can be imported into GitLab. - Review the [GitLab projects documentation](../user/project/_index.md). -- Consider [repository mirroring](../user/project/repository/mirror/_index.md), an [alternative to project migrations](../ci/ci_cd_for_external_repos/_index.md). +- Consider [Repository Mirroring](../user/project/repository/mirror/_index.md), an [alternative to project migrations](../ci/ci_cd_for_external_repos/_index.md). - Check out our [migration index](../user/project/import/_index.md) for documentation on common migration paths. - Schedule your project exports with our [import/export API](../api/project_import_export.md#schedule-an-export). @@ -82,18 +82,18 @@ While this isn't an exhaustive list, following these steps gives you a solid sta - Use a long root password, stored in a vault. - Install trusted SSL certificate and establish a process for renewal and revocation. -- [Configure SSH key restrictions](../security/ssh_keys_restrictions.md) per your organization's guidelines. -- [Disable new sign-ups](settings/sign_up_restrictions.md#disable-new-sign-ups). +- [Configure SSH key restrictions](../security/ssh_keys_restrictions.md) according to your organization's guidelines. +- [Turn off new sign-ups](settings/sign_up_restrictions.md#disable-new-sign-ups). - Require email confirmation. - Set password length limit, configure SSO or SAML user management. - Limit email domains if allowing sign-up. - Require two-factor authentication (2FA). -- [Disable password authentication](settings/sign_in_restrictions.md#password-authentication-enabled) for Git over HTTPS. +- [Turn off password authentication](settings/sign_in_restrictions.md#password-authentication-enabled) for Git over HTTPS. - Set up [email notification for unknown sign-ins](settings/sign_in_restrictions.md#email-notification-for-unknown-sign-ins). - Configure [user and IP rate limits](https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/#user-and-ip-rate-limits). - Limit [webhooks local access](https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/#webhooks). - Set [rate limits for protected paths](settings/protected_paths.md). -- Sign up for [Security Alerts](https://about.gitlab.com/company/preference-center/) from the Communication Preference Center. +- Subscribe to [Security Alerts](https://about.gitlab.com/company/preference-center/) from the Communication Preference Center. - Keep track of security best practices on our [blog page](https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/). ## Monitor GitLab performance @@ -104,7 +104,7 @@ Unlike other monitoring solutions (for example, Zabbix or New Relic), Prometheus - [Prometheus](monitoring/prometheus/_index.md) captures [these GitLab metrics](monitoring/prometheus/gitlab_metrics.md#metrics-available). - Learn more about GitLab [bundled software metrics](monitoring/prometheus/_index.md#bundled-software-metrics). -- Prometheus and its exporters are on by default. However, you need to [configure the service](monitoring/prometheus/_index.md#configuring-prometheus). +- Prometheus and its exporters are on by default. However, you must [configure the service](monitoring/prometheus/_index.md#configuring-prometheus). - Find out why [application performance metrics](https://about.gitlab.com/blog/2020/05/07/working-with-performance-metrics/) matter. - Integrate Grafana to [build visual dashboards](https://youtu.be/f4R7s0An1qE) based on performance metrics. @@ -134,7 +134,7 @@ GitLab provides backup methods to keep your data safe and recoverable. Whether y The routine differs, depending on whether you deployed with the Linux package or the Helm chart. -When backing up (single node) GitLab server installed using the Linux package, you can use a single Rake task. +To back up a single-node installation that uses the Linux package, you can use a single Rake task. Learn about [backing up Linux package or Helm variations](backup_restore/_index.md). This process backs up your entire instance, but does not back up the configuration files. Ensure those are backed up separately. @@ -174,18 +174,18 @@ All backups are encrypted. After 90 days, backups are deleted. You should not use [direct transfer](../user/group/import/_index.md) or [project export files](../user/project/settings/import_export.md) to back up your data. -Using project export files for backups does not always work, and not all items are exported. +Project export files do not always work for data backups, and not all items are exported. {{< /alert >}} ### Alternative backup strategies -In some situations the Rake task for backups may not be the most optimal solution. Here are some +In some situations the Rake task for backups might not be the most optimal solution. Here are some [alternatives](backup_restore/_index.md) to consider if the Rake task does not work for you. #### Option 1: File system snapshot -If your GitLab server contains a lot of Git repository data, you may find the GitLab backup script to be too slow. It can be especially slow when backing up to an offsite location. +If your GitLab server contains a lot of Git repository data, you might find the GitLab backup script to be too slow. It can be especially slow when backing up to an offsite location. Slowness typically starts at a Git repository data size of around 200 GB. In this case, you might consider using file system snapshots as part of your backup strategy. For example, consider a GitLab server with the following components: @@ -195,7 +195,7 @@ For example, consider a GitLab server with the following components: The EC2 instance meets the requirements for an application data backup by taking an EBS snapshot. The backup includes all repositories, uploads, and PostgreSQL data. -In general, if you're running GitLab on a virtualized server, you can create VM snapshots of the entire GitLab server. +If you're running GitLab on a virtualized server, you can create VM snapshots of the entire GitLab server. It is common for a VM snapshot to require you to power down the server. #### Option 2: GitLab Geo diff --git a/doc/administration/moderate_users.md b/doc/administration/moderate_users.md index 88d2afa216a..95ba25a877f 100644 --- a/doc/administration/moderate_users.md +++ b/doc/administration/moderate_users.md @@ -229,6 +229,9 @@ When this feature is enabled, GitLab runs a daily job to deactivate the dormant A maximum of 100,000 users can be deactivated per day. +By default, users receive an email notification when their account is deactivated. +You can disable [user deactivation emails](settings/email.md#user-deactivation-emails). + {{< alert type="note" >}} GitLab generated bots are excluded from the automatic deactivation of dormant users. diff --git a/doc/administration/postgresql/replication_and_failover.md b/doc/administration/postgresql/replication_and_failover.md index 75725d9c2ff..38440eb0816 100644 --- a/doc/administration/postgresql/replication_and_failover.md +++ b/doc/administration/postgresql/replication_and_failover.md @@ -1056,6 +1056,15 @@ Considering these, you should carefully plan your PostgreSQL upgrade: sudo gitlab-ctl pg-upgrade ``` +1. Ensure that the compatible versions of `pg_dump` and `pg_restore` are used + on the GitLab Rails instance to avoid version mismatch errors when performing + a backup or restore. You can do this by specifying the PostgreSQL version + in `/etc/gitlab/gitlab.rb` on the Rails instance: + + ```shell + postgresql['version'] = 16 + ``` + If issues are encountered upgrading the replicas, [there is a troubleshooting section](replication_and_failover_troubleshooting.md#postgresql-major-version-upgrade-fails-on-a-patroni-replica) that might be the solution. diff --git a/doc/development/database/foreign_keys.md b/doc/development/database/foreign_keys.md index 627a3a89b29..83e0e63bcb1 100644 --- a/doc/development/database/foreign_keys.md +++ b/doc/development/database/foreign_keys.md @@ -510,9 +510,16 @@ only use this suffix for associations between two tables. If you want to reference an ID on a third party platform the `_xid` suffix is recommended. The spec `spec/db/schema_spec.rb` tests if all columns with the `_id` suffix -have a foreign key constraint. So if that spec fails, don't add the column to -`IGNORED_FK_COLUMNS`, but instead add the FK constraint, or consider naming it -differently. +have a foreign key constraint. If that spec fails, add the column to +`ignored_fk_columns_map` if the column fits any of the two criteria: + +1. The column references another table, such as the two tables belong to +[GitLab schemas](multiple_databases.md#gitlab-schema) that don't +allow Foreign Keys between them. +1. The foreign key is replaced by a [Loose Foreign Key](loose_foreign_keys.md) for performance reasons. +1. The column represents a [polymorphic relationship](polymorphic_associations.md). Note that polymorphic associations should not be used. +1. The column is not meant to reference another table. For example, it's common to have `partition_id` +for partitioned tables. ## Dependent removals diff --git a/lib/gitlab/database/schema_helpers.rb b/lib/gitlab/database/schema_helpers.rb index e40096d2047..ec2bd9f4318 100644 --- a/lib/gitlab/database/schema_helpers.rb +++ b/lib/gitlab/database/schema_helpers.rb @@ -20,6 +20,14 @@ module Gitlab execute("ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL") end + def reset_all_trigger_functions(table_name) + triggers = find_table_triggers(table_name) + + triggers.each do |trigger| + reset_trigger_function(trigger['function_name']) + end + end + def function_exists?(name) !!connection.select_value("SELECT 1 FROM pg_proc WHERE proname = '#{name}'") end @@ -136,6 +144,21 @@ module Gitlab def optional_clause(flag, clause) flag ? clause : "" end + + def find_table_triggers(table_name) + schema_qualified_table = "#{quote_table_name(current_schema)}.#{quote_table_name(table_name)}" + + triggers_query = <<~SQL + SELECT DISTINCT + p.proname AS function_name + FROM pg_trigger tr + JOIN pg_proc p ON tr.tgfoid = p.oid + WHERE tr.tgisinternal IS FALSE + AND tr.tgrelid = '#{schema_qualified_table}'::regclass + SQL + + select_all(triggers_query).to_a + end end end end diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index 841efb663aa..378fd7a8b20 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -25,8 +25,9 @@ RSpec.describe 'Database schema', }.with_indifferent_access.freeze end - # List of columns historically missing a FK, don't add more columns + # List of columns, ending with `_id` but missing a FK # See: https://docs.gitlab.com/ee/development/database/foreign_keys.html#naming-foreign-keys + # TODO: Automate this to reduce the list of exceptions: https://gitlab.com/gitlab-org/gitlab/-/issues/544795 let(:ignored_fk_columns_map) do { abuse_reports: %w[reporter_id user_id], diff --git a/spec/frontend/search/results/components/app_spec.js b/spec/frontend/search/results/components/app_spec.js index 08b08fa2275..e79b76ec314 100644 --- a/spec/frontend/search/results/components/app_spec.js +++ b/spec/frontend/search/results/components/app_spec.js @@ -101,7 +101,7 @@ describe('GlobalSearchResultsApp', () => { beforeEach(async () => { createComponent({ initialState: { - query: { scope: 'blobs' }, + query: { scope: 'blobs', search: 'foo' }, searchType: 'zoekt', navigation: MOCK_NAVIGATION_DATA, }, diff --git a/spec/lib/gitlab/database/schema_helpers_spec.rb b/spec/lib/gitlab/database/schema_helpers_spec.rb index c9b40e9b238..9f63fe26f12 100644 --- a/spec/lib/gitlab/database/schema_helpers_spec.rb +++ b/spec/lib/gitlab/database/schema_helpers_spec.rb @@ -34,4 +34,79 @@ RSpec.describe Gitlab::Database::SchemaHelpers, feature_category: :database do expect(recorder.log).to include(/ALTER FUNCTION "existing_trigger_function" RESET ALL/) end end + + describe '#reset_all_trigger_functions' do + let(:table_name) { '_test_table_for_triggers' } + let(:triggers) { [] } + + before do + connection.execute(<<~SQL) + CREATE TABLE #{table_name} ( + id serial PRIMARY KEY + ); + SQL + + triggers.pluck(:function).uniq.each do |function_name| + migration_context.create_trigger_function(function_name) { "RETURN NEW;" } + end + + triggers.each do |trigger| + migration_context.create_trigger(table_name, trigger[:name], trigger[:function], + fires: 'BEFORE INSERT OR UPDATE') + end + end + + context 'when no triggers exist' do + let(:triggers) { [] } + + it 'does not reset any trigger functions' do + expect(migration_context).not_to receive(:reset_trigger_function) + migration_context.reset_all_trigger_functions(table_name) + end + end + + context 'when one trigger exists' do + let(:triggers) do + [ + { name: 'test_trigger_1', function: 'test_function_1' } + ] + end + + it 'resets the single trigger function' do + expect(migration_context).to receive(:reset_trigger_function).with('test_function_1').once.and_call_original + migration_context.reset_all_trigger_functions(table_name) + end + end + + context 'when multiple triggers exist' do + let(:triggers) do + [ + { name: 'test_trigger_1', function: 'test_function_1' }, + { name: 'test_trigger_2', function: 'test_function_2' } + ] + end + + it 'resets multiple trigger functions' do + expect(migration_context).to receive(:reset_trigger_function).with('test_function_1').once.and_call_original + expect(migration_context).to receive(:reset_trigger_function).with('test_function_2').once.and_call_original + migration_context.reset_all_trigger_functions(table_name) + end + end + + context 'when different triggers use the same function' do + let(:shared_function) { 'shared_trigger_function' } + + let(:triggers) do + [ + { name: 'test_trigger_1', function: shared_function }, + { name: 'test_trigger_2', function: shared_function } + ] + end + + it 'resets the function only once' do + expect(migration_context).to receive(:reset_trigger_function).with(shared_function).once.and_call_original + migration_context.reset_all_trigger_functions(table_name) + end + end + end end