Merge tag 'debian/15.5.7+ds1-1' into bullseye-fasttrack

gitlab Debian release 15.5.7+ds1-1
This commit is contained in:
Mohammed Bilal 2023-01-10 18:47:14 +05:30
commit a900ba5e48
No known key found for this signature in database
GPG key ID: B3F5945285219E1F
106 changed files with 1667 additions and 829 deletions

View file

@ -2,6 +2,41 @@
documentation](doc/development/changelog.md) for instructions on adding your own
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)
### Fixed (3 changes)

View file

@ -1 +1 @@
15.5.4
15.5.7

View file

@ -1 +1 @@
1.62.0
15.5.7

View file

@ -503,7 +503,7 @@ gem 'ssh_data', '~> 1.3'
gem 'spamcheck', '~> 1.0.0'
# Gitaly GRPC protocol definitions
gem 'gitaly', '~> 15.4.0-rc2'
gem 'gitaly', '~> 15.5.2'
# KAS GRPC protocol definitions
gem 'kas-grpc', '~> 0.0.2'

View file

@ -198,7 +198,7 @@
{"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":"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":"gitlab","version":"4.16.1","platform":"ruby","checksum":"13fd7059cbdad5a1a21b15fa2cf9070b97d92e27f8c688581fe3d84dc038074f"},
{"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"},

View file

@ -547,7 +547,7 @@ GEM
rails (>= 3.2.0)
git (1.11.0)
rchardet (~> 1.8)
gitaly (15.4.0.pre.rc2)
gitaly (15.5.2)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab (4.16.1)
@ -1622,7 +1622,7 @@ DEPENDENCIES
gettext (~> 3.3)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly (~> 15.4.0.pre.rc2)
gitaly (~> 15.5.2)
github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5)
gitlab-dangerfiles (~> 3.5.2)

View file

@ -1 +1 @@
15.5.4
15.5.7

View file

@ -57,7 +57,7 @@ module PageLimiter
# Record the page limit being hit in Prometheus
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,
controller: params[:controller],

View file

@ -3,8 +3,6 @@
class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
feature_category :authentication_and_authorization
before_action :check_personal_access_tokens_enabled
def index
set_index_vars
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
(params[:page] || 1).to_i
end
def check_personal_access_tokens_enabled
render_404 if Gitlab::CurrentSettings.personal_access_tokens_disabled?
end
end

View file

@ -4,6 +4,8 @@ class Projects::GrafanaApiController < Projects::ApplicationController
include RenderServiceResults
include MetricsDashboard
before_action :authorize_read_grafana!, only: :proxy
feature_category :metrics
urgency :low

View file

@ -52,6 +52,8 @@ class UploadsController < ApplicationController
# access to itself when a secret is given.
# For instance, user avatars are readable by anyone,
# while temporary, user snippet uploads are not.
return false if !current_user && public_visibility_restricted?
!secret? || can?(current_user, :update_user, model)
when Appearance
true

View file

@ -244,6 +244,10 @@ module DiffHelper
{}
end
def params_with_whitespace
hide_whitespace? ? safe_params.except(:w) : safe_params.merge(w: 1)
end
private
def diff_btn(title, name, selected)
@ -277,10 +281,6 @@ module DiffHelper
params[:w] == '1'
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)
options[:class] = [*options[:class], 'btn gl-button btn-default'].join(' ')
link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: options[:class]

View file

@ -17,22 +17,11 @@ module SubmoduleHelper
url = File.join(Gitlab.config.gitlab.url, repository.project.full_path)
end
if url =~ %r{([^/:]+)/([^/]+(?:\.git)?)\Z}
namespace = Regexp.last_match(1)
project = Regexp.last_match(2)
gitlab_hosts = [Gitlab.config.gitlab.url,
Gitlab.config.gitlab_shell.ssh_path_prefix]
namespace, project = extract_namespace_project(url)
gitlab_hosts.each do |host|
if url.start_with?(host)
namespace, _, project = url.sub(host, '').rpartition('/')
break
if namespace.blank? || project.blank?
return [sanitize_submodule_url(url), nil, nil]
end
end
namespace.delete_prefix!('/')
project.rstrip!
project.delete_suffix!('.git')
if self_url?(url, namespace, project)
[
@ -51,13 +40,34 @@ module SubmoduleHelper
else
[sanitize_submodule_url(url), nil, nil]
end
else
[sanitize_submodule_url(url), nil, nil]
end
end
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)
url =~ %r{gist\.github\.com[/:][^/]+/[^/]+\Z}
end

View file

@ -67,7 +67,7 @@ class ActiveSession
def self.set(user, request)
Gitlab::Redis::Sessions.with do |redis|
session_private_id = request.session.id.private_id
client = DeviceDetector.new(request.user_agent)
client = Gitlab::SafeDeviceDetector.new(request.user_agent)
timestamp = Time.current
expiry = Settings.gitlab['session_expire_delay'] * 60

View file

@ -799,10 +799,6 @@ class ApplicationSetting < ApplicationRecord
::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES.include?(diagram_type)
end
def personal_access_tokens_disabled?
false
end
private
def parsed_grafana_url

View file

@ -13,14 +13,15 @@ module Ci
belongs_to :build, class_name: 'Ci::Build', inverse_of: :runner_session
validates :build, presence: true
validates :url, addressable_url: { schemes: %w(https) }
validates :url, public_url: { schemes: %w(https) }
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?
wss_url = "#{wss_url}/exec"
channel_specification(wss_url, TERMINAL_SUBPROTOCOL)
parsed_wss_url = URI.parse(wss_url)
parsed_wss_url.path += '/exec'
channel_specification(parsed_wss_url, TERMINAL_SUBPROTOCOL)
end
def service_specification(service: nil, path: nil, port: nil, subprotocols: nil)
@ -28,20 +29,21 @@ module Ci
port = port.presence || DEFAULT_PORT_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
channel_specification(url, subprotocols)
channel_specification(parsed_url, subprotocols)
end
private
def channel_specification(url, subprotocol)
return {} if subprotocol.blank? || url.blank?
def channel_specification(parsed_url, subprotocol)
return {} if subprotocol.blank? || parsed_url.blank?
{
subprotocols: Array(subprotocol),
url: url,
url: Addressable::URI.unescape(parsed_url.to_s),
headers: { Authorization: [authorization.presence] }.compact,
ca_pem: certificate.presence
}

View file

@ -41,6 +41,8 @@ class WebHook < ApplicationRecord
validate :no_missing_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
next all unless Feature.enabled?(:web_hooks_disable_failed)
@ -200,6 +202,14 @@ class WebHook < ApplicationRecord
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?
self.class.web_hooks_disable_failed?(self)
end

View file

@ -48,6 +48,13 @@ class WebHookLog < ApplicationRecord
request_data == OVERSIZE_REQUEST_DATA
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
def obfuscate_basic_auth

View file

@ -98,7 +98,10 @@ module Integrations
def self.valid_jira_cloud_url?(url)
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
def data_fields

View file

@ -2145,8 +2145,8 @@ class Project < ApplicationRecord
end
def after_import
repository.remove_prohibited_branches
repository.expire_content_cache
repository.remove_prohibited_branches
wiki.repository.expire_content_cache
DetectRepositoryLanguagesWorker.perform_async(id)

View file

@ -980,12 +980,12 @@ class Repository
end
end
def clone_as_mirror(url, http_authorization_header: "")
import_repository(url, http_authorization_header: http_authorization_header, mirror: true)
def clone_as_mirror(url, http_authorization_header: "", resolved_address: "")
import_repository(url, http_authorization_header: http_authorization_header, mirror: true, resolved_address: resolved_address)
end
def fetch_as_mirror(url, forced: false, refmap: :all_refs, prune: true, http_authorization_header: "")
fetch_remote(url, refmap: refmap, forced: forced, prune: prune, http_authorization_header: 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, resolved_address: resolved_address)
end
def fetch_source_branch!(source_repository, source_branch, local_ref)

View file

@ -1574,7 +1574,7 @@ class User < ApplicationRecord
name: name,
username: username,
avatar_url: avatar_url(only_path: false),
email: public_email.presence || _('[REDACTED]')
email: webhook_email
}
end

View file

@ -272,6 +272,9 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
rule { can?(:admin_group) & resource_access_token_feature_available }.policy do
enable :read_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
end
@ -332,12 +335,16 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
true
end
def resource_access_token_create_feature_available?
true
end
def can_read_group_member?
!(@subject.private? && access_level == GroupMember::NO_ACCESS)
end
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
def valid_dependency_proxy_deploy_token

View file

@ -25,3 +25,5 @@ module Packages
end
end
end
Packages::Policies::GroupPolicy.prepend_mod_with('Packages::Policies::GroupPolicy')

View file

@ -52,3 +52,5 @@ module Packages
end
end
end
Packages::Policies::ProjectPolicy.prepend_mod_with('Packages::Policies::ProjectPolicy')

View file

@ -157,7 +157,9 @@ class ProjectPolicy < BasePolicy
condition(:service_desk_enabled) { @subject.service_desk_enabled? }
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? }
# 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?(:read_container_image) }.enable :build_read_container_image
rule { guest & ~public_project }.enable :read_grafana
rule { can?(:reporter_access) }.policy do
enable :admin_issue_board
enable :download_code
@ -342,6 +346,7 @@ class ProjectPolicy < BasePolicy
enable :read_package
enable :read_product_analytics
enable :read_ci_cd_analytics
enable :read_grafana
end
# 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 { 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
enable :read_resource_access_tokens
@ -915,12 +920,16 @@ class ProjectPolicy < BasePolicy
true
end
def resource_access_token_create_feature_available?
true
end
def resource_access_token_creation_allowed?
group = project.group
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
def project

View file

@ -2,6 +2,8 @@
module ErrorTracking
class ListProjectsService < ErrorTracking::BaseService
MASKED_TOKEN_REGEX = /\A\*+\z/.freeze
private
def perform
@ -21,23 +23,31 @@ module ErrorTracking
def project_error_tracking_setting
@project_error_tracking_setting ||= begin
(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(
api_host: params[:api_host],
organization_slug: 'org',
project_slug: 'proj'
)
setting.token = token(setting)
setting.token = token(setting, url_changed)
setting.enabled = true
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
return params[:token] unless /\A\*+\z/.match?(params[:token])
return params[:token] unless masked_token?
setting.token
end
def masked_token?
MASKED_TOKEN_REGEX.match?(params[:token])
end
end
end

View file

@ -104,9 +104,15 @@ module Packages
entry = zip_file.glob('*.nuspec').first
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

View file

@ -53,6 +53,8 @@ module Projects
private
attr_reader :resolved_address
def after_execute_hook
# Defined in EE::Projects::ImportService
end
@ -64,11 +66,7 @@ module Projects
def add_repository_to_project
if project.external_import? && !unknown_url?
begin
Gitlab::UrlBlocker.validate!(
project.import_url,
schemes: Project::VALID_IMPORT_PROTOCOLS,
ports: Project::VALID_IMPORT_PORTS
)
@resolved_address = get_resolved_address
rescue Gitlab::UrlBlocker::BlockedUrlError => e
raise e, s_("ImportProjects|Blocked import URL: %{message}") % { message: e.message }
end
@ -97,9 +95,9 @@ module Projects
if refmap
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
project.repository.import_repository(project.import_url)
project.repository.import_repository(project.import_url, resolved_address: resolved_address)
end
rescue ::Gitlab::Git::CommandError => e
# Expire cache to prevent scenarios such as:
@ -157,6 +155,26 @@ module Projects
def importer_imports_repository?
has_importer? && importer_class.try(:imports_repository?)
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

View file

@ -13,6 +13,7 @@ module ResourceAccessTokens
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
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
@ -107,7 +108,7 @@ module ResourceAccessTokens
end
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
def log_event(token)
@ -121,6 +122,12 @@ module ResourceAccessTokens
def success(access_token)
ServiceResponse.success(payload: { access_token: access_token })
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

View file

@ -31,6 +31,7 @@ module Users
assign_identity
build_canonical_email
reset_unconfirmed_email
if @user.save(validate: validate) && update_status
notify_success(user_exists)
@ -64,6 +65,13 @@ module Users
Users::UpdateCanonicalEmailService.new(user: @user).execute
end
def reset_unconfirmed_email
return unless @user.persisted?
return unless @user.email_changed?
@user.update_column(:unconfirmed_email, nil)
end
def update_status
return true unless @status_params

View file

@ -24,6 +24,8 @@ module WebHooks
private
def log_execution
log_data[:request_headers]['X-Gitlab-Token'] = _('[REDACTED]') if hook.token?
WebHookLog.create!(web_hook: hook, **log_data)
end

View file

@ -1,7 +1,7 @@
- confirmation_link = confirmation_url(@resource, confirmation_token: @token)
- if @resource.unconfirmed_email.present? || !@resource.created_recently?
#content
= email_default_heading(@resource.unconfirmed_email || @resource.email)
= email_default_heading(@email)
%p= _('Click the link below to confirm your email address.')
#cta
= link_to _('Confirm your email address'), confirmation_link

View file

@ -1,5 +1,5 @@
<% if @resource.unconfirmed_email.present? || !@resource.created_recently? %>
<%= @resource.unconfirmed_email || @resource.email %>,
<%= @email %>,
<%= _('Use the link below to confirm your email address.') %>
<% else %>
<% if Gitlab.com? %>

View file

@ -51,7 +51,6 @@
= link_to profile_chat_names_path do
%strong.fly-out-top-item-name
= _('Chat')
- unless Gitlab::CurrentSettings.personal_access_tokens_disabled?
= nav_link(controller: :personal_access_tokens) do
= link_to profile_personal_access_tokens_path do
.nav-icon-container

View file

@ -1,3 +1,4 @@
- if can?(current_user, :read_release, release)
.gl-text-secondary
= sprite_icon("rocket", size: 12)
= _("Release")

View file

@ -57,6 +57,7 @@
%pre.wrap{ data: { qa_selector: 'tag_message_content' } }
= strip_signature(@tag.message)
- if can?(current_user, :read_release, @release)
.gl-mb-3.gl-mt-3
- if @release&.description.present?
.description.md{ data: { qa_selector: 'tag_release_notes_content' } }

23
debian/changelog vendored
View file

@ -1,3 +1,26 @@
gitlab (15.5.7+ds1-1) experimental; urgency=medium
* Remove abandoned omniauth gems from depends
* New upstream version 15.5.7+ds1
* Refresh patch
-- Mohammed Bilal <mdbilal@disroot.org> Tue, 10 Jan 2023 11:35:55 +0530
gitlab (15.5.4+ds3-4) experimental; urgency=medium
* Team Upload.
* Set "Rules-Requires-Root: no" to circumvent debhelper bug, see
https://lists.debian.org/debian-devel/2022/12/msg00108.html
* Remove dead symlink, choking build
-- Nilesh Patra <nilesh@debian.org> Thu, 15 Dec 2022 21:39:00 +0000
gitlab (15.5.4+ds3-3) experimental; urgency=medium
* Relax dependency on gitlab-labkit (to match gitaly)
-- Pirate Praveen <praveen@debian.org> Mon, 12 Dec 2022 21:45:29 +0530
gitlab (15.5.4+ds3-2~fto11+2) bullseye-fasttrack; urgency=medium
* Relax dependency on gitlab-labkit (to match gitaly)

5
debian/control vendored
View file

@ -77,6 +77,7 @@ Vcs-Browser: https://salsa.debian.org/ruby-team/gitlab
Homepage: https://about.gitlab.com/
XS-Ruby-Versions: all
XS-Go-Import-Path: gitlab.com/gitlab-org/gitlab
Rules-Requires-Root: no
Package: gitlab
Section: contrib/net
@ -127,8 +128,6 @@ Depends: ${shlibs:Depends}, ${misc:Depends},
ruby-omniauth (>= 2.1~),
ruby-omniauth-auth0 (>= 2.0~),
ruby-omniauth-azure-activedirectory-v2 (>= 2.0~),
ruby-omniauth-azure-oauth2 (>= 0.0.10~),
ruby-omniauth-cas3 (>= 1.1.4~),
ruby-omniauth-dingtalk-oauth2 (>= 1.0.1~),
ruby-omniauth-alicloud (>= 2.0~),
ruby-omniauth-facebook (>= 4.0~),
@ -141,10 +140,8 @@ Depends: ${shlibs:Depends}, ${misc:Depends},
ruby-omniauth-shibboleth (>= 1.3~),
ruby-omniauth-twitter (>= 1.4~),
ruby-omniauth-oauth (>= 1.2~),
ruby-omniauth-crowd (>= 2.2~),
ruby-omniauth-authentiq (>= 0.3.3~),
ruby-omniauth-openid-connect (>= 0.10~),
ruby-omniauth-salesforce (>= 1.0.5~),
ruby-omniauth-atlassian-oauth2 (>= 0.2.0~),
ruby-rack-oauth2 (>= 1.21.3~),
ruby-jwt (>= 2.1~),

View file

@ -455,8 +455,8 @@ gitlab Gemfile
+gem 'spamcheck', '~> 1.0'
# Gitaly GRPC protocol definitions
-gem 'gitaly', '~> 15.4.0-rc2'
+gem 'gitaly', '~> 15.4'
-gem 'gitaly', '~> 15.5.2'
+gem 'gitaly', '~> 15.5'
# KAS GRPC protocol definitions
gem 'kas-grpc', '~> 0.0.2'

2
debian/rules vendored
View file

@ -19,6 +19,8 @@ override_dh_auto_configure-arch:
if [ -d ${BUILDDIR}/vendor ]; then ${RM} -rf ${BUILDDIR}/vendor; fi
if [ -d ${BUILDDIR}/workhorse-vendor ]; then mv ${BUILDDIR}/workhorse-vendor \
${BUILDDIR}/vendor; fi
# Remove non-existent symlink
find ${BUILDDIR} -name test.git -delete
# temporary step till protobuf 1.5 vs 1.3 is resolved
ln -s /usr/share/gocode/src/gitlab.com/gitlab-org/gitaly/v15/vendor/github.com/prometheus ${BUILDDIR}/vendor/github.com
ln -s /usr/share/gocode/src/gitlab.com/gitlab-org/gitaly/v15/vendor/github.com/matttproud ${BUILDDIR}/vendor/github.com

View file

@ -55,9 +55,10 @@ To set up the Grafana API in Grafana:
1. Select **Save Changes**.
NOTE:
If the Grafana integration is enabled, any user with read access to the GitLab
project can query metrics from the Prometheus instance. All requests proxied
through GitLab are authenticated with the same Grafana Administrator API token.
If the Grafana integration is enabled, users with the Reporter role on public
projects and the Guest role on non-public projects can query metrics from the
Prometheus instance. All requests proxied through GitLab are authenticated with
the same Grafana Administrator API token.
### Generate a link to a panel

View file

@ -43,6 +43,9 @@ using Omnibus, learn to install a custom CA in the
Alternatively, learn where to install custom certificates by using
`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
The external authorization service can be enabled by an administrator:

View file

@ -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)
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
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214045) in GitLab 14.7.

View file

@ -62,6 +62,7 @@ For most package types, the following credential types are valid:
NOTE:
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

View file

@ -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).
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
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/348660) in GitLab 15.3, default expiration of 30 days is populated in the UI.

View file

@ -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. |
| 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
A deploy key has a defined scope when it is created:

View file

@ -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
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
A deploy token's scope determines the actions it can perform.

View file

@ -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)
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
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89114) in GitLab 15.1, Owners can select Owner role for project access tokens.

View file

@ -94,7 +94,8 @@ module API
success Entities::Ci::JobRequest::Response
http_codes [[201, 'Job was scheduled'],
[204, 'No job for Runner'],
[403, 'Forbidden']]
[403, 'Forbidden'],
[409, 'Conflict']]
end
params do
requires :token, type: String, desc: %q(Runner's authentication token)

View file

@ -165,6 +165,8 @@ module Gitlab
end
def with_deploy_token(raw, &block)
raise ::Gitlab::Auth::UnauthorizedError if Gitlab::ExternalAuthorization.enabled?
token = ::DeployToken.active.find_by_token(raw.password)
return unless token

View file

@ -147,6 +147,7 @@ module Gitlab
# deploy tokens are accepted with deploy token headers and basic auth headers
def deploy_token_from_request
return unless route_authentication_setting[:deploy_token_allowed]
return if Gitlab::ExternalAuthorization.enabled?
token = current_request.env[DEPLOY_TOKEN_HEADER].presence || parsed_oauth_token

View file

@ -855,7 +855,11 @@ module Gitlab
# no_tags - should we use --no-tags flag?
# prune - should we use --prune flag?
# 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
gitaly_repository_client.fetch_remote(
url,
@ -866,16 +870,17 @@ module Gitlab
prune: prune,
check_tags_changed: check_tags_changed,
timeout: GITLAB_PROJECTS_TIMEOUT,
http_authorization_header: http_authorization_header
http_authorization_header: http_authorization_header,
resolved_address: resolved_address
)
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?('.', '/')
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

View file

@ -367,7 +367,7 @@ module Gitlab
end
def deploy_key?
actor.is_a?(DeployKey)
actor.is_a?(DeployKey) && !Gitlab::ExternalAuthorization.enabled?
end
def deploy_token
@ -375,7 +375,7 @@ module Gitlab
end
def deploy_token?
actor.is_a?(DeployToken)
actor.is_a?(DeployToken) && !Gitlab::ExternalAuthorization.enabled?
end
def ci?

View file

@ -78,7 +78,7 @@ module Gitlab
# rubocop: disable Metrics/ParameterLists
# The `remote` parameter is going away soonish anyway, at which point the
# 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(
repository: @gitaly_repo,
force: forced,
@ -89,7 +89,8 @@ module Gitlab
remote_params: Gitaly::Remote.new(
url: url,
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
def import_repository(source, http_authorization_header: '', mirror: false)
def import_repository(source, http_authorization_header: '', mirror: false, resolved_address: '')
request = Gitaly::CreateRepositoryFromURLRequest.new(
repository: @gitaly_repo,
url: source,
http_authorization_header: http_authorization_header,
mirror: mirror
mirror: mirror,
resolved_address: resolved_address
)
GitalyClient.call(

View file

@ -57,7 +57,7 @@ module Gitlab
end
def user_email(user)
user.respond_to?(:email) ? user.email : ""
user.respond_to?(:webhook_email) ? user.webhook_email : ""
end
def event_specific_project_data(event)

View file

@ -43,7 +43,7 @@ module Gitlab
project_id: project.id,
user_username: project_member.user.username,
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,
access_level: project_member.human_access,
project_visibility: project.visibility

View 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

View file

@ -36,14 +36,6 @@ RSpec.describe Profiles::PersonalAccessTokensController do
expect(created_token.expires_at).to eq(expires_at)
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
let(:url) { :create }
end
@ -78,14 +70,6 @@ RSpec.describe Profiles::PersonalAccessTokensController do
)
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
before do
stub_feature_flags(access_token_pagination: true)

View file

@ -2,13 +2,20 @@
require 'spec_helper'
RSpec.describe Projects::GrafanaApiController do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do
let_it_be(:project) { create(:project, :public) }
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
project.add_reporter(user)
sign_in(user)
sign_in(user) if user
end
describe 'GET #proxy' do
@ -41,6 +48,39 @@ RSpec.describe Projects::GrafanaApiController do
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
let(:service_result) { { status: :success, body: '{}' } }
@ -96,6 +136,38 @@ RSpec.describe Projects::GrafanaApiController do
it_behaves_like 'error response', :bad_request
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
describe 'GET #metrics_dashboard' do

View file

@ -1380,7 +1380,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
{
'Channel' => {
'Subprotocols' => ["terminal.gitlab.com"],
'Url' => 'wss://localhost/proxy/build/default_port/',
'Url' => 'wss://gitlab.example.com/proxy/build/default_port/',
'Header' => {
'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)
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
end

View file

@ -268,6 +268,11 @@ RSpec.describe UploadsController do
end
context "when not signed in" do
context "when restricted visibility level is not set to public" do
before do
stub_application_setting(restricted_visibility_levels: [])
end
it "responds with status 200" do
get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" }
@ -282,6 +287,19 @@ RSpec.describe UploadsController do
end
end
end
context "when restricted visibility level is set to public" do
before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
end
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
context "when viewing a project avatar" do

View file

@ -716,7 +716,7 @@ FactoryBot.define do
trait :with_runner_session do
after(:build) do |build|
build.build_runner_session(url: 'https://localhost')
build.build_runner_session(url: 'https://gitlab.example.com')
end
end

View file

@ -6,6 +6,10 @@ FactoryBot.define do
enable_ssl_verification { false }
project
trait :url_variables do
url_variables { { 'abc' => 'supers3cret' } }
end
trait :token do
token { generate(:token) }
end

View file

@ -329,7 +329,7 @@ RSpec.describe 'Project' do
it 'has working links to submodules' do
click_link('645f6c4c')
expect(page).to have_selector('[data-testid="branches-select"]', text: '645f6c4c82fd3f5e06f67134450a570b795e55a6')
expect(page).to have_selector('.ref-selector', text: '645f6c4c82fd3f5e06f67134450a570b795e55a6')
end
context 'for signed commit on default branch', :js do

View file

@ -53,6 +53,8 @@ RSpec.describe 'Developer views tags' do
end
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'
expect(page).to have_current_path(

View file

@ -1,67 +1,66 @@
-----BEGIN CERTIFICATE-----
MIIGYzCCBUugAwIBAgIQAaQHyOeT/PBR4ioLKYneZDANBgkqhkiG9w0BAQsFADBY
MIIGYjCCBUqgAwIBAgIQATfkha/xTr3pbLHVWlPq4jANBgkqhkiG9w0BAQsFADBY
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEuMCwGA1UE
AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgSDIgMjAyMTAeFw0yMTEw
MTgxODUwMDRaFw0yMjExMTkxODUwMDNaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWSo0eziN/0lq5
dIcS7ZceJw2odzZeT0tRkcKEW8iagNul6JetrFlk6h5lxoLEu35+MK6/fWHNmt7u
eQk7HS0uRipskAzeGrL1Hvk8EjIcHXXTxpRu7JqWOu7ZSXwNxW5cqn7L9/N2gYwt
Jg/sfkv9AFQiNOdKrarKfbcBstxmra6rQbh5ggLG5UBT23N4ZrA3XnzvEx3+GjtO
u/a5izbk7FQP3gyXKyfm/SQRpNsytYa9jJqu5Hmyzfap5KaueOJbtJEOk8dR/HWR
i/gmAUevq62MNxorYbz8YU/P1468tS7iORkD31Tc2QWCMQSPya5qGaCGnz7dVgWy
E1xTPbBXAgMBAAGjggNkMIIDYDAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgMjAyMiBRMzAeFw0yMjA3
MjIxOTQyMTFaFw0yMzA4MjMxOTQyMTBaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFFFQs8EITaWo5
0U18/mPTDLencU/7siJT/4P8oeDkemyx98wzK6vuNj/2JEZ3v1psKun5n8Pb/fHa
somKd/4icHgC4rnxrO6zayfb+cKzVghQe12Nj75lx6RtppqTgAmSOa3Tai5niICT
I8s3d2wsHtfEgqAavcD0/zdPIk25Ji7yfquldSthnlhQqI4Pm3OxTiyFj/V5ZhFl
IWZLvQaENjBSDVZQDcaPdWwodfXNA8fJmqk7cTLQ9P9NgjWvva7acl+Yd6hOFzV0
EllBl/WF1KB+YzGuHI0CQHT7sv3GW1lXeE2EqrWoSdLTOSAqm6y02DyE79d1xvG6
XXfX5ILlAgMBAAGjggNjMIIDXzAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
HQYDVR0OBBYEFJFVruwpjWeUfGJXl3m5grAjhAwPMFcGA1UdIARQME4wCAYGZ4EM
HQYDVR0OBBYEFHK7MnjGDptQWjfmJ2fr3IrjxEopMFcGA1UdIARQME4wCAYGZ4EM
AQIBMEIGCisGAQQBoDIKAQMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDAYDVR0TAQH/BAIwADCBngYIKwYBBQUH
AQEEgZEwgY4wQAYIKwYBBQUHMAGGNGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29t
L2NhL2dzYXRsYXNyM2R2dGxzY2FoMjIwMjEwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2FoMjIw
MjEuY3J0MB8GA1UdIwQYMBaAFCo0uar6vzyI8Ufy0hJ4vsXlqrBpMEgGA1UdHwRB
L2NhL2dzYXRsYXNyM2R2dGxzY2EyMDIycTMwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2EyMDIy
cTMuY3J0MB8GA1UdIwQYMBaAFPqROWOa+60QJOW+tbnaq9nERmmrMEgGA1UdHwRB
MD8wPaA7oDmGN2h0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3NhdGxhc3Iz
ZHZ0bHNjYWgyMjAyMS5jcmwwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB3AG9T
dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABfJS9R5YAAAQDAEgwRgIh
AOOZmc41vB2ICwkwEB5Bmpm/X8UHfjbxwrCXEdeRmO+qAiEAg/JugZIrG2PeV4bA
Gm6rry7HUfB954bQJ4p0PeQVmwsAdABGpVXrdfqRIDC1oolp9PN9ESxBdL79SbiF
q/L8cP5tRwAAAXyUvUeOAAAEAwBFMEMCHyRAiTz2fZ8DuQF6hrVP+IMTCPBtjB3D
m4naI8tC/foCIDXFCRIYjRb00CFI6piLYGihRy+GYF5nMQhQ9uE6hltzAHcAUaOw
9f0BeZxWbbg3eI8MpHrMGyfL956IQpoN/tSLBeUAAAF8lL1ICgAABAMASDBGAiEA
5d/bXb9TPZWhwSH8GGji/LDFL6OJnZtOV94sBaDiFgMCIQCtl00oCRMFFnqsvBo6
SRtnDqJkEHYBS12I4LyC+D1onjANBgkqhkiG9w0BAQsFAAOCAQEAE5xcno79J+Ec
DIPJKnJCugKiM7yKjCjCp/63osCbRC+jUwRyXBIe/oTdY3geKwDOQAvyEeJPSWP1
LbNp0l3yHbYXfsYl/NMTrJpjrJrrRO5BxG/d3IPwXIlcZrrdDSoGfGYIF9N23iqB
in15L7B+PodTl8/mSQZTjbLoecPvl+AOcLyStcWCKYQUlQb3x4UV3R4Z1ukwGbBC
cDbTR2XOSJzA9ECJcxKnWjQRQUc54pdG3pt13Wu2dVapX5sWZpV05rga3bBDjCqw
DcfKuYbOChm2i6CQ578lAntPTIS02EkGFHrmYxrIAvlhGksHpJNJtRoff1KkQKni
r8emWp7D2Q==
ZHZ0bHNjYTIwMjJxMy5jcmwwggF9BgorBgEEAdZ5AgQCBIIBbQSCAWkBZwB1AG9T
dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABgiduiHEAAAQDAEYwRAIg
SYQrru/KAKfe+hUqpJmk7Fc8drkgtY3IcAurTOwbM68CIBYO9sbDspd5p7v17RQi
QQkjdRwSjHiIgvlX0Y1JqmXjAHYArfe++nz/EMiLnT2cHj4YarRnKV3PsQwkyoWG
NOvcgooAAAGCJ26IcQAABAMARzBFAiBc5a10annqMEH69bdEFy/Vo1gb3S3GQ993
BCRV7ZXG4gIhAMqnsoKkU6ITwRXwE9KGjHnijJ8QrBrnK0i+JFaGe1ffAHYAs3N3
B+GEUPhjhtYFqdwRCUp5LbFnDAuH3PADDnk2pZoAAAGCJ26I6QAABAMARzBFAiAf
lW8Agd0DB68YA8XAbnlq7QNHw3uRMzNdS8gtRUe75gIhANTe+mt2p1ryW83P31OW
jH3cEGJxdUNT/oDM3Fzesx94MA0GCSqGSIb3DQEBCwUAA4IBAQAfivKEmjqqOFFh
VsX2XYkoDtreghpqMwHMCLwNk852Alr/Seyv9Ilng8cunU4NmhvEtsYVXkfE4XvB
0QIVxkg1w7A+p7ejMjh6doLJ0aWNWIVW/DwOeP0qstF9lqvLdLDABoVn0BtYCDTH
gjG80e2xpvPiKHGvBL+hlOIJwUuIAT3jN23sS1GoiYQGKsz0lovB09/6MGG0Qj8C
3i9a59T9XBpwSKdpKd4u/CB6koBXD3atbBNBACuAMcFckTEtmkCFtSpqBuocJGKf
LB4MFVaEwrd7Lc1ACC1et5FDtEI4I3/CerkRZTV+mRz5n6tB91AK3dRvjElfhiuh
XXYRULvB
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIExTCCA62gAwIBAgIQeimFGrf0XWZ5UGZBtv/XHTANBgkqhkiG9w0BAQsFADBM
MIIEjzCCA3egAwIBAgIQfCoMIT/GVVNFyR8ZH7hO+jANBgkqhkiG9w0BAQsFADBM
MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv
YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMTA2MTYxMjAwMDBaFw0y
NDA2MTYwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSBI
MiAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1JTAQMj+QUYF
3d9X5eOWFOphbB6GpHE3J0uvUXcQwxnd8Jz26aQCE1ZYxJFEc2WmsxuVeVXU+rZj
7+MYD7Mg72bhuiwUdwRGRN4a2N122LfIQlTFlHu/fwcNqYX/fe3phvZt9upnH4oJ
aLBbay+t+HPPC4em74x2WKaIl31ZXzgzllLomnlLISLOKiQe1rEHp4yy3/yE2a4G
1l/lprA49dcyM/oylm9Bbkum2F4C+EOjHgTAoDVJrJpdWvPj0CU+HkmftujfFp4S
55LECSr2TfJt7xjgR3eLUx12nlpoauWEzZ0/i6OIDPfbmqcksw4ani/YO07LbRM6
cY9VZzkAvwIDAQABo4IBlTCCAZEwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMjA0MjAxMjAwMDBaFw0y
NTA0MjAwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSAy
MDIyIFEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKh6ZjxOZpzO
N6VUNU02x5nTqCc28i/G1Rg+6QndBdbXLDQyfAhjSdEQN+V4XRFizm37Lz83lNuP
ezDpXizZVT+y27mgtWA3i6QGMjVQpAmvCkX/qB+bZY7dSuBAoeNjN1iQ3XU7/A4c
gkCYvXCxwUgUFDwES2nd1JwBpukh44IK/uSqvzSgjMvJeW4+XGpSnsTtK8Vp/lA8
k521/y0oqGwGbJ3Fr7JZ+1l3DXR6iISk1B3UuiAGzLUeSE50IRWGdcDMWtEFz1cW
ehMX7MJKrtUecqoiWoycgjLEEOZCbiGGaHyAIzA1072wXgopK/AUsRg32Vklw+c4
2enULTY1ZQIDAQABo4IBXzCCAVswDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
BBQqNLmq+r88iPFH8tISeL7F5aqwaTAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
BBT6kTljmvutECTlvrW52qvZxEZpqzAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw
Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1
cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w
K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwVwYD
VR0gBFAwTjAIBgZngQwBAgEwQgYKKwYBBAGgMgoBAzA0MDIGCCsGAQUFBwIBFiZo
dHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0B
AQsFAAOCAQEAEsIwXEhdAfoUGaKAnYfVI7zsOY7Sx8bpC/obGxXa4Kyu8CVx+TtT
g8WmKNF7+I7C51NZEmhvb8UDI1G9ny7iYIRDajQD5AeZowbfC69aHQSI9LiOeAZb
YaRDJfWps9redPwoaC0iT5R4xLOnWwCtmIho1bv/YG3pMAvaQ+qn04kuUvWO7LEp
u7FdHmx1DdgkefcqYgN/rAZ8E39S9VxWV+64PNUDey8vkAIH8FCTxbWiITty6dsH
SulKQ9pSa93k9PHTf+di08mMQBq5WBWTiFeMYZEWyE/z7NHdU3eLMZjq6y/nKlF9
nywrToh4AgdZK6JnbU+lqbNiexJbaBoA3w==
K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwIQYD
VR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAGgMgoBAzANBgkqhkiG9w0BAQsFAAOC
AQEAFDMseeU/gsZwP9pZOKe7onasYRgFaFfZDfuKRrzxqOgMcAIdxi+X7TY+nlKG
L1xi2NVHQ5pz0Sslh59EtBTrJrwhR3QgvZ+kv7OAHU01fc25tdpV8pBQyLIXTg60
YYgpX0RdA39XkYHQ6zCu1SrsgiDOTtKwi5UCYXPYaTT0rWMOXOQgH6l97Y7lHAS7
Ip/HqSLKmT0Cp2foBi36BGu7SdJsmVdjbC3CYXjhILH79r/hgjk5PHvvfRqVSrJy
2lWQru3d4nCQfBrutTJaXc/W+kXyngEMMS+JhP4xYA/97qZbhNXHGOak+UAwKRge
/vxBtbkpBXWLYhpbIi6/5FlssA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G

View file

@ -1,28 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIExTCCA62gAwIBAgIQeimFGrf0XWZ5UGZBtv/XHTANBgkqhkiG9w0BAQsFADBM
MIIEjzCCA3egAwIBAgIQfCoMIT/GVVNFyR8ZH7hO+jANBgkqhkiG9w0BAQsFADBM
MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv
YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMTA2MTYxMjAwMDBaFw0y
NDA2MTYwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSBI
MiAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1JTAQMj+QUYF
3d9X5eOWFOphbB6GpHE3J0uvUXcQwxnd8Jz26aQCE1ZYxJFEc2WmsxuVeVXU+rZj
7+MYD7Mg72bhuiwUdwRGRN4a2N122LfIQlTFlHu/fwcNqYX/fe3phvZt9upnH4oJ
aLBbay+t+HPPC4em74x2WKaIl31ZXzgzllLomnlLISLOKiQe1rEHp4yy3/yE2a4G
1l/lprA49dcyM/oylm9Bbkum2F4C+EOjHgTAoDVJrJpdWvPj0CU+HkmftujfFp4S
55LECSr2TfJt7xjgR3eLUx12nlpoauWEzZ0/i6OIDPfbmqcksw4ani/YO07LbRM6
cY9VZzkAvwIDAQABo4IBlTCCAZEwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMjA0MjAxMjAwMDBaFw0y
NTA0MjAwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSAy
MDIyIFEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKh6ZjxOZpzO
N6VUNU02x5nTqCc28i/G1Rg+6QndBdbXLDQyfAhjSdEQN+V4XRFizm37Lz83lNuP
ezDpXizZVT+y27mgtWA3i6QGMjVQpAmvCkX/qB+bZY7dSuBAoeNjN1iQ3XU7/A4c
gkCYvXCxwUgUFDwES2nd1JwBpukh44IK/uSqvzSgjMvJeW4+XGpSnsTtK8Vp/lA8
k521/y0oqGwGbJ3Fr7JZ+1l3DXR6iISk1B3UuiAGzLUeSE50IRWGdcDMWtEFz1cW
ehMX7MJKrtUecqoiWoycgjLEEOZCbiGGaHyAIzA1072wXgopK/AUsRg32Vklw+c4
2enULTY1ZQIDAQABo4IBXzCCAVswDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
BBQqNLmq+r88iPFH8tISeL7F5aqwaTAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
BBT6kTljmvutECTlvrW52qvZxEZpqzAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw
Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1
cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w
K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwVwYD
VR0gBFAwTjAIBgZngQwBAgEwQgYKKwYBBAGgMgoBAzA0MDIGCCsGAQUFBwIBFiZo
dHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0B
AQsFAAOCAQEAEsIwXEhdAfoUGaKAnYfVI7zsOY7Sx8bpC/obGxXa4Kyu8CVx+TtT
g8WmKNF7+I7C51NZEmhvb8UDI1G9ny7iYIRDajQD5AeZowbfC69aHQSI9LiOeAZb
YaRDJfWps9redPwoaC0iT5R4xLOnWwCtmIho1bv/YG3pMAvaQ+qn04kuUvWO7LEp
u7FdHmx1DdgkefcqYgN/rAZ8E39S9VxWV+64PNUDey8vkAIH8FCTxbWiITty6dsH
SulKQ9pSa93k9PHTf+di08mMQBq5WBWTiFeMYZEWyE/z7NHdU3eLMZjq6y/nKlF9
nywrToh4AgdZK6JnbU+lqbNiexJbaBoA3w==
K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwIQYD
VR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAGgMgoBAzANBgkqhkiG9w0BAQsFAAOC
AQEAFDMseeU/gsZwP9pZOKe7onasYRgFaFfZDfuKRrzxqOgMcAIdxi+X7TY+nlKG
L1xi2NVHQ5pz0Sslh59EtBTrJrwhR3QgvZ+kv7OAHU01fc25tdpV8pBQyLIXTg60
YYgpX0RdA39XkYHQ6zCu1SrsgiDOTtKwi5UCYXPYaTT0rWMOXOQgH6l97Y7lHAS7
Ip/HqSLKmT0Cp2foBi36BGu7SdJsmVdjbC3CYXjhILH79r/hgjk5PHvvfRqVSrJy
2lWQru3d4nCQfBrutTJaXc/W+kXyngEMMS+JhP4xYA/97qZbhNXHGOak+UAwKRge
/vxBtbkpBXWLYhpbIi6/5FlssA==
-----END CERTIFICATE-----

View file

@ -1,37 +1,37 @@
-----BEGIN CERTIFICATE-----
MIIGYzCCBUugAwIBAgIQAaQHyOeT/PBR4ioLKYneZDANBgkqhkiG9w0BAQsFADBY
MIIGYjCCBUqgAwIBAgIQATfkha/xTr3pbLHVWlPq4jANBgkqhkiG9w0BAQsFADBY
MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEuMCwGA1UE
AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgSDIgMjAyMTAeFw0yMTEw
MTgxODUwMDRaFw0yMjExMTkxODUwMDNaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWSo0eziN/0lq5
dIcS7ZceJw2odzZeT0tRkcKEW8iagNul6JetrFlk6h5lxoLEu35+MK6/fWHNmt7u
eQk7HS0uRipskAzeGrL1Hvk8EjIcHXXTxpRu7JqWOu7ZSXwNxW5cqn7L9/N2gYwt
Jg/sfkv9AFQiNOdKrarKfbcBstxmra6rQbh5ggLG5UBT23N4ZrA3XnzvEx3+GjtO
u/a5izbk7FQP3gyXKyfm/SQRpNsytYa9jJqu5Hmyzfap5KaueOJbtJEOk8dR/HWR
i/gmAUevq62MNxorYbz8YU/P1468tS7iORkD31Tc2QWCMQSPya5qGaCGnz7dVgWy
E1xTPbBXAgMBAAGjggNkMIIDYDAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgMjAyMiBRMzAeFw0yMjA3
MjIxOTQyMTFaFw0yMzA4MjMxOTQyMTBaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFFFQs8EITaWo5
0U18/mPTDLencU/7siJT/4P8oeDkemyx98wzK6vuNj/2JEZ3v1psKun5n8Pb/fHa
somKd/4icHgC4rnxrO6zayfb+cKzVghQe12Nj75lx6RtppqTgAmSOa3Tai5niICT
I8s3d2wsHtfEgqAavcD0/zdPIk25Ji7yfquldSthnlhQqI4Pm3OxTiyFj/V5ZhFl
IWZLvQaENjBSDVZQDcaPdWwodfXNA8fJmqk7cTLQ9P9NgjWvva7acl+Yd6hOFzV0
EllBl/WF1KB+YzGuHI0CQHT7sv3GW1lXeE2EqrWoSdLTOSAqm6y02DyE79d1xvG6
XXfX5ILlAgMBAAGjggNjMIIDXzAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
HQYDVR0OBBYEFJFVruwpjWeUfGJXl3m5grAjhAwPMFcGA1UdIARQME4wCAYGZ4EM
HQYDVR0OBBYEFHK7MnjGDptQWjfmJ2fr3IrjxEopMFcGA1UdIARQME4wCAYGZ4EM
AQIBMEIGCisGAQQBoDIKAQMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDAYDVR0TAQH/BAIwADCBngYIKwYBBQUH
AQEEgZEwgY4wQAYIKwYBBQUHMAGGNGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29t
L2NhL2dzYXRsYXNyM2R2dGxzY2FoMjIwMjEwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2FoMjIw
MjEuY3J0MB8GA1UdIwQYMBaAFCo0uar6vzyI8Ufy0hJ4vsXlqrBpMEgGA1UdHwRB
L2NhL2dzYXRsYXNyM2R2dGxzY2EyMDIycTMwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2EyMDIy
cTMuY3J0MB8GA1UdIwQYMBaAFPqROWOa+60QJOW+tbnaq9nERmmrMEgGA1UdHwRB
MD8wPaA7oDmGN2h0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3NhdGxhc3Iz
ZHZ0bHNjYWgyMjAyMS5jcmwwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB3AG9T
dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABfJS9R5YAAAQDAEgwRgIh
AOOZmc41vB2ICwkwEB5Bmpm/X8UHfjbxwrCXEdeRmO+qAiEAg/JugZIrG2PeV4bA
Gm6rry7HUfB954bQJ4p0PeQVmwsAdABGpVXrdfqRIDC1oolp9PN9ESxBdL79SbiF
q/L8cP5tRwAAAXyUvUeOAAAEAwBFMEMCHyRAiTz2fZ8DuQF6hrVP+IMTCPBtjB3D
m4naI8tC/foCIDXFCRIYjRb00CFI6piLYGihRy+GYF5nMQhQ9uE6hltzAHcAUaOw
9f0BeZxWbbg3eI8MpHrMGyfL956IQpoN/tSLBeUAAAF8lL1ICgAABAMASDBGAiEA
5d/bXb9TPZWhwSH8GGji/LDFL6OJnZtOV94sBaDiFgMCIQCtl00oCRMFFnqsvBo6
SRtnDqJkEHYBS12I4LyC+D1onjANBgkqhkiG9w0BAQsFAAOCAQEAE5xcno79J+Ec
DIPJKnJCugKiM7yKjCjCp/63osCbRC+jUwRyXBIe/oTdY3geKwDOQAvyEeJPSWP1
LbNp0l3yHbYXfsYl/NMTrJpjrJrrRO5BxG/d3IPwXIlcZrrdDSoGfGYIF9N23iqB
in15L7B+PodTl8/mSQZTjbLoecPvl+AOcLyStcWCKYQUlQb3x4UV3R4Z1ukwGbBC
cDbTR2XOSJzA9ECJcxKnWjQRQUc54pdG3pt13Wu2dVapX5sWZpV05rga3bBDjCqw
DcfKuYbOChm2i6CQ578lAntPTIS02EkGFHrmYxrIAvlhGksHpJNJtRoff1KkQKni
r8emWp7D2Q==
ZHZ0bHNjYTIwMjJxMy5jcmwwggF9BgorBgEEAdZ5AgQCBIIBbQSCAWkBZwB1AG9T
dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABgiduiHEAAAQDAEYwRAIg
SYQrru/KAKfe+hUqpJmk7Fc8drkgtY3IcAurTOwbM68CIBYO9sbDspd5p7v17RQi
QQkjdRwSjHiIgvlX0Y1JqmXjAHYArfe++nz/EMiLnT2cHj4YarRnKV3PsQwkyoWG
NOvcgooAAAGCJ26IcQAABAMARzBFAiBc5a10annqMEH69bdEFy/Vo1gb3S3GQ993
BCRV7ZXG4gIhAMqnsoKkU6ITwRXwE9KGjHnijJ8QrBrnK0i+JFaGe1ffAHYAs3N3
B+GEUPhjhtYFqdwRCUp5LbFnDAuH3PADDnk2pZoAAAGCJ26I6QAABAMARzBFAiAf
lW8Agd0DB68YA8XAbnlq7QNHw3uRMzNdS8gtRUe75gIhANTe+mt2p1ryW83P31OW
jH3cEGJxdUNT/oDM3Fzesx94MA0GCSqGSIb3DQEBCwUAA4IBAQAfivKEmjqqOFFh
VsX2XYkoDtreghpqMwHMCLwNk852Alr/Seyv9Ilng8cunU4NmhvEtsYVXkfE4XvB
0QIVxkg1w7A+p7ejMjh6doLJ0aWNWIVW/DwOeP0qstF9lqvLdLDABoVn0BtYCDTH
gjG80e2xpvPiKHGvBL+hlOIJwUuIAT3jN23sS1GoiYQGKsz0lovB09/6MGG0Qj8C
3i9a59T9XBpwSKdpKd4u/CB6koBXD3atbBNBACuAMcFckTEtmkCFtSpqBuocJGKf
LB4MFVaEwrd7Lc1ACC1et5FDtEI4I3/CerkRZTV+mRz5n6tB91AK3dRvjElfhiuh
XXYRULvB
-----END CERTIFICATE-----

Binary file not shown.

View file

@ -445,6 +445,19 @@ RSpec.describe DiffHelper do
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
subject { helper.render_fork_suggestion }

View file

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe SubmoduleHelper do
RSpec.describe SubmoduleHelper, feature_category: :source_code_management do
include RepoHelpers
let(:submodule_item) { double(id: 'hash', path: 'rack') }

View file

@ -114,6 +114,18 @@ RSpec.describe Gitlab::APIAuthentication::TokenResolver do
it_behaves_like 'an unauthorized request'
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
context 'with :personal_access_token' do

View file

@ -188,7 +188,7 @@ RSpec.describe Gitlab::Auth::AuthFinders do
end
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)
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 }
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
describe '#find_user_from_access_token' do

View file

@ -528,12 +528,13 @@ RSpec.describe Gitlab::Git::Repository do
prune: false,
check_tags_changed: false,
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)
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
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
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
repository.import_repository(url)

View file

@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::GitAccess, :aggregate_failures do
include TermsHelper
include AdminModeHelper
include ExternalAuthorizationServiceHelpers
let(:user) { create(:user) }
let(:actor) { user }
@ -111,6 +112,19 @@ RSpec.describe Gitlab::GitAccess, :aggregate_failures do
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
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
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

View file

@ -133,6 +133,40 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
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
let(:url) { 'https://example.com/git/repo.git' }
@ -141,7 +175,8 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
remote_params: Gitaly::Remote.new(
url: url,
http_authorization_header: "",
mirror_refmaps: []
mirror_refmaps: [],
resolved_address: ''
),
ssh_key: '',
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)
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
where(:ssh_mirror_url, :ssh_key_auth, :ssh_private_key, :ssh_known_hosts, :expected_params) do
false | false | 'key' | 'known_hosts' | {}

View file

@ -29,8 +29,8 @@ RSpec.describe Gitlab::HookData::ProjectBuilder do
expect(data[:path_with_namespace]).to eq(project.full_path)
expect(data[:project_id]).to eq(project.id)
expect(data[:owner_name]).to eq('John')
expect(data[:owner_email]).to eq('john@example.com')
expect(data[:owners]).to contain_exactly({ name: 'John', email: 'john@example.com' })
expect(data[:owner_email]).to eq(_('[REDACTED]'))
expect(data[:owners]).to contain_exactly({ name: 'John', email: _('[REDACTED]') })
expect(data[:project_visibility]).to eq('internal')
end
end

View file

@ -27,7 +27,7 @@ RSpec.describe Gitlab::HookData::ProjectMemberBuilder do
expect(data[:user_username]).to eq('johndoe')
expect(data[:user_name]).to eq('John Doe')
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[:project_visibility]).to eq('internal')
end

View 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

View file

@ -89,31 +89,32 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
describe '.categories' do
it 'gets CE unique category names' do
expect(described_class.categories).to include(
'deploy_token_packages',
'user_packages',
'ecosystem',
'analytics',
'ide_edit',
'search',
'source_code',
'incident_management',
'incident_management_alerts',
'testing',
'issues_edit',
'snippets',
'code_review',
'terraform',
'ci_templates',
'quickactions',
'pipeline_authoring',
'secure',
'importer',
'geo',
'work_items',
'ci_users',
'code_review',
'deploy_token_packages',
'ecosystem',
'environments',
'error_tracking',
'geo',
'ide_edit',
'importer',
'incident_management_alerts',
'incident_management',
'issues_edit',
'kubernetes_agent',
'manage',
'kubernetes_agent'
'pipeline_authoring',
'quickactions',
'search',
'secure',
'snippets',
'source_code',
'terraform',
'testing',
'user_packages',
'work_items'
)
end
end

View file

@ -11,7 +11,7 @@ RSpec.describe DeviseMailer do
subject { described_class.confirmation_instructions(user, 'faketoken', {}) }
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
expect(subject.body.encoded).to have_text "Welcome"
@ -20,7 +20,13 @@ RSpec.describe DeviseMailer do
end
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
expect(subject.body.encoded).not_to have_text "Welcome"
@ -30,7 +36,7 @@ RSpec.describe DeviseMailer do
end
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
expect(subject.body.encoded).not_to have_text "Welcome"

View file

@ -1466,10 +1466,4 @@ RSpec.describe ApplicationSetting do
expect(setting.personal_access_token_prefix).to eql('glpat-')
end
end
describe '.personal_access_tokens_disabled?' do
it 'is false' do
expect(setting.personal_access_tokens_disabled?).to eq(false)
end
end
end

View file

@ -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(: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
it 'creates a new session' do
simple_build = create(:ci_build)
@ -49,6 +88,12 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
expect(specification).to be_empty
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
it 'returns ca_pem nil if empty certificate' do
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) }
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
it 'returns default service proxy websocket subprotocol' do
@ -85,11 +130,17 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
expect(specification).to be_empty
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
let(:port) { nil }
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
@ -97,7 +148,7 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
let(:service) { '' }
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

View file

@ -185,4 +185,22 @@ RSpec.describe WebHookLog do
it { expect(web_hook_log.internal_error?).to be_truthy }
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

View file

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe WebHook do
RSpec.describe WebHook, feature_category: :integrations do
include AfterNextHelpers
let_it_be(:project) { create(:project) }
@ -131,6 +131,62 @@ RSpec.describe WebHook do
expect(hook.push_events_branch_filter).to eq('')
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
describe 'encrypted attributes' do
@ -242,7 +298,7 @@ RSpec.describe WebHook do
end
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
[

View file

@ -230,8 +230,11 @@ RSpec.describe Integrations::Jira do
where(:url, :result) do
'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
'https://somethingelse.com' | false
'javascript://test.atlassian.net/%250dalert(document.domain)' | false
'https://example.com".atlassian.net' | false
nil | false
end
@ -289,7 +292,7 @@ RSpec.describe Integrations::Jira do
let(:server_info_results) { { 'deploymentType' => 'FutureCloud' } }
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
expect(integration.jira_tracker_data).to be_deployment_cloud
@ -297,7 +300,7 @@ RSpec.describe Integrations::Jira do
end
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
expect(integration.jira_tracker_data).to be_deployment_server
@ -309,7 +312,7 @@ RSpec.describe Integrations::Jira do
let(:server_info_results) { {} }
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
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
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
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)

View file

@ -22,7 +22,7 @@ RSpec.describe ProjectImportState, type: :model do
before do
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
allow(Project).to receive(:find).with(project.id).and_return(project)

View file

@ -5521,8 +5521,8 @@ RSpec.describe Project, factory_default: :keep do
let(:import_state) { create(:import_state, project: project) }
it 'runs the correct hooks' do
expect(project.repository).to receive(:remove_prohibited_branches)
expect(project.repository).to receive(:expire_content_cache)
expect(project.repository).to receive(:expire_content_cache).ordered
expect(project.repository).to receive(:remove_prohibited_branches).ordered
expect(project.wiki.repository).to receive(:expire_content_cache)
expect(import_state).to receive(:finish)
expect(project).to receive(:update_project_counter_caches)

View file

@ -1224,11 +1224,22 @@ RSpec.describe Repository do
it 'fetches the URL without creating a remote' do
expect(repository)
.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)
repository.fetch_as_mirror(url)
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
describe '#fetch_ref' do

View file

@ -292,6 +292,34 @@ RSpec.describe User do
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
describe 'validations' do

View file

@ -643,6 +643,35 @@ RSpec.describe ProjectPolicy do
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
context 'when no user' do
let(:current_user) { anonymous }

View file

@ -10,18 +10,6 @@ RSpec.describe Admin::ImpersonationTokensController, :enable_admin_mode do
sign_in(admin)
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
before do
stub_config_setting(impersonation_enabled: false)

View file

@ -949,6 +949,41 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
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)
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' }

View file

@ -31,5 +31,16 @@ RSpec.describe JiraConnect::UsersController do
expect(response.body).not_to include('Return to GitLab')
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

View file

@ -2,7 +2,7 @@
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(:project, reload: true) { create(:project) }
@ -51,7 +51,10 @@ RSpec.describe ErrorTracking::ListProjectsService do
end
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) }
context 'with the current api host' do
let(:api_host) { 'https://sentrytest.gitlab.com' }
before do
expect(error_tracking_setting).to receive(:list_sentry_projects)
@ -63,6 +66,21 @@ RSpec.describe ErrorTracking::ListProjectsService do
end
end
context 'with a new api host' do
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
context 'with invalid url' do
let(:params) do
ActionController::Parameters.new(

View file

@ -114,5 +114,16 @@ RSpec.describe Packages::Nuget::MetadataExtractionService do
it { expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError, 'nuspec file too big') }
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

View file

@ -127,6 +127,41 @@ RSpec.describe Projects::ImportService do
project.import_type = 'bitbucket'
end
context 'when importer supports refmap' do
before do
project.import_type = 'gitea'
end
it 'succeeds if repository fetch as mirror is successful' do
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
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')
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
context 'when importer does not support refmap' do
it 'succeeds if repository import is successful' do
expect(project.repository).to receive(:import_repository).and_return(true)
expect_next_instance_of(Gitlab::BitbucketImport::Importer) do |importer|
@ -145,6 +180,7 @@ RSpec.describe Projects::ImportService do
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
@ -152,6 +188,7 @@ RSpec.describe Projects::ImportService do
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
context 'when lfs import fails' do
it 'logs the error' do
@ -287,6 +324,102 @@ RSpec.describe Projects::ImportService do
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
let(:base_log_data) do
{

View file

@ -77,6 +77,34 @@ RSpec.describe Users::UpdateService do
subject
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
def update_user(user, opts)
described_class.new(user, opts.merge(user: user)).execute(check_password: true)
@ -139,8 +167,23 @@ RSpec.describe Users::UpdateService do
update_user(user, job_title: 'supreme leader of the universe')
end.not_to change { user.user_canonical_email }
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
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)
described_class.new(user, opts.merge(user: user)).execute

View file

@ -129,7 +129,10 @@ RSpec.describe WebHookService, :request_store, :clean_gitlab_redis_shared_state
context 'there is userinfo' 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)
end

Some files were not shown because too many files have changed in this diff Show more