Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
ba557e8fea
commit
7503415f61
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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';
|
||||
|
|
@ -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,
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
import initCycleAnalytics from '~/cycle_analytics';
|
||||
import initCycleAnalytics from '~/analytics/cycle_analytics';
|
||||
|
||||
initCycleAnalytics();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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. |
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
$$;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
$$;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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;
|
||||
|
|
@ -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';
|
||||
|
||||
|
|
@ -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', () => {
|
||||
|
|
@ -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;
|
||||
|
|
@ -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,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import * as getters from '~/cycle_analytics/store/getters';
|
||||
import * as getters from '~/analytics/cycle_analytics/store/getters';
|
||||
|
||||
import {
|
||||
allowedStages,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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;
|
||||
|
|
@ -4,7 +4,7 @@ import {
|
|||
formatMedianValues,
|
||||
filterStagesByHiddenStatus,
|
||||
buildCycleAnalyticsInitialData,
|
||||
} from '~/cycle_analytics/utils';
|
||||
} from '~/analytics/cycle_analytics/utils';
|
||||
import {
|
||||
selectedStage,
|
||||
allowedStages,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue