Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-12-01 03:07:25 +00:00
parent ba557e8fea
commit 7503415f61
57 changed files with 583 additions and 163 deletions

View File

@ -3160,7 +3160,6 @@ Layout/LineLength:
- 'lib/gitlab/database/reindexing/coordinator.rb'
- 'lib/gitlab/database/reindexing/grafana_notifier.rb'
- 'lib/gitlab/database/reindexing/reindex_concurrently.rb'
- 'lib/gitlab/database/schema_cleaner.rb'
- 'lib/gitlab/database/schema_migrations/context.rb'
- 'lib/gitlab/database/similarity_score.rb'
- 'lib/gitlab/database/with_lock_retries.rb'

View File

@ -5,9 +5,9 @@ import { getCookie, setCookie } from '~/lib/utils/common_utils';
import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue';
import { VSA_METRICS_GROUPS } from '~/analytics/shared/constants';
import { toYmd } from '~/analytics/shared/utils';
import PathNavigation from '~/cycle_analytics/components/path_navigation.vue';
import StageTable from '~/cycle_analytics/components/stage_table.vue';
import ValueStreamFilters from '~/cycle_analytics/components/value_stream_filters.vue';
import PathNavigation from '~/analytics/cycle_analytics/components/path_navigation.vue';
import StageTable from '~/analytics/cycle_analytics/components/stage_table.vue';
import ValueStreamFilters from '~/analytics/cycle_analytics/components/value_stream_filters.vue';
import UrlSync from '~/vue_shared/components/url_sync.vue';
import { __ } from '~/locale';
import { SUMMARY_METRICS_REQUEST, METRICS_REQUESTS } from '../constants';

View File

@ -8,7 +8,7 @@ import {
GlTable,
GlBadge,
} from '@gitlab/ui';
import FormattedStageCount from '~/cycle_analytics/components/formatted_stage_count.vue';
import FormattedStageCount from '~/analytics/cycle_analytics/components/formatted_stage_count.vue';
import { __ } from '~/locale';
import Tracking from '~/tracking';
import {

View File

@ -3,7 +3,7 @@ import {
extractFilterQueryParameters,
extractPaginationQueryParameters,
} from '~/analytics/shared/utils';
import Translate from '../vue_shared/translate';
import Translate from '~/vue_shared/translate';
import CycleAnalytics from './components/base.vue';
import createStore from './store';
import { buildCycleAnalyticsInitialData } from './utils';

View File

@ -1,7 +1,7 @@
import {
PAGINATION_SORT_FIELD_END_EVENT,
PAGINATION_SORT_DIRECTION_DESC,
} from '~/cycle_analytics/constants';
} from '~/analytics/cycle_analytics/constants';
export default () => ({
id: null,

View File

@ -1,3 +1,3 @@
import initCycleAnalytics from '~/cycle_analytics';
import initCycleAnalytics from '~/analytics/cycle_analytics';
initCycleAnalytics();

View File

@ -2334,9 +2334,7 @@ class User < ApplicationRecord
end
def check_password_weakness
if Feature.enabled?(:block_weak_passwords) &&
password.present? &&
Security::WeakPasswords.weak_for_user?(password, self)
if password.present? && Security::WeakPasswords.weak_for_user?(password, self)
errors.add(:password, _('must not contain commonly used combinations of words and letters'))
end
end

View File

@ -1,8 +0,0 @@
---
name: block_weak_passwords
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86310
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/363445
milestone: '15.4'
type: development
group: group::authentication and authorization
default_enabled: false

View File

@ -1,8 +0,0 @@
---
name: dast_api_scanner
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73564
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345837
milestone: '14.7'
type: development
group: group::dynamic analysis
default_enabled: true

View File

@ -0,0 +1,8 @@
---
name: automatic_lock_writes_on_table
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99287
rollout_issue_url:
milestone: '15.7'
type: ops
group: group::pods
default_enabled: false

View File

@ -14,7 +14,7 @@ A short downtime is expected for all methods.
## Omnibus installations
If you have used the [Omnibus packages](https://about.gitlab.com/install/) to install GitLab, then
If you have used the [Omnibus packages](https://about.gitlab.com/install/) to install GitLab,
you should already have `gitlab-ctl` in your `PATH`.
`gitlab-ctl` interacts with the Omnibus packages and can be used to restart the
@ -88,16 +88,14 @@ sudo gitlab-ctl reconfigure
Reconfiguring GitLab should occur in the event that something in its
configuration (`/etc/gitlab/gitlab.rb`) has changed.
When you run this command, [Chef](https://www.chef.io/products/chef-infra), the underlying configuration management
application that powers Omnibus GitLab, makes sure that all things like directories,
permissions, and services are in place and in the same shape that they were
initially shipped.
When you run `gitlab-ctl reconfigure`, [Chef](https://www.chef.io/products/chef-infra),
the underlying configuration management application that powers Omnibus GitLab, runs some checks.
Chef ensures directories, permissions, and services are in place and working.
It also [restarts GitLab components](#how-to-restart-gitlab)
where needed, if any of their configuration files have changed.
Chef also [restarts GitLab components](#how-to-restart-gitlab) if any of their configuration files have changed.
If you manually edit any files in `/var/opt/gitlab` that are managed by Chef,
running reconfigure reverts the changes and restarts the services that
running `reconfigure` reverts the changes and restarts the services that
depend on those files.
## Installations from source
@ -118,7 +116,7 @@ This should restart Puma, Sidekiq, GitLab Workhorse, and [Mailroom](reply_by_ema
## Helm chart installations
There is no single command to restart the entire GitLab application installed via
There is no single command to restart the entire GitLab application installed through
the [cloud-native Helm chart](https://docs.gitlab.com/charts/). Usually, it should be
enough to restart a specific component separately (for example, `gitaly`, `puma`,
`workhorse`, or `gitlab-shell`) by deleting all the pods related to it:

View File

@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Uploads administration **(FREE SELF)**
Uploads represent all user data that may be sent to GitLab as a single file. As an example, avatars and notes' attachments are uploads. Uploads are integral to GitLab functionality, and therefore cannot be disabled.
Uploads represent all user data that may be sent to GitLab as a single file. For example, avatars and note attachments are uploads. Uploads are integral to GitLab functionality and therefore cannot be disabled.
## Using local storage
@ -14,15 +14,15 @@ This is the default configuration. To change the location where the uploads are
stored locally, use the steps in this section based on your installation method:
NOTE:
For historical reasons, instance level uploads (for example the [favicon](../user/admin_area/appearance.md#favicon)) are stored into a base directory,
which by default is `uploads/-/system`. It is strongly discouraged to change the base
directory on an existing GitLab installation.
For historical reasons, uploads for the whole instance (for example the [favicon](../user/admin_area/appearance.md#favicon)) are stored in a base directory,
which by default is `uploads/-/system`. Changing the base
directory on an existing GitLab installation is strongly discouraged.
**In Omnibus GitLab installations:**
_The uploads are stored by default in `/var/opt/gitlab/gitlab-rails/uploads`._
1. To change the storage path for example to `/mnt/storage/uploads`, edit
1. To change the storage path, for example to `/mnt/storage/uploads`, edit
`/etc/gitlab/gitlab.rb` and add the following line:
```ruby
@ -38,7 +38,7 @@ _The uploads are stored by default in `/var/opt/gitlab/gitlab-rails/uploads`._
_The uploads are stored by default in
`/home/git/gitlab/public/uploads`._
1. To change the storage path for example to `/mnt/storage/uploads`, edit
1. To change the storage path, for example to `/mnt/storage/uploads`, edit
`/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
```yaml
@ -57,7 +57,7 @@ This configuration relies on valid AWS credentials to be configured already.
[Read more about using object storage with GitLab](object_storage.md).
We recommend using the [consolidated object storage settings](object_storage.md#consolidated-object-storage-configuration). The following instructions apply to the original configuration format.
You should use the [consolidated object storage settings](object_storage.md#consolidated-object-storage-configuration). The following instructions apply to the original configuration format.
### Object Storage Settings

View File

@ -2098,8 +2098,8 @@ Input type: `DastSiteProfileCreateInput`
| <a id="mutationdastsiteprofilecreatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the site profile belongs to. |
| <a id="mutationdastsiteprofilecreateprofilename"></a>`profileName` | [`String!`](#string) | Name of the site profile. |
| <a id="mutationdastsiteprofilecreaterequestheaders"></a>`requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. |
| <a id="mutationdastsiteprofilecreatescanfilepath"></a>`scanFilePath` | [`String`](#string) | File Path or URL used as input for the scan method. Will not be saved or updated if `dast_api_scanner` feature flag is disabled. |
| <a id="mutationdastsiteprofilecreatescanmethod"></a>`scanMethod` | [`DastScanMethodType`](#dastscanmethodtype) | Scan method by the scanner. Is not saved or updated if `dast_api_scanner` feature flag is disabled. |
| <a id="mutationdastsiteprofilecreatescanfilepath"></a>`scanFilePath` | [`String`](#string) | File Path or URL used as input for the scan method. |
| <a id="mutationdastsiteprofilecreatescanmethod"></a>`scanMethod` | [`DastScanMethodType`](#dastscanmethodtype) | Scan method by the scanner. |
| <a id="mutationdastsiteprofilecreatetargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | Type of target to be scanned. |
| <a id="mutationdastsiteprofilecreatetargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be scanned. |
@ -2146,8 +2146,8 @@ Input type: `DastSiteProfileUpdateInput`
| <a id="mutationdastsiteprofileupdateid"></a>`id` | [`DastSiteProfileID!`](#dastsiteprofileid) | ID of the site profile to be updated. |
| <a id="mutationdastsiteprofileupdateprofilename"></a>`profileName` | [`String!`](#string) | Name of the site profile. |
| <a id="mutationdastsiteprofileupdaterequestheaders"></a>`requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. |
| <a id="mutationdastsiteprofileupdatescanfilepath"></a>`scanFilePath` | [`String`](#string) | File Path or URL used as input for the scan method. Will not be saved or updated if `dast_api_scanner` feature flag is disabled. |
| <a id="mutationdastsiteprofileupdatescanmethod"></a>`scanMethod` | [`DastScanMethodType`](#dastscanmethodtype) | Scan method by the scanner. Is not saved or updated if `dast_api_scanner` feature flag is disabled. |
| <a id="mutationdastsiteprofileupdatescanfilepath"></a>`scanFilePath` | [`String`](#string) | File Path or URL used as input for the scan method. |
| <a id="mutationdastsiteprofileupdatescanmethod"></a>`scanMethod` | [`DastScanMethodType`](#dastscanmethodtype) | Scan method by the scanner. |
| <a id="mutationdastsiteprofileupdatetargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | Type of target to be scanned. |
| <a id="mutationdastsiteprofileupdatetargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be scanned. |
@ -11708,8 +11708,8 @@ Represents a DAST Site Profile.
| <a id="dastsiteprofileprofilename"></a>`profileName` | [`String`](#string) | Name of the site profile. |
| <a id="dastsiteprofilereferencedinsecuritypolicies"></a>`referencedInSecurityPolicies` | [`[String!]`](#string) | List of security policy names that are referencing given project. |
| <a id="dastsiteprofilerequestheaders"></a>`requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. |
| <a id="dastsiteprofilescanfilepath"></a>`scanFilePath` | [`String`](#string) | Scan File Path used as input for the scanner. Will always return `null` if `dast_api_scanner` feature flag is disabled. |
| <a id="dastsiteprofilescanmethod"></a>`scanMethod` | [`DastScanMethodType`](#dastscanmethodtype) | Scan method used by the scanner. Always returns `null` if `dast_api_scanner` feature flag is disabled. |
| <a id="dastsiteprofilescanfilepath"></a>`scanFilePath` | [`String`](#string) | Scan File Path used as input for the scanner. |
| <a id="dastsiteprofilescanmethod"></a>`scanMethod` | [`DastScanMethodType`](#dastscanmethodtype) | Scan method used by the scanner. |
| <a id="dastsiteprofiletargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | Type of target to be scanned. |
| <a id="dastsiteprofiletargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be scanned. |
| <a id="dastsiteprofileuserpermissions"></a>`userPermissions` | [`DastSiteProfilePermissions!`](#dastsiteprofilepermissions) | Permissions for the current user on the resource. |

View File

@ -61,12 +61,8 @@ Self-managed installations can configure the following additional password requi
## Block weak passwords
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23610) in GitLab 15.4 [with a flag](../../administration/feature_flags.md) named `block_weak_passwords`, weak passwords aren't accepted. Disabled by default on self-managed.
> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/363445) on GitLab.com.
FLAG:
On self-managed GitLab, by default blocking weak passwords is not available. To make it available, ask an administrator
to [enable the feature flag](../../administration/feature_flags.md) named `block_weak_passwords`. On GitLab.com, this
feature is available but can be configured by GitLab.com administrators only.
> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/363445) on GitLab.com in GitLab 15.6.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/363445) and enabled on self-managed in GitLab 15.7. Feature flag `block_weak_passwords` removed.
GitLab disallows weak passwords. Your password is considered weak when it:

View File

@ -6,7 +6,9 @@
# Each table / view needs to have assigned gitlab_schema. Names supported today:
#
# - gitlab_shared - defines a set of tables that are found on all databases (data accessed is dependent on connection)
# - gitlab_main / gitlab_ci - defines a set of tables that can only exist on a given database
# - gitlab_main / gitlab_ci - defines a set of tables that can only exist on a given application database
# - gitlab_geo - defines a set of tables that can only exist on the geo database
# - gitlab_internal - defines all internal tables of Rails and PostgreSQL
#
# Tables for the purpose of tests should be prefixed with `_test_my_table_name`
@ -55,7 +57,7 @@ module Gitlab
tables.map { |table| table_schema(table) }.to_set
end
def self.table_schema(name)
def self.table_schema(name, undefined: true)
schema_name, table_name = name.split('.', 2) # Strip schema name like: `public.`
# Most of names do not have schemas, ensure that this is table
@ -84,6 +86,8 @@ module Gitlab
return :gitlab_ci if table_name.start_with?('_test_gitlab_ci_')
return :gitlab_geo if table_name.start_with?('_test_gitlab_geo_')
# All tables that start with `_test_` without a following schema are shared and ignored
return :gitlab_shared if table_name.start_with?('_test_')
@ -91,7 +95,7 @@ module Gitlab
return :gitlab_internal if table_name.start_with?('pg_')
# When undefined it's best to return a unique name so that we don't incorrectly assume that 2 undefined schemas belong on the same database
:"undefined_#{table_name}"
undefined ? :"undefined_#{table_name}" : nil
end
def self.tables_to_schema

View File

@ -51,6 +51,10 @@ module Gitlab
include Gitlab::Database::MigrationHelpers::RestrictGitlabSchema
end
class V2_1 < V2_0 # rubocop:disable Naming/ClassAndModuleCamelCase
include Gitlab::Database::MigrationHelpers::AutomaticLockWritesOnTables
end
def self.[](version)
version = version.to_s
name = "V#{version.tr('.', '_')}"
@ -61,7 +65,7 @@ module Gitlab
# The current version to be used in new migrations
def self.current_version
2.0
2.1
end
end
end

View File

@ -0,0 +1,74 @@
# frozen_string_literal: true
module Gitlab
module Database
module MigrationHelpers
module AutomaticLockWritesOnTables
extend ActiveSupport::Concern
included do
class_attribute :skip_automatic_lock_on_writes
end
def exec_migration(connection, direction)
return super if %w[main ci].exclude?(Gitlab::Database.db_config_name(connection))
return super if automatic_lock_on_writes_disabled?
# This compares the tables only on the `public` schema. Partitions are not affected
tables = connection.tables
super
new_tables = connection.tables - tables
new_tables.each do |table_name|
lock_writes_on_table(connection, table_name) if should_lock_writes_on_table?(table_name)
end
end
private
def automatic_lock_on_writes_disabled?
# Feature flags are set on the main database, see tables features/feature_gates.
# That is why we switch the ActiveRecord::Base.connection temporarily here back to the 'main' database
# for the cases when the migration is targeting another database, like the 'ci' database.
with_restored_connection_stack do |_|
Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.with_suppressed do
skip_automatic_lock_on_writes ||
Gitlab::Utils.to_boolean(ENV['SKIP_AUTOMATIC_LOCK_ON_WRITES']) ||
Feature.disabled?(:automatic_lock_writes_on_table, type: :ops)
end
end
end
def should_lock_writes_on_table?(table_name)
# currently gitlab_schema represents only present existing tables, this is workaround for deleted tables
# that should be skipped as they will be removed in a future migration.
return false if Gitlab::Database::GitlabSchema::DELETED_TABLES[table_name]
table_schema = Gitlab::Database::GitlabSchema.table_schema(table_name.to_s, undefined: false)
if table_schema.nil?
error_message = <<~ERROR
No gitlab_schema is defined for the table #{table_name}. Please consider
adding it to the file config 'lib/gitlab/database/gitlab_schemas.yml'
ERROR
raise error_message
end
return false unless %i[gitlab_main gitlab_ci].include?(table_schema)
Gitlab::Database.gitlab_schemas_for_connection(connection).exclude?(table_schema)
end
def lock_writes_on_table(connection, table_name)
database_name = Gitlab::Database.db_config_name(connection)
LockWritesManager.new(
table_name: table_name,
connection: connection,
database_name: database_name,
logger: Logger.new($stdout)
).lock_writes
end
end
end
end
end

View File

@ -25,7 +25,23 @@ module Gitlab
# The intention here is to not introduce an assumption about the standard schema,
# unless we have a good reason to do so.
structure.gsub!(/public\.(\w+)/, '\1')
structure.gsub!(/CREATE EXTENSION IF NOT EXISTS (\w+) WITH SCHEMA public;/, 'CREATE EXTENSION IF NOT EXISTS \1;')
structure.gsub!(
/CREATE EXTENSION IF NOT EXISTS (\w+) WITH SCHEMA public;/,
'CREATE EXTENSION IF NOT EXISTS \1;'
)
# Table lock-writes triggers should not be added to the schema
# These triggers are added by the rake task gitlab:db:lock_writes for a decomposed database.
structure.gsub!(
%r{
^CREATE.TRIGGER.gitlab_schema_write_trigger_\w+
\s
BEFORE.INSERT.OR.DELETE.OR.UPDATE.OR.TRUNCATE.ON.\w+
\s
FOR.EACH.STATEMENT.EXECUTE.FUNCTION.gitlab_schema_prevent_write\(\);$
}x,
''
)
structure.gsub!(/\n{3,}/, "\n\n")

View File

@ -55,7 +55,7 @@
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "3.11.0",
"@gitlab/ui": "49.11.2",
"@gitlab/ui": "50.1.2",
"@gitlab/visual-review-tools": "1.7.3",
"@gitlab/web-ide": "0.0.1-dev-20221114183058",
"@rails/actioncable": "6.1.4-7",

View File

@ -9,9 +9,10 @@ module RuboCop
include MigrationHelpers
ENFORCED_SINCE = 2021_09_02_00_00_00
CURRENT_DATABASE_MIGRATION_CLASS = 'Gitlab::Database::Migration[2.1]'
MSG_INHERIT = 'Don\'t inherit from ActiveRecord::Migration but use Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.'
MSG_INCLUDE = 'Don\'t include migration helper modules directly. Inherit from Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.'
MSG_INHERIT = 'Don\'t inherit from ActiveRecord::Migration but use Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.'
MSG_INCLUDE = 'Don\'t include migration helper modules directly. Inherit from Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.'
ACTIVERECORD_MIGRATION_CLASS = 'ActiveRecord::Migration'

View File

@ -486,34 +486,22 @@ RSpec.describe RegistrationsController do
subject { post(:create, params: new_user_params) }
context 'when block_weak_passwords is enabled (default)' do
it 'renders the form with errors' do
expect { subject }.not_to change(User, :count)
it 'renders the form with errors' do
expect { subject }.not_to change(User, :count)
expect(controller.current_user).to be_nil
expect(response).to render_template(:new)
expect(response.body).to include(_('Password must not contain commonly used combinations of words and letters'))
end
it 'tracks the error' do
subject
expect_snowplow_event(
category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
action: 'track_weak_password_error',
controller: 'RegistrationsController',
method: 'create'
)
end
expect(controller.current_user).to be_nil
expect(response).to render_template(:new)
expect(response.body).to include(_('Password must not contain commonly used combinations of words and letters'))
end
context 'when block_weak_passwords is disabled' do
before do
stub_feature_flags(block_weak_passwords: false)
end
it 'permits weak passwords' do
expect { subject }.to change(User, :count).by(1)
end
it 'tracks the error' do
subject
expect_snowplow_event(
category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
action: 'track_weak_password_error',
controller: 'RegistrationsController',
method: 'create'
)
end
end

View File

@ -77,3 +77,17 @@ ALTER TABLE ONLY public.abuse_reports
CREATE INDEX index_abuse_reports_on_user_id ON public.abuse_reports USING btree (user_id);
CREATE TRIGGER gitlab_schema_write_trigger_for_users BEFORE INSERT OR DELETE OR UPDATE OR TRUNCATE ON users FOR EACH STATEMENT EXECUTE FUNCTION gitlab_schema_prevent_write();
CREATE FUNCTION gitlab_schema_prevent_write() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF COALESCE(NULLIF(current_setting(CONCAT('lock_writes.', TG_TABLE_NAME), true), ''), 'true') THEN
RAISE EXCEPTION 'Table: "%" is write protected within this Gitlab database.', TG_TABLE_NAME
USING ERRCODE = 'modifying_sql_data_not_permitted',
HINT = 'Make sure you are using the right database connection';
END IF;
RETURN NEW;
END
$$;

View File

@ -24,3 +24,16 @@ ALTER TABLE ONLY abuse_reports
ADD CONSTRAINT abuse_reports_pkey PRIMARY KEY (id);
CREATE INDEX index_abuse_reports_on_user_id ON abuse_reports USING btree (user_id);
CREATE FUNCTION gitlab_schema_prevent_write() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF COALESCE(NULLIF(current_setting(CONCAT('lock_writes.', TG_TABLE_NAME), true), ''), 'true') THEN
RAISE EXCEPTION 'Table: "%" is write protected within this Gitlab database.', TG_TABLE_NAME
USING ERRCODE = 'modifying_sql_data_not_permitted',
HINT = 'Make sure you are using the right database connection';
END IF;
RETURN NEW;
END
$$;

View File

@ -4,12 +4,12 @@ import Vue from 'vue';
import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue';
import BaseComponent from '~/cycle_analytics/components/base.vue';
import PathNavigation from '~/cycle_analytics/components/path_navigation.vue';
import StageTable from '~/cycle_analytics/components/stage_table.vue';
import ValueStreamFilters from '~/cycle_analytics/components/value_stream_filters.vue';
import { NOT_ENOUGH_DATA_ERROR } from '~/cycle_analytics/constants';
import initState from '~/cycle_analytics/store/state';
import BaseComponent from '~/analytics/cycle_analytics/components/base.vue';
import PathNavigation from '~/analytics/cycle_analytics/components/path_navigation.vue';
import StageTable from '~/analytics/cycle_analytics/components/stage_table.vue';
import ValueStreamFilters from '~/analytics/cycle_analytics/components/value_stream_filters.vue';
import { NOT_ENOUGH_DATA_ERROR } from '~/analytics/cycle_analytics/constants';
import initState from '~/analytics/cycle_analytics/store/state';
import {
transformedProjectStagePathData,
selectedStage,

View File

@ -7,8 +7,8 @@ import {
filterMilestones,
filterLabels,
} from 'jest/vue_shared/components/filtered_search_bar/store/modules/filters/mock_data';
import FilterBar from '~/cycle_analytics/components/filter_bar.vue';
import storeConfig from '~/cycle_analytics/store';
import FilterBar from '~/analytics/cycle_analytics/components/filter_bar.vue';
import storeConfig from '~/analytics/cycle_analytics/store';
import * as commonUtils from '~/lib/utils/common_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import {

View File

@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import Component from '~/cycle_analytics/components/formatted_stage_count.vue';
import Component from '~/analytics/cycle_analytics/components/formatted_stage_count.vue';
describe('Formatted Stage Count', () => {
let wrapper = null;

View File

@ -12,7 +12,7 @@ import {
PAGINATION_TYPE,
PAGINATION_SORT_DIRECTION_DESC,
PAGINATION_SORT_FIELD_END_EVENT,
} from '~/cycle_analytics/constants';
} from '~/analytics/cycle_analytics/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { getDateInPast } from '~/lib/utils/datetime_utility';

View File

@ -2,7 +2,7 @@ import { GlPath, GlSkeletonLoader } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import Component from '~/cycle_analytics/components/path_navigation.vue';
import Component from '~/analytics/cycle_analytics/components/path_navigation.vue';
import { transformedProjectStagePathData, selectedStage } from './mock_data';
describe('Project PathNavigation', () => {

View File

@ -3,8 +3,8 @@ import { shallowMount, mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import StageTable from '~/cycle_analytics/components/stage_table.vue';
import { PAGINATION_SORT_FIELD_DURATION } from '~/cycle_analytics/constants';
import StageTable from '~/analytics/cycle_analytics/components/stage_table.vue';
import { PAGINATION_SORT_FIELD_DURATION } from '~/analytics/cycle_analytics/constants';
import { issueEvents, issueStage, reviewStage, reviewEvents } from './mock_data';
let wrapper = null;

View File

@ -1,8 +1,8 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/cycle_analytics/store/actions';
import * as getters from '~/cycle_analytics/store/getters';
import * as actions from '~/analytics/cycle_analytics/store/actions';
import * as getters from '~/analytics/cycle_analytics/store/getters';
import httpStatusCodes from '~/lib/utils/http_status';
import {
allowedStages,

View File

@ -1,4 +1,4 @@
import * as getters from '~/cycle_analytics/store/getters';
import * as getters from '~/analytics/cycle_analytics/store/getters';
import {
allowedStages,

View File

@ -1,10 +1,10 @@
import { useFakeDate } from 'helpers/fake_date';
import * as types from '~/cycle_analytics/store/mutation_types';
import mutations from '~/cycle_analytics/store/mutations';
import * as types from '~/analytics/cycle_analytics/store/mutation_types';
import mutations from '~/analytics/cycle_analytics/store/mutations';
import {
PAGINATION_SORT_FIELD_END_EVENT,
PAGINATION_SORT_DIRECTION_DESC,
} from '~/cycle_analytics/constants';
} from '~/analytics/cycle_analytics/constants';
import {
selectedStage,
rawIssueEvents,

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils';
import TotalTime from '~/cycle_analytics/components/total_time.vue';
import TotalTime from '~/analytics/cycle_analytics/components/total_time.vue';
describe('TotalTime', () => {
let wrapper = null;

View File

@ -4,7 +4,7 @@ import {
formatMedianValues,
filterStagesByHiddenStatus,
buildCycleAnalyticsInitialData,
} from '~/cycle_analytics/utils';
} from '~/analytics/cycle_analytics/utils';
import {
selectedStage,
allowedStages,

View File

@ -1,8 +1,8 @@
import { shallowMount } from '@vue/test-utils';
import Daterange from '~/analytics/shared/components/daterange.vue';
import ProjectsDropdownFilter from '~/analytics/shared/components/projects_dropdown_filter.vue';
import FilterBar from '~/cycle_analytics/components/filter_bar.vue';
import ValueStreamFilters from '~/cycle_analytics/components/value_stream_filters.vue';
import FilterBar from '~/analytics/cycle_analytics/components/filter_bar.vue';
import ValueStreamFilters from '~/analytics/cycle_analytics/components/value_stream_filters.vue';
import {
createdAfter as startDate,
createdBefore as endDate,

View File

@ -3,7 +3,7 @@
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CreateModelGeneratorTestFoos < Gitlab::Database::Migration[2.0]
class CreateModelGeneratorTestFoos < Gitlab::Database::Migration[2.1]
# When using the methods "add_concurrent_index" or "remove_concurrent_index"
# you must disable the use of transactions
# as these methods can not run in an existing transaction.

View File

@ -0,0 +1,333 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::MigrationHelpers::AutomaticLockWritesOnTables,
:reestablished_active_record_base, query_analyzers: false do
using RSpec::Parameterized::TableSyntax
let(:schema_class) { Class.new(Gitlab::Database::Migration[2.1]) }
let(:gitlab_main_table_name) { :_test_gitlab_main_table }
let(:gitlab_ci_table_name) { :_test_gitlab_ci_table }
let(:gitlab_geo_table_name) { :_test_gitlab_geo_table }
let(:gitlab_shared_table_name) { :_test_table }
before do
stub_feature_flags(automatic_lock_writes_on_table: true)
reconfigure_db_connection(model: ActiveRecord::Base, config_model: config_model)
end
shared_examples 'does not lock writes on table' do |config_model|
let(:config_model) { config_model }
it 'allows deleting records from the table' do
allow_next_instance_of(Gitlab::Database::LockWritesManager) do |instance|
expect(instance).not_to receive(:lock_writes)
end
run_migration
expect do
migration_class.connection.execute("DELETE FROM #{table_name}")
end.not_to raise_error
end
end
shared_examples 'locks writes on table' do |config_model|
let(:config_model) { config_model }
it 'errors on deleting' do
allow_next_instance_of(Gitlab::Database::LockWritesManager) do |instance|
expect(instance).to receive(:lock_writes).and_call_original
end
run_migration
expect do
migration_class.connection.execute("DELETE FROM #{table_name}")
end.to raise_error(ActiveRecord::StatementInvalid, /is write protected/)
end
end
context 'when executing create_table migrations' do
let(:create_gitlab_main_table_migration_class) { create_table_migration(gitlab_main_table_name) }
let(:create_gitlab_ci_table_migration_class) { create_table_migration(gitlab_ci_table_name) }
let(:create_gitlab_shared_table_migration_class) { create_table_migration(gitlab_shared_table_name) }
context 'when single database' do
let(:config_model) { Gitlab::Database.database_base_models[:main] }
before do
skip_if_multiple_databases_are_setup
end
it 'does not lock any newly created tables' do
allow_next_instance_of(Gitlab::Database::LockWritesManager) do |instance|
expect(instance).not_to receive(:lock_writes)
end
create_gitlab_main_table_migration_class.migrate(:up)
create_gitlab_ci_table_migration_class.migrate(:up)
create_gitlab_shared_table_migration_class.migrate(:up)
expect do
create_gitlab_main_table_migration_class.connection.execute("DELETE FROM #{gitlab_main_table_name}")
create_gitlab_ci_table_migration_class.connection.execute("DELETE FROM #{gitlab_ci_table_name}")
create_gitlab_shared_table_migration_class.connection.execute("DELETE FROM #{gitlab_shared_table_name}")
end.not_to raise_error
end
end
context 'when multiple databases' do
before do
skip_if_multiple_databases_not_setup
end
let(:skip_automatic_lock_on_writes) { false }
let(:migration_class) { create_table_migration(table_name, skip_automatic_lock_on_writes) }
let(:run_migration) { migration_class.migrate(:up) }
context 'for creating a gitlab_main table' do
let(:table_name) { gitlab_main_table_name }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main]
it_behaves_like 'locks writes on table', Gitlab::Database.database_base_models[:ci]
context 'when table listed as a deleted table' do
before do
stub_const("Gitlab::Database::GitlabSchema::DELETED_TABLES", { table_name.to_s => :gitlab_main })
end
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:ci]
end
context 'when the migration skips automatic locking of tables' do
let(:skip_automatic_lock_on_writes) { true }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:ci]
end
context 'when the SKIP_AUTOMATIC_LOCK_ON_WRITES feature flag is set' do
before do
stub_env('SKIP_AUTOMATIC_LOCK_ON_WRITES' => 'true')
end
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:ci]
end
context 'when the automatic_lock_writes_on_table feature flag is disabled' do
before do
stub_feature_flags(automatic_lock_writes_on_table: false)
end
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:ci]
end
end
context 'for creating a gitlab_ci table' do
let(:table_name) { gitlab_ci_table_name }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:ci]
it_behaves_like 'locks writes on table', Gitlab::Database.database_base_models[:main]
context 'when table listed as a deleted table' do
before do
stub_const("Gitlab::Database::GitlabSchema::DELETED_TABLES", { table_name.to_s => :gitlab_ci })
end
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main]
end
context 'when the migration skips automatic locking of tables' do
let(:skip_automatic_lock_on_writes) { true }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main]
end
context 'when the SKIP_AUTOMATIC_LOCK_ON_WRITES feature flag is set' do
before do
stub_env('SKIP_AUTOMATIC_LOCK_ON_WRITES' => 'true')
end
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main]
end
context 'when the automatic_lock_writes_on_table feature flag is disabled' do
before do
stub_feature_flags(automatic_lock_writes_on_table: false)
end
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main]
end
end
context 'for creating gitlab_shared table' do
let(:table_name) { gitlab_shared_table_name }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main]
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:ci]
end
context 'for creating a gitlab_geo table' do
before do
skip unless geo_configured?
end
let(:table_name) { gitlab_geo_table_name }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:geo]
end
context 'for creating an unknown gitlab_schema table' do
let(:table_name) { :foobar } # no gitlab_schema defined
let(:config_model) { Gitlab::Database.database_base_models[:main] }
it "raises an error about undefined gitlab_schema" do
expected_error_message = <<~ERROR
No gitlab_schema is defined for the table #{table_name}. Please consider
adding it to the file config 'lib/gitlab/database/gitlab_schemas.yml'
ERROR
expect { run_migration }.to raise_error(expected_error_message)
end
end
end
end
context 'when renaming a table' do
before do
skip_if_multiple_databases_not_setup
create_table_migration(old_table_name).migrate(:up) # create the table first before renaming it
end
let(:migration_class) { rename_table_migration(old_table_name, table_name) }
let(:run_migration) { migration_class.migrate(:up) }
context 'when a gitlab_main table' do
let(:old_table_name) { gitlab_main_table_name }
let(:table_name) { :_test_gitlab_main_new_table }
let(:database_base_model) { Gitlab::Database.database_base_models[:main] }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main]
it_behaves_like 'locks writes on table', Gitlab::Database.database_base_models[:ci]
end
context 'when a gitlab_ci table' do
let(:old_table_name) { gitlab_ci_table_name }
let(:table_name) { :_test_gitlab_ci_new_table }
let(:database_base_model) { Gitlab::Database.database_base_models[:ci] }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:ci]
it_behaves_like 'locks writes on table', Gitlab::Database.database_base_models[:main]
end
end
context 'when reversing drop_table migrations' do
let(:drop_gitlab_main_table_migration_class) { drop_table_migration(gitlab_main_table_name) }
let(:drop_gitlab_ci_table_migration_class) { drop_table_migration(gitlab_ci_table_name) }
let(:drop_gitlab_shared_table_migration_class) { drop_table_migration(gitlab_shared_table_name) }
context 'when single database' do
let(:config_model) { Gitlab::Database.database_base_models[:main] }
before do
skip_if_multiple_databases_are_setup
end
it 'does not lock any newly created tables' do
allow_next_instance_of(Gitlab::Database::LockWritesManager) do |instance|
expect(instance).not_to receive(:lock_writes)
end
drop_gitlab_main_table_migration_class.connection.execute("CREATE TABLE #{gitlab_main_table_name}()")
drop_gitlab_ci_table_migration_class.connection.execute("CREATE TABLE #{gitlab_ci_table_name}()")
drop_gitlab_shared_table_migration_class.connection.execute("CREATE TABLE #{gitlab_shared_table_name}()")
drop_gitlab_main_table_migration_class.migrate(:up)
drop_gitlab_ci_table_migration_class.migrate(:up)
drop_gitlab_shared_table_migration_class.migrate(:up)
drop_gitlab_main_table_migration_class.migrate(:down)
drop_gitlab_ci_table_migration_class.migrate(:down)
drop_gitlab_shared_table_migration_class.migrate(:down)
expect do
drop_gitlab_main_table_migration_class.connection.execute("DELETE FROM #{gitlab_main_table_name}")
drop_gitlab_ci_table_migration_class.connection.execute("DELETE FROM #{gitlab_ci_table_name}")
drop_gitlab_shared_table_migration_class.connection.execute("DELETE FROM #{gitlab_shared_table_name}")
end.not_to raise_error
end
end
context 'when multiple databases' do
before do
skip_if_multiple_databases_not_setup
migration_class.connection.execute("CREATE TABLE #{table_name}()")
migration_class.migrate(:up)
end
let(:migration_class) { drop_table_migration(table_name) }
let(:run_migration) { migration_class.migrate(:down) }
context 'for re-creating a gitlab_main table' do
let(:table_name) { gitlab_main_table_name }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main]
it_behaves_like 'locks writes on table', Gitlab::Database.database_base_models[:ci]
end
context 'for re-creating a gitlab_ci table' do
let(:table_name) { gitlab_ci_table_name }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:ci]
it_behaves_like 'locks writes on table', Gitlab::Database.database_base_models[:main]
end
context 'for re-creating a gitlab_shared table' do
let(:table_name) { gitlab_shared_table_name }
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main]
it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:ci]
end
end
end
def create_table_migration(table_name, skip_lock_on_writes = false)
migration_class = Class.new(schema_class) do
class << self; attr_accessor :table_name; end
def change
create_table self.class.table_name
end
end
migration_class.skip_automatic_lock_on_writes = skip_lock_on_writes
migration_class.tap { |klass| klass.table_name = table_name }
end
def rename_table_migration(old_table_name, new_table_name)
migration_class = Class.new(schema_class) do
class << self; attr_accessor :old_table_name, :new_table_name; end
def change
rename_table self.class.old_table_name, self.class.new_table_name
end
end
migration_class.tap do |klass|
klass.old_table_name = old_table_name
klass.new_table_name = new_table_name
end
end
def drop_table_migration(table_name)
migration_class = Class.new(schema_class) do
class << self; attr_accessor :table_name; end
def change
drop_table(self.class.table_name) {}
end
end
migration_class.tap { |klass| klass.table_name = table_name }
end
def geo_configured?
!!ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'geo')
end
end

View File

@ -14,7 +14,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers::RestrictGitlabSchema, query_a
describe '#restrict_gitlab_migration' do
it 'invalid schema raises exception' do
expect { schema_class.restrict_gitlab_migration gitlab_schema: :gitlab_non_exisiting }
expect { schema_class.restrict_gitlab_migration gitlab_schema: :gitlab_non_existing }
.to raise_error /Unknown 'gitlab_schema:/
end
@ -102,7 +102,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers::RestrictGitlabSchema, query_a
"does add index to projects in gitlab_main and gitlab_ci" => {
migration: ->(klass) do
def change
# Due to running in transactin we cannot use `add_concurrent_index`
# Due to running in transaction we cannot use `add_concurrent_index`
add_index :projects, :hidden
end
end,

View File

@ -19,6 +19,15 @@ RSpec.describe Gitlab::Database::SchemaCleaner do
expect(subject).not_to match(/public\.\w+/)
end
it 'cleans up all the gitlab_schema_prevent_write table triggers' do
expect(subject).not_to match(/CREATE TRIGGER gitlab_schema_write_trigger_for_\w+/)
expect(subject).not_to match(/FOR EACH STATEMENT EXECUTE FUNCTION gitlab_schema_prevent_write/)
end
it 'keeps the lock_writes trigger functions' do
expect(subject).to match(/CREATE FUNCTION gitlab_schema_prevent_write/)
end
it 'cleans up the full schema as expected (blackbox test with example)' do
expected_schema = fixture_file(File.join('gitlab', 'database', 'structure_example_cleaned.sql'))

View File

@ -345,52 +345,33 @@ RSpec.describe User do
context 'check_password_weakness' do
let(:weak_password) { "qwertyuiop" }
context 'when feature flag is disabled' do
before do
stub_feature_flags(block_weak_passwords: false)
end
it 'does not add an error when password is weak' do
expect(Security::WeakPasswords).not_to receive(:weak_for_user?)
user.password = weak_password
expect(user).to be_valid
end
it 'checks for password weakness when password changes' do
expect(Security::WeakPasswords).to receive(:weak_for_user?)
.with(weak_password, user).and_call_original
user.password = weak_password
expect(user).not_to be_valid
end
context 'when feature flag is enabled' do
before do
stub_feature_flags(block_weak_passwords: true)
end
it 'adds an error when password is weak' do
user.password = weak_password
expect(user).not_to be_valid
expect(user.errors).to be_of_kind(:password, 'must not contain commonly used combinations of words and letters')
end
it 'checks for password weakness when password changes' do
expect(Security::WeakPasswords).to receive(:weak_for_user?)
.with(weak_password, user).and_call_original
user.password = weak_password
expect(user).not_to be_valid
end
it 'is valid when password is not weak' do
user.password = ::User.random_password
expect(user).to be_valid
end
it 'adds an error when password is weak' do
user.password = weak_password
expect(user).not_to be_valid
expect(user.errors).to be_of_kind(:password, 'must not contain commonly used combinations of words and letters')
end
it 'is valid when weak password was already set' do
user = build(:user, password: weak_password)
user.save!(validate: false)
it 'is valid when password is not weak' do
user.password = ::User.random_password
expect(user).to be_valid
end
expect(Security::WeakPasswords).not_to receive(:weak_for_user?)
it 'is valid when weak password was already set' do
user = build(:user, password: weak_password)
user.save!(validate: false)
expect(Security::WeakPasswords).not_to receive(:weak_for_user?)
# Change an unrelated value
user.name = "Example McExampleFace"
expect(user).to be_valid
end
# Change an unrelated value
user.name = "Example McExampleFace"
expect(user).to be_valid
end
end
end

View File

@ -6,7 +6,7 @@ require_relative '../../../../rubocop/cop/migration/versioned_migration_class'
RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass do
let(:migration) do
<<~SOURCE
class TestMigration < Gitlab::Database::Migration[1.0]
class TestMigration < Gitlab::Database::Migration[2.1]
def up
execute 'select 1'
end
@ -49,23 +49,23 @@ RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass do
it 'adds an offence if inheriting from ActiveRecord::Migration' do
expect_offense(<<~RUBY)
class MyMigration < ActiveRecord::Migration[6.1]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration but use Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration but use Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
end
RUBY
end
it 'adds an offence if including Gitlab::Database::MigrationHelpers directly' do
expect_offense(<<~RUBY)
class MyMigration < Gitlab::Database::Migration[1.0]
class MyMigration < Gitlab::Database::Migration[2.1]
include Gitlab::Database::MigrationHelpers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't include migration helper modules directly. Inherit from Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't include migration helper modules directly. Inherit from Gitlab::Database::Migration[2.1] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
end
RUBY
end
it 'excludes ActiveRecord classes defined inside the migration' do
expect_no_offenses(<<~RUBY)
class TestMigration < Gitlab::Database::Migration[1.0]
class TestMigration < Gitlab::Database::Migration[2.1]
class TestModel < ApplicationRecord
end

View File

@ -1125,10 +1125,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.11.0.tgz#91e8e25583cddef48c0c79175203e5b0a4eaa519"
integrity sha512-1cJu1WXPoOHfGgv5fT3nmA9cgAQ3U1Fm/oMSVYUgBxU35R0I8W704GMLsIZwBuQ/S/Ow7WLwIkoOhLb/spNKPg==
"@gitlab/ui@49.11.2":
version "49.11.2"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-49.11.2.tgz#290bba7a3d4682365ad81747cf54a2f9927526c1"
integrity sha512-qu5qcl+4niYBCPIZS9ZU0i1h/IGL4ZOp4hDsEAIUFGJg9Sp0TBmwdjwKJQbvnexDS3xs1eSBzi+kQ57H+c9wQQ==
"@gitlab/ui@50.1.2":
version "50.1.2"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-50.1.2.tgz#d24100b6d6fc77c7708d9139f09e2142b1292d31"
integrity sha512-bRzF9SkDGY2WrmIuFriFLyRMym2ydAeJB71FCXfHvhei3EWAeaiZv5oEB/a4oMN8nmt0rt4GrPQ5PpGiQKoKfQ==
dependencies:
"@popperjs/core" "^2.11.2"
bootstrap-vue "2.20.1"