-
-
diff --git a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
index 038fb3ea61c..bd15dfe29a6 100644
--- a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
+++ b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
@@ -163,7 +163,7 @@ export default {
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 5a90e246499..8ed24257d61 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -51,6 +51,7 @@ module ApplicationSettingImplementation
container_registry_token_expire_delay: 5,
container_registry_vendor: '',
container_registry_version: '',
+ container_registry_db_enabled: false,
custom_http_clone_url_root: nil,
decompress_archive_file_timeout: 210,
default_artifacts_expire_in: '30 days',
diff --git a/app/models/clusters/agent_token.rb b/app/models/clusters/agent_token.rb
index f4c497a42cc..e2754db73b9 100644
--- a/app/models/clusters/agent_token.rb
+++ b/app/models/clusters/agent_token.rb
@@ -33,6 +33,10 @@ module Clusters
revoked: 1
}
+ def revoke!
+ update(status: :revoked)
+ end
+
def to_ability_name
:cluster
end
diff --git a/app/services/clusters/agent_tokens/revoke_service.rb b/app/services/clusters/agent_tokens/revoke_service.rb
index 5d89b405969..46873fbbc47 100644
--- a/app/services/clusters/agent_tokens/revoke_service.rb
+++ b/app/services/clusters/agent_tokens/revoke_service.rb
@@ -13,7 +13,7 @@ module Clusters
def execute
return error_no_permissions unless current_user.can?(:create_cluster, token.agent.project)
- if token.update(status: token.class.statuses[:revoked])
+ if token.revoke!
log_activity_event(token)
ServiceResponse.success
diff --git a/app/views/admin/users/_profile.html.haml b/app/views/admin/users/_profile.html.haml
index bb89b5baf28..df0a59ccfc3 100644
--- a/app/views/admin/users/_profile.html.haml
+++ b/app/views/admin/users/_profile.html.haml
@@ -1,4 +1,4 @@
-= render Pajamas::CardComponent.new(body_options: { class: 'gl-py-0' }) do |c|
+= render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-5' }, body_options: { class: 'gl-py-0' }) do |c|
- c.with_header do
= _('Profile')
- c.with_body do
diff --git a/app/workers/merge_worker.rb b/app/workers/merge_worker.rb
index a0594b15e31..29f0c0bbbf4 100644
--- a/app/workers/merge_worker.rb
+++ b/app/workers/merge_worker.rb
@@ -16,8 +16,6 @@ class MergeWorker # rubocop:disable Scalability/IdempotentWorker
deduplicate :until_executed, including_scheduled: true
def perform(merge_request_id, current_user_id, params)
- params = params.with_indifferent_access
-
begin
current_user = User.find(current_user_id)
merge_request = MergeRequest.find(merge_request_id)
@@ -25,6 +23,9 @@ class MergeWorker # rubocop:disable Scalability/IdempotentWorker
return
end
+ params = params.with_indifferent_access
+ params[:check_mergeability_retry_lease] = true unless params.has_key?(:check_mergeability_retry_lease)
+
MergeRequests::MergeService.new(project: merge_request.target_project, current_user: current_user, params: params)
.execute(merge_request)
end
diff --git a/config/initializers/active_record_table_definition.rb b/config/initializers/active_record_table_definition.rb
index 2e571ec7525..3c6311f034f 100644
--- a/config/initializers/active_record_table_definition.rb
+++ b/config/initializers/active_record_table_definition.rb
@@ -36,13 +36,6 @@ module ActiveRecord
def aliased_types(name, fallback)
fallback
end
-
- # Adds a compatible_table_definition method that
- # returns the value passed in so that all of the
- # versioned Migrations can always return super.
- def compatible_table_definition(table)
- table
- end
end
end
end
diff --git a/config/initializers/gitlab_http.rb b/config/initializers/gitlab_http.rb
new file mode 100644
index 00000000000..8a84313a7fb
--- /dev/null
+++ b/config/initializers/gitlab_http.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+# When including this gem, we also initialize the patch / override classes in the gem.
+require 'gitlab-http'
+
+Gitlab::HTTP_V2.configure do |config|
+ config.allowed_internal_uris = [
+ URI::HTTP.build(
+ scheme: Gitlab.config.gitlab.protocol,
+ host: Gitlab.config.gitlab.host,
+ port: Gitlab.config.gitlab.port
+ ),
+ URI::Generic.build(
+ scheme: 'ssh',
+ host: Gitlab.config.gitlab_shell.ssh_host,
+ port: Gitlab.config.gitlab_shell.ssh_port
+ )
+ ]
+
+ config.log_exception_proc = ->(exception, extra_info) do
+ Gitlab::ErrorTracking.log_exception(exception, extra_info)
+ end
+ config.silent_mode_log_info_proc = ->(message, http_method) do
+ Gitlab::SilentMode.log_info(message: message, outbound_http_request_method: http_method)
+ end
+end
diff --git a/config/initializers/http_hostname_override.rb b/config/initializers/http_hostname_override.rb
deleted file mode 100644
index 3d840cd3251..00000000000
--- a/config/initializers/http_hostname_override.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-# This override allows passing `@hostname_override` to the SNI protocol,
-# which is used to lookup the correct SSL certificate in the
-# request handshake process.
-#
-# Given we've forced the HTTP request to be sent to the resolved
-# IP address in a few scenarios (e.g.: `Gitlab::HTTP` through
-# `Gitlab::UrlBlocker.validate!`), we need to provide the _original_
-# hostname via SNI in order to have a clean connection setup.
-#
-# This is ultimately needed in order to avoid DNS rebinding attacks
-# through HTTP requests.
-#
-class OpenSSL::SSL::SSLContext
- attr_accessor :hostname_override
-end
-
-class OpenSSL::SSL::SSLSocket
- module HostnameOverride
- # rubocop: disable Gitlab/ModuleWithInstanceVariables
- def hostname=(hostname)
- super(@context.hostname_override || hostname)
- end
-
- def post_connection_check(hostname)
- super(@context.hostname_override || hostname)
- end
- # rubocop: enable Gitlab/ModuleWithInstanceVariables
- end
-
- prepend HostnameOverride
-end
-
-class Net::HTTP
- attr_accessor :hostname_override
-
- SSL_IVNAMES << :@hostname_override
- SSL_ATTRIBUTES << :hostname_override
-
- module HostnameOverride
- def addr_port
- return super unless hostname_override
-
- addr = hostname_override
- default_port = use_ssl? ? Net::HTTP.https_default_port : Net::HTTP.http_default_port
- default_port == port ? addr : "#{addr}:#{port}"
- end
- end
-
- prepend HostnameOverride
-end
diff --git a/config/initializers/net_http_patch.rb b/config/initializers/net_http_patch.rb
deleted file mode 100644
index 8231423e1a5..00000000000
--- a/config/initializers/net_http_patch.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# frozen_string_literal: true
-
-# Monkey patch Net::HTTP to fix missing URL decoding for username and password in proxy settings
-#
-# See proposed upstream fix https://github.com/ruby/net-http/pull/5
-# See Ruby-lang issue https://bugs.ruby-lang.org/issues/17542
-# See issue on GitLab https://gitlab.com/gitlab-org/gitlab/-/issues/289836
-
-require 'net/http'
-
-# This file can be removed once Ruby 3.0 is no longer supported:
-# https://gitlab.com/gitlab-org/gitlab/-/issues/396223
-return if Gem::Version.new(Net::HTTP::VERSION) >= Gem::Version.new('0.2.0')
-
-module Net
- class HTTP < Protocol
- def proxy_user
- if environment_variable_is_multiuser_safe? && @proxy_from_env
- user = proxy_uri&.user
- CGI.unescape(user) unless user.nil?
- else
- @proxy_user
- end
- end
-
- def proxy_pass
- if environment_variable_is_multiuser_safe? && @proxy_from_env
- pass = proxy_uri&.password
- CGI.unescape(pass) unless pass.nil?
- else
- @proxy_pass
- end
- end
-
- def environment_variable_is_multiuser_safe?
- ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE
- end
- end
-end
diff --git a/config/initializers/net_http_response_patch.rb b/config/initializers/net_http_response_patch.rb
deleted file mode 100644
index 4f3eaeec24a..00000000000
--- a/config/initializers/net_http_response_patch.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-module Net
- class HTTPResponse
- # rubocop: disable Cop/LineBreakAfterGuardClauses
- # rubocop: disable Cop/LineBreakAroundConditionalBlock
- # rubocop: disable Layout/EmptyLineAfterGuardClause
- # rubocop: disable Style/AndOr
- # rubocop: disable Style/CharacterLiteral
- # rubocop: disable Style/InfiniteLoop
-
- # Original method:
- # https://github.com/ruby/ruby/blob/v2_7_5/lib/net/http/response.rb#L54-L69
- #
- # Our changes:
- # - Pass along the `start_time` to `Gitlab::BufferedIo`, so we can raise a timeout
- # if reading the headers takes too long.
- # - Limit the regexes to avoid ReDoS attacks.
- def self.each_response_header(sock)
- start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- key = value = nil
- while true
- line = sock.is_a?(Gitlab::BufferedIo) ? sock.readuntil("\n", true, start_time) : sock.readuntil("\n", true)
- line = line.sub(/\s{0,10}\z/, '')
- break if line.empty?
- if line[0] == ?\s or line[0] == ?\t and value
- # rubocop:disable Gitlab/NoCodeCoverageComment
- # :nocov:
- value << ' ' unless value.empty?
- value << line.strip
- # :nocov:
- # rubocop:enable Gitlab/NoCodeCoverageComment
- else
- yield key, value if key
- key, value = line.strip.split(/\s{0,10}:\s{0,10}/, 2)
- raise Net::HTTPBadResponse, 'wrong header line format' if value.nil?
- end
- end
- yield key, value if key
- end
- # rubocop: enable Cop/LineBreakAfterGuardClauses
- # rubocop: enable Cop/LineBreakAroundConditionalBlock
- # rubocop: enable Layout/EmptyLineAfterGuardClause
- # rubocop: enable Style/AndOr
- # rubocop: enable Style/CharacterLiteral
- # rubocop: enable Style/InfiniteLoop
- end
-end
diff --git a/db/migrate/20221206211814_add_authorized_scopes_to_slack_integration.rb b/db/migrate/20221206211814_add_authorized_scopes_to_slack_integration.rb
index 40abf087dfe..94d553fdab5 100644
--- a/db/migrate/20221206211814_add_authorized_scopes_to_slack_integration.rb
+++ b/db/migrate/20221206211814_add_authorized_scopes_to_slack_integration.rb
@@ -9,7 +9,7 @@ class AddAuthorizedScopesToSlackIntegration < Gitlab::Database::Migration[2.1]
end
create_table :slack_integrations_scopes do |t|
- references :slack_api_scope,
+ t.references :slack_api_scope,
null: false,
index: false, # See composite index
foreign_key: {
@@ -17,7 +17,7 @@ class AddAuthorizedScopesToSlackIntegration < Gitlab::Database::Migration[2.1]
on_delete: :cascade
}
- references :slack_integration,
+ t.references :slack_integration,
null: false,
index: false, # see composite index
foreign_key: {
diff --git a/db/migrate/20230919123305_add_container_registry_db_enabled_to_application_settings.rb b/db/migrate/20230919123305_add_container_registry_db_enabled_to_application_settings.rb
new file mode 100644
index 00000000000..861294054e8
--- /dev/null
+++ b/db/migrate/20230919123305_add_container_registry_db_enabled_to_application_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddContainerRegistryDbEnabledToApplicationSettings < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :application_settings, :container_registry_db_enabled, :boolean, null: false, default: false
+ end
+end
diff --git a/db/migrate/20230920153321_add_last_assigned_users_refreshed_at_to_subscription_add_on_purchases.rb b/db/migrate/20230920153321_add_last_assigned_users_refreshed_at_to_subscription_add_on_purchases.rb
new file mode 100644
index 00000000000..7f347e55031
--- /dev/null
+++ b/db/migrate/20230920153321_add_last_assigned_users_refreshed_at_to_subscription_add_on_purchases.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddLastAssignedUsersRefreshedAtToSubscriptionAddOnPurchases < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column(:subscription_add_on_purchases, :last_assigned_users_refreshed_at, :datetime_with_timezone)
+ end
+end
diff --git a/db/post_migrate/20230918084159_drop_columns_from_geo_node_status_table.rb b/db/post_migrate/20230918084159_drop_columns_from_geo_node_status_table.rb
new file mode 100644
index 00000000000..54941552ef9
--- /dev/null
+++ b/db/post_migrate/20230918084159_drop_columns_from_geo_node_status_table.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+class DropColumnsFromGeoNodeStatusTable < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def up
+ remove_columns :geo_node_statuses,
+ :wikis_checksum_failed_count,
+ :wikis_checksum_mismatch_count,
+ :wikis_checksummed_count,
+ :wikis_failed_count,
+ :wikis_retrying_verification_count,
+ :wikis_synced_count,
+ :wikis_verification_failed_count,
+ :wikis_verified_count,
+ :design_repositories_count,
+ :design_repositories_synced_count,
+ :design_repositories_failed_count,
+ :design_repositories_registry_count
+ end
+
+ def down
+ change_table(:geo_node_statuses) do |t|
+ t.integer :wikis_checksum_failed_count
+ t.integer :wikis_checksum_mismatch_count
+ t.integer :wikis_checksummed_count
+ t.integer :wikis_failed_count
+ t.integer :wikis_retrying_verification_count
+ t.integer :wikis_synced_count
+ t.integer :wikis_verification_failed_count
+ t.integer :wikis_verified_count
+ t.integer :design_repositories_count
+ t.integer :design_repositories_synced_count
+ t.integer :design_repositories_failed_count
+ t.integer :design_repositories_registry_count
+ end
+ end
+end
diff --git a/db/schema_migrations/20230918084159 b/db/schema_migrations/20230918084159
new file mode 100644
index 00000000000..c436c247702
--- /dev/null
+++ b/db/schema_migrations/20230918084159
@@ -0,0 +1 @@
+0e31f2b685b3d229816f7e330b54cf5cafb7abb71aa4489d88af768dfb3629fc
\ No newline at end of file
diff --git a/db/schema_migrations/20230919123305 b/db/schema_migrations/20230919123305
new file mode 100644
index 00000000000..d497f91a90b
--- /dev/null
+++ b/db/schema_migrations/20230919123305
@@ -0,0 +1 @@
+6f95154ad6b0a9417935a203cb666aea99e06eef22f32c110e1f0e3914c87778
\ No newline at end of file
diff --git a/db/schema_migrations/20230920153321 b/db/schema_migrations/20230920153321
new file mode 100644
index 00000000000..edce6fcce4c
--- /dev/null
+++ b/db/schema_migrations/20230920153321
@@ -0,0 +1 @@
+821bf9cd2c93d34323edc587949a70779acdcc3f7866d7165ef3ebec2127ea0a
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 13e77a40ce5..8b7eae7eb47 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -12052,6 +12052,7 @@ CREATE TABLE application_settings (
decompress_archive_file_timeout integer DEFAULT 210 NOT NULL,
search_rate_limit_allowlist text[] DEFAULT '{}'::text[] NOT NULL,
snowplow_database_collector_hostname text,
+ container_registry_db_enabled boolean DEFAULT false NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
@@ -16602,8 +16603,6 @@ CREATE TABLE geo_node_statuses (
replication_slots_count integer,
replication_slots_used_count integer,
replication_slots_max_retained_wal_bytes bigint,
- wikis_synced_count integer,
- wikis_failed_count integer,
job_artifacts_count integer,
job_artifacts_synced_count integer,
job_artifacts_failed_count integer,
@@ -16611,28 +16610,18 @@ CREATE TABLE geo_node_statuses (
revision character varying,
repositories_verified_count integer,
repositories_verification_failed_count integer,
- wikis_verified_count integer,
- wikis_verification_failed_count integer,
lfs_objects_synced_missing_on_primary_count integer,
job_artifacts_synced_missing_on_primary_count integer,
repositories_checksummed_count integer,
repositories_checksum_failed_count integer,
repositories_checksum_mismatch_count integer,
- wikis_checksummed_count integer,
- wikis_checksum_failed_count integer,
- wikis_checksum_mismatch_count integer,
storage_configuration_digest bytea,
repositories_retrying_verification_count integer,
- wikis_retrying_verification_count integer,
projects_count integer,
container_repositories_count integer,
container_repositories_synced_count integer,
container_repositories_failed_count integer,
container_repositories_registry_count integer,
- design_repositories_count integer,
- design_repositories_synced_count integer,
- design_repositories_failed_count integer,
- design_repositories_registry_count integer,
status jsonb DEFAULT '{}'::jsonb NOT NULL
);
@@ -23650,6 +23639,7 @@ CREATE TABLE subscription_add_on_purchases (
quantity integer NOT NULL,
expires_on date NOT NULL,
purchase_xid text NOT NULL,
+ last_assigned_users_refreshed_at timestamp with time zone,
CONSTRAINT check_3313c4d200 CHECK ((char_length(purchase_xid) <= 255))
);
diff --git a/doc/administration/settings/continuous_integration.md b/doc/administration/settings/continuous_integration.md
index f0423021e8b..841b6e644eb 100644
--- a/doc/administration/settings/continuous_integration.md
+++ b/doc/administration/settings/continuous_integration.md
@@ -231,7 +231,8 @@ It is also possible to specify a [custom CI/CD configuration file for a specific
## Set CI/CD limits
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352175) in GitLab 14.10.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352175) in GitLab 14.10.
+> - **Maximum number of active pipelines per project** setting [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/368195) in GitLab 16.0.
You can configure some [CI/CD limits](../../administration/instance_limits.md#cicd-limits)
from the Admin Area:
@@ -243,7 +244,6 @@ from the Admin Area:
1. In the **CI/CD limits** section, you can set the following limits:
- **Maximum number of jobs in a single pipeline**
- **Total number of jobs in currently active pipelines**
- - **Maximum number of active pipelines per project**
- **Maximum number of pipeline subscriptions to and from a project**
- **Maximum number of pipeline schedules**
- **Maximum number of DAG dependencies that a job can have**
diff --git a/doc/api/job_artifacts.md b/doc/api/job_artifacts.md
index 2ee7b8ead61..e9d4915da57 100644
--- a/doc/api/job_artifacts.md
+++ b/doc/api/job_artifacts.md
@@ -315,9 +315,20 @@ If the artifacts were deleted successfully, a response with status `204 No Conte
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223793) in GitLab 14.7 [with a flag](../administration/feature_flags.md) named `bulk_expire_project_artifacts`. Enabled by default on GitLab self-managed. Enabled on GitLab.com.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/350609) in GitLab 14.10.
-Delete artifacts of a project that can be deleted.
+Delete artifacts eligible for deletion in a project. By default, artifacts from
+[the most recent successful pipeline of each ref](../ci/jobs/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs).
+are not deleted.
-By default, [artifacts from the most recent successful pipeline of each ref are kept](../ci/jobs/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs).
+Requests to this endpoint set the expiry of all artifacts that
+can be deleted to the current time. The files are then deleted from the system as part
+of the regular cleanup of expired job artifacts. Job logs are never deleted.
+
+The regular cleanup occurs asynchronously on a schedule, so there might be a short delay
+before artifacts are deleted.
+
+Prerequisite:
+
+- You must have at least the Maintainer role for the project.
```plaintext
DELETE /projects/:id/artifacts
@@ -333,8 +344,4 @@ Example request:
curl --request DELETE --header "PRIVATE-TOKEN:
" "https://gitlab.example.com/api/v4/projects/1/artifacts"
```
-NOTE:
-At least Maintainer role is required to delete artifacts.
-
-Schedules a worker to update to the current time the expiry of all artifacts that can be deleted.
A response with status `202 Accepted` is returned.
diff --git a/gems/gitlab-http/lib/net_http/response_patch.rb b/gems/gitlab-http/lib/net_http/response_patch.rb
index e5477a31318..303d629b32e 100644
--- a/gems/gitlab-http/lib/net_http/response_patch.rb
+++ b/gems/gitlab-http/lib/net_http/response_patch.rb
@@ -20,11 +20,12 @@ module Net
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
key = value = nil
while true
- line = if sock.is_a?(Gitlab::HTTP_V2::BufferedIo)
- sock.readuntil("\n", true, start_time)
- else
- sock.readuntil("\n", true)
- end
+ uses_buffered_io = sock.is_a?(Gitlab::HTTP_V2::BufferedIo)
+
+ # TODO: Gitlab::BufferedIo is temporarily used for an easy migration.
+ uses_buffered_io ||= sock.is_a?(Gitlab::BufferedIo) if defined?(Gitlab::BufferedIo)
+
+ line = uses_buffered_io ? sock.readuntil("\n", true, start_time) : sock.readuntil("\n", true)
line = line.sub(/\s{0,10}\z/, '')
break if line.empty?
if line[0] == ?\s or line[0] == ?\t and value
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/net_http_patch_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/net_http_patch_spec.rb
index b82646fb365..f34b0d98403 100644
--- a/gems/gitlab-http/spec/gitlab/http_v2/net_http_patch_spec.rb
+++ b/gems/gitlab-http/spec/gitlab/http_v2/net_http_patch_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'net/http'
-RSpec.describe 'Net::HTTP patch proxy user and password encoding' do
+RSpec.describe 'Net::HTTP patch proxy user and password encoding', feature_category: :shared do
let(:net_http) { Net::HTTP.new('hostname.example') }
before do
diff --git a/lib/api/concerns/packages/npm_endpoints.rb b/lib/api/concerns/packages/npm_endpoints.rb
index 4278510e999..bfaba5c4d7a 100644
--- a/lib/api/concerns/packages/npm_endpoints.rb
+++ b/lib/api/concerns/packages/npm_endpoints.rb
@@ -76,12 +76,14 @@ module API
]
failure [
{ code: 400, message: 'Bad Request' },
+ { code: 401, message: 'Unauthorized' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not Found' }
]
tags %w[npm_packages]
end
- route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
+ route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true,
+ authenticate_non_public: true
get 'dist-tags', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do
package_name = params[:package_name]
@@ -186,6 +188,7 @@ module API
]
failure [
{ code: 400, message: 'Bad Request' },
+ { code: 401, message: 'Unauthorized' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not Found' }
]
@@ -194,7 +197,8 @@ module API
params do
use :package_name
end
- route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
+ route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true,
+ authenticate_non_public: true
get '*package_name', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do
package_name = params[:package_name]
available_packages =
@@ -224,9 +228,7 @@ module API
).execute
if available_packages.any? && available_packages_to_user.empty?
- forbidden! if current_user
-
- not_found!('Packages')
+ current_user ? forbidden! : unauthorized!
end
available_packages = available_packages_to_user
diff --git a/lib/api/helpers/packages/npm.rb b/lib/api/helpers/packages/npm.rb
index a80122c5309..ef3da055b19 100644
--- a/lib/api/helpers/packages/npm.rb
+++ b/lib/api/helpers/packages/npm.rb
@@ -102,8 +102,7 @@ module API
def group
group = find_group(params[:id])
- not_found!('Group') unless can?(current_user, :read_group, group)
- group
+ check_group_access(group)
end
strong_memoize_attr :group
diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb
index b83d67c359d..e2a1b8296f6 100644
--- a/lib/container_registry/client.rb
+++ b/lib/container_registry/client.rb
@@ -10,6 +10,7 @@ module ContainerRegistry
REGISTRY_VERSION_HEADER = 'gitlab-container-registry-version'
REGISTRY_FEATURES_HEADER = 'gitlab-container-registry-features'
REGISTRY_TAG_DELETE_FEATURE = 'tag_delete'
+ REGISTRY_DB_ENABLED_HEADER = 'gitlab-container-registry-database-enabled'
DEFAULT_TAGS_PAGE_SIZE = 10000
@@ -47,11 +48,13 @@ module ContainerRegistry
version = response.headers[REGISTRY_VERSION_HEADER]
features = response.headers.fetch(REGISTRY_FEATURES_HEADER, '')
+ db_enabled = response.headers.fetch(REGISTRY_DB_ENABLED_HEADER, '')
{
version: version,
features: features.split(',').map(&:strip),
- vendor: version ? 'gitlab' : 'other'
+ vendor: version ? 'gitlab' : 'other',
+ db_enabled: ::Gitlab::Utils.to_boolean(db_enabled, default: false)
}
end
diff --git a/lib/gitlab/database/migration_helpers/v2.rb b/lib/gitlab/database/migration_helpers/v2.rb
index 07e22963177..7cfafa1a6a6 100644
--- a/lib/gitlab/database/migration_helpers/v2.rb
+++ b/lib/gitlab/database/migration_helpers/v2.rb
@@ -43,7 +43,7 @@ module Gitlab
end
end
- t.instance_eval(&block) unless block.nil?
+ yield t unless block.nil?
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index d4277a26485..a53c8f8b10a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -27504,9 +27504,6 @@ msgstr ""
msgid "Last year"
msgstr ""
-msgid "LastCommit|authored"
-msgstr ""
-
msgid "LastPushEvent|You pushed to"
msgstr ""
@@ -46691,9 +46688,6 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
-msgid "Targe branch"
-msgstr ""
-
msgid "Target"
msgstr ""
diff --git a/package.json b/package.json
index 9105864d7e5..f612e6d3728 100644
--- a/package.json
+++ b/package.json
@@ -176,7 +176,7 @@
"mousetrap": "1.6.5",
"orderedmap": "^2.1.1",
"papaparse": "^5.3.1",
- "patch-package": "^6.4.7",
+ "patch-package": "6.5.1",
"pdfjs-dist": "^2.16.105",
"pikaday": "^1.8.0",
"popper.js": "^1.16.1",
diff --git a/patches/@rails+ujs+7.0.6.patch b/patches/@rails+ujs+7.0.8.patch
similarity index 100%
rename from patches/@rails+ujs+7.0.6.patch
rename to patches/@rails+ujs+7.0.8.patch
diff --git a/qa/qa/page/file/shared/commit_message.rb b/qa/qa/page/file/shared/commit_message.rb
index 12154cdb728..9d90400f42f 100644
--- a/qa/qa/page/file/shared/commit_message.rb
+++ b/qa/qa/page/file/shared/commit_message.rb
@@ -14,7 +14,7 @@ module QA
element :commit_message_field
end
- base.view 'app/assets/javascripts/repository/components/last_commit.vue' do
+ base.view 'app/assets/javascripts/repository/components/commit_info.vue' do
element :commit_content
end
diff --git a/scripts/frontend/postinstall.js b/scripts/frontend/postinstall.js
index 50052bb806e..07456ef36c9 100644
--- a/scripts/frontend/postinstall.js
+++ b/scripts/frontend/postinstall.js
@@ -1,4 +1,4 @@
-const { execSync } = require('child_process');
+const { spawnSync } = require('child_process');
const chalk = require('chalk');
// check that fsevents is available if we're on macOS
@@ -24,5 +24,7 @@ console.log(`${chalk.green('success')} Dependency postinstall check passed.`);
// Apply any patches to our packages
// See https://gitlab.com/gitlab-org/gitlab/-/issues/336138
-execSync('node_modules/.bin/patch-package --error-on-fail');
-console.log(`${chalk.green('success')} Packages successfully patched.`);
+process.exitCode =
+ spawnSync('node_modules/.bin/patch-package', ['--error-on-fail', '--error-on-warn'], {
+ stdio: ['ignore', 'inherit', 'inherit'],
+ }).status ?? 1;
diff --git a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
index 3f901dc61b8..e48041c1032 100644
--- a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
+++ b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
@@ -1,97 +1,48 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Repository last commit component renders commit widget 1`] = `
-
-
-
- Commit title
-
-
-
- Test
-
- authored
-
-
+
-
-
-
-
-
-
-
- 12345678
-
-
-
-
+ 12345678
+
+
+
-
+
`;
diff --git a/spec/frontend/repository/components/commit_info_spec.js b/spec/frontend/repository/components/commit_info_spec.js
new file mode 100644
index 00000000000..34e941aa858
--- /dev/null
+++ b/spec/frontend/repository/components/commit_info_spec.js
@@ -0,0 +1,87 @@
+import { nextTick } from 'vue';
+import { GlButton } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import CommitInfo from '~/repository/components/commit_info.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+
+let wrapper;
+const commit = {
+ title: 'Commit title',
+ titleHtml: 'Commit title html',
+ message: 'Commit message',
+ authoredDate: '2019-01-01',
+ authorName: 'Test authorName',
+ author: { name: 'Test name', avatarUrl: 'https://test.com', webPath: '/test' },
+};
+
+const findTextExpander = () => wrapper.findComponent(GlButton);
+const findUserLink = () => wrapper.findByText(commit.author.name);
+const findUserAvatarLink = () => wrapper.findComponent(UserAvatarLink);
+const findAuthorName = () => wrapper.findByText(`${commit.authorName} authored`);
+const findCommitRowDescription = () => wrapper.find('pre');
+const findTitleHtml = () => wrapper.findByText(commit.titleHtml);
+
+const createComponent = async ({ commitMock = {} } = {}) => {
+ wrapper = shallowMountExtended(CommitInfo, {
+ propsData: { commit: { ...commit, ...commitMock } },
+ });
+
+ await nextTick();
+};
+
+describe('Repository last commit component', () => {
+ it('renders author info', () => {
+ createComponent();
+
+ expect(findUserLink().exists()).toBe(true);
+ expect(findUserAvatarLink().exists()).toBe(true);
+ });
+
+ it('hides author component when author does not exist', () => {
+ createComponent({ commitMock: { author: null } });
+
+ expect(findUserLink().exists()).toBe(false);
+ expect(findUserAvatarLink().exists()).toBe(false);
+ expect(findAuthorName().exists()).toBe(true);
+ });
+
+ it('does not render description expander when description is null', () => {
+ createComponent();
+
+ expect(findTextExpander().exists()).toBe(false);
+ expect(findCommitRowDescription().exists()).toBe(false);
+ });
+
+ describe('when the description is present', () => {
+ beforeEach(() => {
+ createComponent({ commitMock: { descriptionHtml: '
Update ADOPTERS.md' } });
+ });
+
+ it('strips the first newline of the description', () => {
+ expect(findCommitRowDescription().html()).toBe(
+ 'Update ADOPTERS.md
',
+ );
+ });
+
+ it('renders commit description collapsed by default', () => {
+ expect(findCommitRowDescription().classes('gl-display-block!')).toBe(false);
+ expect(findTextExpander().classes('open')).toBe(false);
+ expect(findTextExpander().props('selected')).toBe(false);
+ });
+
+ it('expands commit description when clicking expander', async () => {
+ findTextExpander().vm.$emit('click');
+ await nextTick();
+
+ expect(findCommitRowDescription().classes('gl-display-block!')).toBe(true);
+ expect(findTextExpander().classes('open')).toBe(true);
+ expect(findTextExpander().props('selected')).toBe(true);
+ });
+ });
+
+ it('sets correct CSS class if the commit message is empty', () => {
+ createComponent({ commitMock: { message: '' } });
+
+ expect(findTitleHtml().classes()).toContain('gl-font-style-italic');
+ });
+});
diff --git a/spec/frontend/repository/components/last_commit_spec.js b/spec/frontend/repository/components/last_commit_spec.js
index c207d32d61d..d5ec34b1f6d 100644
--- a/spec/frontend/repository/components/last_commit_spec.js
+++ b/spec/frontend/repository/components/last_commit_spec.js
@@ -1,29 +1,26 @@
import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
import { GlLoadingIcon } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import LastCommit from '~/repository/components/last_commit.vue';
+import CommitInfo from '~/repository/components/commit_info.vue';
import SignatureBadge from '~/commit/components/signature_badge.vue';
-import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import eventHub from '~/repository/event_hub';
import pathLastCommitQuery from 'shared_queries/repository/path_last_commit.query.graphql';
import { FORK_UPDATED_EVENT } from '~/repository/constants';
import { refMock } from '../mock_data';
let wrapper;
+let commitData;
let mockResolver;
const findPipeline = () => wrapper.find('.js-commit-pipeline');
-const findTextExpander = () => wrapper.find('.text-expander');
-const findUserLink = () => wrapper.find('.js-user-link');
-const findUserAvatarLink = () => wrapper.findComponent(UserAvatarLink);
const findLastCommitLabel = () => wrapper.findByTestId('last-commit-id-label');
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
-const findCommitRowDescription = () => wrapper.find('.commit-row-description');
const findStatusBox = () => wrapper.findComponent(SignatureBadge);
-const findItemTitle = () => wrapper.find('.item-title');
+const findCommitInfo = () => wrapper.findComponent(CommitInfo);
const defaultPipelineEdges = [
{
@@ -44,23 +41,7 @@ const defaultPipelineEdges = [
},
];
-const defaultAuthor = {
- __typename: 'UserCore',
- id: 'gid://gitlab/User/1',
- name: 'Test',
- avatarUrl: 'https://test.com',
- webPath: '/test',
-};
-
-const defaultMessage = 'Commit title';
-
-const createCommitData = ({
- pipelineEdges = defaultPipelineEdges,
- author = defaultAuthor,
- descriptionHtml = '',
- signature = null,
- message = defaultMessage,
-}) => {
+const createCommitData = ({ pipelineEdges = defaultPipelineEdges, signature = null }) => {
return {
data: {
project: {
@@ -79,13 +60,19 @@ const createCommitData = ({
sha: '123456789',
title: 'Commit title',
titleHtml: 'Commit title',
- descriptionHtml,
- message,
+ descriptionHtml: '',
+ message: '',
webPath: '/commit/123',
authoredDate: '2019-01-01',
authorName: 'Test',
authorGravatar: 'https://test.com',
- author,
+ author: {
+ __typename: 'UserCore',
+ id: 'gid://gitlab/User/1',
+ name: 'Test',
+ avatarUrl: 'https://test.com',
+ webPath: '/test',
+ },
signature,
pipelines: {
__typename: 'PipelineConnection',
@@ -101,12 +88,13 @@ const createCommitData = ({
};
};
-const createComponent = (data = {}) => {
+const createComponent = async (data = {}) => {
Vue.use(VueApollo);
const currentPath = 'path';
- mockResolver = jest.fn().mockResolvedValue(createCommitData(data));
+ commitData = createCommitData(data);
+ mockResolver = jest.fn().mockResolvedValue(commitData);
wrapper = shallowMountExtended(LastCommit, {
apolloProvider: createMockApollo([[pathLastCommitQuery, mockResolver]]),
@@ -116,8 +104,13 @@ const createComponent = (data = {}) => {
SignatureBadge,
},
});
+
+ await waitForPromises();
+ await nextTick();
};
+beforeEach(() => createComponent());
+
afterEach(() => {
mockResolver = null;
});
@@ -137,17 +130,17 @@ describe('Repository last commit component', () => {
expect(findLoadingIcon().exists()).toBe(loading);
});
- it('renders commit widget', async () => {
- createComponent();
- await waitForPromises();
+ it('renders a CommitInfo component', () => {
+ const commit = { ...commitData.project?.repository.paginatedTree.nodes[0].lastCommit };
+ expect(findCommitInfo().props().commit).toMatchObject(commit);
+ });
+
+ it('renders commit widget', () => {
expect(wrapper.element).toMatchSnapshot();
});
- it('renders short commit ID', async () => {
- createComponent();
- await waitForPromises();
-
+ it('renders short commit ID', () => {
expect(findLastCommitLabel().text()).toBe('12345678');
});
@@ -158,29 +151,10 @@ describe('Repository last commit component', () => {
expect(findPipeline().exists()).toBe(false);
});
- it('renders pipeline components when pipeline exists', async () => {
- createComponent();
- await waitForPromises();
-
+ it('renders pipeline components when pipeline exists', () => {
expect(findPipeline().exists()).toBe(true);
});
- it('hides author component when author does not exist', async () => {
- createComponent({ author: null });
- await waitForPromises();
-
- expect(findUserLink().exists()).toBe(false);
- expect(findUserAvatarLink().exists()).toBe(false);
- });
-
- it('does not render description expander when description is null', async () => {
- createComponent();
- await waitForPromises();
-
- expect(findTextExpander().exists()).toBe(false);
- expect(findCommitRowDescription().exists()).toBe(false);
- });
-
describe('created', () => {
it('binds `epicsListScrolled` event listener via eventHub', () => {
jest.spyOn(eventHub, '$on').mockImplementation(() => {});
@@ -200,32 +174,6 @@ describe('Repository last commit component', () => {
});
});
- describe('when the description is present', () => {
- beforeEach(async () => {
- createComponent({ descriptionHtml: '
Update ADOPTERS.md' });
- await waitForPromises();
- });
-
- it('strips the first newline of the description', () => {
- expect(findCommitRowDescription().html()).toBe(
- 'Update ADOPTERS.md
',
- );
- });
-
- it('expands commit description when clicking expander', async () => {
- expect(findCommitRowDescription().classes('d-block')).toBe(false);
- expect(findTextExpander().classes('open')).toBe(false);
- expect(findTextExpander().props('selected')).toBe(false);
-
- findTextExpander().vm.$emit('click');
- await nextTick();
-
- expect(findCommitRowDescription().classes('d-block')).toBe(true);
- expect(findTextExpander().classes('open')).toBe(true);
- expect(findTextExpander().props('selected')).toBe(true);
- });
- });
-
it('renders the signature HTML as returned by the backend', async () => {
const signatureResponse = {
__typename: 'GpgSignature',
@@ -241,11 +189,4 @@ describe('Repository last commit component', () => {
expect(findStatusBox().props()).toMatchObject({ signature: signatureResponse });
});
-
- it('sets correct CSS class if the commit message is empty', async () => {
- createComponent({ message: '' });
- await waitForPromises();
-
- expect(findItemTitle().classes()).toContain('font-italic');
- });
});
diff --git a/spec/initializers/gitlab_http_spec.rb b/spec/initializers/gitlab_http_spec.rb
new file mode 100644
index 00000000000..7715112abf4
--- /dev/null
+++ b/spec/initializers/gitlab_http_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::HTTP_V2, feature_category: :shared do
+ it 'handles log_exception_proc' do
+ expect(Gitlab::HTTP_V2::Client).to receive(:httparty_perform_request)
+ .and_raise(Net::ReadTimeout)
+
+ expect(Gitlab::ErrorTracking).to receive(:log_exception)
+ .with(Net::ReadTimeout, {})
+
+ expect { described_class.get('http://example.org') }.to raise_error(Net::ReadTimeout)
+ end
+
+ context 'when silent_mode_enabled is true' do
+ before do
+ stub_application_setting(silent_mode_enabled: true)
+ end
+
+ context 'when sending a POST request' do
+ it 'handles silent_mode_log_info_proc' do
+ expect(::Gitlab::AppJsonLogger).to receive(:info).with(
+ message: "Outbound HTTP request blocked",
+ outbound_http_request_method: 'Net::HTTP::Post',
+ silent_mode_enabled: true
+ )
+
+ expect { described_class.post('http://example.org', silent_mode_enabled: true) }.to raise_error(
+ Gitlab::HTTP_V2::SilentModeBlockedError
+ )
+ end
+ end
+
+ context 'when sending a GET request' do
+ before do
+ stub_request(:get, 'http://example.org').to_return(body: 'hello')
+ end
+
+ it 'does not raise an error' do
+ expect(::Gitlab::AppJsonLogger).not_to receive(:info)
+
+ expect(described_class.get('http://example.org', silent_mode_enabled: true).body).to eq('hello')
+ end
+ end
+ end
+end
diff --git a/spec/initializers/net_http_patch_spec.rb b/spec/initializers/net_http_patch_spec.rb
index b9f5299b58c..959eae954c4 100644
--- a/spec/initializers/net_http_patch_spec.rb
+++ b/spec/initializers/net_http_patch_spec.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
-require 'net/http'
+# TODO: This spec file can be removed after fully migration to the gitlab-http gem.
+# It's already covered in gems/gitlab-http/spec/gitlab/http_v2/net_http_patch_spec.rb
-require_relative '../../config/initializers/net_http_patch'
+require 'spec_helper'
-RSpec.describe 'Net::HTTP patch proxy user and password encoding' do
+RSpec.describe 'Net::HTTP patch proxy user and password encoding', feature_category: :shared do
let(:net_http) { Net::HTTP.new('hostname.example') }
before do
diff --git a/spec/initializers/net_http_response_patch_spec.rb b/spec/initializers/net_http_response_patch_spec.rb
index cd261d7b997..8074047d6aa 100644
--- a/spec/initializers/net_http_response_patch_spec.rb
+++ b/spec/initializers/net_http_response_patch_spec.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# TODO: This spec file can be removed after fully migration to the gitlab-http gem.
+# It's already covered in gems/gitlab-http/spec/gitlab/http_v2/net_http_response_patch_spec.rb
+
require 'spec_helper'
RSpec.describe 'Net::HTTPResponse patch header read timeout', feature_category: :shared do
diff --git a/spec/lib/container_registry/client_spec.rb b/spec/lib/container_registry/client_spec.rb
index a1425169dee..39409cf8d3a 100644
--- a/spec/lib/container_registry/client_spec.rb
+++ b/spec/lib/container_registry/client_spec.rb
@@ -89,13 +89,14 @@ RSpec.describe ContainerRegistry::Client do
it_behaves_like 'handling timeouts'
end
- shared_examples 'handling repository info' do
+ shared_examples 'handling registry info' do
context 'when the check is successful' do
context 'when using the GitLab container registry' do
before do
stub_registry_info(headers: {
'GitLab-Container-Registry-Version' => '2.9.1-gitlab',
- 'GitLab-Container-Registry-Features' => 'a,b,c'
+ 'GitLab-Container-Registry-Features' => 'a,b,c',
+ 'GitLab-Container-Registry-Database-Enabled' => 'true'
})
end
@@ -106,6 +107,10 @@ RSpec.describe ContainerRegistry::Client do
it 'identifies version and features' do
expect(subject).to include(version: '2.9.1-gitlab', features: %w[a b c])
end
+
+ it 'identifies the registry DB as enabled' do
+ expect(subject).to include(db_enabled: true)
+ end
end
context 'when using a third-party container registry' do
@@ -120,6 +125,10 @@ RSpec.describe ContainerRegistry::Client do
it 'does not identify version or features' do
expect(subject).to include(version: nil, features: [])
end
+
+ it 'does not identify the registry DB as enabled' do
+ expect(subject).to include(db_enabled: false)
+ end
end
end
@@ -130,6 +139,16 @@ RSpec.describe ContainerRegistry::Client do
expect(subject).to eq({})
end
end
+
+ context 'when the check returns an unexpected value in the database enabled header' do
+ it 'does not identify the registry DB as enabled' do
+ stub_registry_info(headers: {
+ 'GitLab-Container-Registry-Database-Enabled' => '123'
+ })
+
+ expect(subject).to include(db_enabled: false)
+ end
+ end
end
describe '#repository_manifest' do
@@ -360,7 +379,7 @@ RSpec.describe ContainerRegistry::Client do
describe '#registry_info' do
subject { client.registry_info }
- it_behaves_like 'handling repository info'
+ it_behaves_like 'handling registry info'
end
describe '.supports_tag_delete?' do
@@ -446,7 +465,7 @@ RSpec.describe ContainerRegistry::Client do
stub_container_registry_config(enabled: true, api_url: registry_api_url, key: 'spec/fixtures/x509_certificate_pk.key')
end
- it_behaves_like 'handling repository info'
+ it_behaves_like 'handling registry info'
end
def stub_upload(path, content, digest, status = 200)
diff --git a/spec/models/clusters/agent_token_spec.rb b/spec/models/clusters/agent_token_spec.rb
index bc158fc9117..5f731336b4b 100644
--- a/spec/models/clusters/agent_token_spec.rb
+++ b/spec/models/clusters/agent_token_spec.rb
@@ -95,6 +95,15 @@ RSpec.describe Clusters::AgentToken, feature_category: :deployment_management do
expect(agent_token.token).to start_with described_class::TOKEN_PREFIX
end
+
+ it 'is revoked on revoke!' do
+ agent_token = build(:cluster_agent_token, token_encrypted: nil)
+ agent_token.save!
+
+ agent_token.revoke!
+
+ expect(agent_token.active?).to be_falsey
+ end
end
describe '#to_ability_name' do
diff --git a/spec/requests/api/group_export_spec.rb b/spec/requests/api/group_export_spec.rb
index b4add2494b0..ddee2081bcf 100644
--- a/spec/requests/api/group_export_spec.rb
+++ b/spec/requests/api/group_export_spec.rb
@@ -325,8 +325,13 @@ RSpec.describe API::GroupExport, feature_category: :importers do
end
context 'when bulk import is disabled' do
+ before do
+ stub_application_setting(bulk_import_enabled: false)
+ end
+
it_behaves_like '404 response' do
- let(:request) { get api(path, user) }
+ let(:message) { '404 Not Found' }
+ let(:request) { post api(path, user) }
end
end
end
diff --git a/spec/requests/api/npm_group_packages_spec.rb b/spec/requests/api/npm_group_packages_spec.rb
index 7fba75b0630..12b2ccd1bf7 100644
--- a/spec/requests/api/npm_group_packages_spec.rb
+++ b/spec/requests/api/npm_group_packages_spec.rb
@@ -22,11 +22,11 @@ RSpec.describe API::NpmGroupPackages, feature_category: :package_registry do
where(:auth, :group_visibility, :project_visibility, :user_role, :expected_status) do
nil | :public | :public | nil | :ok
- nil | :public | :internal | nil | :not_found
- nil | :public | :private | nil | :not_found
- nil | :internal | :internal | nil | :not_found
- nil | :internal | :private | nil | :not_found
- nil | :private | :private | nil | :not_found
+ nil | :public | :internal | nil | :unauthorized
+ nil | :public | :private | nil | :unauthorized
+ nil | :internal | :internal | nil | :unauthorized
+ nil | :internal | :private | nil | :unauthorized
+ nil | :private | :private | nil | :unauthorized
:oauth | :public | :public | :guest | :ok
:oauth | :public | :internal | :guest | :ok
diff --git a/spec/requests/api/project_export_spec.rb b/spec/requests/api/project_export_spec.rb
index 3603a71151e..8a47eb2dae1 100644
--- a/spec/requests/api/project_export_spec.rb
+++ b/spec/requests/api/project_export_spec.rb
@@ -708,6 +708,8 @@ RSpec.describe API::ProjectExport, :aggregate_failures, :clean_gitlab_redis_cach
describe 'POST /projects/:id/export_relations' do
it_behaves_like '404 response' do
+ let(:message) { '404 Not Found' }
+
subject(:request) { post api(path, user) }
end
end
@@ -721,12 +723,16 @@ RSpec.describe API::ProjectExport, :aggregate_failures, :clean_gitlab_redis_cach
end
it_behaves_like '404 response' do
- subject(:request) { post api(path, user) }
+ let(:message) { '404 Not Found' }
+
+ subject(:request) { get api(download_path, user) }
end
end
describe 'GET /projects/:id/export_relations/status' do
it_behaves_like '404 response' do
+ let(:message) { '404 Not Found' }
+
subject(:request) { get api(status_path, user) }
end
end
@@ -758,11 +764,5 @@ RSpec.describe API::ProjectExport, :aggregate_failures, :clean_gitlab_redis_cach
end
end
end
-
- context 'when bulk import is disabled' do
- it_behaves_like '404 response' do
- subject(:request) { get api(path, user) }
- end
- end
end
end
diff --git a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
index 5f043cdd996..a4091d6bceb 100644
--- a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
@@ -68,22 +68,22 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
nil | :unscoped | false | :public | nil | :accept | :ok
nil | :non_existing | true | :public | nil | :redirect | :redirected
nil | :non_existing | false | :public | nil | :reject | :not_found
- nil | :scoped_naming_convention | true | :private | nil | :reject | :not_found
- nil | :scoped_naming_convention | false | :private | nil | :reject | :not_found
- nil | :scoped_no_naming_convention | true | :private | nil | :reject | :not_found
- nil | :scoped_no_naming_convention | false | :private | nil | :reject | :not_found
- nil | :unscoped | true | :private | nil | :reject | :not_found
- nil | :unscoped | false | :private | nil | :reject | :not_found
+ nil | :scoped_naming_convention | true | :private | nil | :reject | :unauthorized
+ nil | :scoped_naming_convention | false | :private | nil | :reject | :unauthorized
+ nil | :scoped_no_naming_convention | true | :private | nil | :reject | :unauthorized
+ nil | :scoped_no_naming_convention | false | :private | nil | :reject | :unauthorized
+ nil | :unscoped | true | :private | nil | :reject | :unauthorized
+ nil | :unscoped | false | :private | nil | :reject | :unauthorized
nil | :non_existing | true | :private | nil | :redirect | :redirected
- nil | :non_existing | false | :private | nil | :reject | :not_found
- nil | :scoped_naming_convention | true | :internal | nil | :reject | :not_found
- nil | :scoped_naming_convention | false | :internal | nil | :reject | :not_found
- nil | :scoped_no_naming_convention | true | :internal | nil | :reject | :not_found
- nil | :scoped_no_naming_convention | false | :internal | nil | :reject | :not_found
- nil | :unscoped | true | :internal | nil | :reject | :not_found
- nil | :unscoped | false | :internal | nil | :reject | :not_found
+ nil | :non_existing | false | :private | nil | :reject | :unauthorized
+ nil | :scoped_naming_convention | true | :internal | nil | :reject | :unauthorized
+ nil | :scoped_naming_convention | false | :internal | nil | :reject | :unauthorized
+ nil | :scoped_no_naming_convention | true | :internal | nil | :reject | :unauthorized
+ nil | :scoped_no_naming_convention | false | :internal | nil | :reject | :unauthorized
+ nil | :unscoped | true | :internal | nil | :reject | :unauthorized
+ nil | :unscoped | false | :internal | nil | :reject | :unauthorized
nil | :non_existing | true | :internal | nil | :redirect | :redirected
- nil | :non_existing | false | :internal | nil | :reject | :not_found
+ nil | :non_existing | false | :internal | nil | :reject | :unauthorized
:oauth | :scoped_naming_convention | true | :public | :guest | :accept | :ok
:oauth | :scoped_naming_convention | true | :public | :reporter | :accept | :ok
@@ -280,11 +280,15 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
end
end
- if (scope == :group && params[:package_name_type] == :non_existing) &&
- (!params[:request_forward] || (!params[:auth] && params[:request_forward] && params[:visibility] != :public))
+ if scope == :group && params[:package_name_type] == :non_existing && !params[:request_forward] && params[:auth]
status = :not_found
end
+ if scope == :group && params[:package_name_type] == :non_existing && params[:request_forward] && !params[:auth] && params[:visibility] != :public
+ example_name = 'reject metadata request'
+ status = :unauthorized
+ end
+
# Check the error message for :not_found
example_name = 'returning response status with error' if status == :not_found
@@ -522,14 +526,14 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project|
nil | :scoped_no_naming_convention | :public | nil | :accept | :ok
nil | :unscoped | :public | nil | :accept | :ok
nil | :non_existing | :public | nil | :reject | :not_found
- nil | :scoped_naming_convention | :private | nil | :reject | :not_found
- nil | :scoped_no_naming_convention | :private | nil | :reject | :not_found
- nil | :unscoped | :private | nil | :reject | :not_found
- nil | :non_existing | :private | nil | :reject | :not_found
- nil | :scoped_naming_convention | :internal | nil | :reject | :not_found
- nil | :scoped_no_naming_convention | :internal | nil | :reject | :not_found
- nil | :unscoped | :internal | nil | :reject | :not_found
- nil | :non_existing | :internal | nil | :reject | :not_found
+ nil | :scoped_naming_convention | :private | nil | :reject | :unauthorized
+ nil | :scoped_no_naming_convention | :private | nil | :reject | :unauthorized
+ nil | :unscoped | :private | nil | :reject | :unauthorized
+ nil | :non_existing | :private | nil | :reject | :unauthorized
+ nil | :scoped_naming_convention | :internal | nil | :reject | :unauthorized
+ nil | :scoped_no_naming_convention | :internal | nil | :reject | :unauthorized
+ nil | :unscoped | :internal | nil | :reject | :unauthorized
+ nil | :non_existing | :internal | nil | :reject | :unauthorized
:oauth | :scoped_naming_convention | :public | :guest | :accept | :ok
:oauth | :scoped_naming_convention | :public | :reporter | :accept | :ok
diff --git a/spec/workers/merge_worker_spec.rb b/spec/workers/merge_worker_spec.rb
index 9c6a6564df6..48d8ea3ab16 100644
--- a/spec/workers/merge_worker_spec.rb
+++ b/spec/workers/merge_worker_spec.rb
@@ -48,4 +48,61 @@ RSpec.describe MergeWorker, feature_category: :source_code_management do
end
end
end
+
+ describe 'delegation to MergeRequests::MergeService' do
+ # Some ids that should be nonexistentn
+ let(:user_id) { -1 }
+ let(:merge_request_id) { -1 }
+ let(:params) { {} }
+
+ subject { described_class.new.perform(merge_request_id, user_id, params) }
+
+ context 'when user exists' do
+ let!(:user) { create(:user) }
+ let(:user_id) { user.id }
+
+ context 'and merge request exists' do
+ let!(:merge_request) { create(:merge_request, source_project: create(:project, :empty_repo)) }
+ let(:merge_request_id) { merge_request.id }
+ let(:user) { merge_request.author }
+ let(:merge_service_double) { instance_double(MergeRequests::MergeService) }
+
+ it 'delegates to MergeRequests::MergeService' do
+ expect(MergeRequests::MergeService).to receive(:new).with(
+ project: merge_request.target_project,
+ current_user: user,
+ params: { check_mergeability_retry_lease: true }
+ ).and_return(merge_service_double)
+
+ expect(merge_service_double).to receive(:execute)
+ subject
+ end
+
+ context 'and check_mergeability_retry_lease is specified' do
+ let(:params) { { check_mergeability_retry_lease: false } }
+
+ it 'does not change the check_mergeability_retry_lease parameter' do
+ expect(MergeRequests::MergeService).to receive(:new).with(
+ project: merge_request.target_project,
+ current_user: user,
+ params: params
+ ).and_return(merge_service_double)
+
+ expect(merge_service_double).to receive(:execute)
+ subject
+ end
+ end
+ end
+
+ it 'does not call MergeRequests::MergeService' do
+ expect(MergeRequests::MergeService).not_to receive(:new)
+ subject
+ end
+ end
+
+ it 'does not call MergeRequests::MergeService' do
+ expect(MergeRequests::MergeService).not_to receive(:new)
+ subject
+ end
+ end
end
diff --git a/yarn.lock b/yarn.lock
index 4821b2360e7..ca8eef5815a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3510,6 +3510,11 @@ asynckit@^0.4.0:
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+at-least-node@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
+ integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
+
atob@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
@@ -4184,9 +4189,9 @@ ci-info@^2.0.0:
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
ci-info@^3.2.0, ci-info@^3.3.0:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.1.tgz#58331f6f472a25fe3a50a351ae3052936c2c7f32"
- integrity sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91"
+ integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
@@ -6859,14 +6864,15 @@ from2@^2.1.0:
inherits "^2.0.1"
readable-stream "^2.0.0"
-fs-extra@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
- integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+fs-extra@^9.0.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
+ integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
dependencies:
- graceful-fs "^4.1.2"
- jsonfile "^4.0.0"
- universalify "^0.1.0"
+ at-least-node "^1.0.0"
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
fs-minipass@^2.0.0:
version "2.0.0"
@@ -7130,10 +7136,10 @@ gopd@^1.0.1:
dependencies:
get-intrinsic "^1.1.3"
-graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
- version "4.2.10"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
- integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
+graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
graphemer@^1.4.0:
version "1.4.0"
@@ -8687,10 +8693,12 @@ jsonc-parser@^3.0.0, jsonc-parser@~3.2.0:
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
-jsonfile@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
- integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
+jsonfile@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+ integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+ dependencies:
+ universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
@@ -10610,24 +10618,25 @@ pascalcase@^0.1.1:
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
-patch-package@^6.4.7:
- version "6.4.7"
- resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148"
- integrity sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ==
+patch-package@6.5.1:
+ version "6.5.1"
+ resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.5.1.tgz#3e5d00c16997e6160291fee06a521c42ac99b621"
+ integrity sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA==
dependencies:
"@yarnpkg/lockfile" "^1.1.0"
- chalk "^2.4.2"
+ chalk "^4.1.2"
cross-spawn "^6.0.5"
find-yarn-workspace-root "^2.0.0"
- fs-extra "^7.0.1"
+ fs-extra "^9.0.0"
is-ci "^2.0.0"
klaw-sync "^6.0.0"
- minimist "^1.2.0"
+ minimist "^1.2.6"
open "^7.4.2"
rimraf "^2.6.3"
semver "^5.6.0"
slash "^2.0.0"
tmp "^0.0.33"
+ yaml "^1.10.2"
path-browserify@0.0.1:
version "0.0.1"
@@ -11852,9 +11861,9 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1:
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.4, semver@^7.3.5, semver@^7.3.6, semver@^7.3.7, semver@^7.5.0:
- version "7.5.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0"
- integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
@@ -13246,11 +13255,16 @@ unist-util-visit@^4.0.0:
unist-util-is "^5.0.0"
unist-util-visit-parents "^5.0.0"
-universalify@^0.1.0, universalify@^0.1.2:
+universalify@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+universalify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
+ integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
+
unixify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090"
@@ -14096,10 +14110,15 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+yaml@^1.10.2:
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
+ integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+
yaml@^2.0.0, yaml@^2.0.0-10:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec"
- integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144"
+ integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==
yargs-parser@^18.1.2:
version "18.1.3"