Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-03-17 06:08:05 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-17 06:08:05 +0300
commite6ac8e40c2c0fa317c319469d5102eec8be7becd (patch)
tree409145db12c32c6d3e342aeada2e3015d631dc07
parent149436d2a55408accbf67f9301c0bfa3c6706fe6 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/pages/dashboard/todos/index/todos.js8
-rw-r--r--app/models/analytics/cycle_analytics/aggregation.rb12
-rw-r--r--app/views/dashboard/todos/_todo.html.haml6
-rw-r--r--app/views/dashboard/todos/index.html.haml4
-rw-r--r--config/feature_flags/development/vsa_consistency_worker.yml8
-rw-r--r--config/initializers/1_settings.rb3
-rw-r--r--doc/administration/audit_events.md3
-rw-r--r--doc/administration/monitoring/performance/performance_bar.md3
-rw-r--r--doc/administration/pages/index.md9
-rw-r--r--doc/development/documentation/testing.md8
-rw-r--r--doc/development/emails.md3
-rw-r--r--doc/user/application_security/dependency_scanning/index.md3
-rw-r--r--doc/user/compliance/compliance_report/index.md40
-rw-r--r--lib/gitlab/http_connection_adapter.rb5
-rw-r--r--lib/gitlab/import_export/command_line_util.rb28
-rw-r--r--lib/gitlab/metrics/subscribers/active_record.rb20
-rw-r--r--lib/gitlab/url_blocker.rb28
-rw-r--r--lib/peek/views/active_record.rb8
-rw-r--r--spec/lib/gitlab/import_export/command_line_util_spec.rb133
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb67
-rw-r--r--spec/lib/peek/views/active_record_spec.rb12
-rw-r--r--spec/models/analytics/cycle_analytics/aggregation_spec.rb23
-rw-r--r--spec/support/enable_multiple_database_metrics_by_default.rb8
-rw-r--r--spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb35
24 files changed, 338 insertions, 139 deletions
diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
index cabb1b24ae6..c4bbbdcd8ec 100644
--- a/app/assets/javascripts/pages/dashboard/todos/index/todos.js
+++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
@@ -96,6 +96,8 @@ export default class Todos {
target.setAttribute('disabled', true);
target.classList.add('disabled');
+ target.querySelector('.gl-spinner-container').classList.add('gl-mr-2');
+
axios[target.dataset.method](target.dataset.href)
.then(({ data }) => {
this.updateRowState(target);
@@ -118,6 +120,8 @@ export default class Todos {
target.removeAttribute('disabled');
target.classList.remove('disabled');
+ target.querySelector('.gl-spinner-container').classList.remove('gl-mr-2');
+
if (isInactive === true) {
restoreBtn.classList.add('hidden');
doneBtn.classList.remove('hidden');
@@ -140,6 +144,8 @@ export default class Todos {
target.setAttribute('disabled', true);
target.classList.add('disabled');
+ target.querySelector('.gl-spinner-container').classList.add('gl-mr-2');
+
axios[target.dataset.method](target.dataset.href, {
ids: this.todo_ids,
})
@@ -163,6 +169,8 @@ export default class Todos {
target.removeAttribute('disabled');
target.classList.remove('disabled');
+ target.querySelector('.gl-spinner-container').classList.remove('gl-mr-2');
+
this.todo_ids = target === markAllDoneBtn ? data.updated_ids : [];
undoAllBtn.classList.toggle('hidden');
markAllDoneBtn.classList.toggle('hidden');
diff --git a/app/models/analytics/cycle_analytics/aggregation.rb b/app/models/analytics/cycle_analytics/aggregation.rb
index 279938511fd..44d2dc369f7 100644
--- a/app/models/analytics/cycle_analytics/aggregation.rb
+++ b/app/models/analytics/cycle_analytics/aggregation.rb
@@ -7,7 +7,7 @@ class Analytics::CycleAnalytics::Aggregation < ApplicationRecord
validates :incremental_runtimes_in_seconds, :incremental_processed_records, :last_full_run_runtimes_in_seconds, :last_full_run_processed_records, presence: true, length: { maximum: 10 }, allow_blank: true
- scope :priority_order, -> { order('last_incremental_run_at ASC NULLS FIRST') }
+ scope :priority_order, -> (column_to_sort = :last_incremental_run_at) { order(arel_table[column_to_sort].asc.nulls_first) }
scope :enabled, -> { where('enabled IS TRUE') }
def estimated_next_run_at
@@ -55,17 +55,17 @@ class Analytics::CycleAnalytics::Aggregation < ApplicationRecord
connection.select_value("(#{max})")
end
- def self.load_batch(last_run_at, batch_size = 100)
+ def self.load_batch(last_run_at, column_to_query = :last_incremental_run_at, batch_size = 100)
last_run_at_not_set = Analytics::CycleAnalytics::Aggregation
.enabled
- .where(last_incremental_run_at: nil)
- .priority_order
+ .where(column_to_query => nil)
+ .priority_order(column_to_query)
.limit(batch_size)
last_run_at_before = Analytics::CycleAnalytics::Aggregation
.enabled
- .where('last_incremental_run_at < ?', last_run_at)
- .priority_order
+ .where(arel_table[column_to_query].lt(last_run_at))
+ .priority_order(column_to_query)
.limit(batch_size)
Analytics::CycleAnalytics::Aggregation
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index 766900b7a99..c932b416b66 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -50,12 +50,12 @@
.todo-actions.gl-ml-3
- if todo.pending?
= link_to dashboard_todo_path(todo), method: :delete, class: 'gl-button btn btn-default btn-loading d-flex align-items-center js-done-todo', data: { href: dashboard_todo_path(todo) } do
- = gl_loading_icon(inline: true, css_class: 'gl-mr-2')
+ = gl_loading_icon(inline: true)
Done
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'gl-button btn btn-default btn-loading d-flex align-items-center js-undo-todo hidden', data: { href: restore_dashboard_todo_path(todo) } do
- = gl_loading_icon(inline: true, css_class: 'gl-mr-2')
+ = gl_loading_icon(inline: true)
Undo
- else
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'gl-button btn btn-default btn-loading d-flex align-items-center js-add-todo', data: { href: restore_dashboard_todo_path(todo) } do
- = gl_loading_icon(inline: true, css_class: 'gl-mr-2')
+ = gl_loading_icon(inline: true)
Add a to do
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index 7a329fb34a9..cd177db3ed0 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -22,10 +22,10 @@
- if @allowed_todos.any?(&:pending?)
.gl-mr-3
= link_to destroy_all_dashboard_todos_path(todos_filter_params), class: 'gl-button btn btn-default btn-loading align-items-center js-todos-mark-all', method: :delete, data: { href: destroy_all_dashboard_todos_path(todos_filter_params) } do
- = gl_loading_icon(inline: true, css_class: 'gl-mr-2')
+ = gl_loading_icon(inline: true)
= s_("Todos|Mark all as done")
= link_to bulk_restore_dashboard_todos_path, class: 'gl-button btn btn-default btn-loading align-items-center js-todos-undo-all hidden', method: :patch , data: { href: bulk_restore_dashboard_todos_path(todos_filter_params) } do
- = gl_loading_icon(inline: true, css_class: 'gl-mr-2')
+ = gl_loading_icon(inline: true)
= s_("Todos|Undo mark all as done")
.todos-filters
diff --git a/config/feature_flags/development/vsa_consistency_worker.yml b/config/feature_flags/development/vsa_consistency_worker.yml
new file mode 100644
index 00000000000..d880f38af69
--- /dev/null
+++ b/config/feature_flags/development/vsa_consistency_worker.yml
@@ -0,0 +1,8 @@
+---
+name: vsa_consistency_worker
+introduced_by_url:
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/355709
+milestone: '14.9'
+type: development
+group: group::optimize
+default_enabled: false
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 844aff1b060..fe5bf2c8717 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -628,6 +628,9 @@ Gitlab.ee do
Settings.cron_jobs['analytics_cycle_analytics_incremental_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['analytics_cycle_analytics_incremental_worker']['cron'] ||= '*/10 * * * *'
Settings.cron_jobs['analytics_cycle_analytics_incremental_worker']['job_class'] = 'Analytics::CycleAnalytics::IncrementalWorker'
+ Settings.cron_jobs['analytics_cycle_analytics_consistency_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['analytics_cycle_analytics_consistency_worker']['cron'] ||= '*/30 * * * *'
+ Settings.cron_jobs['analytics_cycle_analytics_consistency_worker']['job_class'] = 'Analytics::CycleAnalytics::ConsistencyWorker'
Settings.cron_jobs['active_user_count_threshold_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['active_user_count_threshold_worker']['cron'] ||= '0 12 * * *'
Settings.cron_jobs['active_user_count_threshold_worker']['job_class'] = 'ActiveUserCountThresholdWorker'
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index de2cd9c1f77..955f7a6a830 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -44,6 +44,9 @@ There are two kinds of events logged:
- Instance events scoped to the whole GitLab instance, used by your Compliance team to
perform formal audits.
+NOTE:
+Some events are recorded and available only as [streaming audit events](audit_event_streaming.md).
+
### Impersonation data
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/536) in GitLab 13.0.
diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md
index 93098e43544..bc311f73dfe 100644
--- a/doc/administration/monitoring/performance/performance_bar.md
+++ b/doc/administration/monitoring/performance/performance_bar.md
@@ -30,8 +30,7 @@ From left to right, the performance bar displays:
is enabled. It shows which server role was used for the query.
"Primary" means that the query was sent to the read/write primary server.
"Replica" means it was sent to a read-only replica.
- - **Configuration name**: shows up only when the
- `GITLAB_MULTIPLE_DATABASE_METRICS` environment variable is set. This is
+ - **Configuration name**: this is
used to distinguish between different databases configured for different
GitLab features. The name shown is the same name used to configure database
connections in GitLab.
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index be1ec290c95..56ccf70d169 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -1388,15 +1388,20 @@ This can happen if your `gitlab-secrets.json` file is out of date between GitLab
Pages. Follow steps 8-10 of [Running GitLab Pages on a separate server](#running-gitlab-pages-on-a-separate-server),
in all of your GitLab Pages instances.
-### Intermittent 502 errors when using an AWS Network Load Balancer and GitLab Pages is running on multiple application servers
+### Intermittent 502 errors when using an AWS Network Load Balancer and GitLab Pages
Connections will time out when using a Network Load Balancer with client IP preservation enabled and [the request is looped back to the source server](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-troubleshooting.html#loopback-timeout).
This can happen to GitLab instances with multiple servers
-running both the core GitLab application and GitLab Pages.
+running both the core GitLab application and GitLab Pages. This can also happen when a single
+container is running both the core GitLab application and GitLab Pages.
AWS [recommends using an IP target type](https://aws.amazon.com/premiumsupport/knowledge-center/target-connection-fails-load-balancer/)
to resolve this issue.
+Turning off [client IP preservation](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#client-ip-preservation)
+may resolve this issue when the core GitLab application and GitLab Pages run on the same host or
+container.
+
### 500 error with `securecookie: failed to generate random iv` and `Failed to save the session`
This problem most likely results from an [out-dated operating system](../package_information/supported_os.md#os-versions-that-are-no-longer-supported).
diff --git a/doc/development/documentation/testing.md b/doc/development/documentation/testing.md
index 2c97b5e2aff..49fe0aff3c6 100644
--- a/doc/development/documentation/testing.md
+++ b/doc/development/documentation/testing.md
@@ -270,12 +270,10 @@ build pipelines:
[used (see `variables:` section)](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/.gitlab-ci.yml) when building
the `image:docs-lint-markdown`.
-1. Install [`vale`](https://github.com/errata-ai/vale/releases). For example, to install using
- `brew` for macOS, run:
+1. Install [`vale`](https://github.com/errata-ai/vale/releases). To install for:
- ```shell
- brew install vale
- ```
+ - macOS using `brew`, run: `brew install vale`.
+ - Linux, use your distribution's package manager or a [released binary](https://github.com/errata-ai/vale/releases).
These tools can be [integrated with your code editor](#configure-editors).
diff --git a/doc/development/emails.md b/doc/development/emails.md
index 5361282334f..b8e390988bd 100644
--- a/doc/development/emails.md
+++ b/doc/development/emails.md
@@ -13,6 +13,9 @@ If a mailer argument needs to be added or removed, it is important to ensure
both backward and forward compatibility. Adhere to the Sidekiq steps for
[changing the arguments for a worker](sidekiq/compatibility_across_updates.md#changing-the-arguments-for-a-worker).
+The same applies to a new mailer method, or a new mailer. If you introduce either,
+follow the steps for [adding new workers](sidekiq/compatibility_across_updates.md#adding-new-workers).
+
In the following example from [`NotificationService`](https://gitlab.com/gitlab-org/gitlab/-/blob/33ccb22e4fc271dbaac94b003a7a1a2915a13441/app/services/notification_service.rb#L74)
adding or removing an argument in this mailer's definition may cause problems
during deployment before all Rails and Sidekiq nodes have the updated code.
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 881c1fb8c78..a4a7e6703ab 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -69,7 +69,8 @@ stages in the `.gitlab-ci.yml` file, the `test` stage is required.
To run dependency scanning jobs, by default, you need GitLab Runner with the
[`docker`](https://docs.gitlab.com/runner/executors/docker.html) or
[`kubernetes`](https://docs.gitlab.com/runner/install/kubernetes.html) executor.
-If you're using the shared runners on GitLab.com, this is enabled by default.
+If you're using the shared runners on GitLab.com, this is enabled by default. The analyzer images
+provided are for the Linux/amd64 architecture.
WARNING:
If you use your own runners, make sure your installed version of Docker
diff --git a/doc/user/compliance/compliance_report/index.md b/doc/user/compliance/compliance_report/index.md
index bd4bdb21f35..27783a063da 100644
--- a/doc/user/compliance/compliance_report/index.md
+++ b/doc/user/compliance/compliance_report/index.md
@@ -108,7 +108,8 @@ The remaining records are truncated when this limit is reached.
## Merge request violations
-> Introduced in GitLab 14.6. [Deployed behind the `compliance_violations_report` flag](../../../administration/feature_flags.md). Disabled by default.
+> - Introduced in GitLab 14.6. [Deployed behind the `compliance_violations_report` flag](../../../administration/feature_flags.md). Disabled by default.
+> - GraphQL API [introduced](https://gitlab.com/groups/gitlab-org/-/epics/7222) in GitLab 14.9.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available,
@@ -123,10 +124,10 @@ that exist in projects in a specific group. For each separation of duties compli
- Reason for the compliance violation.
- A link to the merge request that caused the compliance violation.
-Merge request violations can only be access in the GitLab UI, but issues are tracking adding:
+Merge request violations can be accessed:
-- [A GraphQL type to allow retrieval of compliance violations](https://gitlab.com/gitlab-org/gitlab/-/issues/347325).
-- [Consuming the merge request violations GraphQL type in the user interface](https://gitlab.com/gitlab-org/gitlab/-/issues/342897).
+- In the GitLab UI.
+- Using the [GraphQL API](../../../api/graphql/reference/index.md#complianceviolation) (GitLab 14.9 and later).
### View merge request violations
@@ -134,3 +135,34 @@ To view merge request violations:
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Security & Compliance > Compliance report**.
+
+### Severity levels scale
+
+The following is a list of available violation severity levels, ranked from most to least severe:
+
+| Icon | Severity level |
+|:----------------------------------------------|:---------------|
+| **{severity-critical, 18, gl-fill-red-800}** | Critical |
+| **{severity-high, 18, gl-fill-red-600}** | High |
+| **{severity-medium, 18, gl-fill-orange-400}** | Medium |
+| **{severity-low, 18, gl-fill-orange-300}** | Low |
+| **{severity-info, 18, gl-fill-blue-400}** | Info |
+
+### Violation types
+
+The following is a list of violations that are either:
+
+- Already available.
+- Aren't available, but which we are tracking in issues.
+
+| Violation | Severity level | Category | Description | Availability |
+|:-------------------------------------|:----------------|:----------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------|
+| Author approved merge request | High | [Separation of duties](#approval-status-and-separation-of-duties) | The author of the merge request approved their own merge request. [Learn more](../../project/merge_requests/approvals/settings.md#prevent-approval-by-author). | [Unavailable](https://gitlab.com/groups/gitlab-org/-/epics/6870) |
+| Committers approved merge request | High | [Separation of duties](#approval-status-and-separation-of-duties) | The committers of the merge request approved the merge request they contributed to. [Learn more](../../project/merge_requests/approvals/settings.md#prevent-approvals-by-users-who-add-commits). | [Unavailable](https://gitlab.com/groups/gitlab-org/-/epics/6870) |
+| Fewer than two approvals | High | [Separation of duties](#approval-status-and-separation-of-duties) | The merge request was merged with fewer than two approvals. [Learn more](../../project/merge_requests/approvals/rules.md). | [Unavailable](https://gitlab.com/groups/gitlab-org/-/epics/6870) |
+| Pipeline failed | Medium | [Pipeline results](../../../ci/pipelines/index.md) | The merge requests pipeline failed and was merged. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
+| Pipeline passed with warnings | Info | [Pipeline results](../../../ci/pipelines/index.md) | The merge request pipeline passed with warnings and was merged. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
+| Code coverage down more than 10% | High | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | The code coverage report for the merge request indicates a reduction in coverage of more than 10%. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
+| Code coverage down between 5% to 10% | Medium | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | The code coverage report for the merge request indicates a reduction in coverage of between 5% to 10%. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
+| Code coverage down between 1% to 5% | Low | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | The code coverage report for the merge request indicates a reduction in coverage of between 1% to 5%. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
+| Code coverage down less than 1% | Info | [Code coverage](../../../ci/pipelines/settings.md#merge-request-test-coverage-results) | The code coverage report for the merge request indicates a reduction in coverage of less than 1%. | [Unavailable](https://gitlab.com/gitlab-org/gitlab/-/issues/346011) |
diff --git a/lib/gitlab/http_connection_adapter.rb b/lib/gitlab/http_connection_adapter.rb
index 6e3a83f08c3..002708beb3c 100644
--- a/lib/gitlab/http_connection_adapter.rb
+++ b/lib/gitlab/http_connection_adapter.rb
@@ -47,6 +47,7 @@ module Gitlab
def validate_url!(url)
Gitlab::UrlBlocker.validate!(url, allow_local_network: allow_local_requests?,
allow_localhost: allow_local_requests?,
+ allow_object_storage: allow_object_storage?,
dns_rebind_protection: dns_rebind_protection?)
rescue Gitlab::UrlBlocker::BlockedUrlError => e
raise Gitlab::HTTP::BlockedUrlError, "URL '#{url}' is blocked: #{e.message}"
@@ -56,6 +57,10 @@ module Gitlab
options.fetch(:allow_local_requests, allow_settings_local_requests?)
end
+ def allow_object_storage?
+ options.fetch(:allow_object_storage, false)
+ end
+
def dns_rebind_protection?
return false if Gitlab.http_proxy_env?
diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb
index 68d0494fbe2..2b0467d8779 100644
--- a/lib/gitlab/import_export/command_line_util.rb
+++ b/lib/gitlab/import_export/command_line_util.rb
@@ -62,23 +62,27 @@ module Gitlab
end
def download(url, upload_path, size_limit: nil)
- File.open(upload_path, 'w') do |file|
- # Download (stream) file from the uploader's location
- IO.copy_stream(
- URI.parse(url).open(progress_proc: file_size_limiter(size_limit)),
- file
- )
+ File.open(upload_path, 'wb') do |file|
+ current_size = 0
+
+ Gitlab::HTTP.get(url, stream_body: true, allow_object_storage: true) do |fragment|
+ if [301, 302, 307].include?(fragment.code)
+ Gitlab::Import::Logger.warn(message: "received redirect fragment", fragment_code: fragment.code)
+ elsif fragment.code == 200
+ current_size += fragment.bytesize
+
+ raise FileOversizedError if size_limit.present? && current_size > size_limit
+
+ file.write(fragment)
+ else
+ raise Gitlab::ImportExport::Error, "unsupported response downloading fragment #{fragment.code}"
+ end
+ end
end
rescue FileOversizedError
nil
end
- def file_size_limiter(limit)
- return if limit.blank?
-
- -> (current_size) { raise FileOversizedError if current_size > limit }
- end
-
def tar_with_options(archive:, dir:, options:)
execute_cmd(%W(tar -#{options} #{archive} -C #{dir} .))
end
diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb
index 715dd86d93c..12576cabb19 100644
--- a/lib/gitlab/metrics/subscribers/active_record.rb
+++ b/lib/gitlab/metrics/subscribers/active_record.rb
@@ -134,11 +134,7 @@ module Gitlab
:"gitlab_transaction_db_#{counter}_total"
end
- if ENV['GITLAB_MULTIPLE_DATABASE_METRICS']
- current_transaction&.increment(prometheus_key, 1, { db_config_name: db_config_name })
- else
- current_transaction&.increment(prometheus_key, 1)
- end
+ current_transaction&.increment(prometheus_key, 1, { db_config_name: db_config_name })
Gitlab::SafeRequestStore[log_key] = Gitlab::SafeRequestStore[log_key].to_i + 1
@@ -154,11 +150,7 @@ module Gitlab
def observe(histogram, event, &block)
db_config_name = db_config_name(event.payload)
- if ENV['GITLAB_MULTIPLE_DATABASE_METRICS']
- current_transaction&.observe(histogram, event.duration / 1000.0, { db_config_name: db_config_name }, &block)
- else
- current_transaction&.observe(histogram, event.duration / 1000.0, &block)
- end
+ current_transaction&.observe(histogram, event.duration / 1000.0, { db_config_name: db_config_name }, &block)
end
def current_transaction
@@ -193,11 +185,9 @@ module Gitlab
counters << compose_metric_key(metric, role)
end
- if ENV['GITLAB_MULTIPLE_DATABASE_METRICS']
- ::Gitlab::Database.db_config_names.each do |config_name|
- counters << compose_metric_key(metric, nil, config_name) # main
- counters << compose_metric_key(metric, nil, config_name + ::Gitlab::Database::LoadBalancing::LoadBalancer::REPLICA_SUFFIX) # main_replica
- end
+ ::Gitlab::Database.db_config_names.each do |config_name|
+ counters << compose_metric_key(metric, nil, config_name) # main
+ counters << compose_metric_key(metric, nil, config_name + ::Gitlab::Database::LoadBalancing::LoadBalancer::REPLICA_SUFFIX) # main_replica
end
end
diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb
index 48228ede684..60c002853b1 100644
--- a/lib/gitlab/url_blocker.rb
+++ b/lib/gitlab/url_blocker.rb
@@ -13,6 +13,7 @@ module Gitlab
# ports - Raises error if the given URL port does is not between given ports.
# allow_localhost - Raises error if URL resolves to a localhost IP address and argument is false.
# allow_local_network - Raises error if URL resolves to a link-local address and argument is false.
+ # allow_object_storage - Avoid raising an error if URL resolves to an object storage endpoint and argument is true.
# ascii_only - Raises error if URL has unicode characters and argument is true.
# enforce_user - Raises error if URL user doesn't start with alphanumeric characters and argument is true.
# enforce_sanitization - Raises error if URL includes any HTML/CSS/JS tags and argument is true.
@@ -25,6 +26,7 @@ module Gitlab
schemes: [],
allow_localhost: false,
allow_local_network: true,
+ allow_object_storage: false,
ascii_only: false,
enforce_user: false,
enforce_sanitization: false,
@@ -58,6 +60,8 @@ module Gitlab
# Allow url from the GitLab instance itself but only for the configured hostname and ports
return protected_uri_with_hostname if internal?(uri)
+ return protected_uri_with_hostname if allow_object_storage && object_storage_endpoint?(uri)
+
validate_local_request(
address_info: address_info,
allow_localhost: allow_localhost,
@@ -269,6 +273,30 @@ module Gitlab
get_port(uri) == config.gitlab_shell.ssh_port
end
+ def enabled_object_storage_endpoints
+ ObjectStoreSettings::SUPPORTED_TYPES.collect do |type|
+ section_setting = config.try(type)
+
+ next unless section_setting
+
+ object_store_setting = section_setting['object_store']
+
+ next unless object_store_setting && object_store_setting['enabled']
+
+ object_store_setting.dig('connection', 'endpoint')
+ end.compact.uniq
+ end
+
+ def object_storage_endpoint?(uri)
+ enabled_object_storage_endpoints.any? do |endpoint|
+ endpoint_uri = URI(endpoint)
+
+ uri.scheme == endpoint_uri.scheme &&
+ uri.hostname == endpoint_uri.hostname &&
+ get_port(uri) == get_port(endpoint_uri)
+ end
+ end
+
def domain_allowed?(uri)
Gitlab::UrlBlockers::UrlAllowlist.domain_allowed?(uri.normalized_host, port: get_port(uri))
end
diff --git a/lib/peek/views/active_record.rb b/lib/peek/views/active_record.rb
index 6a41de8f0b0..75346626255 100644
--- a/lib/peek/views/active_record.rb
+++ b/lib/peek/views/active_record.rb
@@ -75,14 +75,6 @@ module Peek
"Role: #{role.to_s.capitalize}"
end
-
- def format_call_details(call)
- if ENV['GITLAB_MULTIPLE_DATABASE_METRICS']
- super
- else
- super.except(:db_config_name)
- end
- end
end
end
end
diff --git a/spec/lib/gitlab/import_export/command_line_util_spec.rb b/spec/lib/gitlab/import_export/command_line_util_spec.rb
index 5f1d598e3ab..f5913da08ba 100644
--- a/spec/lib/gitlab/import_export/command_line_util_spec.rb
+++ b/spec/lib/gitlab/import_export/command_line_util_spec.rb
@@ -68,31 +68,126 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil do
end
describe '#download' do
- before do
- stub_request(:get, 'http://localhost:3000/file')
- .to_return(
- status: 200,
- body: File.open(archive),
- headers: {
- 'Content-Type' => 'application/x-tar'
- }
- )
- end
+ let(:content) { File.open('spec/fixtures/rails_sample.tif') }
+
+ context 'a non-localhost uri' do
+ before do
+ stub_request(:get, url)
+ .to_return(
+ status: status,
+ body: content
+ )
+ end
+
+ let(:url) { 'https://gitlab.com/file' }
+
+ context 'with ok status code' do
+ let(:status) { HTTP::Status::OK }
+
+ it 'gets the contents' do
+ Tempfile.create('test') do |file|
+ subject.download(url, file.path)
+ expect(file.read).to eq(File.open('spec/fixtures/rails_sample.tif').read)
+ end
+ end
+
+ it 'streams the contents via Gitlab::HTTP' do
+ expect(Gitlab::HTTP).to receive(:get).with(url, hash_including(stream_body: true))
+
+ Tempfile.create('test') do |file|
+ subject.download(url, file.path)
+ end
+ end
+
+ it 'does not get the content over the size_limit' do
+ Tempfile.create('test') do |file|
+ subject.download(url, file.path, size_limit: 300.kilobytes)
+ expect(file.read).to eq('')
+ end
+ end
+
+ it 'gets the content within the size_limit' do
+ Tempfile.create('test') do |file|
+ subject.download(url, file.path, size_limit: 400.kilobytes)
+ expect(file.read).to eq(File.open('spec/fixtures/rails_sample.tif').read)
+ end
+ end
+ end
- let(:tempfile) { Tempfile.new('test', path) }
+ %w[MOVED_PERMANENTLY FOUND TEMPORARY_REDIRECT].each do |code|
+ context "with a redirect status code #{code}" do
+ let(:status) { HTTP::Status.const_get(code, false) }
- it 'downloads the file in the given path' do
- subject.download('http://localhost:3000/file', tempfile)
+ it 'logs the redirect' do
+ expect(Gitlab::Import::Logger).to receive(:warn)
- expect(File.exist?(tempfile)).to eq(true)
- expect(tempfile.size).to eq(File.size(archive))
+ Tempfile.create('test') do |file|
+ subject.download(url, file.path)
+ end
+ end
+ end
+ end
+
+ %w[ACCEPTED UNAUTHORIZED BAD_REQUEST].each do |code|
+ context "with an invalid status code #{code}" do
+ let(:status) { HTTP::Status.const_get(code, false) }
+
+ it 'throws an error' do
+ Tempfile.create('test') do |file|
+ expect { subject.download(url, file.path) }.to raise_error(Gitlab::ImportExport::Error)
+ end
+ end
+ end
+ end
end
- it 'limit the size of the downloaded file' do
- subject.download('http://localhost:3000/file', tempfile, size_limit: 1.byte)
+ context 'a localhost uri' do
+ include StubRequests
+
+ let(:status) { HTTP::Status::OK }
+ let(:url) { "#{host}/foo/bar" }
+ let(:host) { 'http://localhost:8081' }
- expect(File.exist?(tempfile)).to eq(true)
- expect(tempfile.size).to eq(0)
+ before do
+ # Note: the hostname gets changed to an ip address due to dns_rebind_protection
+ stub_dns(url, ip_address: '127.0.0.1')
+ stub_request(:get, 'http://127.0.0.1:8081/foo/bar')
+ .to_return(
+ status: status,
+ body: content
+ )
+ end
+
+ it 'throws a blocked url error' do
+ Tempfile.create('test') do |file|
+ expect { subject.download(url, file.path) }.to raise_error((Gitlab::HTTP::BlockedUrlError))
+ end
+ end
+
+ context 'for object_storage uri' do
+ let(:enabled_object_storage_setting) do
+ {
+ 'object_store' =>
+ {
+ 'enabled' => true,
+ 'connection' => {
+ 'endpoint' => host
+ }
+ }
+ }
+ end
+
+ before do
+ allow(Settings).to receive(:external_diffs).and_return(enabled_object_storage_setting)
+ end
+
+ it 'gets the content' do
+ Tempfile.create('test') do |file|
+ subject.download(url, file.path)
+ expect(file.read).to eq(File.open('spec/fixtures/rails_sample.tif').read)
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
index 5b77290ce2e..3c51f3b4bcf 100644
--- a/spec/lib/gitlab/url_blocker_spec.rb
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -39,6 +39,73 @@ RSpec.describe Gitlab::UrlBlocker, :stub_invalid_dns_only do
end
end
+ context 'when URI is for a local object storage' do
+ let(:import_url) { "#{host}/external-diffs/merge_request_diffs/mr-1/diff-1" }
+ let(:enabled_object_storage_setting) do
+ {
+ 'object_store' =>
+ {
+ 'enabled' => true,
+ 'connection' => {
+ 'endpoint' => host
+ }
+ }
+ }
+ end
+
+ before do
+ allow(Settings).to receive(:external_diffs).and_return(enabled_object_storage_setting)
+ end
+
+ context 'when allow_object_storage is true' do
+ subject { described_class.validate!(import_url, allow_object_storage: true) }
+
+ context 'with a local domain name' do
+ let(:host) { 'http://review-minio-svc.svc:9000' }
+
+ before do
+ stub_dns(host, ip_address: '127.0.0.1')
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'http://127.0.0.1:9000/external-diffs/merge_request_diffs/mr-1/diff-1' }
+ let(:expected_hostname) { 'review-minio-svc.svc' }
+ end
+ end
+
+ context 'with an IP address' do
+ let(:host) { 'http://127.0.0.1:9000' }
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'http://127.0.0.1:9000/external-diffs/merge_request_diffs/mr-1/diff-1' }
+ let(:expected_hostname) { nil }
+ end
+ end
+ end
+
+ context 'when allow_object_storage is false' do
+ context 'with a local domain name' do
+ let(:host) { 'http://review-minio-svc.svc:9000' }
+
+ before do
+ stub_dns(host, ip_address: '127.0.0.1')
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+
+ context 'with an IP address' do
+ let(:host) { 'http://127.0.0.1:9000' }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+ end
+ end
+
context 'when the URL hostname is a domain' do
context 'when domain can be resolved' do
let(:import_url) { 'https://example.org' }
diff --git a/spec/lib/peek/views/active_record_spec.rb b/spec/lib/peek/views/active_record_spec.rb
index c89f6a21b35..7bc15f40065 100644
--- a/spec/lib/peek/views/active_record_spec.rb
+++ b/spec/lib/peek/views/active_record_spec.rb
@@ -119,16 +119,4 @@ RSpec.describe Peek::Views::ActiveRecord, :request_store do
)
)
end
-
- context 'when the GITLAB_MULTIPLE_DATABASE_METRICS env var is disabled' do
- before do
- stub_env('GITLAB_MULTIPLE_DATABASE_METRICS', nil)
- end
-
- it 'does not include db_config_name field' do
- ActiveSupport::Notifications.publish('sql.active_record', Time.current, Time.current + 1.second, '1', event_1)
-
- expect(subject.results[:details][0][:db_config_name]).to be_nil
- end
- end
end
diff --git a/spec/models/analytics/cycle_analytics/aggregation_spec.rb b/spec/models/analytics/cycle_analytics/aggregation_spec.rb
index 7df1bf60e9c..4bf737df56a 100644
--- a/spec/models/analytics/cycle_analytics/aggregation_spec.rb
+++ b/spec/models/analytics/cycle_analytics/aggregation_spec.rb
@@ -51,14 +51,14 @@ RSpec.describe Analytics::CycleAnalytics::Aggregation, type: :model do
end
describe '#load_batch' do
- let!(:aggregation1) { create(:cycle_analytics_aggregation, last_incremental_run_at: nil) }
+ let!(:aggregation1) { create(:cycle_analytics_aggregation, last_incremental_run_at: nil, last_consistency_check_updated_at: 3.days.ago).reload }
let!(:aggregation2) { create(:cycle_analytics_aggregation, last_incremental_run_at: 5.days.ago).reload }
- let!(:aggregation3) { create(:cycle_analytics_aggregation, last_incremental_run_at: nil) }
- let!(:aggregation5) { create(:cycle_analytics_aggregation, last_incremental_run_at: 10.days.ago).reload }
+ let!(:aggregation3) { create(:cycle_analytics_aggregation, last_incremental_run_at: nil, last_consistency_check_updated_at: 2.days.ago).reload }
+ let!(:aggregation4) { create(:cycle_analytics_aggregation, last_incremental_run_at: 10.days.ago).reload }
before do
create(:cycle_analytics_aggregation, :disabled) # disabled rows are skipped
- create(:cycle_analytics_aggregation, last_incremental_run_at: 1.day.ago) # "early" rows are filtered out
+ create(:cycle_analytics_aggregation, last_incremental_run_at: 1.day.ago, last_consistency_check_updated_at: 1.hour.ago) # "early" rows are filtered out
end
it 'loads records in priority order' do
@@ -70,7 +70,20 @@ RSpec.describe Analytics::CycleAnalytics::Aggregation, type: :model do
# Using match_array because the order can be undeterministic for nil values.
expect(first_two).to match_array([aggregation1, aggregation3])
- expect(last_two).to eq([aggregation5, aggregation2])
+ expect(last_two).to eq([aggregation4, aggregation2])
+ end
+
+ context 'when loading batch for last_consistency_check_updated_at' do
+ it 'loads records in priority order' do
+ batch = described_class.load_batch(1.day.ago, :last_consistency_check_updated_at).to_a
+
+ expect(batch.size).to eq(4)
+ first_two = batch.first(2)
+ last_two = batch.last(2)
+
+ expect(first_two).to match_array([aggregation2, aggregation4])
+ expect(last_two).to eq([aggregation1, aggregation3])
+ end
end
end
diff --git a/spec/support/enable_multiple_database_metrics_by_default.rb b/spec/support/enable_multiple_database_metrics_by_default.rb
deleted file mode 100644
index 6eeb4acd3d6..00000000000
--- a/spec/support/enable_multiple_database_metrics_by_default.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.configure do |config|
- config.before do
- # Enable this by default in all tests so it behaves like a FF
- stub_env('GITLAB_MULTIPLE_DATABASE_METRICS', '1')
- end
-end
diff --git a/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb b/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb
index 6e8c340582a..3f187a7e9e4 100644
--- a/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb
+++ b/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb
@@ -91,21 +91,6 @@ RSpec.shared_examples 'store ActiveRecord info in RequestStore' do |db_role|
end
end
end
-
- context 'when the GITLAB_MULTIPLE_DATABASE_METRICS env var is disabled' do
- before do
- stub_env('GITLAB_MULTIPLE_DATABASE_METRICS', nil)
- end
-
- it 'does not include per database metrics' do
- Gitlab::WithRequestStore.with_request_store do
- subscriber.sql(event)
-
- expect(described_class.db_counter_payload).not_to include(:"db_replica_#{db_config_name}_duration_s")
- expect(described_class.db_counter_payload).not_to include(:"db_replica_#{db_config_name}_count")
- end
- end
- end
end
RSpec.shared_examples 'record ActiveRecord metrics in a metrics transaction' do |db_role|
@@ -160,26 +145,6 @@ RSpec.shared_examples 'record ActiveRecord metrics in a metrics transaction' do
subscriber.sql(event)
end
-
- context 'when the GITLAB_MULTIPLE_DATABASE_METRICS env var is disabled' do
- before do
- stub_env('GITLAB_MULTIPLE_DATABASE_METRICS', nil)
- end
-
- it 'does not include db_config_name label' do
- allow(transaction).to receive(:increment) do |*args|
- labels = args[2] || {}
- expect(labels).not_to include(:db_config_name)
- end
-
- allow(transaction).to receive(:observe) do |*args|
- labels = args[2] || {}
- expect(labels).not_to include(:db_config_name)
- end
-
- subscriber.sql(event)
- end
- end
end
RSpec.shared_examples 'record ActiveRecord metrics' do |db_role|