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,40 +17,26 @@ 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
end
end
if namespace.blank? || project.blank?
return [sanitize_submodule_url(url), nil, nil]
end
namespace.delete_prefix!('/')
project.rstrip!
project.delete_suffix!('.git')
if self_url?(url, namespace, project)
[
url_helpers.namespace_project_path(namespace, project),
url_helpers.namespace_project_tree_path(namespace, project, submodule_item_id),
(url_helpers.namespace_project_compare_path(namespace, project, to: submodule_item_id, from: old_submodule_item_id) if old_submodule_item_id)
]
elsif relative_self_url?(url)
relative_self_links(url, submodule_item_id, old_submodule_item_id, repository.project)
elsif gist_github_dot_com_url?(url)
gist_github_com_tree_links(namespace, project, submodule_item_id)
elsif github_dot_com_url?(url)
github_com_tree_links(namespace, project, submodule_item_id, old_submodule_item_id)
elsif gitlab_dot_com_url?(url)
gitlab_com_tree_links(namespace, project, submodule_item_id, old_submodule_item_id)
else
[sanitize_submodule_url(url), nil, nil]
end
if self_url?(url, namespace, project)
[
url_helpers.namespace_project_path(namespace, project),
url_helpers.namespace_project_tree_path(namespace, project, submodule_item_id),
(url_helpers.namespace_project_compare_path(namespace, project, to: submodule_item_id, from: old_submodule_item_id) if old_submodule_item_id)
]
elsif relative_self_url?(url)
relative_self_links(url, submodule_item_id, old_submodule_item_id, repository.project)
elsif gist_github_dot_com_url?(url)
gist_github_com_tree_links(namespace, project, submodule_item_id)
elsif github_dot_com_url?(url)
github_com_tree_links(namespace, project, submodule_item_id, old_submodule_item_id)
elsif gitlab_dot_com_url?(url)
gitlab_com_tree_links(namespace, project, submodule_item_id, old_submodule_item_id)
else
[sanitize_submodule_url(url), nil, nil]
end
@ -58,6 +44,30 @@ module SubmoduleHelper
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,18 +51,17 @@
= 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
= sprite_icon('token')
%span.nav-item-name
= _('Access Tokens')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :personal_access_tokens, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_personal_access_tokens_path do
%strong.fly-out-top-item-name
= _('Access Tokens')
= nav_link(controller: :personal_access_tokens) do
= link_to profile_personal_access_tokens_path do
.nav-icon-container
= sprite_icon('token')
%span.nav-item-name
= _('Access Tokens')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :personal_access_tokens, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_personal_access_tokens_path do
%strong.fly-out-top-item-name
= _('Access Tokens')
= nav_link(controller: :emails) do
= link_to profile_emails_path, data: { qa_selector: 'profile_emails_link' } do
.nav-icon-container

View file

@ -1,4 +1,5 @@
.gl-text-secondary
= sprite_icon("rocket", size: 12)
= _("Release")
= link_to release.name, project_release_path(project, release), class: "gl-text-blue-600!"
- if can?(current_user, :read_release, release)
.gl-text-secondary
= sprite_icon("rocket", size: 12)
= _("Release")
= link_to release.name, project_release_path(project, release), class: "gl-text-blue-600!"

View file

@ -57,12 +57,13 @@
%pre.wrap{ data: { qa_selector: 'tag_message_content' } }
= strip_signature(@tag.message)
.gl-mb-3.gl-mt-3
- if @release&.description.present?
.description.md{ data: { qa_selector: 'tag_release_notes_content' } }
= markdown_field(@release, :description)
- else
= s_('TagsPage|This tag has no release notes.')
- 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' } }
= markdown_field(@release, :description)
- else
= s_('TagsPage|This tag has no release notes.')
- if can?(current_user, :admin_tag, @project)
.js-delete-tag-modal

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,17 +268,35 @@ RSpec.describe UploadsController do
end
context "when not signed in" do
it "responds with status 200" do
get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" }
context "when restricted visibility level is not set to public" do
before do
stub_application_setting(restricted_visibility_levels: [])
end
expect(response).to have_gitlab_http_status(:ok)
it "responds with status 200" do
get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" }
expect(response).to have_gitlab_http_status(:ok)
end
it_behaves_like 'content publicly cached' do
subject do
get :show, params: { model: 'user', mounted_as: 'avatar', id: user.id, filename: 'dk.png' }
response
end
end
end
it_behaves_like 'content publicly cached' do
subject do
get :show, params: { model: 'user', mounted_as: 'avatar', id: user.id, filename: 'dk.png' }
context "when restricted visibility level is set to public" do
before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
end
response
it "responds with status 401" do
get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" }
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end

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-----

View file

@ -1,294 +1,294 @@
User-Agent: Microsoft-MacOutlook/10.22.0.200209
Date: Mon, 17 Feb 2020 22:56:47 +0100
Subject: Re: htmltest | test issue (#1)
From: "Louzan Martinez, Diego (ext) (SI BP R&D ZG)"
<diego.louzan.ext@siemens.com>
To: Administrator / htmltest
<dlouzan.dummy+c034670b1623e617e15a3df64223d363@gmail.com>
Message-ID: <012E37D9-2A3F-4AC8-B79A-871F42914D86@siemens.com>
Thread-Topic: htmltest | test issue (#1)
References: <reply-c034670b1623e617e15a3df64223d363@169.254.169.254>
<issue_451@169.254.169.254>
<note_1797@169.254.169.254>
In-Reply-To: <note_1797@169.254.169.254>
Content-type: multipart/signed;
protocol="application/pkcs7-signature";
micalg=sha256;
boundary="B_3664825007_1904734766"
MIME-Version: 1.0
--B_3664825007_1904734766
Content-type: multipart/mixed;
boundary="B_3664825007_384940722"
--B_3664825007_384940722
Content-type: multipart/alternative;
boundary="B_3664825007_1519466360"
--B_3664825007_1519466360
Content-type: text/plain;
charset="UTF-8"
Content-transfer-encoding: quoted-printable
Me too, with an attachment
=20
From: Administrator <dlouzan.dummy@gmail.com>
Reply to: Administrator / htmltest <dlouzan.dummy+c034670b1623e617e15a3df64=
223d363@gmail.com>
Date: Monday, 17 February 2020 at 22:55
To: "Louzan Martinez, Diego (ext) (SOP IT STG XS)" <diego.louzan.ext@siemen=
s.com>
Subject: Re: htmltest | test issue (#1)
=20
Administrator commented:=20
I pity the foo !!!
=E2=80=94=20
Reply to this email directly or view it on GitLab.=20
You're receiving this email because of your account on 169.254.169.254. If =
you'd like to receive fewer emails, you can unsubscribe from this thread or =
adjust your notification settings.=20
--B_3664825007_1519466360
Content-type: text/html;
charset="UTF-8"
Content-transfer-encoding: quoted-printable
<html xmlns:o=3D"urn:schemas-microsoft-com:office:office" xmlns:w=3D"urn:schema=
s-microsoft-com:office:word" xmlns:m=3D"http://schemas.microsoft.com/office/20=
04/12/omml" xmlns=3D"http://www.w3.org/TR/REC-html40"><head><meta http-equiv=3DC=
ontent-Type content=3D"text/html; charset=3Dutf-8"><meta name=3DGenerator content=3D=
"Microsoft Word 15 (filtered medium)"><title>GitLab</title><style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
{page:WordSection1;}
--></style></head><body lang=3Den-ES link=3Dblue vlink=3Dpurple><div class=3DWordSe=
ction1><p class=3DMsoNormal><span lang=3DEN-US style=3D'mso-fareast-language:EN-US=
'>Me too, with an attachment<o:p></o:p></span></p><p class=3DMsoNormal><span s=
tyle=3D'mso-fareast-language:EN-US'><o:p>&nbsp;</o:p></span></p><div style=3D'bo=
rder:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=
=3DMsoNormal><b><span style=3D'font-size:12.0pt;color:black'>From: </span></b><s=
pan style=3D'font-size:12.0pt;color:black'>Administrator &lt;dlouzan.dummy@gma=
il.com&gt;<br><b>Reply to: </b>Administrator / htmltest &lt;dlouzan.dummy+c0=
34670b1623e617e15a3df64223d363@gmail.com&gt;<br><b>Date: </b>Monday, 17 Febr=
uary 2020 at 22:55<br><b>To: </b>&quot;Louzan Martinez, Diego (ext) (SOP IT =
STG XS)&quot; &lt;diego.louzan.ext@siemens.com&gt;<br><b>Subject: </b>Re: ht=
mltest | test issue (#1)<o:p></o:p></span></p></div><div><p class=3DMsoNormal>=
<o:p>&nbsp;</o:p></p></div><div><p><span style=3D'color:#777777'><a href=3D"http=
://localhost:3000/root">Administrator</a> commented: <o:p></o:p></span></p><=
div><p>I pity the foo !!!<o:p></o:p></p></div></div><div style=3D'margin-top:7=
.5pt'><p><span style=3D'font-size:12.0pt;color:#777777'>=E2=80=94 <br>Reply to this =
email directly or <a href=3D"http://localhost:3000/root/htmltest/issues/1#note=
_1797">view it on GitLab</a>. <br>You're receiving this email because of you=
r account on 169.254.169.254. If you'd like to receive fewer emails, you can=
<a href=3D"http://localhost:3000/sent_notifications/c034670b1623e617e15a3df64=
223d363/unsubscribe">unsubscribe</a> from this thread or adjust your notific=
ation settings. <o:p></o:p></span></p></div></div></body></html>
--B_3664825007_1519466360--
--B_3664825007_384940722
Content-type: image/png; name="gitlab_logo.png";
x-mac-creator="4F50494D";
x-mac-type="504E4766"
Content-disposition: attachment;
filename="gitlab_logo.png"
Content-transfer-encoding: base64
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
--B_3664825007_384940722--
--B_3664825007_1904734766
Content-type: application/pkcs7-signature; name="smime.p7s"
Content-transfer-encoding: base64
Content-disposition: attachment;
filename="smime.p7s"
MIIRpwYJKoZIhvcNAQcCoIIRmDCCEZQCAQExDzANBglghkgBZQMEAgEFADALBgkqhkiG9w0B
BwGggg8VMIIHojCCBYqgAwIBAgIEZ5a6PTANBgkqhkiG9w0BAQsFADCBtjELMAkGA1UEBhMC
REUxDzANBgNVBAgMBkJheWVybjERMA8GA1UEBwwITXVlbmNoZW4xEDAOBgNVBAoMB1NpZW1l
bnMxETAPBgNVBAUTCFpaWlpaWkE2MR0wGwYDVQQLDBRTaWVtZW5zIFRydXN0IENlbnRlcjE/
MD0GA1UEAww2U2llbWVucyBJc3N1aW5nIENBIE1lZGl1bSBTdHJlbmd0aCBBdXRoZW50aWNh
dGlvbiAyMDE2MB4XDTE5MTEyMTE0NDQ0N1oXDTIwMTEyMTE0NDQ0N1owdzERMA8GA1UEBRMI
WjAwM0gwOFQxDjAMBgNVBCoMBURpZWdvMRgwFgYDVQQEDA9Mb3V6YW4gTWFydGluZXoxGDAW
BgNVBAoMD1NpZW1lbnMtUGFydG5lcjEeMBwGA1UEAwwVTG91emFuIE1hcnRpbmV6IERpZWdv
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuInpNaC7NRYD+0pOpHDz2pk9xmPt
JGj860SF6Nmn6Eu9EMYKEDfneC6z5QcH+mPS2d0VWgqVVGbRXSPsxJtbi9TCWjQUZdHglEZK
z9zxoFDh2dvW5/+TOT5Jf78FXyqak0YtY6+oMjQ/i9RUqPL7sIlyXLrBYrILzQ9Afo+7bXZg
v3ypp6xtqAV2ctHzQWFi0onJzxLVYguiVb7fFF9rBEMvSZonuw5tvOwJIhbe5FDFOrDcfbyU
ofZ/wikIZ+A+CE5GryXuuQmGxJaC2QqOkRAWQDzLDx9nG+rKiEs5OvlfEZC7EV1PyjZ93coM
faCVdlAgcFZ5fvd37CjyjKl+1QIDAQABo4IC9DCCAvAwggEEBggrBgEFBQcBAQSB9zCB9DAy
BggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBNi5jcnQwQQYI
KwYBBQUHMAKGNWxkYXA6Ly9hbC5zaWVtZW5zLm5ldC9DTj1aWlpaWlpBNixMPVBLST9jQUNl
cnRpZmljYXRlMEkGCCsGAQUFBzAChj1sZGFwOi8vYWwuc2llbWVucy5jb20vQ049WlpaWlpa
QTYsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUFBzABhiRodHRwOi8vb2Nz
cC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wHwYDVR0jBBgwFoAU+BVdRwxsd3tyxAIXkWii
tvdqCUQwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGDSsGAQQBoWkHAgIEAQMwKTAnBggr
BgEFBQcCARYbaHR0cDovL3d3dy5zaWVtZW5zLmNvbS9wa2kvMIHKBgNVHR8EgcIwgb8wgbyg
gbmggbaGJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTYuY3JshkFsZGFwOi8v
Y2wuc2llbWVucy5uZXQvQ049WlpaWlpaQTYsTD1QS0k/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
TGlzdIZJbGRhcDovL2NsLnNpZW1lbnMuY29tL0NOPVpaWlpaWkE2LG89VHJ1c3RjZW50ZXI/
Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
AwQwDgYDVR0PAQH/BAQDAgeAMFUGA1UdEQROMEygLAYKKwYBBAGCNxQCA6AeDBxkaWVnby5s
b3V6YW4uZXh0QHNpZW1lbnMuY29tgRxkaWVnby5sb3V6YW4uZXh0QHNpZW1lbnMuY29tMB0G
A1UdDgQWBBQj8k8aqZey68w8ALYKGJSGMt5hZDANBgkqhkiG9w0BAQsFAAOCAgEAFDHqxpb1
R9cB4noC9vx09bkNbmXCpVfl3XCQUmAWTznC0nwEssTTjo0PWuIV4C3jnsp0MRUeHZ6lsyhZ
OzS1ETwYgvj6wzjb8RF3wgn7N/JOvFGaErMz5HZpKOfzGiNpW6/Rmd4hsRDjAwOVQOXUTqc/
0Bj3FMoLRCSWSnTp5HdyvrY2xOKHfTrTjzmcLdFaKE2F5n7+dBkwCKVfzut8CqfVq/I7ks4m
D1IHk93/P6l9U34R2FHPt6zRTNZcWmDirRSlMH4L18CnfiNPuDN/PtRYlt3Vng5EdYN0VCg2
NM/uees0U4ingCb0NFjg66uQ/tjfPQk55MN4Wpls4N6TkMoTCWLiqZzYTGdmVQexzroL6940
tmMr8LoN3TpPf0OdvdKEpyH7fzsx5QlmQyywIWec6X+Fx6+l0g91VJnPEtqACpfZIBZtviHl
gfX298w+SsvBK8C48Pqs8Ijh7tLrCxx7VMLVHZqwWWPK53ga+CDWmjoSQPxi+CPZF7kao6N5
4GrJWwSHlHh6WzTbLyLvTJZZ775Utp4W8s8xMUsQJ413iYzEaC8FcSeNjSk5UiDDiHrKmzpM
tbApD3pUXStblUMKYGTG1Mj9BcEBFkCdoGlw/ulszIrKFfOyRNDG3Ay+Dj/oMjoKsJphu3px
wyft82rTer7UW/I7o0h0DAG4lkMwggdrMIIFU6ADAgECAgR5nlqfMA0GCSqGSIb3DQEBCwUA
MIGeMQswCQYDVQQGEwJERTEPMA0GA1UECAwGQmF5ZXJuMREwDwYDVQQHDAhNdWVuY2hlbjEQ
MA4GA1UECgwHU2llbWVuczERMA8GA1UEBRMIWlpaWlpaQTMxHTAbBgNVBAsMFFNpZW1lbnMg
VHJ1c3QgQ2VudGVyMScwJQYDVQQDDB5TaWVtZW5zIElzc3VpbmcgQ0EgRUUgRW5jIDIwMTYw
HhcNMTkwOTI3MDgwMTM5WhcNMjAwOTI3MDgwMTM3WjB3MREwDwYDVQQFEwhaMDAzSDA4VDEO
MAwGA1UEKgwFRGllZ28xGDAWBgNVBAQMD0xvdXphbiBNYXJ0aW5lejEYMBYGA1UECgwPU2ll
bWVucy1QYXJ0bmVyMR4wHAYDVQQDDBVMb3V6YW4gTWFydGluZXogRGllZ28wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyby5qKzZIrGYWRqxnaAyMt/a/uc0uMk0F3MjwxvPM
vh5DllUpqx0l8ZDakDjPhlEXTeoL4DHNgmh+CDCs76CppM3cNG/1W1Ajo/L2iwMoXaxYuQ/F
q7ED+02KEkWX2DDVVG3fhrUGP20QAq77xPDptmVWZnUnuobZBNYkC49Xfl9HJvkJL8P0+Jqb
Eae7p4roiEr7wNkGriwrVXgA3oPNF/W+OuI76JTNTajS/6PAK/GeqIvLjfuBXpdBZTY031nE
Cztca8vI1jUjQzVhS+0dWpvpfhkVumbvOnid8DI9lapYsX8dpZFsa3ya+T3tjUdGSOOKi0kg
lWf/XYyyfhmDAgMBAAGjggLVMIIC0TAdBgNVHQ4EFgQUprhTCDwNLfPImpSfWdq+QvPTo9Mw
JwYDVR0RBCAwHoEcZGllZ28ubG91emFuLmV4dEBzaWVtZW5zLmNvbTAOBgNVHQ8BAf8EBAMC
BDAwLAYDVR0lBCUwIwYIKwYBBQUHAwQGCisGAQQBgjcKAwQGCysGAQQBgjcKAwQBMIHKBgNV
HR8EgcIwgb8wgbyggbmggbaGJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTMu
Y3JshkFsZGFwOi8vY2wuc2llbWVucy5uZXQvQ049WlpaWlpaQTMsTD1QS0k/Y2VydGlmaWNh
dGVSZXZvY2F0aW9uTGlzdIZJbGRhcDovL2NsLnNpZW1lbnMuY29tL0NOPVpaWlpaWkEzLG89
VHJ1c3RjZW50ZXI/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDBFBgNVHSAEPjA8MDoGDSsG
AQQBoWkHAgIEAQMwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5zaWVtZW5zLmNvbS9wa2kv
MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUoassbqB68NPCTeof8R4hivwMre8wggEEBggr
BgEFBQcBAQSB9zCB9DAyBggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9a
WlpaWlpBMy5jcnQwQQYIKwYBBQUHMAKGNWxkYXA6Ly9hbC5zaWVtZW5zLm5ldC9DTj1aWlpa
WlpBMyxMPVBLST9jQUNlcnRpZmljYXRlMEkGCCsGAQUFBzAChj1sZGFwOi8vYWwuc2llbWVu
cy5jb20vQ049WlpaWlpaQTMsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUF
BzABhiRodHRwOi8vb2NzcC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wDQYJKoZIhvcNAQEL
BQADggIBAF98ZMNg28LgkwdjOdvOGbC1QitsWjZTyotmQESF0nClDLUhb0O5675vVixntbrf
eB8xy1+KRiadk40GnAIJ0YzmNl4Tav6hPYv9VBWe5olsWG7C4qB3Q/SwhvW/e+owxv1cBra8
R3oRudiN81eTZQHyNghRephVqQG/dpPYqydoANfIhEpHa79QlpaCAeYl4896AZOS8HYbkDFs
hLdv7sEHtl79YuSWI1wBjbJl70c0Sb4wLRgCPuHyQj2Uw/vQ5xJlEvBDZAIXXe1TP/nqiuY6
7nweJbbeqfFE6ZP3kCe+mEIWGSaO0iThZyLGer8fHs1XiEmhhPgvC7P7KodzpXU6+hX+ZzbD
DxEjFfetV5sh0aNSXG9xx4hZmS9bpImBGR8MvZ7cgxqItvLtY2xvfUbYW244d4RcWesaCDq3
ZEIo6uCIzOzJAwjUdLIac+lLV0rxiHmb7O3cQ19kjpWDB31hmfrus/TKJ55pBKVWBX5m/mFv
K8Ep5USpGrNS0EzOP7I1kQZv2VsvAhSxk/m5FMLpDy8T0O8YgbLypTXoeJFWCF6RduSjVsaZ
lkAtTQYud683pjyOMxJXaQUYGU1PmEYSOonMkVsT9aBcxYkXLp+Ln/+8G0OCYu7dRdwnj+Ut
7yR/ltxtgDcaFApCb0qBTKbgbqZk1fASmkOp+kbdYmoUMYICVjCCAlICAQEwgb8wgbYxCzAJ
BgNVBAYTAkRFMQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVuMRAwDgYDVQQK
DAdTaWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwUU2llbWVucyBUcnVzdCBD
ZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBDQSBNZWRpdW0gU3RyZW5ndGggQXV0
aGVudGljYXRpb24gMjAxNgIEZ5a6PTANBglghkgBZQMEAgEFAKBpMC8GCSqGSIb3DQEJBDEi
BCAOR58AbNfSrI+vtMs+dgAQtn3IVZ3RjYC5hz3j9k+6TTAYBgkqhkiG9w0BCQMxCwYJKoZI
hvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMDAyMTcyMTU2NDdaMA0GCSqGSIb3DQEBAQUABIIB
AHLSBcFHhNHPevbwqvA2ecuVb/aKnj45CFF6l8esP1H5DRm1ee5qMKuIS84NFuFC9RUENNhW
DBzsB+BVGz64o1f8QgIklYVrIJ4JZ0q1abNG7NbkVKWIpS3CQo//YWShUTYg+JpKx4YbahGR
sP5zbufbU4eagrrqBChjPTLy+njdjwCNu0XPykBTKOOf6BMjnS33AYjHJyh83JOY7rw3IDLx
8POQH4g5EMRpl9354s0rEkIezMt7pfUAsqY3QnQ8hvlE4KTikPQ+tvLMK1l/ffcLAP8BdBNI
YA3ikb3qCoGNSLKieYzNnBPhNOIJELUtEEaljAFZYMQzMKCbI4JdiDs=
--B_3664825007_1904734766--
User-Agent: Microsoft-MacOutlook/10.22.0.200209
Date: Mon, 17 Feb 2020 22:56:47 +0100
Subject: Re: htmltest | test issue (#1)
From: "Louzan Martinez, Diego (ext) (SI BP R&D ZG)"
<diego.louzan.ext@siemens.com>
To: Administrator / htmltest
<dlouzan.dummy+c034670b1623e617e15a3df64223d363@gmail.com>
Message-ID: <012E37D9-2A3F-4AC8-B79A-871F42914D86@siemens.com>
Thread-Topic: htmltest | test issue (#1)
References: <reply-c034670b1623e617e15a3df64223d363@169.254.169.254>
<issue_451@169.254.169.254>
<note_1797@169.254.169.254>
In-Reply-To: <note_1797@169.254.169.254>
Content-type: multipart/signed;
protocol="application/pkcs7-signature";
micalg=sha256;
boundary="B_3664825007_1904734766"
MIME-Version: 1.0
--B_3664825007_1904734766
Content-type: multipart/mixed;
boundary="B_3664825007_384940722"
--B_3664825007_384940722
Content-type: multipart/alternative;
boundary="B_3664825007_1519466360"
--B_3664825007_1519466360
Content-type: text/plain;
charset="UTF-8"
Content-transfer-encoding: quoted-printable
Me too, with an attachment
=20
From: Administrator <dlouzan.dummy@gmail.com>
Reply to: Administrator / htmltest <dlouzan.dummy+c034670b1623e617e15a3df64=
223d363@gmail.com>
Date: Monday, 17 February 2020 at 22:55
To: "Louzan Martinez, Diego (ext) (SOP IT STG XS)" <diego.louzan.ext@siemen=
s.com>
Subject: Re: htmltest | test issue (#1)
=20
Administrator commented:=20
I pity the foo !!!
=E2=80=94=20
Reply to this email directly or view it on GitLab.=20
You're receiving this email because of your account on 169.254.169.254. If =
you'd like to receive fewer emails, you can unsubscribe from this thread or =
adjust your notification settings.=20
--B_3664825007_1519466360
Content-type: text/html;
charset="UTF-8"
Content-transfer-encoding: quoted-printable
<html xmlns:o=3D"urn:schemas-microsoft-com:office:office" xmlns:w=3D"urn:schema=
s-microsoft-com:office:word" xmlns:m=3D"http://schemas.microsoft.com/office/20=
04/12/omml" xmlns=3D"http://www.w3.org/TR/REC-html40"><head><meta http-equiv=3DC=
ontent-Type content=3D"text/html; charset=3Dutf-8"><meta name=3DGenerator content=3D=
"Microsoft Word 15 (filtered medium)"><title>GitLab</title><style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
{page:WordSection1;}
--></style></head><body lang=3Den-ES link=3Dblue vlink=3Dpurple><div class=3DWordSe=
ction1><p class=3DMsoNormal><span lang=3DEN-US style=3D'mso-fareast-language:EN-US=
'>Me too, with an attachment<o:p></o:p></span></p><p class=3DMsoNormal><span s=
tyle=3D'mso-fareast-language:EN-US'><o:p>&nbsp;</o:p></span></p><div style=3D'bo=
rder:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=
=3DMsoNormal><b><span style=3D'font-size:12.0pt;color:black'>From: </span></b><s=
pan style=3D'font-size:12.0pt;color:black'>Administrator &lt;dlouzan.dummy@gma=
il.com&gt;<br><b>Reply to: </b>Administrator / htmltest &lt;dlouzan.dummy+c0=
34670b1623e617e15a3df64223d363@gmail.com&gt;<br><b>Date: </b>Monday, 17 Febr=
uary 2020 at 22:55<br><b>To: </b>&quot;Louzan Martinez, Diego (ext) (SOP IT =
STG XS)&quot; &lt;diego.louzan.ext@siemens.com&gt;<br><b>Subject: </b>Re: ht=
mltest | test issue (#1)<o:p></o:p></span></p></div><div><p class=3DMsoNormal>=
<o:p>&nbsp;</o:p></p></div><div><p><span style=3D'color:#777777'><a href=3D"http=
://localhost:3000/root">Administrator</a> commented: <o:p></o:p></span></p><=
div><p>I pity the foo !!!<o:p></o:p></p></div></div><div style=3D'margin-top:7=
.5pt'><p><span style=3D'font-size:12.0pt;color:#777777'>=E2=80=94 <br>Reply to this =
email directly or <a href=3D"http://localhost:3000/root/htmltest/issues/1#note=
_1797">view it on GitLab</a>. <br>You're receiving this email because of you=
r account on 169.254.169.254. If you'd like to receive fewer emails, you can=
<a href=3D"http://localhost:3000/sent_notifications/c034670b1623e617e15a3df64=
223d363/unsubscribe">unsubscribe</a> from this thread or adjust your notific=
ation settings. <o:p></o:p></span></p></div></div></body></html>
--B_3664825007_1519466360--
--B_3664825007_384940722
Content-type: image/png; name="gitlab_logo.png";
x-mac-creator="4F50494D";
x-mac-type="504E4766"
Content-disposition: attachment;
filename="gitlab_logo.png"
Content-transfer-encoding: base64
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
--B_3664825007_384940722--
--B_3664825007_1904734766
Content-type: application/pkcs7-signature; name="smime.p7s"
Content-transfer-encoding: base64
Content-disposition: attachment;
filename="smime.p7s"
MIIRpwYJKoZIhvcNAQcCoIIRmDCCEZQCAQExDzANBglghkgBZQMEAgEFADALBgkqhkiG9w0B
BwGggg8VMIIHojCCBYqgAwIBAgIEZ5a6PTANBgkqhkiG9w0BAQsFADCBtjELMAkGA1UEBhMC
REUxDzANBgNVBAgMBkJheWVybjERMA8GA1UEBwwITXVlbmNoZW4xEDAOBgNVBAoMB1NpZW1l
bnMxETAPBgNVBAUTCFpaWlpaWkE2MR0wGwYDVQQLDBRTaWVtZW5zIFRydXN0IENlbnRlcjE/
MD0GA1UEAww2U2llbWVucyBJc3N1aW5nIENBIE1lZGl1bSBTdHJlbmd0aCBBdXRoZW50aWNh
dGlvbiAyMDE2MB4XDTE5MTEyMTE0NDQ0N1oXDTIwMTEyMTE0NDQ0N1owdzERMA8GA1UEBRMI
WjAwM0gwOFQxDjAMBgNVBCoMBURpZWdvMRgwFgYDVQQEDA9Mb3V6YW4gTWFydGluZXoxGDAW
BgNVBAoMD1NpZW1lbnMtUGFydG5lcjEeMBwGA1UEAwwVTG91emFuIE1hcnRpbmV6IERpZWdv
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuInpNaC7NRYD+0pOpHDz2pk9xmPt
JGj860SF6Nmn6Eu9EMYKEDfneC6z5QcH+mPS2d0VWgqVVGbRXSPsxJtbi9TCWjQUZdHglEZK
z9zxoFDh2dvW5/+TOT5Jf78FXyqak0YtY6+oMjQ/i9RUqPL7sIlyXLrBYrILzQ9Afo+7bXZg
v3ypp6xtqAV2ctHzQWFi0onJzxLVYguiVb7fFF9rBEMvSZonuw5tvOwJIhbe5FDFOrDcfbyU
ofZ/wikIZ+A+CE5GryXuuQmGxJaC2QqOkRAWQDzLDx9nG+rKiEs5OvlfEZC7EV1PyjZ93coM
faCVdlAgcFZ5fvd37CjyjKl+1QIDAQABo4IC9DCCAvAwggEEBggrBgEFBQcBAQSB9zCB9DAy
BggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9aWlpaWlpBNi5jcnQwQQYI
KwYBBQUHMAKGNWxkYXA6Ly9hbC5zaWVtZW5zLm5ldC9DTj1aWlpaWlpBNixMPVBLST9jQUNl
cnRpZmljYXRlMEkGCCsGAQUFBzAChj1sZGFwOi8vYWwuc2llbWVucy5jb20vQ049WlpaWlpa
QTYsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUFBzABhiRodHRwOi8vb2Nz
cC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wHwYDVR0jBBgwFoAU+BVdRwxsd3tyxAIXkWii
tvdqCUQwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGDSsGAQQBoWkHAgIEAQMwKTAnBggr
BgEFBQcCARYbaHR0cDovL3d3dy5zaWVtZW5zLmNvbS9wa2kvMIHKBgNVHR8EgcIwgb8wgbyg
gbmggbaGJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTYuY3JshkFsZGFwOi8v
Y2wuc2llbWVucy5uZXQvQ049WlpaWlpaQTYsTD1QS0k/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
TGlzdIZJbGRhcDovL2NsLnNpZW1lbnMuY29tL0NOPVpaWlpaWkE2LG89VHJ1c3RjZW50ZXI/
Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
AwQwDgYDVR0PAQH/BAQDAgeAMFUGA1UdEQROMEygLAYKKwYBBAGCNxQCA6AeDBxkaWVnby5s
b3V6YW4uZXh0QHNpZW1lbnMuY29tgRxkaWVnby5sb3V6YW4uZXh0QHNpZW1lbnMuY29tMB0G
A1UdDgQWBBQj8k8aqZey68w8ALYKGJSGMt5hZDANBgkqhkiG9w0BAQsFAAOCAgEAFDHqxpb1
R9cB4noC9vx09bkNbmXCpVfl3XCQUmAWTznC0nwEssTTjo0PWuIV4C3jnsp0MRUeHZ6lsyhZ
OzS1ETwYgvj6wzjb8RF3wgn7N/JOvFGaErMz5HZpKOfzGiNpW6/Rmd4hsRDjAwOVQOXUTqc/
0Bj3FMoLRCSWSnTp5HdyvrY2xOKHfTrTjzmcLdFaKE2F5n7+dBkwCKVfzut8CqfVq/I7ks4m
D1IHk93/P6l9U34R2FHPt6zRTNZcWmDirRSlMH4L18CnfiNPuDN/PtRYlt3Vng5EdYN0VCg2
NM/uees0U4ingCb0NFjg66uQ/tjfPQk55MN4Wpls4N6TkMoTCWLiqZzYTGdmVQexzroL6940
tmMr8LoN3TpPf0OdvdKEpyH7fzsx5QlmQyywIWec6X+Fx6+l0g91VJnPEtqACpfZIBZtviHl
gfX298w+SsvBK8C48Pqs8Ijh7tLrCxx7VMLVHZqwWWPK53ga+CDWmjoSQPxi+CPZF7kao6N5
4GrJWwSHlHh6WzTbLyLvTJZZ775Utp4W8s8xMUsQJ413iYzEaC8FcSeNjSk5UiDDiHrKmzpM
tbApD3pUXStblUMKYGTG1Mj9BcEBFkCdoGlw/ulszIrKFfOyRNDG3Ay+Dj/oMjoKsJphu3px
wyft82rTer7UW/I7o0h0DAG4lkMwggdrMIIFU6ADAgECAgR5nlqfMA0GCSqGSIb3DQEBCwUA
MIGeMQswCQYDVQQGEwJERTEPMA0GA1UECAwGQmF5ZXJuMREwDwYDVQQHDAhNdWVuY2hlbjEQ
MA4GA1UECgwHU2llbWVuczERMA8GA1UEBRMIWlpaWlpaQTMxHTAbBgNVBAsMFFNpZW1lbnMg
VHJ1c3QgQ2VudGVyMScwJQYDVQQDDB5TaWVtZW5zIElzc3VpbmcgQ0EgRUUgRW5jIDIwMTYw
HhcNMTkwOTI3MDgwMTM5WhcNMjAwOTI3MDgwMTM3WjB3MREwDwYDVQQFEwhaMDAzSDA4VDEO
MAwGA1UEKgwFRGllZ28xGDAWBgNVBAQMD0xvdXphbiBNYXJ0aW5lejEYMBYGA1UECgwPU2ll
bWVucy1QYXJ0bmVyMR4wHAYDVQQDDBVMb3V6YW4gTWFydGluZXogRGllZ28wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyby5qKzZIrGYWRqxnaAyMt/a/uc0uMk0F3MjwxvPM
vh5DllUpqx0l8ZDakDjPhlEXTeoL4DHNgmh+CDCs76CppM3cNG/1W1Ajo/L2iwMoXaxYuQ/F
q7ED+02KEkWX2DDVVG3fhrUGP20QAq77xPDptmVWZnUnuobZBNYkC49Xfl9HJvkJL8P0+Jqb
Eae7p4roiEr7wNkGriwrVXgA3oPNF/W+OuI76JTNTajS/6PAK/GeqIvLjfuBXpdBZTY031nE
Cztca8vI1jUjQzVhS+0dWpvpfhkVumbvOnid8DI9lapYsX8dpZFsa3ya+T3tjUdGSOOKi0kg
lWf/XYyyfhmDAgMBAAGjggLVMIIC0TAdBgNVHQ4EFgQUprhTCDwNLfPImpSfWdq+QvPTo9Mw
JwYDVR0RBCAwHoEcZGllZ28ubG91emFuLmV4dEBzaWVtZW5zLmNvbTAOBgNVHQ8BAf8EBAMC
BDAwLAYDVR0lBCUwIwYIKwYBBQUHAwQGCisGAQQBgjcKAwQGCysGAQQBgjcKAwQBMIHKBgNV
HR8EgcIwgb8wgbyggbmggbaGJmh0dHA6Ly9jaC5zaWVtZW5zLmNvbS9wa2k/WlpaWlpaQTMu
Y3JshkFsZGFwOi8vY2wuc2llbWVucy5uZXQvQ049WlpaWlpaQTMsTD1QS0k/Y2VydGlmaWNh
dGVSZXZvY2F0aW9uTGlzdIZJbGRhcDovL2NsLnNpZW1lbnMuY29tL0NOPVpaWlpaWkEzLG89
VHJ1c3RjZW50ZXI/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDBFBgNVHSAEPjA8MDoGDSsG
AQQBoWkHAgIEAQMwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5zaWVtZW5zLmNvbS9wa2kv
MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUoassbqB68NPCTeof8R4hivwMre8wggEEBggr
BgEFBQcBAQSB9zCB9DAyBggrBgEFBQcwAoYmaHR0cDovL2FoLnNpZW1lbnMuY29tL3BraT9a
WlpaWlpBMy5jcnQwQQYIKwYBBQUHMAKGNWxkYXA6Ly9hbC5zaWVtZW5zLm5ldC9DTj1aWlpa
WlpBMyxMPVBLST9jQUNlcnRpZmljYXRlMEkGCCsGAQUFBzAChj1sZGFwOi8vYWwuc2llbWVu
cy5jb20vQ049WlpaWlpaQTMsbz1UcnVzdGNlbnRlcj9jQUNlcnRpZmljYXRlMDAGCCsGAQUF
BzABhiRodHRwOi8vb2NzcC5wa2ktc2VydmljZXMuc2llbWVucy5jb20wDQYJKoZIhvcNAQEL
BQADggIBAF98ZMNg28LgkwdjOdvOGbC1QitsWjZTyotmQESF0nClDLUhb0O5675vVixntbrf
eB8xy1+KRiadk40GnAIJ0YzmNl4Tav6hPYv9VBWe5olsWG7C4qB3Q/SwhvW/e+owxv1cBra8
R3oRudiN81eTZQHyNghRephVqQG/dpPYqydoANfIhEpHa79QlpaCAeYl4896AZOS8HYbkDFs
hLdv7sEHtl79YuSWI1wBjbJl70c0Sb4wLRgCPuHyQj2Uw/vQ5xJlEvBDZAIXXe1TP/nqiuY6
7nweJbbeqfFE6ZP3kCe+mEIWGSaO0iThZyLGer8fHs1XiEmhhPgvC7P7KodzpXU6+hX+ZzbD
DxEjFfetV5sh0aNSXG9xx4hZmS9bpImBGR8MvZ7cgxqItvLtY2xvfUbYW244d4RcWesaCDq3
ZEIo6uCIzOzJAwjUdLIac+lLV0rxiHmb7O3cQ19kjpWDB31hmfrus/TKJ55pBKVWBX5m/mFv
K8Ep5USpGrNS0EzOP7I1kQZv2VsvAhSxk/m5FMLpDy8T0O8YgbLypTXoeJFWCF6RduSjVsaZ
lkAtTQYud683pjyOMxJXaQUYGU1PmEYSOonMkVsT9aBcxYkXLp+Ln/+8G0OCYu7dRdwnj+Ut
7yR/ltxtgDcaFApCb0qBTKbgbqZk1fASmkOp+kbdYmoUMYICVjCCAlICAQEwgb8wgbYxCzAJ
BgNVBAYTAkRFMQ8wDQYDVQQIDAZCYXllcm4xETAPBgNVBAcMCE11ZW5jaGVuMRAwDgYDVQQK
DAdTaWVtZW5zMREwDwYDVQQFEwhaWlpaWlpBNjEdMBsGA1UECwwUU2llbWVucyBUcnVzdCBD
ZW50ZXIxPzA9BgNVBAMMNlNpZW1lbnMgSXNzdWluZyBDQSBNZWRpdW0gU3RyZW5ndGggQXV0
aGVudGljYXRpb24gMjAxNgIEZ5a6PTANBglghkgBZQMEAgEFAKBpMC8GCSqGSIb3DQEJBDEi
BCAOR58AbNfSrI+vtMs+dgAQtn3IVZ3RjYC5hz3j9k+6TTAYBgkqhkiG9w0BCQMxCwYJKoZI
hvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMDAyMTcyMTU2NDdaMA0GCSqGSIb3DQEBAQUABIIB
AHLSBcFHhNHPevbwqvA2ecuVb/aKnj45CFF6l8esP1H5DRm1ee5qMKuIS84NFuFC9RUENNhW
DBzsB+BVGz64o1f8QgIklYVrIJ4JZ0q1abNG7NbkVKWIpS3CQo//YWShUTYg+JpKx4YbahGR
sP5zbufbU4eagrrqBChjPTLy+njdjwCNu0XPykBTKOOf6BMjnS33AYjHJyh83JOY7rw3IDLx
8POQH4g5EMRpl9354s0rEkIezMt7pfUAsqY3QnQ8hvlE4KTikPQ+tvLMK1l/ffcLAP8BdBNI
YA3ikb3qCoGNSLKieYzNnBPhNOIJELUtEEaljAFZYMQzMKCbI4JdiDs=
--B_3664825007_1904734766--

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,9 +230,12 @@ 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
nil | false
'javascript://test.atlassian.net/%250dalert(document.domain)' | false
'https://example.com".atlassian.net' | false
nil | false
end
with_them do
@ -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,15 +51,33 @@ 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) }
before do
expect(error_tracking_setting).to receive(:list_sentry_projects)
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)
.and_return({ projects: [] })
end
it 'uses database token' do
expect { subject.execute }.not_to change { error_tracking_setting.token }
end
end
it 'uses database token' do
expect { subject.execute }.not_to change { error_tracking_setting.token }
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

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,30 +127,67 @@ RSpec.describe Projects::ImportService do
project.import_type = 'bitbucket'
end
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|
expect(importer).to receive(:execute).and_return(true)
context 'when importer supports refmap' do
before do
project.import_type = 'gitea'
end
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
expect(service).to receive(:execute).and_return(status: :success)
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
result = subject.execute
it 'fails if repository fetch as mirror fails' do
expect(project).to receive(:ensure_repository)
expect(project.repository)
.to receive(:fetch_as_mirror)
.and_raise(Gitlab::Git::CommandError, 'Failed to import the repository /a/b/c')
expect(result[:status]).to eq :success
result = subject.execute
expect(result[:status]).to eq :error
expect(result[:message]).to eq "Error importing repository #{project.safe_import_url} into #{project.full_path} - Failed to import the repository [FILTERED]"
end
end
it 'fails if repository import fails' do
expect(project.repository)
.to receive(:import_repository)
.and_raise(Gitlab::Git::CommandError, 'Failed to import the repository /a/b/c')
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|
expect(importer).to receive(:execute).and_return(true)
end
result = subject.execute
expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
expect(service).to receive(:execute).and_return(status: :success)
end
expect(result[:status]).to eq :error
expect(result[:message]).to eq "Error importing repository #{project.safe_import_url} into #{project.full_path} - Failed to import the repository [FILTERED]"
result = subject.execute
expect(result[:status]).to eq :success
end
it 'fails if repository import fails' do
expect(project.repository)
.to receive(:import_repository)
.with('https://bitbucket.org/vim/vim.git', resolved_address: '')
.and_raise(Gitlab::Git::CommandError, 'Failed to import the repository /a/b/c')
result = subject.execute
expect(result[:status]).to eq :error
expect(result[:message]).to eq "Error importing repository #{project.safe_import_url} into #{project.full_path} - Failed to import the repository [FILTERED]"
end
end
context 'when lfs import fails' 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,9 +167,24 @@ 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
end

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