Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
149436d2a5
commit
e6ac8e40c2
|
@ -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');
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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'
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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).
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
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
|
||||
|
||||
%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 'logs the redirect' do
|
||||
expect(Gitlab::Import::Logger).to receive(:warn)
|
||||
|
||||
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
|
||||
|
||||
context 'a localhost uri' do
|
||||
include StubRequests
|
||||
|
||||
let(:status) { HTTP::Status::OK }
|
||||
let(:url) { "#{host}/foo/bar" }
|
||||
let(:host) { 'http://localhost:8081' }
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
let(:tempfile) { Tempfile.new('test', path) }
|
||||
before do
|
||||
allow(Settings).to receive(:external_diffs).and_return(enabled_object_storage_setting)
|
||||
end
|
||||
|
||||
it 'downloads the file in the given path' do
|
||||
subject.download('http://localhost:3000/file', tempfile)
|
||||
|
||||
expect(File.exist?(tempfile)).to eq(true)
|
||||
expect(tempfile.size).to eq(File.size(archive))
|
||||
end
|
||||
|
||||
it 'limit the size of the downloaded file' do
|
||||
subject.download('http://localhost:3000/file', tempfile, size_limit: 1.byte)
|
||||
|
||||
expect(File.exist?(tempfile)).to eq(true)
|
||||
expect(tempfile.size).to eq(0)
|
||||
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
|
||||
|
||||
|
|
|
@ -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' }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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|
|
||||
|
|
Loading…
Reference in New Issue