Update upstream source from tag 'upstream/15.5.7+ds1'
Update to upstream version '15.5.7+ds1'
with Debian dir ab44def76f
This commit is contained in:
commit
f142dbd410
102 changed files with 1639 additions and 823 deletions
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -2,6 +2,41 @@
|
||||||
documentation](doc/development/changelog.md) for instructions on adding your own
|
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||||
entry.
|
entry.
|
||||||
|
|
||||||
|
## 15.5.7 (2023-01-09)
|
||||||
|
|
||||||
|
### Security (10 changes)
|
||||||
|
|
||||||
|
- [Avoid regex with potential for poorly performing backtracking](gitlab-org/security/gitlab@c3f8d8c93e99ac3f226668086bfbf21739b02a0e) ([merge request](gitlab-org/security/gitlab!2989))
|
||||||
|
- [Protect web-hook url variables after changing URL](gitlab-org/security/gitlab@8a18fea752a2759938b4c3d28516b6ed9386404f) ([merge request](gitlab-org/security/gitlab!2978))
|
||||||
|
- [Limit the size of user agent to reduce ReDos attack](gitlab-org/security/gitlab@293db707009b7dd133a9a55b25892506013062fd) ([merge request](gitlab-org/security/gitlab!2991))
|
||||||
|
- [Only allow safe params for diff helper](gitlab-org/security/gitlab@0c5de464c1d062103d6bc81cca45f7298929ca68) ([merge request](gitlab-org/security/gitlab!2951))
|
||||||
|
- [Protect Sentry auth-token after changing URL](gitlab-org/security/gitlab@a2c3380748eb3aa36f23c74f1666c741fafec635) ([merge request](gitlab-org/security/gitlab!2986))
|
||||||
|
- [Delete project specific licenses when license policy is deleted](gitlab-org/security/gitlab@312a28196df206b501861b6528b4b6fcaf7cc686) ([merge request](gitlab-org/security/gitlab!2896))
|
||||||
|
- [Restrict user avatar availability based on visibility restrictions](gitlab-org/security/gitlab@f7b5c0a57b64c15edb0f555dd53c26b9d6147f0e) ([merge request](gitlab-org/security/gitlab!2973))
|
||||||
|
- [Policy change to read and destroy token without license for .com](gitlab-org/security/gitlab@b51bc20ba07d8ef3d339aeacd1b0f904521f4158) ([merge request](gitlab-org/security/gitlab!2914))
|
||||||
|
- [Restrict Grafana API access on public projects](gitlab-org/security/gitlab@d9798aa2d31ddef9ed6fedfc7b32bc8a8bac76bc) ([merge request](gitlab-org/security/gitlab!2959))
|
||||||
|
- [Fix "Race condition enables verified email forgery"](gitlab-org/security/gitlab@95e65f637ed193b9c8b3c39af58a9bc0d552bad2) ([merge request](gitlab-org/security/gitlab!2962))
|
||||||
|
|
||||||
|
## 15.5.6 (2022-12-07)
|
||||||
|
|
||||||
|
No changes.
|
||||||
|
|
||||||
|
## 15.5.5 (2022-11-30)
|
||||||
|
|
||||||
|
### Security (11 changes)
|
||||||
|
|
||||||
|
- [Send resolved_address param to gitaly during repository import](gitlab-org/security/gitlab@768edcdca74fa09f7ba50c324aacd86fb71ed7e7) ([merge request](gitlab-org/security/gitlab!2939))
|
||||||
|
- [Add size validation during nuspec file extraction](gitlab-org/security/gitlab@27f79d015684896b66e0418db253613e3efa1df7) ([merge request](gitlab-org/security/gitlab!2936))
|
||||||
|
- [Cross-site scripting in Jira Integration](gitlab-org/security/gitlab@efcb2fc3110b7cf997b3e1a1e173e6462a54f208) ([merge request](gitlab-org/security/gitlab!2931))
|
||||||
|
- [Protect web-hook secret tokens after changing URL](gitlab-org/security/gitlab@00b75ba0c52c10a578091ad89440e8ae78cbe066) ([merge request](gitlab-org/security/gitlab!2921))
|
||||||
|
- [Redact secret tokens from web-hook logs](gitlab-org/security/gitlab@27699db7e44e7808f5ec415860ed03c55ae554b0) ([merge request](gitlab-org/security/gitlab!2917))
|
||||||
|
- [Prevent unauthorized users from seeing Release information on tag pages](gitlab-org/security/gitlab@112d45bdba5e0d34f77eec1ffaf86443e28b2c8c) ([merge request](gitlab-org/security/gitlab!2926))
|
||||||
|
- [Update after_import to expire cache before removing prohibited branches](gitlab-org/security/gitlab@5e84ca50689dceb7614e181ee7addbc3671dc935) ([merge request](gitlab-org/security/gitlab!2904))
|
||||||
|
- [Deny all package permissions when group access is restricted by IP](gitlab-org/security/gitlab@23a8ba46641053317c45f58037499235438b5ad8) ([merge request](gitlab-org/security/gitlab!2901))
|
||||||
|
- [Redact user emails from project webhook data](gitlab-org/security/gitlab@9f49c4d34fffd598af19d2db548281847855f987) ([merge request](gitlab-org/security/gitlab!2907))
|
||||||
|
- [Disallow local URls for build_runner_session if dictated by app setting](gitlab-org/security/gitlab@087415cf7a780c97b1d4055590858a98c673c64b) ([merge request](gitlab-org/security/gitlab!2867))
|
||||||
|
- [Prevent token bypass for extenal authorisation](gitlab-org/security/gitlab@96a6193a6e03bd1f76c2792cca404d2e672dfcf4) ([merge request](gitlab-org/security/gitlab!2884))
|
||||||
|
|
||||||
## 15.5.4 (2022-11-11)
|
## 15.5.4 (2022-11-11)
|
||||||
|
|
||||||
### Fixed (3 changes)
|
### Fixed (3 changes)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
15.5.4
|
15.5.7
|
|
@ -1 +1 @@
|
||||||
1.62.0
|
15.5.7
|
2
Gemfile
2
Gemfile
|
@ -503,7 +503,7 @@ gem 'ssh_data', '~> 1.3'
|
||||||
gem 'spamcheck', '~> 1.0.0'
|
gem 'spamcheck', '~> 1.0.0'
|
||||||
|
|
||||||
# Gitaly GRPC protocol definitions
|
# Gitaly GRPC protocol definitions
|
||||||
gem 'gitaly', '~> 15.4.0-rc2'
|
gem 'gitaly', '~> 15.5.2'
|
||||||
|
|
||||||
# KAS GRPC protocol definitions
|
# KAS GRPC protocol definitions
|
||||||
gem 'kas-grpc', '~> 0.0.2'
|
gem 'kas-grpc', '~> 0.0.2'
|
||||||
|
|
|
@ -198,7 +198,7 @@
|
||||||
{"name":"gettext_i18n_rails","version":"1.8.0","platform":"ruby","checksum":"95e5cf8440b1e08705b27f2bccb56143272c5a7a0dabcf54ea1bd701140a496f"},
|
{"name":"gettext_i18n_rails","version":"1.8.0","platform":"ruby","checksum":"95e5cf8440b1e08705b27f2bccb56143272c5a7a0dabcf54ea1bd701140a496f"},
|
||||||
{"name":"gettext_i18n_rails_js","version":"1.3.0","platform":"ruby","checksum":"5d10afe4be3639bff78c50a56768c20f39aecdabc580c08aa45573911c2bd687"},
|
{"name":"gettext_i18n_rails_js","version":"1.3.0","platform":"ruby","checksum":"5d10afe4be3639bff78c50a56768c20f39aecdabc580c08aa45573911c2bd687"},
|
||||||
{"name":"git","version":"1.11.0","platform":"ruby","checksum":"7e95ba4da8298a0373ef1a6862aa22007d761f3c8274b675aa787966fecea0f1"},
|
{"name":"git","version":"1.11.0","platform":"ruby","checksum":"7e95ba4da8298a0373ef1a6862aa22007d761f3c8274b675aa787966fecea0f1"},
|
||||||
{"name":"gitaly","version":"15.4.0.pre.rc2","platform":"ruby","checksum":"48764528a730605a46f00cf86c7cfcb92d25f4f3d8cb9e09557baac3e9f3f8e3"},
|
{"name":"gitaly","version":"15.5.2","platform":"ruby","checksum":"62babe0596a4505bf95051ea50f17160055e6cf6cacf209273691542120d7881"},
|
||||||
{"name":"github-markup","version":"1.7.0","platform":"ruby","checksum":"97eb27c70662d9cc1d5997cd6c99832026fae5d4913b5dce1ce6c9f65078e69d"},
|
{"name":"github-markup","version":"1.7.0","platform":"ruby","checksum":"97eb27c70662d9cc1d5997cd6c99832026fae5d4913b5dce1ce6c9f65078e69d"},
|
||||||
{"name":"gitlab","version":"4.16.1","platform":"ruby","checksum":"13fd7059cbdad5a1a21b15fa2cf9070b97d92e27f8c688581fe3d84dc038074f"},
|
{"name":"gitlab","version":"4.16.1","platform":"ruby","checksum":"13fd7059cbdad5a1a21b15fa2cf9070b97d92e27f8c688581fe3d84dc038074f"},
|
||||||
{"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"},
|
{"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"},
|
||||||
|
|
|
@ -547,7 +547,7 @@ GEM
|
||||||
rails (>= 3.2.0)
|
rails (>= 3.2.0)
|
||||||
git (1.11.0)
|
git (1.11.0)
|
||||||
rchardet (~> 1.8)
|
rchardet (~> 1.8)
|
||||||
gitaly (15.4.0.pre.rc2)
|
gitaly (15.5.2)
|
||||||
grpc (~> 1.0)
|
grpc (~> 1.0)
|
||||||
github-markup (1.7.0)
|
github-markup (1.7.0)
|
||||||
gitlab (4.16.1)
|
gitlab (4.16.1)
|
||||||
|
@ -1622,7 +1622,7 @@ DEPENDENCIES
|
||||||
gettext (~> 3.3)
|
gettext (~> 3.3)
|
||||||
gettext_i18n_rails (~> 1.8.0)
|
gettext_i18n_rails (~> 1.8.0)
|
||||||
gettext_i18n_rails_js (~> 1.3)
|
gettext_i18n_rails_js (~> 1.3)
|
||||||
gitaly (~> 15.4.0.pre.rc2)
|
gitaly (~> 15.5.2)
|
||||||
github-markup (~> 1.7.0)
|
github-markup (~> 1.7.0)
|
||||||
gitlab-chronic (~> 0.10.5)
|
gitlab-chronic (~> 0.10.5)
|
||||||
gitlab-dangerfiles (~> 3.5.2)
|
gitlab-dangerfiles (~> 3.5.2)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
15.5.4
|
15.5.7
|
|
@ -57,7 +57,7 @@ module PageLimiter
|
||||||
|
|
||||||
# Record the page limit being hit in Prometheus
|
# Record the page limit being hit in Prometheus
|
||||||
def record_page_limit_interception
|
def record_page_limit_interception
|
||||||
dd = DeviceDetector.new(request.user_agent)
|
dd = Gitlab::SafeDeviceDetector.new(request.user_agent)
|
||||||
|
|
||||||
Gitlab::Metrics.counter(:gitlab_page_out_of_bounds,
|
Gitlab::Metrics.counter(:gitlab_page_out_of_bounds,
|
||||||
controller: params[:controller],
|
controller: params[:controller],
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
|
class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
|
||||||
feature_category :authentication_and_authorization
|
feature_category :authentication_and_authorization
|
||||||
|
|
||||||
before_action :check_personal_access_tokens_enabled
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
set_index_vars
|
set_index_vars
|
||||||
scopes = params[:scopes].split(',').map(&:squish).select(&:present?).map(&:to_sym) unless params[:scopes].nil?
|
scopes = params[:scopes].split(',').map(&:squish).select(&:present?).map(&:to_sym) unless params[:scopes].nil?
|
||||||
|
@ -85,8 +83,4 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
|
||||||
def page
|
def page
|
||||||
(params[:page] || 1).to_i
|
(params[:page] || 1).to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_personal_access_tokens_enabled
|
|
||||||
render_404 if Gitlab::CurrentSettings.personal_access_tokens_disabled?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,8 @@ class Projects::GrafanaApiController < Projects::ApplicationController
|
||||||
include RenderServiceResults
|
include RenderServiceResults
|
||||||
include MetricsDashboard
|
include MetricsDashboard
|
||||||
|
|
||||||
|
before_action :authorize_read_grafana!, only: :proxy
|
||||||
|
|
||||||
feature_category :metrics
|
feature_category :metrics
|
||||||
urgency :low
|
urgency :low
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ class UploadsController < ApplicationController
|
||||||
# access to itself when a secret is given.
|
# access to itself when a secret is given.
|
||||||
# For instance, user avatars are readable by anyone,
|
# For instance, user avatars are readable by anyone,
|
||||||
# while temporary, user snippet uploads are not.
|
# while temporary, user snippet uploads are not.
|
||||||
|
return false if !current_user && public_visibility_restricted?
|
||||||
|
|
||||||
!secret? || can?(current_user, :update_user, model)
|
!secret? || can?(current_user, :update_user, model)
|
||||||
when Appearance
|
when Appearance
|
||||||
true
|
true
|
||||||
|
|
|
@ -244,6 +244,10 @@ module DiffHelper
|
||||||
{}
|
{}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def params_with_whitespace
|
||||||
|
hide_whitespace? ? safe_params.except(:w) : safe_params.merge(w: 1)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def diff_btn(title, name, selected)
|
def diff_btn(title, name, selected)
|
||||||
|
@ -277,10 +281,6 @@ module DiffHelper
|
||||||
params[:w] == '1'
|
params[:w] == '1'
|
||||||
end
|
end
|
||||||
|
|
||||||
def params_with_whitespace
|
|
||||||
hide_whitespace? ? request.query_parameters.except(:w) : request.query_parameters.merge(w: 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
def toggle_whitespace_link(url, options)
|
def toggle_whitespace_link(url, options)
|
||||||
options[:class] = [*options[:class], 'btn gl-button btn-default'].join(' ')
|
options[:class] = [*options[:class], 'btn gl-button btn-default'].join(' ')
|
||||||
link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: options[:class]
|
link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: options[:class]
|
||||||
|
|
|
@ -17,40 +17,26 @@ module SubmoduleHelper
|
||||||
url = File.join(Gitlab.config.gitlab.url, repository.project.full_path)
|
url = File.join(Gitlab.config.gitlab.url, repository.project.full_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
if url =~ %r{([^/:]+)/([^/]+(?:\.git)?)\Z}
|
namespace, project = extract_namespace_project(url)
|
||||||
namespace = Regexp.last_match(1)
|
|
||||||
project = Regexp.last_match(2)
|
|
||||||
gitlab_hosts = [Gitlab.config.gitlab.url,
|
|
||||||
Gitlab.config.gitlab_shell.ssh_path_prefix]
|
|
||||||
|
|
||||||
gitlab_hosts.each do |host|
|
if namespace.blank? || project.blank?
|
||||||
if url.start_with?(host)
|
return [sanitize_submodule_url(url), nil, nil]
|
||||||
namespace, _, project = url.sub(host, '').rpartition('/')
|
end
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
namespace.delete_prefix!('/')
|
if self_url?(url, namespace, project)
|
||||||
project.rstrip!
|
[
|
||||||
project.delete_suffix!('.git')
|
url_helpers.namespace_project_path(namespace, project),
|
||||||
|
url_helpers.namespace_project_tree_path(namespace, project, submodule_item_id),
|
||||||
if self_url?(url, namespace, project)
|
(url_helpers.namespace_project_compare_path(namespace, project, to: submodule_item_id, from: old_submodule_item_id) if old_submodule_item_id)
|
||||||
[
|
]
|
||||||
url_helpers.namespace_project_path(namespace, project),
|
elsif relative_self_url?(url)
|
||||||
url_helpers.namespace_project_tree_path(namespace, project, submodule_item_id),
|
relative_self_links(url, submodule_item_id, old_submodule_item_id, repository.project)
|
||||||
(url_helpers.namespace_project_compare_path(namespace, project, to: submodule_item_id, from: old_submodule_item_id) if old_submodule_item_id)
|
elsif gist_github_dot_com_url?(url)
|
||||||
]
|
gist_github_com_tree_links(namespace, project, submodule_item_id)
|
||||||
elsif relative_self_url?(url)
|
elsif github_dot_com_url?(url)
|
||||||
relative_self_links(url, submodule_item_id, old_submodule_item_id, repository.project)
|
github_com_tree_links(namespace, project, submodule_item_id, old_submodule_item_id)
|
||||||
elsif gist_github_dot_com_url?(url)
|
elsif gitlab_dot_com_url?(url)
|
||||||
gist_github_com_tree_links(namespace, project, submodule_item_id)
|
gitlab_com_tree_links(namespace, project, submodule_item_id, old_submodule_item_id)
|
||||||
elsif github_dot_com_url?(url)
|
|
||||||
github_com_tree_links(namespace, project, submodule_item_id, old_submodule_item_id)
|
|
||||||
elsif gitlab_dot_com_url?(url)
|
|
||||||
gitlab_com_tree_links(namespace, project, submodule_item_id, old_submodule_item_id)
|
|
||||||
else
|
|
||||||
[sanitize_submodule_url(url), nil, nil]
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
[sanitize_submodule_url(url), nil, nil]
|
[sanitize_submodule_url(url), nil, nil]
|
||||||
end
|
end
|
||||||
|
@ -58,6 +44,30 @@ module SubmoduleHelper
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
def extract_namespace_project(url)
|
||||||
|
namespace_fragment, _, project = url.rpartition('/')
|
||||||
|
namespace = namespace_fragment.rpartition(%r{[:/]}).last
|
||||||
|
|
||||||
|
return [nil, nil] unless project.present? && namespace.present?
|
||||||
|
|
||||||
|
gitlab_hosts = [Gitlab.config.gitlab.url,
|
||||||
|
Gitlab.config.gitlab_shell.ssh_path_prefix]
|
||||||
|
|
||||||
|
matching_host = gitlab_hosts.find do |host|
|
||||||
|
url.start_with?(host)
|
||||||
|
end
|
||||||
|
|
||||||
|
if matching_host
|
||||||
|
namespace, _, project = url.delete_prefix(matching_host).rpartition('/')
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace.delete_prefix!('/')
|
||||||
|
project.rstrip!
|
||||||
|
project.delete_suffix!('.git')
|
||||||
|
|
||||||
|
[namespace, project]
|
||||||
|
end
|
||||||
|
|
||||||
def gist_github_dot_com_url?(url)
|
def gist_github_dot_com_url?(url)
|
||||||
url =~ %r{gist\.github\.com[/:][^/]+/[^/]+\Z}
|
url =~ %r{gist\.github\.com[/:][^/]+/[^/]+\Z}
|
||||||
end
|
end
|
||||||
|
|
|
@ -67,7 +67,7 @@ class ActiveSession
|
||||||
def self.set(user, request)
|
def self.set(user, request)
|
||||||
Gitlab::Redis::Sessions.with do |redis|
|
Gitlab::Redis::Sessions.with do |redis|
|
||||||
session_private_id = request.session.id.private_id
|
session_private_id = request.session.id.private_id
|
||||||
client = DeviceDetector.new(request.user_agent)
|
client = Gitlab::SafeDeviceDetector.new(request.user_agent)
|
||||||
timestamp = Time.current
|
timestamp = Time.current
|
||||||
expiry = Settings.gitlab['session_expire_delay'] * 60
|
expiry = Settings.gitlab['session_expire_delay'] * 60
|
||||||
|
|
||||||
|
|
|
@ -799,10 +799,6 @@ class ApplicationSetting < ApplicationRecord
|
||||||
::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES.include?(diagram_type)
|
::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES.include?(diagram_type)
|
||||||
end
|
end
|
||||||
|
|
||||||
def personal_access_tokens_disabled?
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def parsed_grafana_url
|
def parsed_grafana_url
|
||||||
|
|
|
@ -13,14 +13,15 @@ module Ci
|
||||||
belongs_to :build, class_name: 'Ci::Build', inverse_of: :runner_session
|
belongs_to :build, class_name: 'Ci::Build', inverse_of: :runner_session
|
||||||
|
|
||||||
validates :build, presence: true
|
validates :build, presence: true
|
||||||
validates :url, addressable_url: { schemes: %w(https) }
|
validates :url, public_url: { schemes: %w(https) }
|
||||||
|
|
||||||
def terminal_specification
|
def terminal_specification
|
||||||
wss_url = Gitlab::UrlHelpers.as_wss(self.url)
|
wss_url = Gitlab::UrlHelpers.as_wss(Addressable::URI.escape(self.url))
|
||||||
return {} unless wss_url.present?
|
return {} unless wss_url.present?
|
||||||
|
|
||||||
wss_url = "#{wss_url}/exec"
|
parsed_wss_url = URI.parse(wss_url)
|
||||||
channel_specification(wss_url, TERMINAL_SUBPROTOCOL)
|
parsed_wss_url.path += '/exec'
|
||||||
|
channel_specification(parsed_wss_url, TERMINAL_SUBPROTOCOL)
|
||||||
end
|
end
|
||||||
|
|
||||||
def service_specification(service: nil, path: nil, port: nil, subprotocols: nil)
|
def service_specification(service: nil, path: nil, port: nil, subprotocols: nil)
|
||||||
|
@ -28,20 +29,21 @@ module Ci
|
||||||
|
|
||||||
port = port.presence || DEFAULT_PORT_NAME
|
port = port.presence || DEFAULT_PORT_NAME
|
||||||
service = service.presence || DEFAULT_SERVICE_NAME
|
service = service.presence || DEFAULT_SERVICE_NAME
|
||||||
url = "#{self.url}/proxy/#{service}/#{port}/#{path}"
|
parsed_url = URI.parse(Addressable::URI.escape(self.url))
|
||||||
|
parsed_url.path += "/proxy/#{service}/#{port}/#{path}"
|
||||||
subprotocols = subprotocols.presence || ::Ci::BuildRunnerSession::TERMINAL_SUBPROTOCOL
|
subprotocols = subprotocols.presence || ::Ci::BuildRunnerSession::TERMINAL_SUBPROTOCOL
|
||||||
|
|
||||||
channel_specification(url, subprotocols)
|
channel_specification(parsed_url, subprotocols)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def channel_specification(url, subprotocol)
|
def channel_specification(parsed_url, subprotocol)
|
||||||
return {} if subprotocol.blank? || url.blank?
|
return {} if subprotocol.blank? || parsed_url.blank?
|
||||||
|
|
||||||
{
|
{
|
||||||
subprotocols: Array(subprotocol),
|
subprotocols: Array(subprotocol),
|
||||||
url: url,
|
url: Addressable::URI.unescape(parsed_url.to_s),
|
||||||
headers: { Authorization: [authorization.presence] }.compact,
|
headers: { Authorization: [authorization.presence] }.compact,
|
||||||
ca_pem: certificate.presence
|
ca_pem: certificate.presence
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ class WebHook < ApplicationRecord
|
||||||
validate :no_missing_url_variables
|
validate :no_missing_url_variables
|
||||||
|
|
||||||
after_initialize :initialize_url_variables
|
after_initialize :initialize_url_variables
|
||||||
|
before_validation :reset_token
|
||||||
|
before_validation :reset_url_variables, unless: ->(hook) { hook.is_a?(ServiceHook) }
|
||||||
|
|
||||||
scope :executable, -> do
|
scope :executable, -> do
|
||||||
next all unless Feature.enabled?(:web_hooks_disable_failed)
|
next all unless Feature.enabled?(:web_hooks_disable_failed)
|
||||||
|
@ -200,6 +202,14 @@ class WebHook < ApplicationRecord
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def reset_token
|
||||||
|
self.token = nil if url_changed? && !encrypted_token_changed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_url_variables
|
||||||
|
self.url_variables = {} if url_changed? && !encrypted_url_variables_changed?
|
||||||
|
end
|
||||||
|
|
||||||
def web_hooks_disable_failed?
|
def web_hooks_disable_failed?
|
||||||
self.class.web_hooks_disable_failed?(self)
|
self.class.web_hooks_disable_failed?(self)
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,6 +48,13 @@ class WebHookLog < ApplicationRecord
|
||||||
request_data == OVERSIZE_REQUEST_DATA
|
request_data == OVERSIZE_REQUEST_DATA
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def request_headers
|
||||||
|
super unless web_hook.token?
|
||||||
|
super if self[:request_headers]['X-Gitlab-Token'] == _('[REDACTED]')
|
||||||
|
|
||||||
|
self[:request_headers].merge('X-Gitlab-Token' => _('[REDACTED]'))
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def obfuscate_basic_auth
|
def obfuscate_basic_auth
|
||||||
|
|
|
@ -98,7 +98,10 @@ module Integrations
|
||||||
def self.valid_jira_cloud_url?(url)
|
def self.valid_jira_cloud_url?(url)
|
||||||
return false unless url.present?
|
return false unless url.present?
|
||||||
|
|
||||||
!!URI(url).hostname&.end_with?(JIRA_CLOUD_HOST)
|
uri = URI.parse(url)
|
||||||
|
uri.is_a?(URI::HTTPS) && !!uri.hostname&.end_with?(JIRA_CLOUD_HOST)
|
||||||
|
rescue URI::InvalidURIError
|
||||||
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def data_fields
|
def data_fields
|
||||||
|
|
|
@ -2145,8 +2145,8 @@ class Project < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_import
|
def after_import
|
||||||
repository.remove_prohibited_branches
|
|
||||||
repository.expire_content_cache
|
repository.expire_content_cache
|
||||||
|
repository.remove_prohibited_branches
|
||||||
wiki.repository.expire_content_cache
|
wiki.repository.expire_content_cache
|
||||||
|
|
||||||
DetectRepositoryLanguagesWorker.perform_async(id)
|
DetectRepositoryLanguagesWorker.perform_async(id)
|
||||||
|
|
|
@ -980,12 +980,12 @@ class Repository
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def clone_as_mirror(url, http_authorization_header: "")
|
def clone_as_mirror(url, http_authorization_header: "", resolved_address: "")
|
||||||
import_repository(url, http_authorization_header: http_authorization_header, mirror: true)
|
import_repository(url, http_authorization_header: http_authorization_header, mirror: true, resolved_address: resolved_address)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_as_mirror(url, forced: false, refmap: :all_refs, prune: true, http_authorization_header: "")
|
def fetch_as_mirror(url, forced: false, refmap: :all_refs, prune: true, http_authorization_header: "", resolved_address: "")
|
||||||
fetch_remote(url, refmap: refmap, forced: forced, prune: prune, http_authorization_header: http_authorization_header)
|
fetch_remote(url, refmap: refmap, forced: forced, prune: prune, http_authorization_header: http_authorization_header, resolved_address: resolved_address)
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_source_branch!(source_repository, source_branch, local_ref)
|
def fetch_source_branch!(source_repository, source_branch, local_ref)
|
||||||
|
|
|
@ -1574,7 +1574,7 @@ class User < ApplicationRecord
|
||||||
name: name,
|
name: name,
|
||||||
username: username,
|
username: username,
|
||||||
avatar_url: avatar_url(only_path: false),
|
avatar_url: avatar_url(only_path: false),
|
||||||
email: public_email.presence || _('[REDACTED]')
|
email: webhook_email
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,9 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
|
||||||
rule { can?(:admin_group) & resource_access_token_feature_available }.policy do
|
rule { can?(:admin_group) & resource_access_token_feature_available }.policy do
|
||||||
enable :read_resource_access_tokens
|
enable :read_resource_access_tokens
|
||||||
enable :destroy_resource_access_tokens
|
enable :destroy_resource_access_tokens
|
||||||
|
end
|
||||||
|
|
||||||
|
rule { can?(:admin_group) & resource_access_token_creation_allowed }.policy do
|
||||||
enable :admin_setting_to_allow_project_access_token_creation
|
enable :admin_setting_to_allow_project_access_token_creation
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -332,12 +335,16 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resource_access_token_create_feature_available?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
def can_read_group_member?
|
def can_read_group_member?
|
||||||
!(@subject.private? && access_level == GroupMember::NO_ACCESS)
|
!(@subject.private? && access_level == GroupMember::NO_ACCESS)
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_access_token_creation_allowed?
|
def resource_access_token_creation_allowed?
|
||||||
resource_access_token_feature_available? && group.root_ancestor.namespace_settings.resource_access_token_creation_allowed?
|
resource_access_token_create_feature_available? && group.root_ancestor.namespace_settings.resource_access_token_creation_allowed?
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid_dependency_proxy_deploy_token
|
def valid_dependency_proxy_deploy_token
|
||||||
|
|
|
@ -25,3 +25,5 @@ module Packages
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Packages::Policies::GroupPolicy.prepend_mod_with('Packages::Policies::GroupPolicy')
|
||||||
|
|
|
@ -52,3 +52,5 @@ module Packages
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Packages::Policies::ProjectPolicy.prepend_mod_with('Packages::Policies::ProjectPolicy')
|
||||||
|
|
|
@ -157,7 +157,9 @@ class ProjectPolicy < BasePolicy
|
||||||
condition(:service_desk_enabled) { @subject.service_desk_enabled? }
|
condition(:service_desk_enabled) { @subject.service_desk_enabled? }
|
||||||
|
|
||||||
with_scope :subject
|
with_scope :subject
|
||||||
condition(:resource_access_token_feature_available) { resource_access_token_feature_available? }
|
condition(:resource_access_token_feature_available) do
|
||||||
|
resource_access_token_feature_available?
|
||||||
|
end
|
||||||
condition(:resource_access_token_creation_allowed) { resource_access_token_creation_allowed? }
|
condition(:resource_access_token_creation_allowed) { resource_access_token_creation_allowed? }
|
||||||
|
|
||||||
# We aren't checking `:read_issue` or `:read_merge_request` in this case
|
# We aren't checking `:read_issue` or `:read_merge_request` in this case
|
||||||
|
@ -310,6 +312,8 @@ class ProjectPolicy < BasePolicy
|
||||||
rule { guest & can?(:download_code) }.enable :build_download_code
|
rule { guest & can?(:download_code) }.enable :build_download_code
|
||||||
rule { guest & can?(:read_container_image) }.enable :build_read_container_image
|
rule { guest & can?(:read_container_image) }.enable :build_read_container_image
|
||||||
|
|
||||||
|
rule { guest & ~public_project }.enable :read_grafana
|
||||||
|
|
||||||
rule { can?(:reporter_access) }.policy do
|
rule { can?(:reporter_access) }.policy do
|
||||||
enable :admin_issue_board
|
enable :admin_issue_board
|
||||||
enable :download_code
|
enable :download_code
|
||||||
|
@ -342,6 +346,7 @@ class ProjectPolicy < BasePolicy
|
||||||
enable :read_package
|
enable :read_package
|
||||||
enable :read_product_analytics
|
enable :read_product_analytics
|
||||||
enable :read_ci_cd_analytics
|
enable :read_ci_cd_analytics
|
||||||
|
enable :read_grafana
|
||||||
end
|
end
|
||||||
|
|
||||||
# We define `:public_user_access` separately because there are cases in gitlab-ee
|
# We define `:public_user_access` separately because there are cases in gitlab-ee
|
||||||
|
@ -794,7 +799,7 @@ class ProjectPolicy < BasePolicy
|
||||||
|
|
||||||
rule { project_bot }.enable :project_bot_access
|
rule { project_bot }.enable :project_bot_access
|
||||||
|
|
||||||
rule { can?(:read_all_resources) & resource_access_token_feature_available }.enable :read_resource_access_tokens
|
rule { can?(:read_all_resources) }.enable :read_resource_access_tokens
|
||||||
|
|
||||||
rule { can?(:admin_project) & resource_access_token_feature_available }.policy do
|
rule { can?(:admin_project) & resource_access_token_feature_available }.policy do
|
||||||
enable :read_resource_access_tokens
|
enable :read_resource_access_tokens
|
||||||
|
@ -915,12 +920,16 @@ class ProjectPolicy < BasePolicy
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resource_access_token_create_feature_available?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
def resource_access_token_creation_allowed?
|
def resource_access_token_creation_allowed?
|
||||||
group = project.group
|
group = project.group
|
||||||
|
|
||||||
return true unless group # always enable for projects in personal namespaces
|
return true unless group # always enable for projects in personal namespaces
|
||||||
|
|
||||||
resource_access_token_feature_available? && group.root_ancestor.namespace_settings.resource_access_token_creation_allowed?
|
resource_access_token_create_feature_available? && group.root_ancestor.namespace_settings.resource_access_token_creation_allowed?
|
||||||
end
|
end
|
||||||
|
|
||||||
def project
|
def project
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
module ErrorTracking
|
module ErrorTracking
|
||||||
class ListProjectsService < ErrorTracking::BaseService
|
class ListProjectsService < ErrorTracking::BaseService
|
||||||
|
MASKED_TOKEN_REGEX = /\A\*+\z/.freeze
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
@ -21,23 +23,31 @@ module ErrorTracking
|
||||||
def project_error_tracking_setting
|
def project_error_tracking_setting
|
||||||
@project_error_tracking_setting ||= begin
|
@project_error_tracking_setting ||= begin
|
||||||
(super || project.build_error_tracking_setting).tap do |setting|
|
(super || project.build_error_tracking_setting).tap do |setting|
|
||||||
|
url_changed = !setting.api_url&.start_with?(params[:api_host])
|
||||||
|
|
||||||
setting.api_url = ErrorTracking::ProjectErrorTrackingSetting.build_api_url_from(
|
setting.api_url = ErrorTracking::ProjectErrorTrackingSetting.build_api_url_from(
|
||||||
api_host: params[:api_host],
|
api_host: params[:api_host],
|
||||||
organization_slug: 'org',
|
organization_slug: 'org',
|
||||||
project_slug: 'proj'
|
project_slug: 'proj'
|
||||||
)
|
)
|
||||||
|
|
||||||
setting.token = token(setting)
|
setting.token = token(setting, url_changed)
|
||||||
setting.enabled = true
|
setting.enabled = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def token(setting)
|
def token(setting, url_changed)
|
||||||
|
return if url_changed && masked_token?
|
||||||
|
|
||||||
# Use param token if not masked, otherwise use database token
|
# Use param token if not masked, otherwise use database token
|
||||||
return params[:token] unless /\A\*+\z/.match?(params[:token])
|
return params[:token] unless masked_token?
|
||||||
|
|
||||||
setting.token
|
setting.token
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def masked_token?
|
||||||
|
MASKED_TOKEN_REGEX.match?(params[:token])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,9 +104,15 @@ module Packages
|
||||||
entry = zip_file.glob('*.nuspec').first
|
entry = zip_file.glob('*.nuspec').first
|
||||||
|
|
||||||
raise ExtractionError, 'nuspec file not found' unless entry
|
raise ExtractionError, 'nuspec file not found' unless entry
|
||||||
raise ExtractionError, 'nuspec file too big' if entry.size > MAX_FILE_SIZE
|
raise ExtractionError, 'nuspec file too big' if MAX_FILE_SIZE < entry.size
|
||||||
|
|
||||||
entry.get_input_stream.read
|
Tempfile.open("nuget_extraction_package_file_#{@package_file_id}") do |file|
|
||||||
|
entry.extract(file.path) { true } # allow #extract to overwrite the file
|
||||||
|
file.unlink
|
||||||
|
file.read
|
||||||
|
end
|
||||||
|
rescue Zip::EntrySizeError => e
|
||||||
|
raise ExtractionError, "nuspec file has the wrong entry size: #{e.message}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ module Projects
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
attr_reader :resolved_address
|
||||||
|
|
||||||
def after_execute_hook
|
def after_execute_hook
|
||||||
# Defined in EE::Projects::ImportService
|
# Defined in EE::Projects::ImportService
|
||||||
end
|
end
|
||||||
|
@ -64,11 +66,7 @@ module Projects
|
||||||
def add_repository_to_project
|
def add_repository_to_project
|
||||||
if project.external_import? && !unknown_url?
|
if project.external_import? && !unknown_url?
|
||||||
begin
|
begin
|
||||||
Gitlab::UrlBlocker.validate!(
|
@resolved_address = get_resolved_address
|
||||||
project.import_url,
|
|
||||||
schemes: Project::VALID_IMPORT_PROTOCOLS,
|
|
||||||
ports: Project::VALID_IMPORT_PORTS
|
|
||||||
)
|
|
||||||
rescue Gitlab::UrlBlocker::BlockedUrlError => e
|
rescue Gitlab::UrlBlocker::BlockedUrlError => e
|
||||||
raise e, s_("ImportProjects|Blocked import URL: %{message}") % { message: e.message }
|
raise e, s_("ImportProjects|Blocked import URL: %{message}") % { message: e.message }
|
||||||
end
|
end
|
||||||
|
@ -97,9 +95,9 @@ module Projects
|
||||||
|
|
||||||
if refmap
|
if refmap
|
||||||
project.ensure_repository
|
project.ensure_repository
|
||||||
project.repository.fetch_as_mirror(project.import_url, refmap: refmap)
|
project.repository.fetch_as_mirror(project.import_url, refmap: refmap, resolved_address: resolved_address)
|
||||||
else
|
else
|
||||||
project.repository.import_repository(project.import_url)
|
project.repository.import_repository(project.import_url, resolved_address: resolved_address)
|
||||||
end
|
end
|
||||||
rescue ::Gitlab::Git::CommandError => e
|
rescue ::Gitlab::Git::CommandError => e
|
||||||
# Expire cache to prevent scenarios such as:
|
# Expire cache to prevent scenarios such as:
|
||||||
|
@ -157,6 +155,26 @@ module Projects
|
||||||
def importer_imports_repository?
|
def importer_imports_repository?
|
||||||
has_importer? && importer_class.try(:imports_repository?)
|
has_importer? && importer_class.try(:imports_repository?)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_resolved_address
|
||||||
|
Gitlab::UrlBlocker
|
||||||
|
.validate!(
|
||||||
|
project.import_url,
|
||||||
|
schemes: Project::VALID_IMPORT_PROTOCOLS,
|
||||||
|
ports: Project::VALID_IMPORT_PORTS,
|
||||||
|
dns_rebind_protection: dns_rebind_protection?)
|
||||||
|
.then do |(import_url, resolved_host)|
|
||||||
|
next '' if resolved_host.nil? || !import_url.scheme.in?(%w[http https])
|
||||||
|
|
||||||
|
import_url.host.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def dns_rebind_protection?
|
||||||
|
return false if Gitlab.http_proxy_env?
|
||||||
|
|
||||||
|
Gitlab::CurrentSettings.dns_rebinding_protection_enabled?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ module ResourceAccessTokens
|
||||||
return error("User does not have permission to create #{resource_type} access token") unless has_permission_to_create?
|
return error("User does not have permission to create #{resource_type} access token") unless has_permission_to_create?
|
||||||
|
|
||||||
access_level = params[:access_level] || Gitlab::Access::MAINTAINER
|
access_level = params[:access_level] || Gitlab::Access::MAINTAINER
|
||||||
|
return error("Could not provision owner access to project access token") if do_not_allow_owner_access_level_for_project_bot?(access_level)
|
||||||
|
|
||||||
user = create_user
|
user = create_user
|
||||||
|
|
||||||
|
@ -107,7 +108,7 @@ module ResourceAccessTokens
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_membership(resource, user, access_level)
|
def create_membership(resource, user, access_level)
|
||||||
resource.add_member(user, access_level, current_user: current_user, expires_at: params[:expires_at])
|
resource.add_member(user, access_level, expires_at: params[:expires_at])
|
||||||
end
|
end
|
||||||
|
|
||||||
def log_event(token)
|
def log_event(token)
|
||||||
|
@ -121,6 +122,12 @@ module ResourceAccessTokens
|
||||||
def success(access_token)
|
def success(access_token)
|
||||||
ServiceResponse.success(payload: { access_token: access_token })
|
ServiceResponse.success(payload: { access_token: access_token })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def do_not_allow_owner_access_level_for_project_bot?(access_level)
|
||||||
|
resource.is_a?(Project) &&
|
||||||
|
access_level == Gitlab::Access::OWNER &&
|
||||||
|
!current_user.can?(:manage_owners, resource)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ module Users
|
||||||
|
|
||||||
assign_identity
|
assign_identity
|
||||||
build_canonical_email
|
build_canonical_email
|
||||||
|
reset_unconfirmed_email
|
||||||
|
|
||||||
if @user.save(validate: validate) && update_status
|
if @user.save(validate: validate) && update_status
|
||||||
notify_success(user_exists)
|
notify_success(user_exists)
|
||||||
|
@ -64,6 +65,13 @@ module Users
|
||||||
Users::UpdateCanonicalEmailService.new(user: @user).execute
|
Users::UpdateCanonicalEmailService.new(user: @user).execute
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset_unconfirmed_email
|
||||||
|
return unless @user.persisted?
|
||||||
|
return unless @user.email_changed?
|
||||||
|
|
||||||
|
@user.update_column(:unconfirmed_email, nil)
|
||||||
|
end
|
||||||
|
|
||||||
def update_status
|
def update_status
|
||||||
return true unless @status_params
|
return true unless @status_params
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ module WebHooks
|
||||||
private
|
private
|
||||||
|
|
||||||
def log_execution
|
def log_execution
|
||||||
|
log_data[:request_headers]['X-Gitlab-Token'] = _('[REDACTED]') if hook.token?
|
||||||
|
|
||||||
WebHookLog.create!(web_hook: hook, **log_data)
|
WebHookLog.create!(web_hook: hook, **log_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
- confirmation_link = confirmation_url(@resource, confirmation_token: @token)
|
- confirmation_link = confirmation_url(@resource, confirmation_token: @token)
|
||||||
- if @resource.unconfirmed_email.present? || !@resource.created_recently?
|
- if @resource.unconfirmed_email.present? || !@resource.created_recently?
|
||||||
#content
|
#content
|
||||||
= email_default_heading(@resource.unconfirmed_email || @resource.email)
|
= email_default_heading(@email)
|
||||||
%p= _('Click the link below to confirm your email address.')
|
%p= _('Click the link below to confirm your email address.')
|
||||||
#cta
|
#cta
|
||||||
= link_to _('Confirm your email address'), confirmation_link
|
= link_to _('Confirm your email address'), confirmation_link
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<% if @resource.unconfirmed_email.present? || !@resource.created_recently? %>
|
<% if @resource.unconfirmed_email.present? || !@resource.created_recently? %>
|
||||||
<%= @resource.unconfirmed_email || @resource.email %>,
|
<%= @email %>,
|
||||||
<%= _('Use the link below to confirm your email address.') %>
|
<%= _('Use the link below to confirm your email address.') %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<% if Gitlab.com? %>
|
<% if Gitlab.com? %>
|
||||||
|
|
|
@ -51,18 +51,17 @@
|
||||||
= link_to profile_chat_names_path do
|
= link_to profile_chat_names_path do
|
||||||
%strong.fly-out-top-item-name
|
%strong.fly-out-top-item-name
|
||||||
= _('Chat')
|
= _('Chat')
|
||||||
- unless Gitlab::CurrentSettings.personal_access_tokens_disabled?
|
= nav_link(controller: :personal_access_tokens) do
|
||||||
= nav_link(controller: :personal_access_tokens) do
|
= link_to profile_personal_access_tokens_path do
|
||||||
= link_to profile_personal_access_tokens_path do
|
.nav-icon-container
|
||||||
.nav-icon-container
|
= sprite_icon('token')
|
||||||
= sprite_icon('token')
|
%span.nav-item-name
|
||||||
%span.nav-item-name
|
= _('Access Tokens')
|
||||||
= _('Access Tokens')
|
%ul.sidebar-sub-level-items.is-fly-out-only
|
||||||
%ul.sidebar-sub-level-items.is-fly-out-only
|
= nav_link(controller: :personal_access_tokens, html_options: { class: "fly-out-top-item" } ) do
|
||||||
= nav_link(controller: :personal_access_tokens, html_options: { class: "fly-out-top-item" } ) do
|
= link_to profile_personal_access_tokens_path do
|
||||||
= link_to profile_personal_access_tokens_path do
|
%strong.fly-out-top-item-name
|
||||||
%strong.fly-out-top-item-name
|
= _('Access Tokens')
|
||||||
= _('Access Tokens')
|
|
||||||
= nav_link(controller: :emails) do
|
= nav_link(controller: :emails) do
|
||||||
= link_to profile_emails_path, data: { qa_selector: 'profile_emails_link' } do
|
= link_to profile_emails_path, data: { qa_selector: 'profile_emails_link' } do
|
||||||
.nav-icon-container
|
.nav-icon-container
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
.gl-text-secondary
|
- if can?(current_user, :read_release, release)
|
||||||
= sprite_icon("rocket", size: 12)
|
.gl-text-secondary
|
||||||
= _("Release")
|
= sprite_icon("rocket", size: 12)
|
||||||
= link_to release.name, project_release_path(project, release), class: "gl-text-blue-600!"
|
= _("Release")
|
||||||
|
= link_to release.name, project_release_path(project, release), class: "gl-text-blue-600!"
|
||||||
|
|
|
@ -57,12 +57,13 @@
|
||||||
%pre.wrap{ data: { qa_selector: 'tag_message_content' } }
|
%pre.wrap{ data: { qa_selector: 'tag_message_content' } }
|
||||||
= strip_signature(@tag.message)
|
= strip_signature(@tag.message)
|
||||||
|
|
||||||
.gl-mb-3.gl-mt-3
|
- if can?(current_user, :read_release, @release)
|
||||||
- if @release&.description.present?
|
.gl-mb-3.gl-mt-3
|
||||||
.description.md{ data: { qa_selector: 'tag_release_notes_content' } }
|
- if @release&.description.present?
|
||||||
= markdown_field(@release, :description)
|
.description.md{ data: { qa_selector: 'tag_release_notes_content' } }
|
||||||
- else
|
= markdown_field(@release, :description)
|
||||||
= s_('TagsPage|This tag has no release notes.')
|
- else
|
||||||
|
= s_('TagsPage|This tag has no release notes.')
|
||||||
|
|
||||||
- if can?(current_user, :admin_tag, @project)
|
- if can?(current_user, :admin_tag, @project)
|
||||||
.js-delete-tag-modal
|
.js-delete-tag-modal
|
||||||
|
|
|
@ -55,9 +55,10 @@ To set up the Grafana API in Grafana:
|
||||||
1. Select **Save Changes**.
|
1. Select **Save Changes**.
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
If the Grafana integration is enabled, any user with read access to the GitLab
|
If the Grafana integration is enabled, users with the Reporter role on public
|
||||||
project can query metrics from the Prometheus instance. All requests proxied
|
projects and the Guest role on non-public projects can query metrics from the
|
||||||
through GitLab are authenticated with the same Grafana Administrator API token.
|
Prometheus instance. All requests proxied through GitLab are authenticated with
|
||||||
|
the same Grafana Administrator API token.
|
||||||
|
|
||||||
### Generate a link to a panel
|
### Generate a link to a panel
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,9 @@ using Omnibus, learn to install a custom CA in the
|
||||||
Alternatively, learn where to install custom certificates by using
|
Alternatively, learn where to install custom certificates by using
|
||||||
`openssl version -d`.
|
`openssl version -d`.
|
||||||
|
|
||||||
|
When external authorization is enabled, [deploy tokens](../../project/deploy_tokens/index.md)
|
||||||
|
and [deploy keys](../../project/deploy_keys/index.md) can't be used for Git operations.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
The external authorization service can be enabled by an administrator:
|
The external authorization service can be enabled by an administrator:
|
||||||
|
|
|
@ -48,9 +48,6 @@ You cannot use group access tokens to create other group, project, or personal a
|
||||||
Group access tokens inherit the [default prefix setting](../../admin_area/settings/account_and_limit_settings.md#personal-access-token-prefix)
|
Group access tokens inherit the [default prefix setting](../../admin_area/settings/account_and_limit_settings.md#personal-access-token-prefix)
|
||||||
configured for personal access tokens.
|
configured for personal access tokens.
|
||||||
|
|
||||||
NOTE:
|
|
||||||
Group access tokens are not FIPS compliant and creation and use are disabled when [FIPS mode](../../../development/fips_compliance.md) is enabled.
|
|
||||||
|
|
||||||
## Create a group access token using UI
|
## Create a group access token using UI
|
||||||
|
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214045) in GitLab 14.7.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214045) in GitLab 14.7.
|
||||||
|
|
|
@ -62,6 +62,7 @@ For most package types, the following credential types are valid:
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
If you have not activated the "Packages" feature for your project at **Settings > General > Project features**, you will receive a 403 Forbidden response.
|
If you have not activated the "Packages" feature for your project at **Settings > General > Project features**, you will receive a 403 Forbidden response.
|
||||||
|
Accessing package registry via deploy token is not available when external authorization is enabled.
|
||||||
|
|
||||||
## Use GitLab CI/CD to build packages
|
## Use GitLab CI/CD to build packages
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,6 @@ For examples of how you can use a personal access token to authenticate with the
|
||||||
Alternately, GitLab administrators can use the API to create [impersonation tokens](../../api/index.md#impersonation-tokens).
|
Alternately, GitLab administrators can use the API to create [impersonation tokens](../../api/index.md#impersonation-tokens).
|
||||||
Use impersonation tokens to automate authentication as a specific user.
|
Use impersonation tokens to automate authentication as a specific user.
|
||||||
|
|
||||||
NOTE:
|
|
||||||
Personal access tokens are not FIPS compliant and creation and use are disabled when [FIPS mode](../../development/fips_compliance.md) is enabled.
|
|
||||||
|
|
||||||
## Create a personal access token
|
## Create a personal access token
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/348660) in GitLab 15.3, default expiration of 30 days is populated in the UI.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/348660) in GitLab 15.3, default expiration of 30 days is populated in the UI.
|
||||||
|
|
|
@ -18,6 +18,8 @@ Depending on your needs, you might want to use a [deploy token](../deploy_tokens
|
||||||
| Validity | Valid as long as it's registered and enabled. | Can be given an expiration date. |
|
| Validity | Valid as long as it's registered and enabled. | Can be given an expiration date. |
|
||||||
| Registry access | Cannot access a package registry. | Can read from and write to a package registry. |
|
| Registry access | Cannot access a package registry. | Can read from and write to a package registry. |
|
||||||
|
|
||||||
|
Deploy keys can't be used for Git operations if [external authorization](../../admin_area/settings/external_authorization.md) is enabled.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
A deploy key has a defined scope when it is created:
|
A deploy key has a defined scope when it is created:
|
||||||
|
|
|
@ -41,6 +41,8 @@ You can create deploy tokens at either the project or group level:
|
||||||
By default, a deploy token does not expire. You can optionally set an expiry date when you create
|
By default, a deploy token does not expire. You can optionally set an expiry date when you create
|
||||||
it. Expiry occurs at midnight UTC on that date.
|
it. Expiry occurs at midnight UTC on that date.
|
||||||
|
|
||||||
|
Deploy tokens can't be used for Git operations and Package Registry operations if [external authorization](../../admin_area/settings/external_authorization.md) is enabled.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
A deploy token's scope determines the actions it can perform.
|
A deploy token's scope determines the actions it can perform.
|
||||||
|
|
|
@ -48,9 +48,6 @@ You cannot use project access tokens to create other group, project, or personal
|
||||||
Project access tokens inherit the [default prefix setting](../../admin_area/settings/account_and_limit_settings.md#personal-access-token-prefix)
|
Project access tokens inherit the [default prefix setting](../../admin_area/settings/account_and_limit_settings.md#personal-access-token-prefix)
|
||||||
configured for personal access tokens.
|
configured for personal access tokens.
|
||||||
|
|
||||||
NOTE:
|
|
||||||
Project access tokens are not FIPS compliant and creation and use are disabled when [FIPS mode](../../../development/fips_compliance.md) is enabled.
|
|
||||||
|
|
||||||
## Create a project access token
|
## Create a project access token
|
||||||
|
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89114) in GitLab 15.1, Owners can select Owner role for project access tokens.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89114) in GitLab 15.1, Owners can select Owner role for project access tokens.
|
||||||
|
|
|
@ -94,7 +94,8 @@ module API
|
||||||
success Entities::Ci::JobRequest::Response
|
success Entities::Ci::JobRequest::Response
|
||||||
http_codes [[201, 'Job was scheduled'],
|
http_codes [[201, 'Job was scheduled'],
|
||||||
[204, 'No job for Runner'],
|
[204, 'No job for Runner'],
|
||||||
[403, 'Forbidden']]
|
[403, 'Forbidden'],
|
||||||
|
[409, 'Conflict']]
|
||||||
end
|
end
|
||||||
params do
|
params do
|
||||||
requires :token, type: String, desc: %q(Runner's authentication token)
|
requires :token, type: String, desc: %q(Runner's authentication token)
|
||||||
|
|
|
@ -165,6 +165,8 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_deploy_token(raw, &block)
|
def with_deploy_token(raw, &block)
|
||||||
|
raise ::Gitlab::Auth::UnauthorizedError if Gitlab::ExternalAuthorization.enabled?
|
||||||
|
|
||||||
token = ::DeployToken.active.find_by_token(raw.password)
|
token = ::DeployToken.active.find_by_token(raw.password)
|
||||||
return unless token
|
return unless token
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,7 @@ module Gitlab
|
||||||
# deploy tokens are accepted with deploy token headers and basic auth headers
|
# deploy tokens are accepted with deploy token headers and basic auth headers
|
||||||
def deploy_token_from_request
|
def deploy_token_from_request
|
||||||
return unless route_authentication_setting[:deploy_token_allowed]
|
return unless route_authentication_setting[:deploy_token_allowed]
|
||||||
|
return if Gitlab::ExternalAuthorization.enabled?
|
||||||
|
|
||||||
token = current_request.env[DEPLOY_TOKEN_HEADER].presence || parsed_oauth_token
|
token = current_request.env[DEPLOY_TOKEN_HEADER].presence || parsed_oauth_token
|
||||||
|
|
||||||
|
|
|
@ -855,7 +855,11 @@ module Gitlab
|
||||||
# no_tags - should we use --no-tags flag?
|
# no_tags - should we use --no-tags flag?
|
||||||
# prune - should we use --prune flag?
|
# prune - should we use --prune flag?
|
||||||
# check_tags_changed - should we ask gitaly to calculate whether any tags changed?
|
# check_tags_changed - should we ask gitaly to calculate whether any tags changed?
|
||||||
def fetch_remote(url, refmap: nil, ssh_auth: nil, forced: false, no_tags: false, prune: true, check_tags_changed: false, http_authorization_header: "")
|
# resolved_address - resolved IP address for provided URL
|
||||||
|
def fetch_remote( # rubocop:disable Metrics/ParameterLists
|
||||||
|
url,
|
||||||
|
refmap: nil, ssh_auth: nil, forced: false, no_tags: false, prune: true,
|
||||||
|
check_tags_changed: false, http_authorization_header: "", resolved_address: "")
|
||||||
wrapped_gitaly_errors do
|
wrapped_gitaly_errors do
|
||||||
gitaly_repository_client.fetch_remote(
|
gitaly_repository_client.fetch_remote(
|
||||||
url,
|
url,
|
||||||
|
@ -866,16 +870,17 @@ module Gitlab
|
||||||
prune: prune,
|
prune: prune,
|
||||||
check_tags_changed: check_tags_changed,
|
check_tags_changed: check_tags_changed,
|
||||||
timeout: GITLAB_PROJECTS_TIMEOUT,
|
timeout: GITLAB_PROJECTS_TIMEOUT,
|
||||||
http_authorization_header: http_authorization_header
|
http_authorization_header: http_authorization_header,
|
||||||
|
resolved_address: resolved_address
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def import_repository(url, http_authorization_header: '', mirror: false)
|
def import_repository(url, http_authorization_header: '', mirror: false, resolved_address: '')
|
||||||
raise ArgumentError, "don't use disk paths with import_repository: #{url.inspect}" if url.start_with?('.', '/')
|
raise ArgumentError, "don't use disk paths with import_repository: #{url.inspect}" if url.start_with?('.', '/')
|
||||||
|
|
||||||
wrapped_gitaly_errors do
|
wrapped_gitaly_errors do
|
||||||
gitaly_repository_client.import_repository(url, http_authorization_header: http_authorization_header, mirror: mirror)
|
gitaly_repository_client.import_repository(url, http_authorization_header: http_authorization_header, mirror: mirror, resolved_address: resolved_address)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -367,7 +367,7 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def deploy_key?
|
def deploy_key?
|
||||||
actor.is_a?(DeployKey)
|
actor.is_a?(DeployKey) && !Gitlab::ExternalAuthorization.enabled?
|
||||||
end
|
end
|
||||||
|
|
||||||
def deploy_token
|
def deploy_token
|
||||||
|
@ -375,7 +375,7 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def deploy_token?
|
def deploy_token?
|
||||||
actor.is_a?(DeployToken)
|
actor.is_a?(DeployToken) && !Gitlab::ExternalAuthorization.enabled?
|
||||||
end
|
end
|
||||||
|
|
||||||
def ci?
|
def ci?
|
||||||
|
|
|
@ -78,7 +78,7 @@ module Gitlab
|
||||||
# rubocop: disable Metrics/ParameterLists
|
# rubocop: disable Metrics/ParameterLists
|
||||||
# The `remote` parameter is going away soonish anyway, at which point the
|
# The `remote` parameter is going away soonish anyway, at which point the
|
||||||
# Rubocop warning can be enabled again.
|
# Rubocop warning can be enabled again.
|
||||||
def fetch_remote(url, refmap:, ssh_auth:, forced:, no_tags:, timeout:, prune: true, check_tags_changed: false, http_authorization_header: "")
|
def fetch_remote(url, refmap:, ssh_auth:, forced:, no_tags:, timeout:, prune: true, check_tags_changed: false, http_authorization_header: "", resolved_address: "")
|
||||||
request = Gitaly::FetchRemoteRequest.new(
|
request = Gitaly::FetchRemoteRequest.new(
|
||||||
repository: @gitaly_repo,
|
repository: @gitaly_repo,
|
||||||
force: forced,
|
force: forced,
|
||||||
|
@ -89,7 +89,8 @@ module Gitlab
|
||||||
remote_params: Gitaly::Remote.new(
|
remote_params: Gitaly::Remote.new(
|
||||||
url: url,
|
url: url,
|
||||||
mirror_refmaps: Array.wrap(refmap).map(&:to_s),
|
mirror_refmaps: Array.wrap(refmap).map(&:to_s),
|
||||||
http_authorization_header: http_authorization_header
|
http_authorization_header: http_authorization_header,
|
||||||
|
resolved_address: resolved_address
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -145,12 +146,13 @@ module Gitlab
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def import_repository(source, http_authorization_header: '', mirror: false)
|
def import_repository(source, http_authorization_header: '', mirror: false, resolved_address: '')
|
||||||
request = Gitaly::CreateRepositoryFromURLRequest.new(
|
request = Gitaly::CreateRepositoryFromURLRequest.new(
|
||||||
repository: @gitaly_repo,
|
repository: @gitaly_repo,
|
||||||
url: source,
|
url: source,
|
||||||
http_authorization_header: http_authorization_header,
|
http_authorization_header: http_authorization_header,
|
||||||
mirror: mirror
|
mirror: mirror,
|
||||||
|
resolved_address: resolved_address
|
||||||
)
|
)
|
||||||
|
|
||||||
GitalyClient.call(
|
GitalyClient.call(
|
||||||
|
|
|
@ -57,7 +57,7 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def user_email(user)
|
def user_email(user)
|
||||||
user.respond_to?(:email) ? user.email : ""
|
user.respond_to?(:webhook_email) ? user.webhook_email : ""
|
||||||
end
|
end
|
||||||
|
|
||||||
def event_specific_project_data(event)
|
def event_specific_project_data(event)
|
||||||
|
|
|
@ -43,7 +43,7 @@ module Gitlab
|
||||||
project_id: project.id,
|
project_id: project.id,
|
||||||
user_username: project_member.user.username,
|
user_username: project_member.user.username,
|
||||||
user_name: project_member.user.name,
|
user_name: project_member.user.name,
|
||||||
user_email: project_member.user.email,
|
user_email: project_member.user.webhook_email,
|
||||||
user_id: project_member.user.id,
|
user_id: project_member.user.id,
|
||||||
access_level: project_member.human_access,
|
access_level: project_member.human_access,
|
||||||
project_visibility: project.visibility
|
project_visibility: project.visibility
|
||||||
|
|
16
lib/gitlab/safe_device_detector.rb
Normal file
16
lib/gitlab/safe_device_detector.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
# rubocop:disable Gitlab/NamespacedClass
|
||||||
|
require 'device_detector'
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
class SafeDeviceDetector < ::DeviceDetector
|
||||||
|
USER_AGENT_MAX_SIZE = 1024
|
||||||
|
|
||||||
|
def initialize(user_agent)
|
||||||
|
super(user_agent)
|
||||||
|
@user_agent = user_agent && user_agent[0..USER_AGENT_MAX_SIZE]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# rubocop:enable Gitlab/NamespacedClass
|
|
@ -36,14 +36,6 @@ RSpec.describe Profiles::PersonalAccessTokensController do
|
||||||
expect(created_token.expires_at).to eq(expires_at)
|
expect(created_token.expires_at).to eq(expires_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not allow creation when personal access tokens are disabled' do
|
|
||||||
allow(::Gitlab::CurrentSettings).to receive_messages(personal_access_tokens_disabled?: true)
|
|
||||||
|
|
||||||
post :create, params: { personal_access_token: token_attributes }
|
|
||||||
|
|
||||||
expect(response).to have_gitlab_http_status(:not_found)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like "#create access token" do
|
it_behaves_like "#create access token" do
|
||||||
let(:url) { :create }
|
let(:url) { :create }
|
||||||
end
|
end
|
||||||
|
@ -78,14 +70,6 @@ RSpec.describe Profiles::PersonalAccessTokensController do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns 404 when personal access tokens are disabled' do
|
|
||||||
allow(::Gitlab::CurrentSettings).to receive_messages(personal_access_tokens_disabled?: true)
|
|
||||||
|
|
||||||
get :index
|
|
||||||
|
|
||||||
expect(response).to have_gitlab_http_status(:not_found)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "access_token_pagination feature flag is enabled" do
|
context "access_token_pagination feature flag is enabled" do
|
||||||
before do
|
before do
|
||||||
stub_feature_flags(access_token_pagination: true)
|
stub_feature_flags(access_token_pagination: true)
|
||||||
|
|
|
@ -2,13 +2,20 @@
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe Projects::GrafanaApiController do
|
RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do
|
||||||
let_it_be(:project) { create(:project) }
|
let_it_be(:project) { create(:project, :public) }
|
||||||
let_it_be(:user) { create(:user) }
|
let_it_be(:reporter) { create(:user) }
|
||||||
|
let_it_be(:guest) { create(:user) }
|
||||||
|
let(:anonymous) { nil }
|
||||||
|
let(:user) { reporter }
|
||||||
|
|
||||||
|
before_all do
|
||||||
|
project.add_reporter(reporter)
|
||||||
|
project.add_guest(guest)
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
project.add_reporter(user)
|
sign_in(user) if user
|
||||||
sign_in(user)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #proxy' do
|
describe 'GET #proxy' do
|
||||||
|
@ -41,6 +48,39 @@ RSpec.describe Projects::GrafanaApiController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
shared_examples_for 'accessible' do
|
||||||
|
let(:service_result) { nil }
|
||||||
|
|
||||||
|
it 'returns non erroneous response' do
|
||||||
|
get :proxy, params: params
|
||||||
|
|
||||||
|
# We don't care about the specific code as long it's not an error.
|
||||||
|
expect(response).to have_gitlab_http_status(:no_content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples_for 'not accessible' do
|
||||||
|
let(:service_result) { nil }
|
||||||
|
|
||||||
|
it 'returns 404 Not found' do
|
||||||
|
get :proxy, params: params
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:not_found)
|
||||||
|
expect(Grafana::ProxyService).not_to have_received(:new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples_for 'login required' do
|
||||||
|
let(:service_result) { nil }
|
||||||
|
|
||||||
|
it 'redirects to login page' do
|
||||||
|
get :proxy, params: params
|
||||||
|
|
||||||
|
expect(response).to redirect_to(new_user_session_path)
|
||||||
|
expect(Grafana::ProxyService).not_to have_received(:new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with a successful result' do
|
context 'with a successful result' do
|
||||||
let(:service_result) { { status: :success, body: '{}' } }
|
let(:service_result) { { status: :success, body: '{}' } }
|
||||||
|
|
||||||
|
@ -96,6 +136,38 @@ RSpec.describe Projects::GrafanaApiController do
|
||||||
it_behaves_like 'error response', :bad_request
|
it_behaves_like 'error response', :bad_request
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'as guest' do
|
||||||
|
let(:user) { guest }
|
||||||
|
|
||||||
|
it_behaves_like 'not accessible'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as anonymous' do
|
||||||
|
let(:user) { anonymous }
|
||||||
|
|
||||||
|
it_behaves_like 'not accessible'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'on a private project' do
|
||||||
|
let_it_be(:project) { create(:project, :private) }
|
||||||
|
|
||||||
|
before_all do
|
||||||
|
project.add_guest(guest)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as anonymous' do
|
||||||
|
let(:user) { anonymous }
|
||||||
|
|
||||||
|
it_behaves_like 'login required'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as guest' do
|
||||||
|
let(:user) { guest }
|
||||||
|
|
||||||
|
it_behaves_like 'accessible'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #metrics_dashboard' do
|
describe 'GET #metrics_dashboard' do
|
||||||
|
|
|
@ -1380,7 +1380,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
|
||||||
{
|
{
|
||||||
'Channel' => {
|
'Channel' => {
|
||||||
'Subprotocols' => ["terminal.gitlab.com"],
|
'Subprotocols' => ["terminal.gitlab.com"],
|
||||||
'Url' => 'wss://localhost/proxy/build/default_port/',
|
'Url' => 'wss://gitlab.example.com/proxy/build/default_port/',
|
||||||
'Header' => {
|
'Header' => {
|
||||||
'Authorization' => [nil]
|
'Authorization' => [nil]
|
||||||
},
|
},
|
||||||
|
@ -1536,7 +1536,8 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
|
||||||
allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_return(nil)
|
allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_return(nil)
|
||||||
|
|
||||||
expect(job.runner_session_url).to start_with('https://')
|
expect(job.runner_session_url).to start_with('https://')
|
||||||
expect(Gitlab::Workhorse).to receive(:channel_websocket).with(a_hash_including(url: "wss://localhost/proxy/build/default_port/"))
|
expect(Gitlab::Workhorse).to receive(:channel_websocket)
|
||||||
|
.with(a_hash_including(url: "wss://gitlab.example.com/proxy/build/default_port/"))
|
||||||
|
|
||||||
make_request
|
make_request
|
||||||
end
|
end
|
||||||
|
|
|
@ -268,17 +268,35 @@ RSpec.describe UploadsController do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when not signed in" do
|
context "when not signed in" do
|
||||||
it "responds with status 200" do
|
context "when restricted visibility level is not set to public" do
|
||||||
get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" }
|
before do
|
||||||
|
stub_application_setting(restricted_visibility_levels: [])
|
||||||
|
end
|
||||||
|
|
||||||
expect(response).to have_gitlab_http_status(:ok)
|
it "responds with status 200" do
|
||||||
|
get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" }
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'content publicly cached' do
|
||||||
|
subject do
|
||||||
|
get :show, params: { model: 'user', mounted_as: 'avatar', id: user.id, filename: 'dk.png' }
|
||||||
|
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'content publicly cached' do
|
context "when restricted visibility level is set to public" do
|
||||||
subject do
|
before do
|
||||||
get :show, params: { model: 'user', mounted_as: 'avatar', id: user.id, filename: 'dk.png' }
|
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
|
||||||
|
end
|
||||||
|
|
||||||
response
|
it "responds with status 401" do
|
||||||
|
get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" }
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -716,7 +716,7 @@ FactoryBot.define do
|
||||||
|
|
||||||
trait :with_runner_session do
|
trait :with_runner_session do
|
||||||
after(:build) do |build|
|
after(:build) do |build|
|
||||||
build.build_runner_session(url: 'https://localhost')
|
build.build_runner_session(url: 'https://gitlab.example.com')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,10 @@ FactoryBot.define do
|
||||||
enable_ssl_verification { false }
|
enable_ssl_verification { false }
|
||||||
project
|
project
|
||||||
|
|
||||||
|
trait :url_variables do
|
||||||
|
url_variables { { 'abc' => 'supers3cret' } }
|
||||||
|
end
|
||||||
|
|
||||||
trait :token do
|
trait :token do
|
||||||
token { generate(:token) }
|
token { generate(:token) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -329,7 +329,7 @@ RSpec.describe 'Project' do
|
||||||
it 'has working links to submodules' do
|
it 'has working links to submodules' do
|
||||||
click_link('645f6c4c')
|
click_link('645f6c4c')
|
||||||
|
|
||||||
expect(page).to have_selector('[data-testid="branches-select"]', text: '645f6c4c82fd3f5e06f67134450a570b795e55a6')
|
expect(page).to have_selector('.ref-selector', text: '645f6c4c82fd3f5e06f67134450a570b795e55a6')
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'for signed commit on default branch', :js do
|
context 'for signed commit on default branch', :js do
|
||||||
|
|
|
@ -53,6 +53,8 @@ RSpec.describe 'Developer views tags' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'views a specific tag page' do
|
it 'views a specific tag page' do
|
||||||
|
create(:release, project: project, tag: 'v1.0.0', name: 'v1.0.0', description: nil)
|
||||||
|
|
||||||
click_on 'v1.0.0'
|
click_on 'v1.0.0'
|
||||||
|
|
||||||
expect(page).to have_current_path(
|
expect(page).to have_current_path(
|
||||||
|
|
99
spec/fixtures/clusters/chain_certificates.pem
vendored
99
spec/fixtures/clusters/chain_certificates.pem
vendored
|
@ -1,67 +1,66 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIGYzCCBUugAwIBAgIQAaQHyOeT/PBR4ioLKYneZDANBgkqhkiG9w0BAQsFADBY
|
MIIGYjCCBUqgAwIBAgIQATfkha/xTr3pbLHVWlPq4jANBgkqhkiG9w0BAQsFADBY
|
||||||
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEuMCwGA1UE
|
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEuMCwGA1UE
|
||||||
AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgSDIgMjAyMTAeFw0yMTEw
|
AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgMjAyMiBRMzAeFw0yMjA3
|
||||||
MTgxODUwMDRaFw0yMjExMTkxODUwMDNaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
|
MjIxOTQyMTFaFw0yMzA4MjMxOTQyMTBaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
|
||||||
Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWSo0eziN/0lq5
|
Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFFFQs8EITaWo5
|
||||||
dIcS7ZceJw2odzZeT0tRkcKEW8iagNul6JetrFlk6h5lxoLEu35+MK6/fWHNmt7u
|
0U18/mPTDLencU/7siJT/4P8oeDkemyx98wzK6vuNj/2JEZ3v1psKun5n8Pb/fHa
|
||||||
eQk7HS0uRipskAzeGrL1Hvk8EjIcHXXTxpRu7JqWOu7ZSXwNxW5cqn7L9/N2gYwt
|
somKd/4icHgC4rnxrO6zayfb+cKzVghQe12Nj75lx6RtppqTgAmSOa3Tai5niICT
|
||||||
Jg/sfkv9AFQiNOdKrarKfbcBstxmra6rQbh5ggLG5UBT23N4ZrA3XnzvEx3+GjtO
|
I8s3d2wsHtfEgqAavcD0/zdPIk25Ji7yfquldSthnlhQqI4Pm3OxTiyFj/V5ZhFl
|
||||||
u/a5izbk7FQP3gyXKyfm/SQRpNsytYa9jJqu5Hmyzfap5KaueOJbtJEOk8dR/HWR
|
IWZLvQaENjBSDVZQDcaPdWwodfXNA8fJmqk7cTLQ9P9NgjWvva7acl+Yd6hOFzV0
|
||||||
i/gmAUevq62MNxorYbz8YU/P1468tS7iORkD31Tc2QWCMQSPya5qGaCGnz7dVgWy
|
EllBl/WF1KB+YzGuHI0CQHT7sv3GW1lXeE2EqrWoSdLTOSAqm6y02DyE79d1xvG6
|
||||||
E1xTPbBXAgMBAAGjggNkMIIDYDAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
|
XXfX5ILlAgMBAAGjggNjMIIDXzAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
|
||||||
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||||
HQYDVR0OBBYEFJFVruwpjWeUfGJXl3m5grAjhAwPMFcGA1UdIARQME4wCAYGZ4EM
|
HQYDVR0OBBYEFHK7MnjGDptQWjfmJ2fr3IrjxEopMFcGA1UdIARQME4wCAYGZ4EM
|
||||||
AQIBMEIGCisGAQQBoDIKAQMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
|
AQIBMEIGCisGAQQBoDIKAQMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
|
||||||
YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDAYDVR0TAQH/BAIwADCBngYIKwYBBQUH
|
YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDAYDVR0TAQH/BAIwADCBngYIKwYBBQUH
|
||||||
AQEEgZEwgY4wQAYIKwYBBQUHMAGGNGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29t
|
AQEEgZEwgY4wQAYIKwYBBQUHMAGGNGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29t
|
||||||
L2NhL2dzYXRsYXNyM2R2dGxzY2FoMjIwMjEwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
|
L2NhL2dzYXRsYXNyM2R2dGxzY2EyMDIycTMwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
|
||||||
ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2FoMjIw
|
ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2EyMDIy
|
||||||
MjEuY3J0MB8GA1UdIwQYMBaAFCo0uar6vzyI8Ufy0hJ4vsXlqrBpMEgGA1UdHwRB
|
cTMuY3J0MB8GA1UdIwQYMBaAFPqROWOa+60QJOW+tbnaq9nERmmrMEgGA1UdHwRB
|
||||||
MD8wPaA7oDmGN2h0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3NhdGxhc3Iz
|
MD8wPaA7oDmGN2h0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3NhdGxhc3Iz
|
||||||
ZHZ0bHNjYWgyMjAyMS5jcmwwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB3AG9T
|
ZHZ0bHNjYTIwMjJxMy5jcmwwggF9BgorBgEEAdZ5AgQCBIIBbQSCAWkBZwB1AG9T
|
||||||
dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABfJS9R5YAAAQDAEgwRgIh
|
dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABgiduiHEAAAQDAEYwRAIg
|
||||||
AOOZmc41vB2ICwkwEB5Bmpm/X8UHfjbxwrCXEdeRmO+qAiEAg/JugZIrG2PeV4bA
|
SYQrru/KAKfe+hUqpJmk7Fc8drkgtY3IcAurTOwbM68CIBYO9sbDspd5p7v17RQi
|
||||||
Gm6rry7HUfB954bQJ4p0PeQVmwsAdABGpVXrdfqRIDC1oolp9PN9ESxBdL79SbiF
|
QQkjdRwSjHiIgvlX0Y1JqmXjAHYArfe++nz/EMiLnT2cHj4YarRnKV3PsQwkyoWG
|
||||||
q/L8cP5tRwAAAXyUvUeOAAAEAwBFMEMCHyRAiTz2fZ8DuQF6hrVP+IMTCPBtjB3D
|
NOvcgooAAAGCJ26IcQAABAMARzBFAiBc5a10annqMEH69bdEFy/Vo1gb3S3GQ993
|
||||||
m4naI8tC/foCIDXFCRIYjRb00CFI6piLYGihRy+GYF5nMQhQ9uE6hltzAHcAUaOw
|
BCRV7ZXG4gIhAMqnsoKkU6ITwRXwE9KGjHnijJ8QrBrnK0i+JFaGe1ffAHYAs3N3
|
||||||
9f0BeZxWbbg3eI8MpHrMGyfL956IQpoN/tSLBeUAAAF8lL1ICgAABAMASDBGAiEA
|
B+GEUPhjhtYFqdwRCUp5LbFnDAuH3PADDnk2pZoAAAGCJ26I6QAABAMARzBFAiAf
|
||||||
5d/bXb9TPZWhwSH8GGji/LDFL6OJnZtOV94sBaDiFgMCIQCtl00oCRMFFnqsvBo6
|
lW8Agd0DB68YA8XAbnlq7QNHw3uRMzNdS8gtRUe75gIhANTe+mt2p1ryW83P31OW
|
||||||
SRtnDqJkEHYBS12I4LyC+D1onjANBgkqhkiG9w0BAQsFAAOCAQEAE5xcno79J+Ec
|
jH3cEGJxdUNT/oDM3Fzesx94MA0GCSqGSIb3DQEBCwUAA4IBAQAfivKEmjqqOFFh
|
||||||
DIPJKnJCugKiM7yKjCjCp/63osCbRC+jUwRyXBIe/oTdY3geKwDOQAvyEeJPSWP1
|
VsX2XYkoDtreghpqMwHMCLwNk852Alr/Seyv9Ilng8cunU4NmhvEtsYVXkfE4XvB
|
||||||
LbNp0l3yHbYXfsYl/NMTrJpjrJrrRO5BxG/d3IPwXIlcZrrdDSoGfGYIF9N23iqB
|
0QIVxkg1w7A+p7ejMjh6doLJ0aWNWIVW/DwOeP0qstF9lqvLdLDABoVn0BtYCDTH
|
||||||
in15L7B+PodTl8/mSQZTjbLoecPvl+AOcLyStcWCKYQUlQb3x4UV3R4Z1ukwGbBC
|
gjG80e2xpvPiKHGvBL+hlOIJwUuIAT3jN23sS1GoiYQGKsz0lovB09/6MGG0Qj8C
|
||||||
cDbTR2XOSJzA9ECJcxKnWjQRQUc54pdG3pt13Wu2dVapX5sWZpV05rga3bBDjCqw
|
3i9a59T9XBpwSKdpKd4u/CB6koBXD3atbBNBACuAMcFckTEtmkCFtSpqBuocJGKf
|
||||||
DcfKuYbOChm2i6CQ578lAntPTIS02EkGFHrmYxrIAvlhGksHpJNJtRoff1KkQKni
|
LB4MFVaEwrd7Lc1ACC1et5FDtEI4I3/CerkRZTV+mRz5n6tB91AK3dRvjElfhiuh
|
||||||
r8emWp7D2Q==
|
XXYRULvB
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIExTCCA62gAwIBAgIQeimFGrf0XWZ5UGZBtv/XHTANBgkqhkiG9w0BAQsFADBM
|
MIIEjzCCA3egAwIBAgIQfCoMIT/GVVNFyR8ZH7hO+jANBgkqhkiG9w0BAQsFADBM
|
||||||
MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv
|
MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv
|
||||||
YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMTA2MTYxMjAwMDBaFw0y
|
YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMjA0MjAxMjAwMDBaFw0y
|
||||||
NDA2MTYwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
|
NTA0MjAwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
|
||||||
IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSBI
|
IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSAy
|
||||||
MiAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1JTAQMj+QUYF
|
MDIyIFEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKh6ZjxOZpzO
|
||||||
3d9X5eOWFOphbB6GpHE3J0uvUXcQwxnd8Jz26aQCE1ZYxJFEc2WmsxuVeVXU+rZj
|
N6VUNU02x5nTqCc28i/G1Rg+6QndBdbXLDQyfAhjSdEQN+V4XRFizm37Lz83lNuP
|
||||||
7+MYD7Mg72bhuiwUdwRGRN4a2N122LfIQlTFlHu/fwcNqYX/fe3phvZt9upnH4oJ
|
ezDpXizZVT+y27mgtWA3i6QGMjVQpAmvCkX/qB+bZY7dSuBAoeNjN1iQ3XU7/A4c
|
||||||
aLBbay+t+HPPC4em74x2WKaIl31ZXzgzllLomnlLISLOKiQe1rEHp4yy3/yE2a4G
|
gkCYvXCxwUgUFDwES2nd1JwBpukh44IK/uSqvzSgjMvJeW4+XGpSnsTtK8Vp/lA8
|
||||||
1l/lprA49dcyM/oylm9Bbkum2F4C+EOjHgTAoDVJrJpdWvPj0CU+HkmftujfFp4S
|
k521/y0oqGwGbJ3Fr7JZ+1l3DXR6iISk1B3UuiAGzLUeSE50IRWGdcDMWtEFz1cW
|
||||||
55LECSr2TfJt7xjgR3eLUx12nlpoauWEzZ0/i6OIDPfbmqcksw4ani/YO07LbRM6
|
ehMX7MJKrtUecqoiWoycgjLEEOZCbiGGaHyAIzA1072wXgopK/AUsRg32Vklw+c4
|
||||||
cY9VZzkAvwIDAQABo4IBlTCCAZEwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
|
2enULTY1ZQIDAQABo4IBXzCCAVswDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
|
||||||
CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
|
CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
|
||||||
BBQqNLmq+r88iPFH8tISeL7F5aqwaTAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
|
BBT6kTljmvutECTlvrW52qvZxEZpqzAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
|
||||||
move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw
|
move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw
|
||||||
Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1
|
Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1
|
||||||
cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w
|
cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w
|
||||||
K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwVwYD
|
K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwIQYD
|
||||||
VR0gBFAwTjAIBgZngQwBAgEwQgYKKwYBBAGgMgoBAzA0MDIGCCsGAQUFBwIBFiZo
|
VR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAGgMgoBAzANBgkqhkiG9w0BAQsFAAOC
|
||||||
dHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0B
|
AQEAFDMseeU/gsZwP9pZOKe7onasYRgFaFfZDfuKRrzxqOgMcAIdxi+X7TY+nlKG
|
||||||
AQsFAAOCAQEAEsIwXEhdAfoUGaKAnYfVI7zsOY7Sx8bpC/obGxXa4Kyu8CVx+TtT
|
L1xi2NVHQ5pz0Sslh59EtBTrJrwhR3QgvZ+kv7OAHU01fc25tdpV8pBQyLIXTg60
|
||||||
g8WmKNF7+I7C51NZEmhvb8UDI1G9ny7iYIRDajQD5AeZowbfC69aHQSI9LiOeAZb
|
YYgpX0RdA39XkYHQ6zCu1SrsgiDOTtKwi5UCYXPYaTT0rWMOXOQgH6l97Y7lHAS7
|
||||||
YaRDJfWps9redPwoaC0iT5R4xLOnWwCtmIho1bv/YG3pMAvaQ+qn04kuUvWO7LEp
|
Ip/HqSLKmT0Cp2foBi36BGu7SdJsmVdjbC3CYXjhILH79r/hgjk5PHvvfRqVSrJy
|
||||||
u7FdHmx1DdgkefcqYgN/rAZ8E39S9VxWV+64PNUDey8vkAIH8FCTxbWiITty6dsH
|
2lWQru3d4nCQfBrutTJaXc/W+kXyngEMMS+JhP4xYA/97qZbhNXHGOak+UAwKRge
|
||||||
SulKQ9pSa93k9PHTf+di08mMQBq5WBWTiFeMYZEWyE/z7NHdU3eLMZjq6y/nKlF9
|
/vxBtbkpBXWLYhpbIi6/5FlssA==
|
||||||
nywrToh4AgdZK6JnbU+lqbNiexJbaBoA3w==
|
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
|
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
|
||||||
|
|
|
@ -1,28 +1,27 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIExTCCA62gAwIBAgIQeimFGrf0XWZ5UGZBtv/XHTANBgkqhkiG9w0BAQsFADBM
|
MIIEjzCCA3egAwIBAgIQfCoMIT/GVVNFyR8ZH7hO+jANBgkqhkiG9w0BAQsFADBM
|
||||||
MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv
|
MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv
|
||||||
YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMTA2MTYxMjAwMDBaFw0y
|
YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMjA0MjAxMjAwMDBaFw0y
|
||||||
NDA2MTYwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
|
NTA0MjAwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
|
||||||
IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSBI
|
IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSAy
|
||||||
MiAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1JTAQMj+QUYF
|
MDIyIFEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKh6ZjxOZpzO
|
||||||
3d9X5eOWFOphbB6GpHE3J0uvUXcQwxnd8Jz26aQCE1ZYxJFEc2WmsxuVeVXU+rZj
|
N6VUNU02x5nTqCc28i/G1Rg+6QndBdbXLDQyfAhjSdEQN+V4XRFizm37Lz83lNuP
|
||||||
7+MYD7Mg72bhuiwUdwRGRN4a2N122LfIQlTFlHu/fwcNqYX/fe3phvZt9upnH4oJ
|
ezDpXizZVT+y27mgtWA3i6QGMjVQpAmvCkX/qB+bZY7dSuBAoeNjN1iQ3XU7/A4c
|
||||||
aLBbay+t+HPPC4em74x2WKaIl31ZXzgzllLomnlLISLOKiQe1rEHp4yy3/yE2a4G
|
gkCYvXCxwUgUFDwES2nd1JwBpukh44IK/uSqvzSgjMvJeW4+XGpSnsTtK8Vp/lA8
|
||||||
1l/lprA49dcyM/oylm9Bbkum2F4C+EOjHgTAoDVJrJpdWvPj0CU+HkmftujfFp4S
|
k521/y0oqGwGbJ3Fr7JZ+1l3DXR6iISk1B3UuiAGzLUeSE50IRWGdcDMWtEFz1cW
|
||||||
55LECSr2TfJt7xjgR3eLUx12nlpoauWEzZ0/i6OIDPfbmqcksw4ani/YO07LbRM6
|
ehMX7MJKrtUecqoiWoycgjLEEOZCbiGGaHyAIzA1072wXgopK/AUsRg32Vklw+c4
|
||||||
cY9VZzkAvwIDAQABo4IBlTCCAZEwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
|
2enULTY1ZQIDAQABo4IBXzCCAVswDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
|
||||||
CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
|
CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
|
||||||
BBQqNLmq+r88iPFH8tISeL7F5aqwaTAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
|
BBT6kTljmvutECTlvrW52qvZxEZpqzAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
|
||||||
move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw
|
move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw
|
||||||
Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1
|
Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1
|
||||||
cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w
|
cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w
|
||||||
K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwVwYD
|
K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwIQYD
|
||||||
VR0gBFAwTjAIBgZngQwBAgEwQgYKKwYBBAGgMgoBAzA0MDIGCCsGAQUFBwIBFiZo
|
VR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAGgMgoBAzANBgkqhkiG9w0BAQsFAAOC
|
||||||
dHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0B
|
AQEAFDMseeU/gsZwP9pZOKe7onasYRgFaFfZDfuKRrzxqOgMcAIdxi+X7TY+nlKG
|
||||||
AQsFAAOCAQEAEsIwXEhdAfoUGaKAnYfVI7zsOY7Sx8bpC/obGxXa4Kyu8CVx+TtT
|
L1xi2NVHQ5pz0Sslh59EtBTrJrwhR3QgvZ+kv7OAHU01fc25tdpV8pBQyLIXTg60
|
||||||
g8WmKNF7+I7C51NZEmhvb8UDI1G9ny7iYIRDajQD5AeZowbfC69aHQSI9LiOeAZb
|
YYgpX0RdA39XkYHQ6zCu1SrsgiDOTtKwi5UCYXPYaTT0rWMOXOQgH6l97Y7lHAS7
|
||||||
YaRDJfWps9redPwoaC0iT5R4xLOnWwCtmIho1bv/YG3pMAvaQ+qn04kuUvWO7LEp
|
Ip/HqSLKmT0Cp2foBi36BGu7SdJsmVdjbC3CYXjhILH79r/hgjk5PHvvfRqVSrJy
|
||||||
u7FdHmx1DdgkefcqYgN/rAZ8E39S9VxWV+64PNUDey8vkAIH8FCTxbWiITty6dsH
|
2lWQru3d4nCQfBrutTJaXc/W+kXyngEMMS+JhP4xYA/97qZbhNXHGOak+UAwKRge
|
||||||
SulKQ9pSa93k9PHTf+di08mMQBq5WBWTiFeMYZEWyE/z7NHdU3eLMZjq6y/nKlF9
|
/vxBtbkpBXWLYhpbIi6/5FlssA==
|
||||||
nywrToh4AgdZK6JnbU+lqbNiexJbaBoA3w==
|
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
58
spec/fixtures/clusters/leaf_certificate.pem
vendored
58
spec/fixtures/clusters/leaf_certificate.pem
vendored
|
@ -1,37 +1,37 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIGYzCCBUugAwIBAgIQAaQHyOeT/PBR4ioLKYneZDANBgkqhkiG9w0BAQsFADBY
|
MIIGYjCCBUqgAwIBAgIQATfkha/xTr3pbLHVWlPq4jANBgkqhkiG9w0BAQsFADBY
|
||||||
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEuMCwGA1UE
|
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEuMCwGA1UE
|
||||||
AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgSDIgMjAyMTAeFw0yMTEw
|
AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgMjAyMiBRMzAeFw0yMjA3
|
||||||
MTgxODUwMDRaFw0yMjExMTkxODUwMDNaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
|
MjIxOTQyMTFaFw0yMzA4MjMxOTQyMTBaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
|
||||||
Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWSo0eziN/0lq5
|
Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFFFQs8EITaWo5
|
||||||
dIcS7ZceJw2odzZeT0tRkcKEW8iagNul6JetrFlk6h5lxoLEu35+MK6/fWHNmt7u
|
0U18/mPTDLencU/7siJT/4P8oeDkemyx98wzK6vuNj/2JEZ3v1psKun5n8Pb/fHa
|
||||||
eQk7HS0uRipskAzeGrL1Hvk8EjIcHXXTxpRu7JqWOu7ZSXwNxW5cqn7L9/N2gYwt
|
somKd/4icHgC4rnxrO6zayfb+cKzVghQe12Nj75lx6RtppqTgAmSOa3Tai5niICT
|
||||||
Jg/sfkv9AFQiNOdKrarKfbcBstxmra6rQbh5ggLG5UBT23N4ZrA3XnzvEx3+GjtO
|
I8s3d2wsHtfEgqAavcD0/zdPIk25Ji7yfquldSthnlhQqI4Pm3OxTiyFj/V5ZhFl
|
||||||
u/a5izbk7FQP3gyXKyfm/SQRpNsytYa9jJqu5Hmyzfap5KaueOJbtJEOk8dR/HWR
|
IWZLvQaENjBSDVZQDcaPdWwodfXNA8fJmqk7cTLQ9P9NgjWvva7acl+Yd6hOFzV0
|
||||||
i/gmAUevq62MNxorYbz8YU/P1468tS7iORkD31Tc2QWCMQSPya5qGaCGnz7dVgWy
|
EllBl/WF1KB+YzGuHI0CQHT7sv3GW1lXeE2EqrWoSdLTOSAqm6y02DyE79d1xvG6
|
||||||
E1xTPbBXAgMBAAGjggNkMIIDYDAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
|
XXfX5ILlAgMBAAGjggNjMIIDXzAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
|
||||||
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||||
HQYDVR0OBBYEFJFVruwpjWeUfGJXl3m5grAjhAwPMFcGA1UdIARQME4wCAYGZ4EM
|
HQYDVR0OBBYEFHK7MnjGDptQWjfmJ2fr3IrjxEopMFcGA1UdIARQME4wCAYGZ4EM
|
||||||
AQIBMEIGCisGAQQBoDIKAQMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
|
AQIBMEIGCisGAQQBoDIKAQMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
|
||||||
YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDAYDVR0TAQH/BAIwADCBngYIKwYBBQUH
|
YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDAYDVR0TAQH/BAIwADCBngYIKwYBBQUH
|
||||||
AQEEgZEwgY4wQAYIKwYBBQUHMAGGNGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29t
|
AQEEgZEwgY4wQAYIKwYBBQUHMAGGNGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29t
|
||||||
L2NhL2dzYXRsYXNyM2R2dGxzY2FoMjIwMjEwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
|
L2NhL2dzYXRsYXNyM2R2dGxzY2EyMDIycTMwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
|
||||||
ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2FoMjIw
|
ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2EyMDIy
|
||||||
MjEuY3J0MB8GA1UdIwQYMBaAFCo0uar6vzyI8Ufy0hJ4vsXlqrBpMEgGA1UdHwRB
|
cTMuY3J0MB8GA1UdIwQYMBaAFPqROWOa+60QJOW+tbnaq9nERmmrMEgGA1UdHwRB
|
||||||
MD8wPaA7oDmGN2h0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3NhdGxhc3Iz
|
MD8wPaA7oDmGN2h0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3NhdGxhc3Iz
|
||||||
ZHZ0bHNjYWgyMjAyMS5jcmwwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB3AG9T
|
ZHZ0bHNjYTIwMjJxMy5jcmwwggF9BgorBgEEAdZ5AgQCBIIBbQSCAWkBZwB1AG9T
|
||||||
dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABfJS9R5YAAAQDAEgwRgIh
|
dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABgiduiHEAAAQDAEYwRAIg
|
||||||
AOOZmc41vB2ICwkwEB5Bmpm/X8UHfjbxwrCXEdeRmO+qAiEAg/JugZIrG2PeV4bA
|
SYQrru/KAKfe+hUqpJmk7Fc8drkgtY3IcAurTOwbM68CIBYO9sbDspd5p7v17RQi
|
||||||
Gm6rry7HUfB954bQJ4p0PeQVmwsAdABGpVXrdfqRIDC1oolp9PN9ESxBdL79SbiF
|
QQkjdRwSjHiIgvlX0Y1JqmXjAHYArfe++nz/EMiLnT2cHj4YarRnKV3PsQwkyoWG
|
||||||
q/L8cP5tRwAAAXyUvUeOAAAEAwBFMEMCHyRAiTz2fZ8DuQF6hrVP+IMTCPBtjB3D
|
NOvcgooAAAGCJ26IcQAABAMARzBFAiBc5a10annqMEH69bdEFy/Vo1gb3S3GQ993
|
||||||
m4naI8tC/foCIDXFCRIYjRb00CFI6piLYGihRy+GYF5nMQhQ9uE6hltzAHcAUaOw
|
BCRV7ZXG4gIhAMqnsoKkU6ITwRXwE9KGjHnijJ8QrBrnK0i+JFaGe1ffAHYAs3N3
|
||||||
9f0BeZxWbbg3eI8MpHrMGyfL956IQpoN/tSLBeUAAAF8lL1ICgAABAMASDBGAiEA
|
B+GEUPhjhtYFqdwRCUp5LbFnDAuH3PADDnk2pZoAAAGCJ26I6QAABAMARzBFAiAf
|
||||||
5d/bXb9TPZWhwSH8GGji/LDFL6OJnZtOV94sBaDiFgMCIQCtl00oCRMFFnqsvBo6
|
lW8Agd0DB68YA8XAbnlq7QNHw3uRMzNdS8gtRUe75gIhANTe+mt2p1ryW83P31OW
|
||||||
SRtnDqJkEHYBS12I4LyC+D1onjANBgkqhkiG9w0BAQsFAAOCAQEAE5xcno79J+Ec
|
jH3cEGJxdUNT/oDM3Fzesx94MA0GCSqGSIb3DQEBCwUAA4IBAQAfivKEmjqqOFFh
|
||||||
DIPJKnJCugKiM7yKjCjCp/63osCbRC+jUwRyXBIe/oTdY3geKwDOQAvyEeJPSWP1
|
VsX2XYkoDtreghpqMwHMCLwNk852Alr/Seyv9Ilng8cunU4NmhvEtsYVXkfE4XvB
|
||||||
LbNp0l3yHbYXfsYl/NMTrJpjrJrrRO5BxG/d3IPwXIlcZrrdDSoGfGYIF9N23iqB
|
0QIVxkg1w7A+p7ejMjh6doLJ0aWNWIVW/DwOeP0qstF9lqvLdLDABoVn0BtYCDTH
|
||||||
in15L7B+PodTl8/mSQZTjbLoecPvl+AOcLyStcWCKYQUlQb3x4UV3R4Z1ukwGbBC
|
gjG80e2xpvPiKHGvBL+hlOIJwUuIAT3jN23sS1GoiYQGKsz0lovB09/6MGG0Qj8C
|
||||||
cDbTR2XOSJzA9ECJcxKnWjQRQUc54pdG3pt13Wu2dVapX5sWZpV05rga3bBDjCqw
|
3i9a59T9XBpwSKdpKd4u/CB6koBXD3atbBNBACuAMcFckTEtmkCFtSpqBuocJGKf
|
||||||
DcfKuYbOChm2i6CQ578lAntPTIS02EkGFHrmYxrIAvlhGksHpJNJtRoff1KkQKni
|
LB4MFVaEwrd7Lc1ACC1et5FDtEI4I3/CerkRZTV+mRz5n6tB91AK3dRvjElfhiuh
|
||||||
r8emWp7D2Q==
|
XXYRULvB
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
BIN
spec/fixtures/packages/nuget/corrupted_package.nupkg
vendored
Normal file
BIN
spec/fixtures/packages/nuget/corrupted_package.nupkg
vendored
Normal file
Binary file not shown.
|
@ -445,6 +445,19 @@ RSpec.describe DiffHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#params_with_whitespace' do
|
||||||
|
before do
|
||||||
|
controller.params[:protocol] = 'HACKED!'
|
||||||
|
controller.params[:host] = 'HACKED!'
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { helper.params_with_whitespace }
|
||||||
|
|
||||||
|
it "filters with safe_params" do
|
||||||
|
expect(subject).to eq({ 'w' => 1 })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#render_fork_suggestion" do
|
describe "#render_fork_suggestion" do
|
||||||
subject { helper.render_fork_suggestion }
|
subject { helper.render_fork_suggestion }
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe SubmoduleHelper do
|
RSpec.describe SubmoduleHelper, feature_category: :source_code_management do
|
||||||
include RepoHelpers
|
include RepoHelpers
|
||||||
|
|
||||||
let(:submodule_item) { double(id: 'hash', path: 'rack') }
|
let(:submodule_item) { double(id: 'hash', path: 'rack') }
|
||||||
|
|
|
@ -114,6 +114,18 @@ RSpec.describe Gitlab::APIAuthentication::TokenResolver do
|
||||||
|
|
||||||
it_behaves_like 'an unauthorized request'
|
it_behaves_like 'an unauthorized request'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the external_authorization_service is enabled' do
|
||||||
|
before do
|
||||||
|
stub_application_setting(external_authorization_service_enabled: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a valid deploy token' do
|
||||||
|
let(:raw) { username_and_password(token.username, token.token) }
|
||||||
|
|
||||||
|
it_behaves_like 'an unauthorized request'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with :personal_access_token' do
|
context 'with :personal_access_token' do
|
||||||
|
|
|
@ -188,7 +188,7 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns nil if valid feed_token and disabled' do
|
it 'returns nil if valid feed_token and disabled' do
|
||||||
allow(Gitlab::CurrentSettings).to receive_messages(disable_feed_token: true)
|
stub_application_setting(disable_feed_token: true)
|
||||||
set_param(:feed_token, user.feed_token)
|
set_param(:feed_token, user.feed_token)
|
||||||
|
|
||||||
expect(find_user_from_feed_token(:rss)).to be_nil
|
expect(find_user_from_feed_token(:rss)).to be_nil
|
||||||
|
@ -388,6 +388,15 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
||||||
it { is_expected.to be_nil }
|
it { is_expected.to be_nil }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the external_authorization_service is enabled' do
|
||||||
|
before do
|
||||||
|
stub_application_setting(external_authorization_service_enabled: true)
|
||||||
|
set_header(described_class::DEPLOY_TOKEN_HEADER, deploy_token.token)
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to be_nil }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#find_user_from_access_token' do
|
describe '#find_user_from_access_token' do
|
||||||
|
|
|
@ -528,12 +528,13 @@ RSpec.describe Gitlab::Git::Repository do
|
||||||
prune: false,
|
prune: false,
|
||||||
check_tags_changed: false,
|
check_tags_changed: false,
|
||||||
refmap: nil,
|
refmap: nil,
|
||||||
http_authorization_header: ""
|
http_authorization_header: "",
|
||||||
|
resolved_address: '172.16.123.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(repository.gitaly_repository_client).to receive(:fetch_remote).with(url, expected_opts)
|
expect(repository.gitaly_repository_client).to receive(:fetch_remote).with(url, expected_opts)
|
||||||
|
|
||||||
repository.fetch_remote(url, ssh_auth: ssh_auth, forced: true, no_tags: true, prune: false, check_tags_changed: false)
|
repository.fetch_remote(url, ssh_auth: ssh_auth, forced: true, no_tags: true, prune: false, check_tags_changed: false, resolved_address: '172.16.123.1')
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RepositoryService, :fetch_remote do
|
it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RepositoryService, :fetch_remote do
|
||||||
|
@ -2454,7 +2455,7 @@ RSpec.describe Gitlab::Git::Repository do
|
||||||
|
|
||||||
it 'delegates to Gitaly' do
|
it 'delegates to Gitaly' do
|
||||||
expect_next_instance_of(Gitlab::GitalyClient::RepositoryService) do |svc|
|
expect_next_instance_of(Gitlab::GitalyClient::RepositoryService) do |svc|
|
||||||
expect(svc).to receive(:import_repository).with(url, http_authorization_header: '', mirror: false).and_return(nil)
|
expect(svc).to receive(:import_repository).with(url, http_authorization_header: '', mirror: false, resolved_address: '').and_return(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
repository.import_repository(url)
|
repository.import_repository(url)
|
||||||
|
|
|
@ -5,6 +5,7 @@ require 'spec_helper'
|
||||||
RSpec.describe Gitlab::GitAccess, :aggregate_failures do
|
RSpec.describe Gitlab::GitAccess, :aggregate_failures do
|
||||||
include TermsHelper
|
include TermsHelper
|
||||||
include AdminModeHelper
|
include AdminModeHelper
|
||||||
|
include ExternalAuthorizationServiceHelpers
|
||||||
|
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:actor) { user }
|
let(:actor) { user }
|
||||||
|
@ -111,6 +112,19 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the external_authorization_service is enabled' do
|
||||||
|
before do
|
||||||
|
stub_application_setting(external_authorization_service_enabled: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'blocks push and pull with "not found"' do
|
||||||
|
aggregate_failures do
|
||||||
|
expect { push_access_check }.to raise_not_found
|
||||||
|
expect { pull_access_check }.to raise_not_found
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when actor is a User' do
|
context 'when actor is a User' do
|
||||||
|
@ -176,6 +190,20 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures do
|
||||||
expect { push_access_check }.to raise_not_found
|
expect { push_access_check }.to raise_not_found
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the external_authorization_service is enabled' do
|
||||||
|
before do
|
||||||
|
stub_application_setting(external_authorization_service_enabled: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'blocks pull access' do
|
||||||
|
expect { pull_access_check }.to raise_not_found
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'blocks the push' do
|
||||||
|
expect { push_access_check }.to raise_not_found
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,40 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#import_repository' do
|
||||||
|
let(:source) { 'https://example.com/git/repo.git' }
|
||||||
|
|
||||||
|
it 'sends a create_repository_from_url message' do
|
||||||
|
expected_request = gitaly_request_with_params(
|
||||||
|
url: source,
|
||||||
|
resolved_address: ''
|
||||||
|
)
|
||||||
|
|
||||||
|
expect_any_instance_of(Gitaly::RepositoryService::Stub)
|
||||||
|
.to receive(:create_repository_from_url)
|
||||||
|
.with(expected_request, kind_of(Hash))
|
||||||
|
.and_return(double(value: true))
|
||||||
|
|
||||||
|
client.import_repository(source)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when http_host is provided' do
|
||||||
|
it 'sends a create_repository_from_url message with http_host provided in the request' do
|
||||||
|
expected_request = gitaly_request_with_params(
|
||||||
|
url: source,
|
||||||
|
resolved_address: '172.16.123.1'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect_any_instance_of(Gitaly::RepositoryService::Stub)
|
||||||
|
.to receive(:create_repository_from_url)
|
||||||
|
.with(expected_request, kind_of(Hash))
|
||||||
|
.and_return(double(value: true))
|
||||||
|
|
||||||
|
client.import_repository(source, resolved_address: '172.16.123.1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#fetch_remote' do
|
describe '#fetch_remote' do
|
||||||
let(:url) { 'https://example.com/git/repo.git' }
|
let(:url) { 'https://example.com/git/repo.git' }
|
||||||
|
|
||||||
|
@ -141,7 +175,8 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
|
||||||
remote_params: Gitaly::Remote.new(
|
remote_params: Gitaly::Remote.new(
|
||||||
url: url,
|
url: url,
|
||||||
http_authorization_header: "",
|
http_authorization_header: "",
|
||||||
mirror_refmaps: []
|
mirror_refmaps: [],
|
||||||
|
resolved_address: ''
|
||||||
),
|
),
|
||||||
ssh_key: '',
|
ssh_key: '',
|
||||||
known_hosts: '',
|
known_hosts: '',
|
||||||
|
@ -159,6 +194,32 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
|
||||||
client.fetch_remote(url, refmap: nil, ssh_auth: nil, forced: false, no_tags: false, timeout: 1, check_tags_changed: false)
|
client.fetch_remote(url, refmap: nil, ssh_auth: nil, forced: false, no_tags: false, timeout: 1, check_tags_changed: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with resolved address' do
|
||||||
|
it 'sends a fetch_remote_request message' do
|
||||||
|
expected_request = gitaly_request_with_params(
|
||||||
|
remote_params: Gitaly::Remote.new(
|
||||||
|
url: url,
|
||||||
|
http_authorization_header: "",
|
||||||
|
mirror_refmaps: [],
|
||||||
|
resolved_address: '172.16.123.1'
|
||||||
|
),
|
||||||
|
ssh_key: '',
|
||||||
|
known_hosts: '',
|
||||||
|
force: false,
|
||||||
|
no_tags: false,
|
||||||
|
no_prune: false,
|
||||||
|
check_tags_changed: false
|
||||||
|
)
|
||||||
|
|
||||||
|
expect_any_instance_of(Gitaly::RepositoryService::Stub)
|
||||||
|
.to receive(:fetch_remote)
|
||||||
|
.with(expected_request, kind_of(Hash))
|
||||||
|
.and_return(double(value: true))
|
||||||
|
|
||||||
|
client.fetch_remote(url, refmap: nil, ssh_auth: nil, forced: false, no_tags: false, timeout: 1, check_tags_changed: false, resolved_address: '172.16.123.1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'SSH auth' do
|
context 'SSH auth' do
|
||||||
where(:ssh_mirror_url, :ssh_key_auth, :ssh_private_key, :ssh_known_hosts, :expected_params) do
|
where(:ssh_mirror_url, :ssh_key_auth, :ssh_private_key, :ssh_known_hosts, :expected_params) do
|
||||||
false | false | 'key' | 'known_hosts' | {}
|
false | false | 'key' | 'known_hosts' | {}
|
||||||
|
|
|
@ -29,8 +29,8 @@ RSpec.describe Gitlab::HookData::ProjectBuilder do
|
||||||
expect(data[:path_with_namespace]).to eq(project.full_path)
|
expect(data[:path_with_namespace]).to eq(project.full_path)
|
||||||
expect(data[:project_id]).to eq(project.id)
|
expect(data[:project_id]).to eq(project.id)
|
||||||
expect(data[:owner_name]).to eq('John')
|
expect(data[:owner_name]).to eq('John')
|
||||||
expect(data[:owner_email]).to eq('john@example.com')
|
expect(data[:owner_email]).to eq(_('[REDACTED]'))
|
||||||
expect(data[:owners]).to contain_exactly({ name: 'John', email: 'john@example.com' })
|
expect(data[:owners]).to contain_exactly({ name: 'John', email: _('[REDACTED]') })
|
||||||
expect(data[:project_visibility]).to eq('internal')
|
expect(data[:project_visibility]).to eq('internal')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,7 +27,7 @@ RSpec.describe Gitlab::HookData::ProjectMemberBuilder do
|
||||||
expect(data[:user_username]).to eq('johndoe')
|
expect(data[:user_username]).to eq('johndoe')
|
||||||
expect(data[:user_name]).to eq('John Doe')
|
expect(data[:user_name]).to eq('John Doe')
|
||||||
expect(data[:user_id]).to eq(user.id)
|
expect(data[:user_id]).to eq(user.id)
|
||||||
expect(data[:user_email]).to eq('john@example.com')
|
expect(data[:user_email]).to eq(_('[REDACTED]'))
|
||||||
expect(data[:access_level]).to eq('Developer')
|
expect(data[:access_level]).to eq('Developer')
|
||||||
expect(data[:project_visibility]).to eq('internal')
|
expect(data[:project_visibility]).to eq('internal')
|
||||||
end
|
end
|
||||||
|
|
20
spec/lib/gitlab/safe_device_detector_spec.rb
Normal file
20
spec/lib/gitlab/safe_device_detector_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'fast_spec_helper'
|
||||||
|
require 'device_detector'
|
||||||
|
require_relative '../../../lib/gitlab/safe_device_detector'
|
||||||
|
|
||||||
|
RSpec.describe Gitlab::SafeDeviceDetector, feature_category: :authentication_and_authorization do
|
||||||
|
it 'retains the behavior for normal user agents' do
|
||||||
|
chrome_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
|
||||||
|
(KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
|
||||||
|
|
||||||
|
expect(described_class.new(chrome_user_agent).user_agent).to be_eql(chrome_user_agent)
|
||||||
|
expect(described_class.new(chrome_user_agent).name).to be_eql('Chrome')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'truncates big user agents' do
|
||||||
|
big_user_agent = "chrome #{'abc' * 1024}"
|
||||||
|
expect(described_class.new(big_user_agent).user_agent).not_to be_eql(big_user_agent)
|
||||||
|
end
|
||||||
|
end
|
|
@ -89,31 +89,32 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
|
||||||
describe '.categories' do
|
describe '.categories' do
|
||||||
it 'gets CE unique category names' do
|
it 'gets CE unique category names' do
|
||||||
expect(described_class.categories).to include(
|
expect(described_class.categories).to include(
|
||||||
'deploy_token_packages',
|
|
||||||
'user_packages',
|
|
||||||
'ecosystem',
|
|
||||||
'analytics',
|
'analytics',
|
||||||
'ide_edit',
|
|
||||||
'search',
|
|
||||||
'source_code',
|
|
||||||
'incident_management',
|
|
||||||
'incident_management_alerts',
|
|
||||||
'testing',
|
|
||||||
'issues_edit',
|
|
||||||
'snippets',
|
|
||||||
'code_review',
|
|
||||||
'terraform',
|
|
||||||
'ci_templates',
|
'ci_templates',
|
||||||
'quickactions',
|
|
||||||
'pipeline_authoring',
|
|
||||||
'secure',
|
|
||||||
'importer',
|
|
||||||
'geo',
|
|
||||||
'work_items',
|
|
||||||
'ci_users',
|
'ci_users',
|
||||||
|
'code_review',
|
||||||
|
'deploy_token_packages',
|
||||||
|
'ecosystem',
|
||||||
|
'environments',
|
||||||
'error_tracking',
|
'error_tracking',
|
||||||
|
'geo',
|
||||||
|
'ide_edit',
|
||||||
|
'importer',
|
||||||
|
'incident_management_alerts',
|
||||||
|
'incident_management',
|
||||||
|
'issues_edit',
|
||||||
|
'kubernetes_agent',
|
||||||
'manage',
|
'manage',
|
||||||
'kubernetes_agent'
|
'pipeline_authoring',
|
||||||
|
'quickactions',
|
||||||
|
'search',
|
||||||
|
'secure',
|
||||||
|
'snippets',
|
||||||
|
'source_code',
|
||||||
|
'terraform',
|
||||||
|
'testing',
|
||||||
|
'user_packages',
|
||||||
|
'work_items'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,7 +11,7 @@ RSpec.describe DeviseMailer do
|
||||||
subject { described_class.confirmation_instructions(user, 'faketoken', {}) }
|
subject { described_class.confirmation_instructions(user, 'faketoken', {}) }
|
||||||
|
|
||||||
context "when confirming a new account" do
|
context "when confirming a new account" do
|
||||||
let(:user) { build(:user, created_at: 1.minute.ago, unconfirmed_email: nil) }
|
let(:user) { create(:user, created_at: 1.minute.ago) }
|
||||||
|
|
||||||
it "shows the expected text" do
|
it "shows the expected text" do
|
||||||
expect(subject.body.encoded).to have_text "Welcome"
|
expect(subject.body.encoded).to have_text "Welcome"
|
||||||
|
@ -20,7 +20,13 @@ RSpec.describe DeviseMailer do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when confirming the unconfirmed_email" do
|
context "when confirming the unconfirmed_email" do
|
||||||
let(:user) { build(:user, unconfirmed_email: 'jdoe@example.com') }
|
subject { described_class.confirmation_instructions(user, user.confirmation_token, { to: user.unconfirmed_email }) }
|
||||||
|
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
user.update!(email: 'unconfirmed-email@example.com')
|
||||||
|
end
|
||||||
|
|
||||||
it "shows the expected text" do
|
it "shows the expected text" do
|
||||||
expect(subject.body.encoded).not_to have_text "Welcome"
|
expect(subject.body.encoded).not_to have_text "Welcome"
|
||||||
|
@ -30,7 +36,7 @@ RSpec.describe DeviseMailer do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when re-confirming the primary email after a security issue" do
|
context "when re-confirming the primary email after a security issue" do
|
||||||
let(:user) { build(:user, created_at: 10.days.ago, unconfirmed_email: nil) }
|
let(:user) { create(:user, created_at: Devise.confirm_within.ago) }
|
||||||
|
|
||||||
it "shows the expected text" do
|
it "shows the expected text" do
|
||||||
expect(subject.body.encoded).not_to have_text "Welcome"
|
expect(subject.body.encoded).not_to have_text "Welcome"
|
||||||
|
|
|
@ -1466,10 +1466,4 @@ RSpec.describe ApplicationSetting do
|
||||||
expect(setting.personal_access_token_prefix).to eql('glpat-')
|
expect(setting.personal_access_token_prefix).to eql('glpat-')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.personal_access_tokens_disabled?' do
|
|
||||||
it 'is false' do
|
|
||||||
expect(setting.personal_access_tokens_disabled?).to eq(false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,45 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
|
||||||
it { is_expected.to validate_presence_of(:build) }
|
it { is_expected.to validate_presence_of(:build) }
|
||||||
it { is_expected.to validate_presence_of(:url).with_message('must be a valid URL') }
|
it { is_expected.to validate_presence_of(:url).with_message('must be a valid URL') }
|
||||||
|
|
||||||
|
context 'url validation of local web hook address' do
|
||||||
|
let(:url) { 'https://127.0.0.1:7777' }
|
||||||
|
|
||||||
|
subject(:build_with_local_runner_session_url) do
|
||||||
|
create(:ci_build).tap { |b| b.update!(runner_session_attributes: { url: url }) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with allow_local_requests_from_web_hooks_and_services? stubbed' do
|
||||||
|
before do
|
||||||
|
allow(ApplicationSetting).to receive(:current).and_return(ApplicationSetting.new)
|
||||||
|
stub_application_setting(allow_local_requests_from_web_hooks_and_services: allow_local_requests)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as returning true' do
|
||||||
|
let(:allow_local_requests) { true }
|
||||||
|
|
||||||
|
it 'creates a new session', :aggregate_failures do
|
||||||
|
session = build_with_local_runner_session_url.reload.runner_session
|
||||||
|
|
||||||
|
expect(session.errors).to be_empty
|
||||||
|
expect(session).to be_a(Ci::BuildRunnerSession)
|
||||||
|
expect(session.url).to eq(url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as returning false' do
|
||||||
|
let(:allow_local_requests) { false }
|
||||||
|
|
||||||
|
it 'does not create a new session' do
|
||||||
|
expect { build_with_local_runner_session_url }.to raise_error(ActiveRecord::RecordInvalid) do |err|
|
||||||
|
expect(err.record.errors.full_messages).to include(
|
||||||
|
'Runner session url is blocked: Requests to localhost are not allowed'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'nested attribute assignment' do
|
context 'nested attribute assignment' do
|
||||||
it 'creates a new session' do
|
it 'creates a new session' do
|
||||||
simple_build = create(:ci_build)
|
simple_build = create(:ci_build)
|
||||||
|
@ -49,6 +88,12 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
|
||||||
expect(specification).to be_empty
|
expect(specification).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns url with appended query if url has query' do
|
||||||
|
subject.url = 'https://new.example.com:7777/some_path?dummy='
|
||||||
|
|
||||||
|
expect(specification[:url]).to eq('wss://new.example.com:7777/some_path/exec?dummy=')
|
||||||
|
end
|
||||||
|
|
||||||
context 'when url is present' do
|
context 'when url is present' do
|
||||||
it 'returns ca_pem nil if empty certificate' do
|
it 'returns ca_pem nil if empty certificate' do
|
||||||
subject.certificate = ''
|
subject.certificate = ''
|
||||||
|
@ -72,7 +117,7 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
|
||||||
let(:specification) { subject.service_specification(service: service, port: port, path: path, subprotocols: subprotocols) }
|
let(:specification) { subject.service_specification(service: service, port: port, path: path, subprotocols: subprotocols) }
|
||||||
|
|
||||||
it 'returns service proxy url' do
|
it 'returns service proxy url' do
|
||||||
expect(specification[:url]).to eq "https://localhost/proxy/#{service}/#{port}/#{path}"
|
expect(specification[:url]).to eq "https://gitlab.example.com/proxy/#{service}/#{port}/#{path}"
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns default service proxy websocket subprotocol' do
|
it 'returns default service proxy websocket subprotocol' do
|
||||||
|
@ -85,11 +130,17 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
|
||||||
expect(specification).to be_empty
|
expect(specification).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns url with appended query if url has query' do
|
||||||
|
subject.url = 'https://new.example.com:7777/some_path?dummy='
|
||||||
|
|
||||||
|
expect(specification[:url]).to eq("https://new.example.com:7777/some_path/proxy/#{service}/#{port}/#{path}?dummy=")
|
||||||
|
end
|
||||||
|
|
||||||
context 'when port is not present' do
|
context 'when port is not present' do
|
||||||
let(:port) { nil }
|
let(:port) { nil }
|
||||||
|
|
||||||
it 'uses the default port name' do
|
it 'uses the default port name' do
|
||||||
expect(specification[:url]).to eq "https://localhost/proxy/#{service}/default_port/#{path}"
|
expect(specification[:url]).to eq "https://gitlab.example.com/proxy/#{service}/default_port/#{path}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -97,7 +148,7 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
|
||||||
let(:service) { '' }
|
let(:service) { '' }
|
||||||
|
|
||||||
it 'uses the service name "build" as default' do
|
it 'uses the service name "build" as default' do
|
||||||
expect(specification[:url]).to eq "https://localhost/proxy/build/#{port}/#{path}"
|
expect(specification[:url]).to eq "https://gitlab.example.com/proxy/build/#{port}/#{path}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -185,4 +185,22 @@ RSpec.describe WebHookLog do
|
||||||
it { expect(web_hook_log.internal_error?).to be_truthy }
|
it { expect(web_hook_log.internal_error?).to be_truthy }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#request_headers' do
|
||||||
|
let(:hook) { build(:project_hook, :token) }
|
||||||
|
let(:web_hook_log) { build(:web_hook_log, request_headers: request_headers) }
|
||||||
|
let(:expected_headers) { { 'X-Gitlab-Token' => _('[REDACTED]') } }
|
||||||
|
|
||||||
|
context 'with redacted headers token' do
|
||||||
|
let(:request_headers) { { 'X-Gitlab-Token' => _('[REDACTED]') } }
|
||||||
|
|
||||||
|
it { expect(web_hook_log.request_headers).to eq(expected_headers) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with exposed headers token' do
|
||||||
|
let(:request_headers) { { 'X-Gitlab-Token' => hook.token } }
|
||||||
|
|
||||||
|
it { expect(web_hook_log.request_headers).to eq(expected_headers) }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe WebHook do
|
RSpec.describe WebHook, feature_category: :integrations do
|
||||||
include AfterNextHelpers
|
include AfterNextHelpers
|
||||||
|
|
||||||
let_it_be(:project) { create(:project) }
|
let_it_be(:project) { create(:project) }
|
||||||
|
@ -131,6 +131,62 @@ RSpec.describe WebHook do
|
||||||
expect(hook.push_events_branch_filter).to eq('')
|
expect(hook.push_events_branch_filter).to eq('')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'before_validation :reset_token' do
|
||||||
|
subject(:hook) { build_stubbed(:project_hook, :token, project: project) }
|
||||||
|
|
||||||
|
it 'resets token if url changed' do
|
||||||
|
hook.url = 'https://webhook.example.com/new-hook'
|
||||||
|
|
||||||
|
expect(hook).to be_valid
|
||||||
|
expect(hook.token).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not reset token if new url is set together with the same token' do
|
||||||
|
hook.url = 'https://webhook.example.com/new-hook'
|
||||||
|
current_token = hook.token
|
||||||
|
hook.token = current_token
|
||||||
|
|
||||||
|
expect(hook).to be_valid
|
||||||
|
expect(hook.token).to eq(current_token)
|
||||||
|
expect(hook.url).to eq('https://webhook.example.com/new-hook')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not reset token if new url is set together with a new token' do
|
||||||
|
hook.url = 'https://webhook.example.com/new-hook'
|
||||||
|
hook.token = 'token'
|
||||||
|
|
||||||
|
expect(hook).to be_valid
|
||||||
|
expect(hook.token).to eq('token')
|
||||||
|
expect(hook.url).to eq('https://webhook.example.com/new-hook')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'before_validation :reset_url_variables' do
|
||||||
|
subject(:hook) { build_stubbed(:project_hook, :url_variables, project: project, url: 'http://example.com/{abc}') }
|
||||||
|
|
||||||
|
it 'resets url variables if url changed' do
|
||||||
|
hook.url = 'http://example.com/new-hook'
|
||||||
|
|
||||||
|
expect(hook).to be_valid
|
||||||
|
expect(hook.url_variables).to eq({})
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'resets url variables if url is changed but url variables stayed the same' do
|
||||||
|
hook.url = 'http://test.example.com/{abc}'
|
||||||
|
|
||||||
|
expect(hook).not_to be_valid
|
||||||
|
expect(hook.url_variables).to eq({})
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not reset url variables if both url and url variables are changed' do
|
||||||
|
hook.url = 'http://example.com/{one}/{two}'
|
||||||
|
hook.url_variables = { 'one' => 'foo', 'two' => 'bar' }
|
||||||
|
|
||||||
|
expect(hook).to be_valid
|
||||||
|
expect(hook.url_variables).to eq({ 'one' => 'foo', 'two' => 'bar' })
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'encrypted attributes' do
|
describe 'encrypted attributes' do
|
||||||
|
@ -242,7 +298,7 @@ RSpec.describe WebHook do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#executable?' do
|
describe '#executable?' do
|
||||||
let(:web_hook) { create(:project_hook, project: project) }
|
let_it_be(:web_hook) { create(:project_hook, project: project) }
|
||||||
|
|
||||||
where(:recent_failures, :not_until, :executable) do
|
where(:recent_failures, :not_until, :executable) do
|
||||||
[
|
[
|
||||||
|
|
|
@ -230,9 +230,12 @@ RSpec.describe Integrations::Jira do
|
||||||
|
|
||||||
where(:url, :result) do
|
where(:url, :result) do
|
||||||
'https://abc.atlassian.net' | true
|
'https://abc.atlassian.net' | true
|
||||||
|
'http://abc.atlassian.net' | false
|
||||||
'abc.atlassian.net' | false # This is how it behaves currently, but we may need to consider adding scheme if missing
|
'abc.atlassian.net' | false # This is how it behaves currently, but we may need to consider adding scheme if missing
|
||||||
'https://somethingelse.com' | false
|
'https://somethingelse.com' | false
|
||||||
nil | false
|
'javascript://test.atlassian.net/%250dalert(document.domain)' | false
|
||||||
|
'https://example.com".atlassian.net' | false
|
||||||
|
nil | false
|
||||||
end
|
end
|
||||||
|
|
||||||
with_them do
|
with_them do
|
||||||
|
@ -289,7 +292,7 @@ RSpec.describe Integrations::Jira do
|
||||||
let(:server_info_results) { { 'deploymentType' => 'FutureCloud' } }
|
let(:server_info_results) { { 'deploymentType' => 'FutureCloud' } }
|
||||||
|
|
||||||
context 'and URL ends in .atlassian.net' do
|
context 'and URL ends in .atlassian.net' do
|
||||||
let(:api_url) { 'http://example-api.atlassian.net' }
|
let(:api_url) { 'https://example-api.atlassian.net' }
|
||||||
|
|
||||||
it 'deployment_type is set to cloud' do
|
it 'deployment_type is set to cloud' do
|
||||||
expect(integration.jira_tracker_data).to be_deployment_cloud
|
expect(integration.jira_tracker_data).to be_deployment_cloud
|
||||||
|
@ -297,7 +300,7 @@ RSpec.describe Integrations::Jira do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'and URL is something else' do
|
context 'and URL is something else' do
|
||||||
let(:api_url) { 'http://my-jira-api.someserver.com' }
|
let(:api_url) { 'https://my-jira-api.someserver.com' }
|
||||||
|
|
||||||
it 'deployment_type is set to server' do
|
it 'deployment_type is set to server' do
|
||||||
expect(integration.jira_tracker_data).to be_deployment_server
|
expect(integration.jira_tracker_data).to be_deployment_server
|
||||||
|
@ -309,7 +312,7 @@ RSpec.describe Integrations::Jira do
|
||||||
let(:server_info_results) { {} }
|
let(:server_info_results) { {} }
|
||||||
|
|
||||||
context 'and URL ends in .atlassian.net' do
|
context 'and URL ends in .atlassian.net' do
|
||||||
let(:api_url) { 'http://example-api.atlassian.net' }
|
let(:api_url) { 'https://example-api.atlassian.net' }
|
||||||
|
|
||||||
it 'deployment_type is set to cloud' do
|
it 'deployment_type is set to cloud' do
|
||||||
expect(Gitlab::AppLogger).to receive(:warn).with(message: "Jira API returned no ServerInfo, setting deployment_type from URL", server_info: server_info_results, url: api_url)
|
expect(Gitlab::AppLogger).to receive(:warn).with(message: "Jira API returned no ServerInfo, setting deployment_type from URL", server_info: server_info_results, url: api_url)
|
||||||
|
@ -318,7 +321,7 @@ RSpec.describe Integrations::Jira do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'and URL is something else' do
|
context 'and URL is something else' do
|
||||||
let(:api_url) { 'http://my-jira-api.someserver.com' }
|
let(:api_url) { 'https://my-jira-api.someserver.com' }
|
||||||
|
|
||||||
it 'deployment_type is set to server' do
|
it 'deployment_type is set to server' do
|
||||||
expect(Gitlab::AppLogger).to receive(:warn).with(message: "Jira API returned no ServerInfo, setting deployment_type from URL", server_info: server_info_results, url: api_url)
|
expect(Gitlab::AppLogger).to receive(:warn).with(message: "Jira API returned no ServerInfo, setting deployment_type from URL", server_info: server_info_results, url: api_url)
|
||||||
|
|
|
@ -22,7 +22,7 @@ RSpec.describe ProjectImportState, type: :model do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:import_repository)
|
allow_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:import_repository)
|
||||||
.with(project.import_url, http_authorization_header: '', mirror: false).and_return(true)
|
.with(project.import_url, http_authorization_header: '', mirror: false, resolved_address: '').and_return(true)
|
||||||
|
|
||||||
# Works around https://github.com/rspec/rspec-mocks/issues/910
|
# Works around https://github.com/rspec/rspec-mocks/issues/910
|
||||||
allow(Project).to receive(:find).with(project.id).and_return(project)
|
allow(Project).to receive(:find).with(project.id).and_return(project)
|
||||||
|
|
|
@ -5521,8 +5521,8 @@ RSpec.describe Project, factory_default: :keep do
|
||||||
let(:import_state) { create(:import_state, project: project) }
|
let(:import_state) { create(:import_state, project: project) }
|
||||||
|
|
||||||
it 'runs the correct hooks' do
|
it 'runs the correct hooks' do
|
||||||
expect(project.repository).to receive(:remove_prohibited_branches)
|
expect(project.repository).to receive(:expire_content_cache).ordered
|
||||||
expect(project.repository).to receive(:expire_content_cache)
|
expect(project.repository).to receive(:remove_prohibited_branches).ordered
|
||||||
expect(project.wiki.repository).to receive(:expire_content_cache)
|
expect(project.wiki.repository).to receive(:expire_content_cache)
|
||||||
expect(import_state).to receive(:finish)
|
expect(import_state).to receive(:finish)
|
||||||
expect(project).to receive(:update_project_counter_caches)
|
expect(project).to receive(:update_project_counter_caches)
|
||||||
|
|
|
@ -1224,11 +1224,22 @@ RSpec.describe Repository do
|
||||||
it 'fetches the URL without creating a remote' do
|
it 'fetches the URL without creating a remote' do
|
||||||
expect(repository)
|
expect(repository)
|
||||||
.to receive(:fetch_remote)
|
.to receive(:fetch_remote)
|
||||||
.with(url, forced: false, prune: true, refmap: :all_refs, http_authorization_header: "")
|
.with(url, forced: false, prune: true, refmap: :all_refs, http_authorization_header: "", resolved_address: '')
|
||||||
.and_return(nil)
|
.and_return(nil)
|
||||||
|
|
||||||
repository.fetch_as_mirror(url)
|
repository.fetch_as_mirror(url)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with http_host provided' do
|
||||||
|
it 'fetches the URL with resolved_address value' do
|
||||||
|
expect(repository)
|
||||||
|
.to receive(:fetch_remote)
|
||||||
|
.with(url, forced: false, prune: true, refmap: :all_refs, http_authorization_header: "", resolved_address: '172.16.123.1')
|
||||||
|
.and_return(nil)
|
||||||
|
|
||||||
|
repository.fetch_as_mirror(url, resolved_address: '172.16.123.1')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#fetch_ref' do
|
describe '#fetch_ref' do
|
||||||
|
|
|
@ -292,6 +292,34 @@ RSpec.describe User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'confirmation instructions for unconfirmed email' do
|
||||||
|
let(:unconfirmed_email) { 'first-unconfirmed-email@example.com' }
|
||||||
|
let(:another_unconfirmed_email) { 'another-unconfirmed-email@example.com' }
|
||||||
|
|
||||||
|
context 'when email is changed to another before performing the job that sends confirmation instructions for previous email change request' do
|
||||||
|
it "mentions the recipient's email in the message body", :aggregate_failures do
|
||||||
|
same_user = User.find(user.id)
|
||||||
|
same_user.update!(email: unconfirmed_email)
|
||||||
|
|
||||||
|
user.update!(email: another_unconfirmed_email)
|
||||||
|
|
||||||
|
perform_enqueued_jobs
|
||||||
|
|
||||||
|
confirmation_instructions_for_unconfirmed_email = ActionMailer::Base.deliveries.find do |message|
|
||||||
|
message.subject == 'Confirmation instructions' && message.to.include?(unconfirmed_email)
|
||||||
|
end
|
||||||
|
expect(confirmation_instructions_for_unconfirmed_email.html_part.body.encoded).to match same_user.unconfirmed_email
|
||||||
|
expect(confirmation_instructions_for_unconfirmed_email.text_part.body.encoded).to match same_user.unconfirmed_email
|
||||||
|
|
||||||
|
confirmation_instructions_for_another_unconfirmed_email = ActionMailer::Base.deliveries.find do |message|
|
||||||
|
message.subject == 'Confirmation instructions' && message.to.include?(another_unconfirmed_email)
|
||||||
|
end
|
||||||
|
expect(confirmation_instructions_for_another_unconfirmed_email.html_part.body.encoded).to match user.unconfirmed_email
|
||||||
|
expect(confirmation_instructions_for_another_unconfirmed_email.text_part.body.encoded).to match user.unconfirmed_email
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'validations' do
|
describe 'validations' do
|
||||||
|
|
|
@ -643,6 +643,35 @@ RSpec.describe ProjectPolicy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'read_grafana', feature_category: :metrics do
|
||||||
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
||||||
|
let(:policy) { :read_grafana }
|
||||||
|
|
||||||
|
where(:project_visibility, :role, :allowed) do
|
||||||
|
:public | :anonymous | false
|
||||||
|
:public | :guest | false
|
||||||
|
:public | :reporter | true
|
||||||
|
:internal | :anonymous | false
|
||||||
|
:internal | :guest | true
|
||||||
|
:internal | :reporter | true
|
||||||
|
:private | :anonymous | false
|
||||||
|
:private | :guest | true
|
||||||
|
:private | :reporter | true
|
||||||
|
end
|
||||||
|
|
||||||
|
with_them do
|
||||||
|
let(:current_user) { public_send(role) }
|
||||||
|
let(:project) { public_send("#{project_visibility}_project") }
|
||||||
|
|
||||||
|
if params[:allowed]
|
||||||
|
it { is_expected.to be_allowed(policy) }
|
||||||
|
else
|
||||||
|
it { is_expected.not_to be_allowed(policy) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'update_max_artifacts_size' do
|
describe 'update_max_artifacts_size' do
|
||||||
context 'when no user' do
|
context 'when no user' do
|
||||||
let(:current_user) { anonymous }
|
let(:current_user) { anonymous }
|
||||||
|
|
|
@ -10,18 +10,6 @@ RSpec.describe Admin::ImpersonationTokensController, :enable_admin_mode do
|
||||||
sign_in(admin)
|
sign_in(admin)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when impersonation is enabled' do
|
|
||||||
before do
|
|
||||||
stub_config_setting(impersonation_enabled: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'responds ok' do
|
|
||||||
get admin_user_impersonation_tokens_path(user_id: user.username)
|
|
||||||
|
|
||||||
expect(response).to have_gitlab_http_status(:ok)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when impersonation is disabled" do
|
context "when impersonation is disabled" do
|
||||||
before do
|
before do
|
||||||
stub_config_setting(impersonation_enabled: false)
|
stub_config_setting(impersonation_enabled: false)
|
||||||
|
|
|
@ -949,6 +949,41 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with session url set to local URL' do
|
||||||
|
let(:job_params) { { session: { url: 'https://127.0.0.1:7777' } } }
|
||||||
|
|
||||||
|
context 'with allow_local_requests_from_web_hooks_and_services? stubbed' do
|
||||||
|
before do
|
||||||
|
allow(ApplicationSetting).to receive(:current).and_return(ApplicationSetting.new)
|
||||||
|
stub_application_setting(allow_local_requests_from_web_hooks_and_services: allow_local_requests)
|
||||||
|
ci_build
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:ci_build) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
|
||||||
|
|
||||||
|
context 'as returning true' do
|
||||||
|
let(:allow_local_requests) { true }
|
||||||
|
|
||||||
|
it 'creates a new session' do
|
||||||
|
request_job(**job_params)
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:created)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as returning false' do
|
||||||
|
let(:allow_local_requests) { false }
|
||||||
|
|
||||||
|
it 'returns :unprocessable_entity status code', :aggregate_failures do
|
||||||
|
request_job(**job_params)
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:conflict)
|
||||||
|
expect(response.body).to include('409 Conflict')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def request_job(token = runner.token, **params)
|
def request_job(token = runner.token, **params)
|
||||||
new_params = params.merge(token: token, last_update: last_update)
|
new_params = params.merge(token: token, last_update: last_update)
|
||||||
post api('/jobs/request'), params: new_params.to_json, headers: { 'User-Agent' => user_agent, 'Content-Type': 'application/json' }
|
post api('/jobs/request'), params: new_params.to_json, headers: { 'User-Agent' => user_agent, 'Content-Type': 'application/json' }
|
||||||
|
|
|
@ -31,5 +31,16 @@ RSpec.describe JiraConnect::UsersController do
|
||||||
expect(response.body).not_to include('Return to GitLab')
|
expect(response.body).not_to include('Return to GitLab')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with a script injected' do
|
||||||
|
let(:return_to) { 'javascript://test.atlassian.net/%250dalert(document.domain)' }
|
||||||
|
|
||||||
|
it 'does not include a return url' do
|
||||||
|
get '/-/jira_connect/users', params: { return_to: return_to }
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
expect(response.body).not_to include('Return to GitLab')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe ErrorTracking::ListProjectsService do
|
RSpec.describe ErrorTracking::ListProjectsService, feature_category: :integrations do
|
||||||
let_it_be(:user) { create(:user) }
|
let_it_be(:user) { create(:user) }
|
||||||
let_it_be(:project, reload: true) { create(:project) }
|
let_it_be(:project, reload: true) { create(:project) }
|
||||||
|
|
||||||
|
@ -51,15 +51,33 @@ RSpec.describe ErrorTracking::ListProjectsService do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'masked param token' do
|
context 'masked param token' do
|
||||||
let(:params) { ActionController::Parameters.new(token: "*********", api_host: new_api_host) }
|
let(:params) { ActionController::Parameters.new(token: "*********", api_host: api_host) }
|
||||||
|
|
||||||
before do
|
context 'with the current api host' do
|
||||||
expect(error_tracking_setting).to receive(:list_sentry_projects)
|
let(:api_host) { 'https://sentrytest.gitlab.com' }
|
||||||
|
|
||||||
|
before do
|
||||||
|
expect(error_tracking_setting).to receive(:list_sentry_projects)
|
||||||
.and_return({ projects: [] })
|
.and_return({ projects: [] })
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'uses database token' do
|
||||||
|
expect { subject.execute }.not_to change { error_tracking_setting.token }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'uses database token' do
|
context 'with a new api host' do
|
||||||
expect { subject.execute }.not_to change { error_tracking_setting.token }
|
let(:api_host) { new_api_host }
|
||||||
|
|
||||||
|
it 'returns an error' do
|
||||||
|
expect(result[:message]).to start_with('Token is a required field')
|
||||||
|
expect(error_tracking_setting).not_to be_valid
|
||||||
|
expect(error_tracking_setting).not_to receive(:list_sentry_projects)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'resets the token' do
|
||||||
|
expect { subject.execute }.to change { error_tracking_setting.token }.from(token).to(nil)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -114,5 +114,16 @@ RSpec.describe Packages::Nuget::MetadataExtractionService do
|
||||||
|
|
||||||
it { expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError, 'nuspec file too big') }
|
it { expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError, 'nuspec file too big') }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with a corrupted nupkg file with a wrong entry size' do
|
||||||
|
let(:nupkg_fixture_path) { expand_fixture_path('packages/nuget/corrupted_package.nupkg') }
|
||||||
|
let(:expected_error) { "nuspec file has the wrong entry size: entry 'DummyProject.DummyPackage.nuspec' should be 255B, but is larger when inflated." }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(Zip::File).to receive(:new).and_return(Zip::File.new(nupkg_fixture_path, false, false))
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError, expected_error) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -127,30 +127,67 @@ RSpec.describe Projects::ImportService do
|
||||||
project.import_type = 'bitbucket'
|
project.import_type = 'bitbucket'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'succeeds if repository import is successful' do
|
context 'when importer supports refmap' do
|
||||||
expect(project.repository).to receive(:import_repository).and_return(true)
|
before do
|
||||||
expect_next_instance_of(Gitlab::BitbucketImport::Importer) do |importer|
|
project.import_type = 'gitea'
|
||||||
expect(importer).to receive(:execute).and_return(true)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
|
it 'succeeds if repository fetch as mirror is successful' do
|
||||||
expect(service).to receive(:execute).and_return(status: :success)
|
expect(project).to receive(:ensure_repository)
|
||||||
|
expect(project.repository).to receive(:fetch_as_mirror).with('https://bitbucket.org/vim/vim.git', refmap: Gitlab::LegacyGithubImport::Importer.refmap, resolved_address: '').and_return(true)
|
||||||
|
expect_next_instance_of(Gitlab::LegacyGithubImport::Importer) do |importer|
|
||||||
|
expect(importer).to receive(:execute).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
|
||||||
|
expect(service).to receive(:execute).and_return(status: :success)
|
||||||
|
end
|
||||||
|
|
||||||
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result[:status]).to eq :success
|
||||||
end
|
end
|
||||||
|
|
||||||
result = subject.execute
|
it 'fails if repository fetch as mirror fails' do
|
||||||
|
expect(project).to receive(:ensure_repository)
|
||||||
|
expect(project.repository)
|
||||||
|
.to receive(:fetch_as_mirror)
|
||||||
|
.and_raise(Gitlab::Git::CommandError, 'Failed to import the repository /a/b/c')
|
||||||
|
|
||||||
expect(result[:status]).to eq :success
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result[:status]).to eq :error
|
||||||
|
expect(result[:message]).to eq "Error importing repository #{project.safe_import_url} into #{project.full_path} - Failed to import the repository [FILTERED]"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'fails if repository import fails' do
|
context 'when importer does not support refmap' do
|
||||||
expect(project.repository)
|
it 'succeeds if repository import is successful' do
|
||||||
.to receive(:import_repository)
|
expect(project.repository).to receive(:import_repository).and_return(true)
|
||||||
.and_raise(Gitlab::Git::CommandError, 'Failed to import the repository /a/b/c')
|
expect_next_instance_of(Gitlab::BitbucketImport::Importer) do |importer|
|
||||||
|
expect(importer).to receive(:execute).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
result = subject.execute
|
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
|
||||||
|
expect(service).to receive(:execute).and_return(status: :success)
|
||||||
|
end
|
||||||
|
|
||||||
expect(result[:status]).to eq :error
|
result = subject.execute
|
||||||
expect(result[:message]).to eq "Error importing repository #{project.safe_import_url} into #{project.full_path} - Failed to import the repository [FILTERED]"
|
|
||||||
|
expect(result[:status]).to eq :success
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fails if repository import fails' do
|
||||||
|
expect(project.repository)
|
||||||
|
.to receive(:import_repository)
|
||||||
|
.with('https://bitbucket.org/vim/vim.git', resolved_address: '')
|
||||||
|
.and_raise(Gitlab::Git::CommandError, 'Failed to import the repository /a/b/c')
|
||||||
|
|
||||||
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result[:status]).to eq :error
|
||||||
|
expect(result[:message]).to eq "Error importing repository #{project.safe_import_url} into #{project.full_path} - Failed to import the repository [FILTERED]"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when lfs import fails' do
|
context 'when lfs import fails' do
|
||||||
|
@ -287,6 +324,102 @@ RSpec.describe Projects::ImportService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when DNS rebind protection is disabled' do
|
||||||
|
before do
|
||||||
|
allow(Gitlab::CurrentSettings).to receive(:dns_rebinding_protection_enabled?).and_return(false)
|
||||||
|
project.import_url = "https://example.com/group/project"
|
||||||
|
|
||||||
|
allow(Gitlab::UrlBlocker).to receive(:validate!)
|
||||||
|
.with(project.import_url, ports: Project::VALID_IMPORT_PORTS, schemes: Project::VALID_IMPORT_PROTOCOLS, dns_rebind_protection: false)
|
||||||
|
.and_return([Addressable::URI.parse("https://example.com/group/project"), nil])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'imports repository with url without additional resolved address' do
|
||||||
|
expect(project.repository).to receive(:import_repository).with('https://example.com/group/project', resolved_address: '').and_return(true)
|
||||||
|
|
||||||
|
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
|
||||||
|
expect(service).to receive(:execute).and_return(status: :success)
|
||||||
|
end
|
||||||
|
|
||||||
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result[:status]).to eq(:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when DNS rebind protection is enabled' do
|
||||||
|
before do
|
||||||
|
allow(Gitlab::CurrentSettings).to receive(:http_proxy_env?).and_return(false)
|
||||||
|
allow(Gitlab::CurrentSettings).to receive(:dns_rebinding_protection_enabled?).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when https url is provided' do
|
||||||
|
before do
|
||||||
|
project.import_url = "https://example.com/group/project"
|
||||||
|
|
||||||
|
allow(Gitlab::UrlBlocker).to receive(:validate!)
|
||||||
|
.with(project.import_url, ports: Project::VALID_IMPORT_PORTS, schemes: Project::VALID_IMPORT_PROTOCOLS, dns_rebind_protection: true)
|
||||||
|
.and_return([Addressable::URI.parse("https://172.16.123.1/group/project"), 'example.com'])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'imports repository with url and additional resolved address' do
|
||||||
|
expect(project.repository).to receive(:import_repository).with('https://example.com/group/project', resolved_address: '172.16.123.1').and_return(true)
|
||||||
|
|
||||||
|
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
|
||||||
|
expect(service).to receive(:execute).and_return(status: :success)
|
||||||
|
end
|
||||||
|
|
||||||
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result[:status]).to eq(:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when http url is provided' do
|
||||||
|
before do
|
||||||
|
project.import_url = "http://example.com/group/project"
|
||||||
|
|
||||||
|
allow(Gitlab::UrlBlocker).to receive(:validate!)
|
||||||
|
.with(project.import_url, ports: Project::VALID_IMPORT_PORTS, schemes: Project::VALID_IMPORT_PROTOCOLS, dns_rebind_protection: true)
|
||||||
|
.and_return([Addressable::URI.parse("http://172.16.123.1/group/project"), 'example.com'])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'imports repository with url and additional resolved address' do
|
||||||
|
expect(project.repository).to receive(:import_repository).with('http://example.com/group/project', resolved_address: '172.16.123.1').and_return(true)
|
||||||
|
|
||||||
|
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
|
||||||
|
expect(service).to receive(:execute).and_return(status: :success)
|
||||||
|
end
|
||||||
|
|
||||||
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result[:status]).to eq(:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when git address is provided' do
|
||||||
|
before do
|
||||||
|
project.import_url = "git://example.com/group/project.git"
|
||||||
|
|
||||||
|
allow(Gitlab::UrlBlocker).to receive(:validate!)
|
||||||
|
.with(project.import_url, ports: Project::VALID_IMPORT_PORTS, schemes: Project::VALID_IMPORT_PROTOCOLS, dns_rebind_protection: true)
|
||||||
|
.and_return([Addressable::URI.parse("git://172.16.123.1/group/project"), 'example.com'])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'imports repository with url and without resolved address' do
|
||||||
|
expect(project.repository).to receive(:import_repository).with('git://example.com/group/project.git', resolved_address: '').and_return(true)
|
||||||
|
|
||||||
|
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
|
||||||
|
expect(service).to receive(:execute).and_return(status: :success)
|
||||||
|
end
|
||||||
|
|
||||||
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result[:status]).to eq(:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it_behaves_like 'measurable service' do
|
it_behaves_like 'measurable service' do
|
||||||
let(:base_log_data) do
|
let(:base_log_data) do
|
||||||
{
|
{
|
||||||
|
|
|
@ -77,6 +77,34 @@ RSpec.describe Users::UpdateService do
|
||||||
subject
|
subject
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when race condition' do
|
||||||
|
# See https://gitlab.com/gitlab-org/gitlab/-/issues/382957
|
||||||
|
it 'updates email for stale user', :aggregate_failures do
|
||||||
|
unconfirmed_email = 'unconfirmed-email-user-has-access-to@example.com'
|
||||||
|
forgery_email = 'forgery@example.com'
|
||||||
|
|
||||||
|
user.update!(email: unconfirmed_email)
|
||||||
|
|
||||||
|
stale_user = User.find(user.id)
|
||||||
|
|
||||||
|
service1 = described_class.new(stale_user, { email: unconfirmed_email }.merge(user: stale_user))
|
||||||
|
|
||||||
|
service2 = described_class.new(user, { email: forgery_email }.merge(user: user))
|
||||||
|
|
||||||
|
service2.execute
|
||||||
|
reloaded_user = User.find(user.id)
|
||||||
|
expect(reloaded_user.unconfirmed_email).to eq(forgery_email)
|
||||||
|
expect(stale_user.confirmation_token).not_to eq(user.confirmation_token)
|
||||||
|
expect(reloaded_user.confirmation_token).to eq(user.confirmation_token)
|
||||||
|
|
||||||
|
service1.execute
|
||||||
|
reloaded_user = User.find(user.id)
|
||||||
|
expect(reloaded_user.unconfirmed_email).to eq(unconfirmed_email)
|
||||||
|
expect(stale_user.confirmation_token).not_to eq(user.confirmation_token)
|
||||||
|
expect(reloaded_user.confirmation_token).to eq(stale_user.confirmation_token)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when check_password is true' do
|
context 'when check_password is true' do
|
||||||
def update_user(user, opts)
|
def update_user(user, opts)
|
||||||
described_class.new(user, opts.merge(user: user)).execute(check_password: true)
|
described_class.new(user, opts.merge(user: user)).execute(check_password: true)
|
||||||
|
@ -139,9 +167,24 @@ RSpec.describe Users::UpdateService do
|
||||||
update_user(user, job_title: 'supreme leader of the universe')
|
update_user(user, job_title: 'supreme leader of the universe')
|
||||||
end.not_to change { user.user_canonical_email }
|
end.not_to change { user.user_canonical_email }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'does not reset unconfirmed email' do
|
||||||
|
unconfirmed_email = 'unconfirmed-email@example.com'
|
||||||
|
user.update!(email: unconfirmed_email)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
update_user(user, job_title: 'supreme leader of the universe')
|
||||||
|
end.not_to change { user.unconfirmed_email }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'does not try to reset unconfirmed email for a new user' do
|
||||||
|
expect do
|
||||||
|
update_user(build(:user), job_title: 'supreme leader of the universe')
|
||||||
|
end.not_to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
def update_user(user, opts)
|
def update_user(user, opts)
|
||||||
described_class.new(user, opts.merge(user: user)).execute
|
described_class.new(user, opts.merge(user: user)).execute
|
||||||
end
|
end
|
||||||
|
|
|
@ -129,7 +129,10 @@ RSpec.describe WebHookService, :request_store, :clean_gitlab_redis_shared_state
|
||||||
|
|
||||||
context 'there is userinfo' do
|
context 'there is userinfo' do
|
||||||
before do
|
before do
|
||||||
project_hook.update!(url: 'http://{one}:{two}@example.com')
|
project_hook.update!(
|
||||||
|
url: 'http://{one}:{two}@example.com',
|
||||||
|
url_variables: { 'one' => 'a', 'two' => 'b' }
|
||||||
|
)
|
||||||
stub_full_request('http://example.com', method: :post)
|
stub_full_request('http://example.com', method: :post)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,15 @@ RSpec.describe WebHooks::LogExecutionService do
|
||||||
travel_to(Time.current) { example.run }
|
travel_to(Time.current) { example.run }
|
||||||
end
|
end
|
||||||
|
|
||||||
let_it_be_with_reload(:project_hook) { create(:project_hook) }
|
let_it_be_with_reload(:project_hook) { create(:project_hook, :token) }
|
||||||
|
|
||||||
let(:response_category) { :ok }
|
let(:response_category) { :ok }
|
||||||
|
let(:request_headers) { { 'Header' => 'header value' } }
|
||||||
let(:data) do
|
let(:data) do
|
||||||
{
|
{
|
||||||
trigger: 'trigger_name',
|
trigger: 'trigger_name',
|
||||||
url: 'https://example.com',
|
url: 'https://example.com',
|
||||||
request_headers: { 'Header' => 'header value' },
|
request_headers: request_headers,
|
||||||
request_data: { 'Request Data' => 'request data value' },
|
request_data: { 'Request Data' => 'request data value' },
|
||||||
response_body: 'Response body',
|
response_body: 'Response body',
|
||||||
response_status: '200',
|
response_status: '200',
|
||||||
|
@ -163,5 +164,15 @@ RSpec.describe WebHooks::LogExecutionService do
|
||||||
service.execute
|
service.execute
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with X-Gitlab-Token' do
|
||||||
|
let(:request_headers) { { 'X-Gitlab-Token' => project_hook.token } }
|
||||||
|
|
||||||
|
it 'redacts the token' do
|
||||||
|
service.execute
|
||||||
|
|
||||||
|
expect(WebHookLog.recent.first.request_headers).to include('X-Gitlab-Token' => '[REDACTED]')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -145,91 +145,92 @@ module GpgHelpers
|
||||||
'5F7EA3981A5845B141ABD522CCFBE19F00AC8B1D'
|
'5F7EA3981A5845B141ABD522CCFBE19F00AC8B1D'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# passphrase for secret key 2 is:
|
||||||
|
# qHGKKXBZ72VamRMUH6d7LsLWsHnJJx3p
|
||||||
def secret_key2
|
def secret_key2
|
||||||
<<~KEY.strip
|
<<~KEY.strip
|
||||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
||||||
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
|
||||||
4f6xMfFu2A==
|
=VtBY
|
||||||
=3YL6
|
|
||||||
-----END PGP PRIVATE KEY BLOCK-----
|
-----END PGP PRIVATE KEY BLOCK-----
|
||||||
KEY
|
KEY
|
||||||
end
|
end
|
||||||
|
@ -238,44 +239,44 @@ module GpgHelpers
|
||||||
<<~KEY.strip
|
<<~KEY.strip
|
||||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
mQGNBF+7O0oBDADvRto4K9PT83Lbyp/qaMPIzBbXHB6ljdDoyb+Pn2UrHk9MhB5v
|
mQGNBGN931ABDADe6KRsn1d37PKH9QSZiDqyGu77Av3vPlAwRHypUEEAc47WNle7
|
||||||
bTgBv+rctOabmimPPalcyaxOQ1GtrYizo1l33YQZupSvaOoStVLWqnBx8eKKcUv8
|
87CmIaDPKQ8f5R7vu9hpVX+Lisoy23s7lM9nvZcjfR/t465oP5JimGSOiQ1Ilcgz
|
||||||
QucS3S2qFhj9G0tdHW7RW2BGrSwEM09d2xFsFKKAj/4RTTU5idYWrvB24DNcrBh+
|
eCvOmbvVdiSQthqrQ5oUY0jmRtnEbpNC4LMV3+i3Npj4UcCeORFOWNf+I1AiTtLX
|
||||||
iKsoa+rmJf1bwL6Mn9f9NwzundG16qibY/UwMlltQriWaVMn2AKVuu6HrX9pe3g5
|
fRyw+ifGjqxe/0dVt4w65kZbpetYlxGoYCjAMPZT287chfJCYeNm8N+8T9BKx3ex
|
||||||
Er2Szjc7DZitt6eAy3PmuWHXzDCCvsO7iPxXlywY49hLhDen3/Warwn1pSbp+im4
|
Z4bpAGY0hcZwH2Qo5Dg6MFGn2oQjvGmD3iVJ48IEN7HPtiHeOoD8rlUG2smiAk7u
|
||||||
/0oJExLZBSS1xHbRSQoR6matF0+V/6TQz8Yo3g8z9HgyEtn1V7QJo3PoNrnEl73e
|
ZuSiNhEKf43p1hSOhUyB1KBrFs8/npNyhOIXzrmE8cFuUgDeUZQX/c7BS0QmNdmr
|
||||||
9yslTqVtzba0Q132oRoO7eEYf82KrPOmVGj6Q9LpSXFLfsl3GlPgoBxRZXpT62CV
|
nRn1CUzYYHSsQB8oGMueQPCmjZh68AqRfIYjZW4KbsqydjPmTRUomZfCB0RWBd/T
|
||||||
3rGalIa2yKmcBQtyICjR1+PTIAJcVIPyr92xTo4RfLwVFW0czX7LM2H0FT2Ksj7L
|
8Ycvdh8NFQRCCcHfcUVj/PnMyaUE1aAf4xApA694ceXK6GtMz+2ZGNAThsLDrzfw
|
||||||
U450ewBz8N6bFDMAEQEAAbQtTmFubmllIEJlcm5oYXJkIDxuYW5uaWUuYmVybmhh
|
VtR6WSOjq+E9Ab8AEQEAAbQtTmFubmllIEJlcm5oYXJkIDxuYW5uaWUuYmVybmhh
|
||||||
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
|
7ysn+Hu60VIDw8enikBOwZE1oTbrKiTywMbufg==
|
||||||
=RAwd
|
=cp3L
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
KEY
|
KEY
|
||||||
end
|
end
|
||||||
|
@ -285,7 +286,7 @@ module GpgHelpers
|
||||||
end
|
end
|
||||||
|
|
||||||
def fingerprint2
|
def fingerprint2
|
||||||
'C447A6F6BFD9CEF8FB371785571625A930241179'
|
'EC164842311CCF9F005DA1A34FD830CEB3E86C97'
|
||||||
end
|
end
|
||||||
|
|
||||||
def names
|
def names
|
||||||
|
|
|
@ -2,33 +2,54 @@
|
||||||
|
|
||||||
RSpec.shared_examples 'user views tag' do
|
RSpec.shared_examples 'user views tag' do
|
||||||
context 'when user views with the tag' do
|
context 'when user views with the tag' do
|
||||||
let(:project) { create(:project, :repository) }
|
let(:project) { create(:project, :repository, :public) }
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:tag_name) { "stable" }
|
let(:tag_name) { "stable" }
|
||||||
let!(:release) { create(:release, project: project, tag: tag_name, name: "ReleaseName") }
|
let(:release_name) { 'ReleaseName' }
|
||||||
|
let(:release_notes) { 'Release notes' }
|
||||||
|
let!(:release) do
|
||||||
|
create(:release, project: project, tag: tag_name, name: release_name, description: release_notes)
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
project.add_developer(user)
|
|
||||||
project.repository.add_tag(user, tag_name, project.default_branch_or_main)
|
project.repository.add_tag(user, tag_name, project.default_branch_or_main)
|
||||||
|
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_examples 'shows tag' do
|
context 'and user is authorized to read release' do
|
||||||
it do
|
before do
|
||||||
visit tag_page
|
project.add_developer(user)
|
||||||
|
end
|
||||||
|
|
||||||
expect(page).to have_content tag_name
|
shared_examples 'shows tag' do
|
||||||
expect(page).to have_link("ReleaseName", href: project_release_path(project, release))
|
it do
|
||||||
|
visit tag_page
|
||||||
|
|
||||||
|
expect(page).to have_content tag_name
|
||||||
|
expect(page).to have_link(release_name, href: project_release_path(project, release))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'shows tag'
|
||||||
|
|
||||||
|
context 'when tag name contains a slash' do
|
||||||
|
let(:tag_name) { "stable/v0.1" }
|
||||||
|
|
||||||
|
it_behaves_like 'shows tag'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'shows tag'
|
context 'and user is not authorized to read release' do
|
||||||
|
before do
|
||||||
|
project.project_feature.update!(releases_access_level: Featurable::PRIVATE)
|
||||||
|
end
|
||||||
|
|
||||||
context 'when tag name contains a slash' do
|
it 'hides release link and notes', :aggregate_failures do
|
||||||
let(:tag_name) { "stable/v0.1" }
|
visit tag_page
|
||||||
|
|
||||||
it_behaves_like 'shows tag'
|
expect(page).not_to have_link(release_name, href: project_release_path(project, release))
|
||||||
|
expect(page).not_to have_text(release_notes)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -71,26 +71,3 @@ RSpec.shared_examples 'Self-managed Core resource access tokens' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
RSpec.shared_examples 'GitLab.com Core resource access tokens' do
|
|
||||||
before do
|
|
||||||
allow(::Gitlab).to receive(:com?).and_return(true)
|
|
||||||
stub_ee_application_setting(should_check_namespace_plan: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with owner access' do
|
|
||||||
let(:current_user) { owner }
|
|
||||||
|
|
||||||
context 'create resource access tokens' do
|
|
||||||
it { is_expected.not_to be_allowed(:create_resource_access_tokens) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'read resource access tokens' do
|
|
||||||
it { is_expected.not_to be_allowed(:read_resource_access_tokens) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'destroy resource access tokens' do
|
|
||||||
it { is_expected.not_to be_allowed(:destroy_resource_access_tokens) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue