Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
fdcaeb38
Commit
fdcaeb38
authored
Jun 03, 2019
by
Yorick Peterse
Browse files
Options
Browse Files
Download
Plain Diff
Merge dev.gitlab.org master into GitLab.com master
parents
3164a4c7
2507ff49
Changes
89
Hide whitespace changes
Inline
Side-by-side
Showing
89 changed files
with
1351 additions
and
214 deletions
+1351
-214
CHANGELOG-EE.md
CHANGELOG-EE.md
+9
-0
CHANGELOG.md
CHANGELOG.md
+18
-0
app/controllers/concerns/milestone_actions.rb
app/controllers/concerns/milestone_actions.rb
+7
-1
app/controllers/sessions_controller.rb
app/controllers/sessions_controller.rb
+9
-0
app/helpers/application_settings_helper.rb
app/helpers/application_settings_helper.rb
+1
-0
app/helpers/notifications_helper.rb
app/helpers/notifications_helper.rb
+4
-0
app/models/application_setting_implementation.rb
app/models/application_setting_implementation.rb
+1
-0
app/models/merge_request.rb
app/models/merge_request.rb
+12
-0
app/models/project.rb
app/models/project.rb
+12
-0
app/views/admin/application_settings/_outbound.html.haml
app/views/admin/application_settings/_outbound.html.haml
+8
-0
app/views/sent_notifications/unsubscribe.html.haml
app/views/sent_notifications/unsubscribe.html.haml
+1
-1
changelogs/unreleased/dm-http-hostname-override.yml
changelogs/unreleased/dm-http-hostname-override.yml
+5
-0
changelogs/unreleased/security-58856-persistent-xss-in-note-objects.yml
...eleased/security-58856-persistent-xss-in-note-objects.yml
+5
-0
changelogs/unreleased/security-60039.yml
changelogs/unreleased/security-60039.yml
+5
-0
changelogs/unreleased/security-fix-confidential-issue-label-visibility-master.yml
...curity-fix-confidential-issue-label-visibility-master.yml
+5
-0
changelogs/unreleased/security-fix-project-existence-disclosure-master.yml
...ased/security-fix-project-existence-disclosure-master.yml
+5
-0
changelogs/unreleased/security-fix_milestones_search_api_leak.yml
...gs/unreleased/security-fix_milestones_search_api_leak.yml
+5
-0
changelogs/unreleased/security-jej-prevent-web-sign-in-bypass.yml
...gs/unreleased/security-jej-prevent-web-sign-in-bypass.yml
+5
-0
changelogs/unreleased/security-unsubscribing-from-issue.yml
changelogs/unreleased/security-unsubscribing-from-issue.yml
+5
-0
config/initializers/hipchat_client_patch.rb
config/initializers/hipchat_client_patch.rb
+3
-3
config/initializers/http_hostname_override.rb
config/initializers/http_hostname_override.rb
+49
-0
db/migrate/20190529142545_add_dns_rebinding_protection_enabled_to_application_settings.rb
...s_rebinding_protection_enabled_to_application_settings.rb
+23
-0
db/schema.rb
db/schema.rb
+1
-0
ee/app/assets/javascripts/sidebar/components/ancestors_tree/ancestors_tree.vue
...ipts/sidebar/components/ancestors_tree/ancestors_tree.vue
+3
-0
ee/app/models/concerns/elastic/application_search.rb
ee/app/models/concerns/elastic/application_search.rb
+27
-21
ee/app/models/concerns/elastic/issues_search.rb
ee/app/models/concerns/elastic/issues_search.rb
+1
-1
ee/app/models/concerns/elastic/merge_requests_search.rb
ee/app/models/concerns/elastic/merge_requests_search.rb
+1
-1
ee/changelogs/unreleased/security-rs-milestone-xss-12-0.yml
ee/changelogs/unreleased/security-rs-milestone-xss-12-0.yml
+5
-0
ee/lib/gitlab/elastic/search_results.rb
ee/lib/gitlab/elastic/search_results.rb
+8
-1
ee/spec/features/groups/billing_spec.rb
ee/spec/features/groups/billing_spec.rb
+9
-1
ee/spec/javascripts/sidebar/ee_ancestor_tree_spec.js
ee/spec/javascripts/sidebar/ee_ancestor_tree_spec.js
+16
-0
ee/spec/lib/gitlab/elastic/search_results_spec.rb
ee/spec/lib/gitlab/elastic/search_results_spec.rb
+107
-17
ee/spec/lib/gitlab/geo/oauth/session_spec.rb
ee/spec/lib/gitlab/geo/oauth/session_spec.rb
+4
-2
ee/spec/services/dependency_proxy/download_blob_service_spec.rb
...c/services/dependency_proxy/download_blob_service_spec.rb
+1
-1
ee/spec/services/dependency_proxy/pull_manifest_service_spec.rb
...c/services/dependency_proxy/pull_manifest_service_spec.rb
+1
-1
ee/spec/services/dependency_proxy/request_token_service_spec.rb
...c/services/dependency_proxy/request_token_service_spec.rb
+1
-1
ee/spec/spec_helper.rb
ee/spec/spec_helper.rb
+2
-0
ee/spec/support/helpers/ee/dependency_proxy_helpers.rb
ee/spec/support/helpers/ee/dependency_proxy_helpers.rb
+5
-3
lib/banzai/redactor.rb
lib/banzai/redactor.rb
+5
-2
lib/gitlab.rb
lib/gitlab.rb
+5
-0
lib/gitlab/git_ref_validator.rb
lib/gitlab/git_ref_validator.rb
+22
-2
lib/gitlab/http.rb
lib/gitlab/http.rb
+1
-1
lib/gitlab/http_connection_adapter.rb
lib/gitlab/http_connection_adapter.rb
+16
-8
lib/gitlab/import_export/attribute_cleaner.rb
lib/gitlab/import_export/attribute_cleaner.rb
+6
-1
lib/gitlab/project_search_results.rb
lib/gitlab/project_search_results.rb
+9
-1
lib/gitlab/search_results.rb
lib/gitlab/search_results.rb
+25
-3
lib/gitlab/url_blocker.rb
lib/gitlab/url_blocker.rb
+62
-13
locale/gitlab.pot
locale/gitlab.pot
+6
-0
spec/controllers/projects/ci/lints_controller_spec.rb
spec/controllers/projects/ci/lints_controller_spec.rb
+3
-1
spec/controllers/projects/milestones_controller_spec.rb
spec/controllers/projects/milestones_controller_spec.rb
+34
-0
spec/controllers/sent_notifications_controller_spec.rb
spec/controllers/sent_notifications_controller_spec.rb
+99
-10
spec/controllers/sessions_controller_spec.rb
spec/controllers/sessions_controller_spec.rb
+33
-1
spec/features/admin/admin_settings_spec.rb
spec/features/admin/admin_settings_spec.rb
+4
-1
spec/features/issuables/issuable_list_spec.rb
spec/features/issuables/issuable_list_spec.rb
+1
-1
spec/features/projects/import_export/export_file_spec.rb
spec/features/projects/import_export/export_file_spec.rb
+1
-1
spec/lib/banzai/redactor_spec.rb
spec/lib/banzai/redactor_spec.rb
+18
-14
spec/lib/gitlab/bitbucket_import/importer_spec.rb
spec/lib/gitlab/bitbucket_import/importer_spec.rb
+1
-0
spec/lib/gitlab/ci/config/external/file/remote_spec.rb
spec/lib/gitlab/ci/config/external/file/remote_spec.rb
+8
-6
spec/lib/gitlab/ci/config/external/mapper_spec.rb
spec/lib/gitlab/ci/config/external/mapper_spec.rb
+3
-1
spec/lib/gitlab/ci/config/external/processor_spec.rb
spec/lib/gitlab/ci/config/external/processor_spec.rb
+13
-7
spec/lib/gitlab/ci/config_spec.rb
spec/lib/gitlab/ci/config_spec.rb
+3
-2
spec/lib/gitlab/ci/yaml_processor_spec.rb
spec/lib/gitlab/ci/yaml_processor_spec.rb
+3
-1
spec/lib/gitlab/git_ref_validator_spec.rb
spec/lib/gitlab/git_ref_validator_spec.rb
+65
-27
spec/lib/gitlab/http_connection_adapter_spec.rb
spec/lib/gitlab/http_connection_adapter_spec.rb
+120
-0
spec/lib/gitlab/http_spec.rb
spec/lib/gitlab/http_spec.rb
+27
-1
spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb
...xport/after_export_strategies/web_upload_strategy_spec.rb
+3
-1
spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
+5
-1
spec/lib/gitlab/import_export/project.json
spec/lib/gitlab/import_export/project.json
+4
-0
spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+20
-0
spec/lib/gitlab/search_results_spec.rb
spec/lib/gitlab/search_results_spec.rb
+23
-0
spec/lib/gitlab/url_blocker_spec.rb
spec/lib/gitlab/url_blocker_spec.rb
+82
-1
spec/lib/gitlab_spec.rb
spec/lib/gitlab_spec.rb
+30
-0
spec/lib/mattermost/session_spec.rb
spec/lib/mattermost/session_spec.rb
+4
-3
spec/models/merge_request_spec.rb
spec/models/merge_request_spec.rb
+34
-0
spec/models/project_services/assembla_service_spec.rb
spec/models/project_services/assembla_service_spec.rb
+4
-2
spec/models/project_services/bamboo_service_spec.rb
spec/models/project_services/bamboo_service_spec.rb
+2
-1
spec/models/project_services/buildkite_service_spec.rb
spec/models/project_services/buildkite_service_spec.rb
+5
-5
spec/models/project_services/campfire_service_spec.rb
spec/models/project_services/campfire_service_spec.rb
+12
-12
spec/models/project_services/pivotaltracker_service_spec.rb
spec/models/project_services/pivotaltracker_service_spec.rb
+6
-4
spec/models/project_services/pushover_service_spec.rb
spec/models/project_services/pushover_service_spec.rb
+4
-2
spec/models/project_services/teamcity_service_spec.rb
spec/models/project_services/teamcity_service_spec.rb
+2
-1
spec/models/project_spec.rb
spec/models/project_spec.rb
+17
-0
spec/requests/api/search_spec.rb
spec/requests/api/search_spec.rb
+42
-4
spec/requests/api/system_hooks_spec.rb
spec/requests/api/system_hooks_spec.rb
+7
-1
spec/services/ci/create_pipeline_service_spec.rb
spec/services/ci/create_pipeline_service_spec.rb
+3
-3
spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
...rvices/projects/lfs_pointers/lfs_download_service_spec.rb
+11
-8
spec/services/submit_usage_ping_service_spec.rb
spec/services/submit_usage_ping_service_spec.rb
+3
-1
spec/services/web_hook_service_spec.rb
spec/services/web_hook_service_spec.rb
+6
-4
spec/support/helpers/stub_requests.rb
spec/support/helpers/stub_requests.rb
+40
-0
No files found.
CHANGELOG-EE.md
View file @
fdcaeb38
...
...
@@ -250,6 +250,15 @@ Please view this file on the master branch, on stable branches it's out of date.
-
Improve project service desk settings. !10381
## 11.9.12 (2019-05-30)
### Security (3 changes, 1 of them is from the community)
-
Filter relative links in wiki for XSS. (kerrizor)
-
Fix XSS in Ancestor tooltip title.
-
Ignore out of range epic IDs.
## 11.9.10 (2019-04-26)
### Security (1 change)
...
...
CHANGELOG.md
View file @
fdcaeb38
...
...
@@ -479,6 +479,24 @@ entry.
-
Removes EE differences for environment_item.vue.
## 11.9.12 (2019-05-30)
### Security (12 changes, 1 of them is from the community)
-
Protect Gitlab::HTTP against DNS rebinding attack.
-
Fix project visibility level validation. (Peter Marko)
-
Update Knative version.
-
Add DNS rebinding protection settings.
-
Prevent XSS injection in note imports.
-
Prevent invalid branch for merge request.
-
Filter relative links in wiki for XSS.
-
Fix confidential issue label disclosure on milestone view.
-
Fix url redaction for issue links.
-
Resolve: Milestones leaked via search API.
-
Prevent bypass of restriction disabling web password sign in.
-
Hide confidential issue title on unsubscribe for anonymous users.
## 11.9.10 (2019-04-26)
### Security (5 changes)
...
...
app/controllers/concerns/milestone_actions.rb
View file @
fdcaeb38
...
...
@@ -26,16 +26,22 @@ module MilestoneActions
end
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def
labels
respond_to
do
|
format
|
format
.
html
{
redirect_to
milestone_redirect_path
}
format
.
json
do
milestone_labels
=
@milestone
.
issue_labels_visible_by_user
(
current_user
)
render
json:
tabs_json
(
"shared/milestones/_labels_tab"
,
{
labels:
@milestone
.
labels
.
map
{
|
label
|
label
.
present
(
issuable_subject:
@milestone
.
parent
)
}
# rubocop:disable Gitlab/ModuleWithInstanceVariables
labels:
milestone_labels
.
map
do
|
label
|
label
.
present
(
issuable_subject:
@milestone
.
parent
)
end
})
end
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
private
...
...
app/controllers/sessions_controller.rb
View file @
fdcaeb38
...
...
@@ -18,6 +18,7 @@ class SessionsController < Devise::SessionsController
prepend_before_action
:store_redirect_uri
,
only:
[
:new
]
prepend_before_action
:ldap_servers
,
only:
[
:new
,
:create
]
prepend_before_action
:require_no_authentication_without_flash
,
only:
[
:new
,
:create
]
prepend_before_action
:ensure_password_authentication_enabled!
,
if: :password_based_login?
,
only:
[
:create
]
before_action
:auto_sign_in_with_provider
,
only:
[
:new
]
before_action
:load_recaptcha
...
...
@@ -138,6 +139,14 @@ class SessionsController < Devise::SessionsController
end
# rubocop: enable CodeReuse/ActiveRecord
def
ensure_password_authentication_enabled!
render_403
unless
Gitlab
::
CurrentSettings
.
password_authentication_enabled_for_web?
end
def
password_based_login?
user_params
[
:login
].
present?
||
user_params
[
:password
].
present?
end
def
user_params
params
.
require
(
:user
).
permit
(
:login
,
:password
,
:remember_me
,
:otp_attempt
,
:device_response
)
end
...
...
app/helpers/application_settings_helper.rb
View file @
fdcaeb38
...
...
@@ -160,6 +160,7 @@ module ApplicationSettingsHelper
:akismet_api_key
,
:akismet_enabled
,
:allow_local_requests_from_hooks_and_services
,
:dns_rebinding_protection_enabled
,
:archive_builds_in_human_readable
,
:authorized_keys_enabled
,
:auto_devops_enabled
,
...
...
app/helpers/notifications_helper.rb
View file @
fdcaeb38
...
...
@@ -100,4 +100,8 @@ module NotificationsHelper
css_class:
"icon notifications-icon js-notifications-icon"
)
end
def
show_unsubscribe_title?
(
noteable
)
can?
(
current_user
,
"read_
#{
noteable
.
to_ability_name
}
"
.
to_sym
,
noteable
)
end
end
app/models/application_setting_implementation.rb
View file @
fdcaeb38
...
...
@@ -21,6 +21,7 @@ module ApplicationSettingImplementation
after_sign_up_text:
nil
,
akismet_enabled:
false
,
allow_local_requests_from_hooks_and_services:
false
,
dns_rebinding_protection_enabled:
true
,
authorized_keys_enabled:
true
,
# TODO default to false if the instance is configured to use AuthorizedKeysCommand
container_registry_token_expire_delay:
5
,
default_artifacts_expire_in:
'30 days'
,
...
...
app/models/merge_request.rb
View file @
fdcaeb38
...
...
@@ -591,6 +591,8 @@ class MergeRequest < ApplicationRecord
return
end
[
:source_branch
,
:target_branch
].
each
{
|
attr
|
validate_branch_name
(
attr
)
}
if
opened?
similar_mrs
=
target_project
.
merge_requests
...
...
@@ -611,6 +613,16 @@ class MergeRequest < ApplicationRecord
end
end
def
validate_branch_name
(
attr
)
return
unless
changes_include?
(
attr
)
branch
=
read_attribute
(
attr
)
return
unless
branch
errors
.
add
(
attr
)
unless
Gitlab
::
GitRefValidator
.
validate_merge_request_branch
(
branch
)
end
def
validate_target_project
return
true
if
target_project
.
merge_requests_enabled?
...
...
app/models/project.rb
View file @
fdcaeb38
...
...
@@ -407,6 +407,7 @@ class Project < ApplicationRecord
scope
:with_builds_enabled
,
->
{
with_feature_enabled
(
:builds
)
}
scope
:with_issues_enabled
,
->
{
with_feature_enabled
(
:issues
)
}
scope
:with_issues_available_for_user
,
->
(
current_user
)
{
with_feature_available_for_user
(
:issues
,
current_user
)
}
scope
:with_merge_requests_available_for_user
,
->
(
current_user
)
{
with_feature_available_for_user
(
:merge_requests
,
current_user
)
}
scope
:with_merge_requests_enabled
,
->
{
with_feature_enabled
(
:merge_requests
)
}
scope
:with_remote_mirrors
,
->
{
joins
(
:remote_mirrors
).
where
(
remote_mirrors:
{
enabled:
true
}).
distinct
}
...
...
@@ -597,6 +598,17 @@ class Project < ApplicationRecord
def
group_ids
joins
(
:namespace
).
where
(
namespaces:
{
type:
'Group'
}).
select
(
:namespace_id
)
end
# Returns ids of projects with milestones available for given user
#
# Used on queries to find milestones which user can see
# For example: Milestone.where(project_id: ids_with_milestone_available_for(user))
def
ids_with_milestone_available_for
(
user
)
with_issues_enabled
=
with_issues_available_for_user
(
user
).
select
(
:id
)
with_merge_requests_enabled
=
with_merge_requests_available_for_user
(
user
).
select
(
:id
)
from_union
([
with_issues_enabled
,
with_merge_requests_enabled
]).
select
(
:id
)
end
end
def
all_pipelines
...
...
app/views/admin/application_settings/_outbound.html.haml
View file @
fdcaeb38
...
...
@@ -8,4 +8,12 @@
=
f
.
label
:allow_local_requests_from_hooks_and_services
,
class:
'form-check-label'
do
Allow requests to the local network from hooks and services
.form-group
.form-check
=
f
.
check_box
:dns_rebinding_protection_enabled
,
class:
'form-check-input'
=
f
.
label
:dns_rebinding_protection_enabled
,
class:
'form-check-label'
do
=
_
(
'Enforce DNS rebinding attack protection'
)
%span
.form-text.text-muted
=
_
(
'Resolves IP addresses once and uses them to submit requests'
)
=
f
.
submit
'Save changes'
,
class:
"btn btn-success"
app/views/sent_notifications/unsubscribe.html.haml
View file @
fdcaeb38
-
noteable
=
@sent_notification
.
noteable
-
noteable_type
=
@sent_notification
.
noteable_type
.
titleize
.
downcase
-
noteable_text
=
%(#{noteable.title} (#{noteable.to_reference})
)
-
noteable_text
=
show_unsubscribe_title?
(
noteable
)
?
%(#{noteable.title} (#{noteable.to_reference}))
:
%(#{noteable.to_reference}
)
-
page_title
_
(
"Unsubscribe"
),
noteable_text
,
noteable_type
.
pluralize
,
@sent_notification
.
project
.
full_name
%h3
.page-title
...
...
changelogs/unreleased/dm-http-hostname-override.yml
0 → 100644
View file @
fdcaeb38
---
title
:
Protect Gitlab::HTTP against DNS rebinding attack
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-58856-persistent-xss-in-note-objects.yml
0 → 100644
View file @
fdcaeb38
---
title
:
Prevent XSS injection in note imports
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-60039.yml
0 → 100644
View file @
fdcaeb38
---
title
:
Prevent invalid branch for merge request
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-fix-confidential-issue-label-visibility-master.yml
0 → 100644
View file @
fdcaeb38
---
title
:
Fix confidential issue label disclosure on milestone view
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-fix-project-existence-disclosure-master.yml
0 → 100644
View file @
fdcaeb38
---
title
:
Fix url redaction for issue links
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-fix_milestones_search_api_leak.yml
0 → 100644
View file @
fdcaeb38
---
title
:
'
Resolve:
Milestones
leaked
via
search
API'
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-jej-prevent-web-sign-in-bypass.yml
0 → 100644
View file @
fdcaeb38
---
title
:
Prevent bypass of restriction disabling web password sign in
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-unsubscribing-from-issue.yml
0 → 100644
View file @
fdcaeb38
---
title
:
Hide confidential issue title on unsubscribe for anonymous users
merge_request
:
author
:
type
:
security
config/initializers/hipchat_client_patch.rb
View file @
fdcaeb38
...
...
@@ -2,14 +2,14 @@
# This monkey patches the HTTParty used in https://github.com/hipchat/hipchat-rb.
module
HipChat
class
Client
connection_adapter
::
Gitlab
::
Proxy
HTTPConnectionAdapter
connection_adapter
::
Gitlab
::
HTTPConnectionAdapter
end
class
Room
connection_adapter
::
Gitlab
::
Proxy
HTTPConnectionAdapter
connection_adapter
::
Gitlab
::
HTTPConnectionAdapter
end
class
User
connection_adapter
::
Gitlab
::
Proxy
HTTPConnectionAdapter
connection_adapter
::
Gitlab
::
HTTPConnectionAdapter
end
end
config/initializers/http_hostname_override.rb
0 → 100644
View file @
fdcaeb38
# This override allows passing `@hostname_override` to the SNI protocol,
# which is used to lookup the correct SSL certificate in the
# request handshake process.
#
# Given we've forced the HTTP request to be sent to the resolved
# IP address in a few scenarios (e.g.: `Gitlab::HTTP` through
# `Gitlab::UrlBlocker.validate!`), we need to provide the _original_
# hostname via SNI in order to have a clean connection setup.
#
# This is ultimately needed in order to avoid DNS rebinding attacks
# through HTTP requests.
#
class
OpenSSL::SSL::SSLContext
attr_accessor
:hostname_override
end
class
OpenSSL::SSL::SSLSocket
module
HostnameOverride
# rubocop: disable Gitlab/ModuleWithInstanceVariables
def
hostname
=
(
hostname
)
super
(
@context
.
hostname_override
||
hostname
)
end
def
post_connection_check
(
hostname
)
super
(
@context
.
hostname_override
||
hostname
)
end
# rubocop: enable Gitlab/ModuleWithInstanceVariables
end
prepend
HostnameOverride
end
class
Net::HTTP
attr_accessor
:hostname_override
SSL_IVNAMES
<<
:@hostname_override
SSL_ATTRIBUTES
<<
:hostname_override
module
HostnameOverride
def
addr_port
return
super
unless
hostname_override
addr
=
hostname_override
default_port
=
use_ssl?
?
Net
::
HTTP
.
https_default_port
:
Net
::
HTTP
.
http_default_port
default_port
==
port
?
addr
:
"
#{
addr
}
:
#{
port
}
"
end
end
prepend
HostnameOverride
end
db/migrate/20190529142545_add_dns_rebinding_protection_enabled_to_application_settings.rb
0 → 100644
View file @
fdcaeb38
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class
AddDnsRebindingProtectionEnabledToApplicationSettings
<
ActiveRecord
::
Migration
[
5.1
]
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
disable_ddl_transaction!
def
up
add_column_with_default
(
:application_settings
,
:dns_rebinding_protection_enabled
,
:boolean
,
default:
true
,
allow_null:
false
)
end
def
down
remove_column
(
:application_settings
,
:dns_rebinding_protection_enabled
)
end
end
db/schema.rb
View file @
fdcaeb38
...
...
@@ -225,6 +225,7 @@ ActiveRecord::Schema.define(version: 20190530154715) do
t
.
integer
"elasticsearch_replicas"
,
default:
1
,
null:
false
t
.
text
"encrypted_lets_encrypt_private_key"
t
.
text
"encrypted_lets_encrypt_private_key_iv"
t
.
boolean
"dns_rebinding_protection_enabled"
,
default:
true
,
null:
false
t
.
index
[
"custom_project_templates_group_id"
],
name:
"index_application_settings_on_custom_project_templates_group_id"
,
using: :btree
t
.
index
[
"file_template_project_id"
],
name:
"index_application_settings_on_file_template_project_id"
,
using: :btree
t
.
index
[
"usage_stats_set_by_user_id"
],
name:
"index_application_settings_on_usage_stats_set_by_user_id"
,
using: :btree
...
...
ee/app/assets/javascripts/sidebar/components/ancestors_tree/ancestors_tree.vue
View file @
fdcaeb38
<
script
>
import
{
GlLoadingIcon
,
GlLink
,
GlTooltip
}
from
'
@gitlab/ui
'
;
import
{
escape
}
from
'
underscore
'
;
import
{
__
}
from
'
~/locale
'
;
import
Icon
from
'
~/vue_shared/components/icon.vue
'
;
...
...
@@ -38,6 +39,8 @@ export default {
// Fallback to None if immediate parent is unavailable.
let
{
title
}
=
immediateParent
;
title
=
escape
(
title
);
const
{
humanReadableEndDate
,
humanReadableTimestamp
}
=
immediateParent
;
if
(
humanReadableEndDate
||
humanReadableTimestamp
)
{
...
...
ee/app/models/concerns/elastic/application_search.rb
View file @
fdcaeb38
...
...
@@ -371,7 +371,7 @@ module Elastic
options
[
:current_user
],
options
[
:project_ids
],
options
[
:public_and_internal_projects
],
options
[
:feature
]
options
[
:feature
s
]
)
query_hash
[
:query
][
:bool
][
:filter
]
||=
[]
...
...
@@ -390,10 +390,10 @@ module Elastic
# Builds an elasticsearch query that will select projects the user is
# granted access to.
#
# If a project feature is specified, it indicates interest in child
# If a project feature
(s)
is specified, it indicates interest in child
# documents gated by that project feature - e.g., "issues". The feature's
# visibility level must be taken into account.
def
project_ids_query
(
user
,
project_ids
,
public_and_internal_projects
,
feature
=
nil
)
def
project_ids_query
(
user
,
project_ids
,
public_and_internal_projects
,
feature
s
=
nil
)
# When reading cross project is not allowed, only allow searching a
# a single project, so the `:read_*` ability is only checked once.
unless
Ability
.
allowed?
(
user
,
:read_cross_project
)
...
...
@@ -404,18 +404,18 @@ module Elastic
# anonymous users.
# Pick private, internal and public projects the user is a member of.
# Pick all private projects for admins & auditors.
conditions
=
[
pick_projects_by_membership
(
project_ids
,
feature
)]
conditions
=
[
pick_projects_by_membership
(
project_ids
,
feature
s
)]
if
public_and_internal_projects
# Skip internal projects for anonymous and external users.
# Others are given access to all internal projects. Admins & auditors
# get access to internal projects where the feature is private.
conditions
<<
pick_projects_by_visibility
(
Project
::
INTERNAL
,
user
,
feature
)
if
user
&&
!
user
.
external?
conditions
<<
pick_projects_by_visibility
(
Project
::
INTERNAL
,
user
,
feature
s
)
if
user
&&
!
user
.
external?
# All users, including anonymous, can access public projects.
# Admins & auditors get access to public projects where the feature is
# private.
conditions
<<
pick_projects_by_visibility
(
Project
::
PUBLIC
,
user
,
feature
)
conditions
<<
pick_projects_by_visibility
(
Project
::
PUBLIC
,
user
,
feature
s
)
end
{
should:
conditions
}
...
...
@@ -430,7 +430,7 @@ module Elastic
# Admins & auditors are given access to all private projects. Access to
# internal or public projects where the project feature is private is not
# granted here.
def
pick_projects_by_membership
(
project_ids
,
feature
=
nil
)
def
pick_projects_by_membership
(
project_ids
,
feature
s
=
nil
)
condition
=
if
project_ids
==
:any
{
term:
{
visibility_level:
Project
::
PRIVATE
}
}
...
...
@@ -438,37 +438,43 @@ module Elastic
{
terms:
{
id:
project_ids
}
}
end
limit_by_feature
(
condition
,
feature
,
include_members_only:
true
)
limit_by_feature
(
condition
,
feature
s
,
include_members_only:
true
)
end
# Grant access to projects of the specified visibility level to the user.
#
# If a project feature is specified, access is only granted if the feature
# is enabled or, for admins & auditors, private.
def
pick_projects_by_visibility
(
visibility
,
user
,
feature
)
def
pick_projects_by_visibility
(
visibility
,
user
,
feature
s
)
condition
=
{
term:
{
visibility_level:
visibility
}
}
limit_by_feature
(
condition
,
feature
,
include_members_only:
user
&
.
full_private_access?
)
limit_by_feature
(
condition
,
feature
s
,
include_members_only:
user
&
.
full_private_access?
)
end
# If a project feature is specified, access is dependent on its visibility
# If a project feature
(s)
is specified, access is dependent on its visibility
# level being enabled (or private if `include_members_only: true`).
#
# This method is a no-op if no project feature is specified.
# It accepts an array of features or a single feature, when an array is provided
# it queries if any of the features is enabled.
#
# Always denies access to projects when the feature
is
disabled - even to
# Always denies access to projects when the feature
s are
disabled - even to
# admins & auditors - as stale child documents may be present.
def
limit_by_feature
(
condition
,
feature
,
include_members_only
:)
return
condition
unless
feature
def
limit_by_feature
(
condition
,
feature
s
,
include_members_only
:)
return
condition
unless
feature
s
limit
=
if
include_members_only
{
terms:
{
"
#{
feature
}
_access_level"
=>
[
::
ProjectFeature
::
ENABLED
,
::
ProjectFeature
::
PRIVATE
]
}
}
else
{
term:
{
"
#{
feature
}
_access_level"
=>
::
ProjectFeature
::
ENABLED
}
}
end
features
=
Array
(
features
)
{
bool:
{
filter:
[
condition
,
limit
]
}
}
features
.
map
do
|
feature
|
limit
=
if
include_members_only
{
terms:
{
"
#{
feature
}
_access_level"
=>
[
::
ProjectFeature
::
ENABLED
,
::
ProjectFeature
::
PRIVATE
]
}
}
else
{
term:
{
"
#{
feature
}
_access_level"
=>
::
ProjectFeature
::
ENABLED
}
}
end
{
bool:
{
filter:
[
condition
,
limit
]
}
}
end
end
end
end
...
...
ee/app/models/concerns/elastic/issues_search.rb
View file @
fdcaeb38
...
...
@@ -33,7 +33,7 @@ module Elastic
basic_query_hash
(
%w(title^2 description)
,
query
)
end
options
[
:feature
]
=
'issues'
options
[
:feature
s
]
=
'issues'
query_hash
=
project_ids_filter
(
query_hash
,
options
)
query_hash
=
confidentiality_filter
(
query_hash
,
options
[
:current_user
])
...
...
ee/app/models/concerns/elastic/merge_requests_search.rb
View file @
fdcaeb38
...
...
@@ -49,7 +49,7 @@ module Elastic
basic_query_hash
(
%w(title^2 description)
,
query
)
end
options
[
:feature
]
=
'merge_requests'
options
[
:feature
s
]
=
'merge_requests'
query_hash
=
project_ids_filter
(
query_hash
,
options
)
self
.
__elasticsearch__
.
search
(
query_hash
)
...
...
ee/changelogs/unreleased/security-rs-milestone-xss-12-0.yml
0 → 100644
View file @
fdcaeb38
---
title
:
Fix XSS in Ancestor tooltip title
merge_request
:
author
:
type
:
security
ee/lib/gitlab/elastic/search_results.rb
View file @
fdcaeb38
...
...
@@ -150,7 +150,14 @@ module Gitlab
end
def
milestones
Milestone
.
elastic_search
(
query
,
options:
base_options
)
# Must pass 'issues' and 'merge_requests' to check
# if any of the features is available for projects in Elastic::ApplicationSearch#project_ids_query
# Otherwise it will ignore project_ids and return milestones
# from projects with milestones disabled.
options
=
base_options
options
[
:features
]
=
[
:issues
,
:merge_requests
]
Milestone
.
elastic_search
(
query
,
options:
options
)
end
def
merge_requests
...
...
ee/spec/features/groups/billing_spec.rb
View file @
fdcaeb38
require
'spec_helper'
describe
'Groups > Billing'
,
:js
do
include
StubRequests
let!
(
:user
)
{
create
(
:user
)
}
let!
(
:group
)
{
create
(
:group
)
}
let!
(
:bronze_plan
)
{
create
(
:bronze_plan
)
}
before
do
stub_
request
(
:get
,
%r{https://customers.gitlab.com/gitlab_plans}
)
stub_
full_request
(
"https://customers.gitlab.com/gitlab_plans?plan=
#{
plan
}
"
)
.
to_return
(
status:
200
,
body:
File
.
new
(
Rails
.
root
.
join
(
'ee/spec/fixtures/gitlab_com_plans.json'
)))
stub_application_setting
(
check_namespace_plan:
true
)
...
...
@@ -16,6 +18,8 @@ describe 'Groups > Billing', :js do
end
context
'with a free plan'
do
let
(
:plan
)
{
'free'
}
before
do
create
(
:gitlab_subscription
,
namespace:
group
,
hosted_plan:
nil
,
seats:
15
)
end
...
...
@@ -28,6 +32,8 @@ describe 'Groups > Billing', :js do
end
context
'with a paid plan'
do
let
(
:plan
)
{
'bronze'
}
before
do
create
(
:gitlab_subscription
,
namespace:
group
,
hosted_plan:
bronze_plan
,
seats:
15
)
end
...
...
@@ -40,6 +46,8 @@ describe 'Groups > Billing', :js do
end
context
'with a legacy paid plan'
do
let
(
:plan
)
{
'bronze'
}
before
do
group
.
update_attribute
(
:plan
,
bronze_plan
)
end
...
...
ee/spec/javascripts/sidebar/ee_ancestor_tree_spec.js
View file @
fdcaeb38
import
Vue
from
'
vue
'
;
import
{
escape
}
from
'
underscore
'
;
import
ancestorsTree
from
'
ee/sidebar/components/ancestors_tree/ancestors_tree.vue
'
;
import
mountComponent
from
'
spec/helpers/vue_mount_component_helper
'
;
...
...
@@ -59,4 +60,19 @@ describe('AncestorsTreeContainer', () => {
.
then
(
done
)
.
catch
(
done
.
fail
);
});
it
(
'
escapes html in the tooltip
'
,
done
=>
{
const
title
=
'
<script>alert(1);</script>
'
;
const
escapedTitle
=
escape
(
title
);
vm
.
$props
.
ancestors
=
[{
id
:
1
,
url
:
''
,
title
,
state
:
'
open
'
}];
vm
.
$nextTick
()
.
then
(()
=>
{
const
tooltip
=
vm
.
$el
.
querySelector
(
'
.collapse-truncated-title
'
);
expect
(
tooltip
.
innerText
).
toBe
(
escapedTitle
);
})
.
then
(
done
)
.
catch
(
done
.
fail
);
});
});
ee/spec/lib/gitlab/elastic/search_results_spec.rb
View file @
fdcaeb38
...
...
@@ -379,6 +379,7 @@ describe Gitlab::Elastic::SearchResults do
describe
'project scoping'
do
it
"returns items for project"
do
project
=
create
:project
,
:repository
,
name:
"term"
project
.
add_developer
(
user
)
# Create issue
create
:issue
,
title:
'bla-bla term'
,
project:
project
...
...
@@ -686,29 +687,118 @@ describe Gitlab::Elastic::SearchResults do
end
context
'Milestones'
do
it
'finds right set of milestine'
do
milestone_1
=
create
:milestone
,
project:
internal_project
,
title:
"Internal project"
create
:milestone
,
project:
private_project1
,
title:
"Private project"
milestone_3
=
create
:milestone
,
project:
private_project2
,
title:
"Private project where I'm a member"
milestone_4
=
create
:milestone
,
project:
public_project
,
title:
"Public project"
let!
(
:milestone_1
)
{
create
(
:milestone
,
project:
internal_project
,
title:
"Internal project"
)
}
let!
(
:milestone_2
)
{
create
(
:milestone
,
project:
private_project1
,
title:
"Private project"
)
}
let!
(
:milestone_3
)
{
create
(
:milestone
,
project:
private_project2
,
title:
"Private project which user is member"
)
}
let!
(
:milestone_4
)
{
create
(
:milestone
,
project:
public_project
,
title:
"Public project"
)
}
before
do
Gitlab
::
Elastic
::
Helper
.
refresh_index
end
# Authenticated search
results
=
described_class
.
new
(
user
,
'project'
,
limit_project_ids
)
milestones
=
results
.
objects
(
'milestones'
)
context
'when project ids are present'
do
context
'when authenticated'
do
context
'when user and merge requests are disabled in a project'
do
it
'returns right set of milestones'
do
private_project2
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
PRIVATE
)
private_project2
.
project_feature
.
update!
(
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
public_project
.
project_feature
.
update!
(
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
public_project
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
PRIVATE
)
internal_project
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
DISABLED
)
Gitlab
::
Elastic
::
Helper
.
refresh_index
project_ids
=
user
.
authorized_projects
.
pluck
(
:id
)
results
=
described_class
.
new
(
user
,
'project'
,
project_ids
)
milestones
=
results
.
objects
(
'milestones'
)
expect
(
milestones
).
to
match_array
([
milestone_1
,
milestone_3
])
end
end
context
'when user is admin'
do
it
'returns right set of milestones'
do
user
.
update
(
admin:
true
)
public_project
.
project_feature
.
update!
(
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
public_project
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
PRIVATE
)
internal_project
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
DISABLED
)
internal_project
.
project_feature
.
update!
(
merge_requests_access_level:
ProjectFeature
::
DISABLED
)
Gitlab
::
Elastic
::
Helper
.
refresh_index
results
=
described_class
.
new
(
user
,
'project'
,
:any
)
milestones
=
results
.
objects
(
'milestones'
)
expect
(
milestones
).
to
match_array
([
milestone_2
,
milestone_3
,
milestone_4
])
end
end
context
'when user can read milestones'
do
it
'returns right set of milestones'
do
# Authenticated search
project_ids
=
user
.
authorized_projects
.
pluck
(
:id
)
results
=
described_class
.
new
(
user
,
'project'
,
project_ids
)
milestones
=
results
.
objects
(
'milestones'
)
expect
(
milestones
).
to
match_array
([
milestone_1
,
milestone_3
,
milestone_4
])
end
end
end
end
expect
(
milestones
).
to
include
milestone_1
expect
(
milestones
).
to
include
milestone_3
expect
(
milestones
).
to
include
milestone_4
expect
(
results
.
milestones_count
).
to
eq
3
context
'when not authenticated'
do
it
'returns right set of milestones'
do
results
=
described_class
.
new
(
nil
,
'project'
,
[])
milestones
=
results
.
objects
(
'milestones'
)
# Unauthenticated search
results
=
described_class
.
new
(
nil
,
'project'
,
[])
milestones
=
results
.
objects
(
'milestones'
)
expect
(
milestones
).
to
include
milestone_4
expect
(
results
.
milestones_count
).
to
eq
1
end
end
context
'when project_ids is not present'
do
context
'when project_ids is :any'
do
it
'returns all milestones'
do
results
=
described_class
.
new
(
user
,
'project'
,
:any
)
milestones
=
results
.
objects
(
'milestones'
)
expect
(
milestones
).
to
include
(
milestone_1
)
expect
(
milestones
).
to
include
(
milestone_2
)
expect
(
milestones
).
to
include
(
milestone_3
)
expect
(
milestones
).
to
include
(
milestone_4
)
expect
(
results
.
milestones_count
).
to
eq
(
4
)
end
end
expect
(
milestones
).
to
include
milestone_4
expect
(
results
.
milestones_count
).
to
eq
1
context
'when authenticated'
do
it
'returns right set of milestones'
do
results
=
described_class
.
new
(
user
,
'project'
,
[])
milestones
=
results
.
objects
(
'milestones'
)
expect
(
milestones
).
to
include
(
milestone_1
)
expect
(
milestones
).
to
include
(
milestone_4
)
expect
(
results
.
milestones_count
).
to
eq
(
2
)
end
end
context
'when not authenticated'
do
it
'returns right set of milestones'
do
# Should not be returned because issues and merge requests feature are disabled
other_public_project
=
create
(
:project
,
:public
)
create
(
:milestone
,
project:
other_public_project
,
title:
'Public project milestone 1'
)
other_public_project
.
project_feature
.
update!
(
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
other_public_project
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
PRIVATE
)
# Should be returned because only issues is disabled
other_public_project_1
=
create
(
:project
,
:public
)
milestone_5
=
create
(
:milestone
,
project:
other_public_project_1
,
title:
'Public project milestone 2'
)
other_public_project_1
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
PRIVATE
)
Gitlab
::
Elastic
::
Helper
.
refresh_index
results
=
described_class
.
new
(
nil
,
'project'
,
[])
milestones
=
results
.
objects
(
'milestones'
)
expect
(
milestones
).
to
match_array
([
milestone_4
,
milestone_5
])
expect
(
results
.
milestones_count
).
to
eq
(
2
)
end
end
end
end
...
...
ee/spec/lib/gitlab/geo/oauth/session_spec.rb
View file @
fdcaeb38
...
...
@@ -52,12 +52,14 @@ describe Gitlab::Geo::Oauth::Session, :geo do
context
'primary is configured with relative URL'
do
it
'includes primary relative URL path'
do
primary_node
.
update
(
url:
'http:://localhost/relative-path/'
)
api_url
=
'http://localhost/relative-path/'
primary_node
.
update
(
url:
api_url
)
api_response
=
double
(
parsed:
true
)
expect_any_instance_of
(
OAuth2
::
AccessToken
)
.
to
receive
(
:get
).
with
(
%r{^
http:://localhost/relative-path/
}
).
and_return
(
api_response
)
.
to
receive
(
:get
).
with
(
%r{^
#{
api_url
}
}
).
and_return
(
api_response
)
subject
.
authenticate
(
'any token'
)
end
...
...
ee/spec/services/dependency_proxy/download_blob_service_spec.rb
View file @
fdcaeb38
...
...
@@ -34,7 +34,7 @@ describe DependencyProxy::DownloadBlobService do
before
do
blob_url
=
DependencyProxy
::
Registry
.
blob_url
(
image
,
blob_sha
)
stub_
request
(
:get
,
blob_url
).
to_timeout
stub_
full_request
(
blob_url
).
to_timeout
end
it
{
expect
(
subject
[
:status
]).
to
eq
(
:error
)
}
...
...
ee/spec/services/dependency_proxy/pull_manifest_service_spec.rb
View file @
fdcaeb38
...
...
@@ -34,7 +34,7 @@ describe DependencyProxy::PullManifestService do
before
do
manifest_link
=
DependencyProxy
::
Registry
.
manifest_url
(
image
,
tag
)
stub_
request
(
:get
,
manifest_link
).
to_timeout
stub_
full_request
(
manifest_link
).
to_timeout
end
it
{
expect
(
subject
[
:status
]).
to
eq
(
:error
)
}
...
...
ee/spec/services/dependency_proxy/request_token_service_spec.rb
View file @
fdcaeb38
...
...
@@ -42,7 +42,7 @@ describe DependencyProxy::RequestTokenService do
before
do
auth_link
=
DependencyProxy
::
Registry
.
auth_url
(
image
)
stub_
request
(
:any
,
auth_link
).
to_timeout
stub_
full_request
(
auth_link
,
method: :any
).
to_timeout
end
it
{
expect
(
subject
[
:status
]).
to
eq
(
:error
)
}
...
...
ee/spec/spec_helper.rb
View file @
fdcaeb38
require
Rails
.
root
.
join
(
"spec/support/helpers/stub_requests.rb"
)
Dir
[
Rails
.
root
.
join
(
"ee/spec/support/helpers/*.rb"
)].
each
{
|
f
|
require
f
}
Dir
[
Rails
.
root
.
join
(
"ee/spec/support/shared_contexts/*.rb"
)].
each
{
|
f
|
require
f
}
Dir
[
Rails
.
root
.
join
(
"ee/spec/support/shared_examples/*.rb"
)].
each
{
|
f
|
require
f
}
...
...
ee/spec/support/helpers/ee/dependency_proxy_helpers.rb
View file @
fdcaeb38
...
...
@@ -2,25 +2,27 @@
module
EE
module
DependencyProxyHelpers
include
StubRequests
def
stub_registry_auth
(
image
,
token
,
status
=
200
,
body
=
nil
)
auth_body
=
{
'token'
=>
token
}.
to_json
auth_link
=
registry
.
auth_url
(
image
)
stub_
request
(
:get
,
auth_link
)
stub_
full_request
(
auth_link
)
.
to_return
(
status:
status
,
body:
body
||
auth_body
)
end
def
stub_manifest_download
(
image
,
tag
,
status
=
200
,
body
=
nil
)
manifest_url
=
registry
.
manifest_url
(
image
,
tag
)
stub_
request
(
:get
,
manifest_url
)
stub_
full_request
(
manifest_url
)
.
to_return
(
status:
status
,
body:
body
||
manifest
)
end
def
stub_blob_download
(
image
,
blob_sha
,
status
=
200
,
body
=
'123456'
)
download_link
=
registry
.
blob_url
(
image
,
blob_sha
)
stub_
request
(
:get
,
download_link
)
stub_
full_request
(
download_link
)
.
to_return
(
status:
status
,
body:
body
)
end
...
...
lib/banzai/redactor.rb
View file @
fdcaeb38
...
...
@@ -70,8 +70,11 @@ module Banzai
# Build the raw <a> tag just with a link as href and content if
# it's originally a link pattern. We shouldn't return a plain text href.
original_link
=
if
link_reference
==
'true'
&&
href
=
original_content
%(<a href="#{href}">#{href}</a>)
if
link_reference
==
'true'
href
=
node
.
attr
(
'href'
)
content
=
original_content
%(<a href="#{href}">#{content}</a>)
end
# The reference should be replaced by the original link's content,
...
...
lib/gitlab.rb
View file @
fdcaeb38
...
...
@@ -40,6 +40,7 @@ module Gitlab
SUBDOMAIN_REGEX
=
%r{
\A
https://[a-z0-9]+
\.
gitlab
\.
com
\z
}
.
freeze
VERSION
=
File
.
read
(
root
.
join
(
"VERSION"
)).
strip
.
freeze
INSTALLATION_TYPE
=
File
.
read
(
root
.
join
(
"INSTALLATION_TYPE"
)).
strip
.
freeze
HTTP_PROXY_ENV_VARS
=
%w(http_proxy https_proxy HTTP_PROXY HTTPS_PROXY)
.
freeze
def
self
.
com?
# Check `gl_subdomain?` as well to keep parity with gitlab.com
...
...
@@ -66,6 +67,10 @@ module Gitlab
end
end
def
self
.
http_proxy_env?
HTTP_PROXY_ENV_VARS
.
any?
{
|
name
|
ENV
[
name
]
}
end
def
self
.
process_name
return
'sidekiq'
if
Sidekiq
.
server?
return
'console'
if
defined?
(
Rails
::
Console
)
...
...
lib/gitlab/git_ref_validator.rb
View file @
fdcaeb38
...
...
@@ -5,12 +5,16 @@
module
Gitlab
module
GitRefValidator
extend
self
EXPANDED_PREFIXES
=
%w(refs/heads/ refs/remotes/)
.
freeze
DISALLOWED_PREFIXES
=
%w(-)
.
freeze
# Validates a given name against the git reference specification
#
# Returns true for a valid reference name, false otherwise
def
validate
(
ref_name
)
not_allowed_prefixes
=
%w(refs/heads/ refs/remotes/ -
)
return
false
if
ref_name
.
start_with?
(
*
not_allowed_prefixes
)
return
false
if
ref_name
.
start_with?
(
*
EXPANDED_PREFIXES
)
return
false
if
ref_name
.
start_with?
(
*
DISALLOWED_PREFIXES
)
return
false
if
ref_name
==
'HEAD'
begin
...
...
@@ -19,5 +23,21 @@ module Gitlab
return
false
end
end
def
validate_merge_request_branch
(
ref_name
)
return
false
if
ref_name
.
start_with?
(
*
DISALLOWED_PREFIXES
)
expanded_name
=
if
ref_name
.
start_with?
(
*
EXPANDED_PREFIXES
)
ref_name
else
"refs/heads/
#{
ref_name
}
"
end
begin
Rugged
::
Reference
.
valid_name?
(
expanded_name
)
rescue
ArgumentError
return
false
end
end
end
end
lib/gitlab/http.rb
View file @
fdcaeb38
...
...
@@ -18,7 +18,7 @@ module Gitlab
include
HTTParty
# rubocop:disable Gitlab/HTTParty
connection_adapter
Proxy
HTTPConnectionAdapter
connection_adapter
HTTPConnectionAdapter
def
self
.
perform_request
(
http_method
,
path
,
options
,
&
block
)
super
...
...
lib/gitlab/
proxy_
http_connection_adapter.rb
→
lib/gitlab/http_connection_adapter.rb
View file @
fdcaeb38
...
...
@@ -10,17 +10,19 @@
#
# This option will take precedence over the global setting.
module
Gitlab
class
Proxy
HTTPConnectionAdapter
<
HTTParty
::
ConnectionAdapter
class
HTTPConnectionAdapter
<
HTTParty
::
ConnectionAdapter
def
connection
unless
allow_local_requests?
begin
Gitlab
::
UrlBlocker
.
validate!
(
uri
,
allow_local_network:
false
)
rescue
Gitlab
::
UrlBlocker
::
BlockedUrlError
=>
e
raise
Gitlab
::
HTTP
::
BlockedUrlError
,
"URL '
#{
uri
}
' is blocked:
#{
e
.
message
}
"
end
begin
@uri
,
hostname
=
Gitlab
::
UrlBlocker
.
validate!
(
uri
,
allow_local_network:
allow_local_requests?
,
allow_localhost:
allow_local_requests?
,
dns_rebind_protection:
dns_rebind_protection?
)
rescue
Gitlab
::
UrlBlocker
::
BlockedUrlError
=>
e
raise
Gitlab
::
HTTP
::
BlockedUrlError
,
"URL '
#{
uri
}
' is blocked:
#{
e
.
message
}
"
end
super
super
.
tap
do
|
http
|
http
.
hostname_override
=
hostname
if
hostname
end
end
private
...
...
@@ -29,6 +31,12 @@ module Gitlab
options
.
fetch
(
:allow_local_requests
,
allow_settings_local_requests?
)
end
def
dns_rebind_protection?
return
false
if
Gitlab
.
http_proxy_env?
Gitlab
::
CurrentSettings
.
dns_rebinding_protection_enabled?
end
def
allow_settings_local_requests?
Gitlab
::
CurrentSettings
.
allow_local_requests_from_hooks_and_services?
end
...
...
lib/gitlab/import_export/attribute_cleaner.rb
View file @
fdcaeb38
...
...
@@ -4,6 +4,7 @@ module Gitlab
module
ImportExport
class
AttributeCleaner
ALLOWED_REFERENCES
=
RelationFactory
::
PROJECT_REFERENCES
+
RelationFactory
::
USER_REFERENCES
+
[
'group_id'
]
PROHIBITED_REFERENCES
=
Regexp
.
union
(
/\Acached_markdown_version\Z/
,
/_id\Z/
,
/_html\Z/
).
freeze
def
self
.
clean
(
*
args
)
new
(
*
args
).
clean
...
...
@@ -24,7 +25,11 @@ module Gitlab
private
def
prohibited_key?
(
key
)
key
.
end_with?
(
'_id'
)
&&
!
ALLOWED_REFERENCES
.
include?
(
key
)
key
=~
PROHIBITED_REFERENCES
&&
!
permitted_key?
(
key
)
end
def
permitted_key?
(
key
)
ALLOWED_REFERENCES
.
include?
(
key
)
end
def
excluded_key?
(
key
)
...
...
lib/gitlab/project_search_results.rb
View file @
fdcaeb38
...
...
@@ -134,8 +134,16 @@ module Gitlab
project
.
repository
.
commit
(
key
)
if
Commit
.
valid_hash?
(
key
)
end
# rubocop: disable CodeReuse/ActiveRecord
def
project_ids_relation
project
Project
.
where
(
id:
project
).
select
(
:id
).
reorder
(
nil
)
end
# rubocop: enabled CodeReuse/ActiveRecord
def
filter_milestones_by_project
(
milestones
)
return
Milestone
.
none
unless
Ability
.
allowed?
(
@current_user
,
:read_milestone
,
@project
)
milestones
.
where
(
project_id:
project
.
id
)
# rubocop: disable CodeReuse/ActiveRecord
end
def
repository_project_ref
...
...
lib/gitlab/search_results.rb
View file @
fdcaeb38
...
...
@@ -103,9 +103,11 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def
milestones
milestones
=
Milestone
.
where
(
project_id:
project_ids_relation
)
milestones
=
milestones
.
search
(
query
)
milestones
.
reorder
(
'milestones.updated_at DESC'
)
milestones
=
Milestone
.
search
(
query
)
milestones
=
filter_milestones_by_project
(
milestones
)
milestones
.
reorder
(
'updated_at DESC'
)
end
# rubocop: enable CodeReuse/ActiveRecord
...
...
@@ -123,6 +125,26 @@ module Gitlab
'projects'
end
# Filter milestones by authorized projects.
# For performance reasons project_id is being plucked
# to be used on a smaller query.
#
# rubocop: disable CodeReuse/ActiveRecord
def
filter_milestones_by_project
(
milestones
)
project_ids
=
milestones
.
where
(
project_id:
project_ids_relation
)
.
select
(
:project_id
).
distinct
.
pluck
(
:project_id
)
return
Milestone
.
none
if
project_ids
.
nil?
authorized_project_ids_relation
=
Project
.
where
(
id:
project_ids
).
ids_with_milestone_available_for
(
current_user
)
milestones
.
where
(
project_id:
authorized_project_ids_relation
)
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def
project_ids_relation
limit_projects
.
select
(
:id
).
reorder
(
nil
)
...
...
lib/gitlab/url_blocker.rb
View file @
fdcaeb38
...
...
@@ -8,38 +8,68 @@ module Gitlab
BlockedUrlError
=
Class
.
new
(
StandardError
)
class
<<
self
def
validate!
(
url
,
ports:
[],
schemes:
[],
allow_localhost:
false
,
allow_local_network:
true
,
ascii_only:
false
,
enforce_user:
false
,
enforce_sanitization:
false
)
return
true
if
url
.
nil?
# Validates the given url according to the constraints specified by arguments.
#
# ports - Raises error if the given URL port does is not between given ports.
# allow_localhost - Raises error if URL resolves to a localhost IP address and argument is true.
# allow_local_network - Raises error if URL resolves to a link-local address and argument is true.
# ascii_only - Raises error if URL has unicode characters and argument is true.
# enforce_user - Raises error if URL user doesn't start with alphanumeric characters and argument is true.
# enforce_sanitization - Raises error if URL includes any HTML/CSS/JS tags and argument is true.
#
# Returns an array with [<uri>, <original-hostname>].
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/ParameterLists
def
validate!
(
url
,
ports:
[],
schemes:
[],
allow_localhost:
false
,
allow_local_network:
true
,
ascii_only:
false
,
enforce_user:
false
,
enforce_sanitization:
false
,
dns_rebind_protection:
true
)
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/ParameterLists
return
[
nil
,
nil
]
if
url
.
nil?
# Param url can be a string, URI or Addressable::URI
uri
=
parse_url
(
url
)
validate_html_tags!
(
uri
)
if
enforce_sanitization
# Allow imports from the GitLab instance itself but only from the configured ports
return
true
if
internal?
(
uri
)
hostname
=
uri
.
hostname
port
=
get_port
(
uri
)
validate_scheme!
(
uri
.
scheme
,
schemes
)
validate_port!
(
port
,
ports
)
if
ports
.
any?
validate_user!
(
uri
.
user
)
if
enforce_user
validate_hostname!
(
uri
.
hostname
)
validate_unicode_restriction!
(
uri
)
if
ascii_only
unless
internal?
(
uri
)
validate_scheme!
(
uri
.
scheme
,
schemes
)
validate_port!
(
port
,
ports
)
if
ports
.
any?
validate_user!
(
uri
.
user
)
if
enforce_user
validate_hostname!
(
hostname
)
validate_unicode_restriction!
(
uri
)
if
ascii_only
end
begin
addrs_info
=
Addrinfo
.
getaddrinfo
(
uri
.
hostname
,
port
,
nil
,
:STREAM
).
map
do
|
addr
|
addrs_info
=
Addrinfo
.
getaddrinfo
(
hostname
,
port
,
nil
,
:STREAM
).
map
do
|
addr
|
addr
.
ipv6_v4mapped?
?
addr
.
ipv6_to_ipv4
:
addr
end
rescue
SocketError
return
true
return
[
uri
,
nil
]
end
protected_uri_with_hostname
=
enforce_uri_hostname
(
addrs_info
,
uri
,
hostname
,
dns_rebind_protection
)
# Allow url from the GitLab instance itself but only for the configured hostname and ports
return
protected_uri_with_hostname
if
internal?
(
uri
)
validate_localhost!
(
addrs_info
)
unless
allow_localhost
validate_loopback!
(
addrs_info
)
unless
allow_localhost
validate_local_network!
(
addrs_info
)
unless
allow_local_network
validate_link_local!
(
addrs_info
)
unless
allow_local_network
tru
e
protected_uri_with_hostnam
e
end
def
blocked_url?
(
*
args
)
...
...
@@ -52,6 +82,25 @@ module Gitlab
private
# Returns the given URI with IP address as hostname and the original hostname respectively
# in an Array.
#
# It checks whether the resolved IP address matches with the hostname. If not, it changes
# the hostname to the resolved IP address.
#
# The original hostname is used to validate the SSL, given in that scenario
# we'll be making the request to the IP address, instead of using the hostname.
def
enforce_uri_hostname
(
addrs_info
,
uri
,
hostname
,
dns_rebind_protection
)
address
=
addrs_info
.
first
ip_address
=
address
&
.
ip_address
return
[
uri
,
nil
]
unless
dns_rebind_protection
&&
ip_address
&&
ip_address
!=
hostname
uri
=
uri
.
dup
uri
.
hostname
=
ip_address
[
uri
,
hostname
]
end
def
get_port
(
uri
)
uri
.
port
||
uri
.
default_port
end
...
...
locale/gitlab.pot
View file @
fdcaeb38
...
...
@@ -4699,6 +4699,9 @@ msgstr ""
msgid "Ends at (UTC)"
msgstr ""
msgid "Enforce DNS rebinding attack protection"
msgstr ""
msgid "Enter at least three characters to search"
msgstr ""
...
...
@@ -10998,6 +11001,9 @@ msgstr ""
msgid "Resolved by %{resolvedByName}"
msgstr ""
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
msgid "Response"
msgstr ""
...
...
spec/controllers/projects/ci/lints_controller_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
Projects
::
Ci
::
LintsController
do
include
StubRequests
let
(
:project
)
{
create
(
:project
,
:repository
)
}
let
(
:user
)
{
create
(
:user
)
}
...
...
@@ -70,7 +72,7 @@ describe Projects::Ci::LintsController do
context
'with a valid gitlab-ci.yml'
do
before
do
WebMock
.
stub_request
(
:get
,
remote_file_path
).
to_return
(
body:
remote_file_content
)
stub_full_request
(
remote_file_path
).
to_return
(
body:
remote_file_content
)
project
.
add_developer
(
user
)
post
:create
,
params:
{
namespace_id:
project
.
namespace
,
project_id:
project
,
content:
content
}
...
...
spec/controllers/projects/milestones_controller_spec.rb
View file @
fdcaeb38
...
...
@@ -175,6 +175,40 @@ describe Projects::MilestonesController do
end
end
describe
'#labels'
do
render_views
context
'as json'
do
let!
(
:guest
)
{
create
(
:user
,
username:
'guest1'
)
}
let!
(
:group
)
{
create
(
:group
,
:public
)
}
let!
(
:project
)
{
create
(
:project
,
:public
,
group:
group
)
}
let!
(
:label
)
{
create
(
:label
,
title:
'test_label_on_private_issue'
,
project:
project
)
}
let!
(
:confidential_issue
)
{
create
(
:labeled_issue
,
confidential:
true
,
project:
project
,
milestone:
milestone
,
labels:
[
label
])
}
it
'does not render labels of private issues if user has no access'
do
sign_in
(
guest
)
get
:labels
,
params:
{
namespace_id:
group
.
id
,
project_id:
project
.
id
,
id:
milestone
.
iid
},
format: :json
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
.
content_type
).
to
eq
'application/json'
expect
(
json_response
[
'html'
]).
not_to
include
(
label
.
title
)
end
it
'does render labels of private issues if user has access'
do
sign_in
(
user
)
get
:labels
,
params:
{
namespace_id:
group
.
id
,
project_id:
project
.
id
,
id:
milestone
.
iid
},
format: :json
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
.
content_type
).
to
eq
'application/json'
expect
(
json_response
[
'html'
]).
to
include
(
label
.
title
)
end
end
end
context
'promotion succeeds'
do
before
do
group
.
add_developer
(
user
)
...
...
spec/controllers/sent_notifications_controller_spec.rb
View file @
fdcaeb38
...
...
@@ -4,15 +4,31 @@ require 'rails_helper'
describe
SentNotificationsController
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:project
)
{
create
(
:project
)
}
let
(
:sent_notification
)
{
create
(
:sent_notification
,
project:
project
,
noteable:
issue
,
recipient:
user
)
}
let
(
:project
)
{
create
(
:project
,
:public
)
}
let
(
:private_project
)
{
create
(
:project
,
:private
)
}
let
(
:sent_notification
)
{
create
(
:sent_notification
,
project:
target_project
,
noteable:
noteable
,
recipient:
user
)
}
let
(
:issue
)
do
create
(
:issue
,
project:
project
,
author:
user
)
do
|
issue
|
issue
.
subscriptions
.
create
(
user:
user
,
project:
project
,
subscribed:
true
)
create
(
:issue
,
project:
target_project
)
do
|
issue
|
issue
.
subscriptions
.
create
(
user:
user
,
project:
target_
project
,
subscribed:
true
)
end
end
let
(
:confidential_issue
)
do
create
(
:issue
,
project:
target_project
,
confidential:
true
)
do
|
issue
|
issue
.
subscriptions
.
create
(
user:
user
,
project:
target_project
,
subscribed:
true
)
end
end
let
(
:merge_request
)
do
create
(
:merge_request
,
source_project:
target_project
,
target_project:
target_project
)
do
|
mr
|
mr
.
subscriptions
.
create
(
user:
user
,
project:
target_project
,
subscribed:
true
)
end
end
let
(
:noteable
)
{
issue
}
let
(
:target_project
)
{
project
}
describe
'GET unsubscribe'
do
context
'when the user is not logged in'
do
context
'when the force param is passed'
do
...
...
@@ -34,20 +50,93 @@ describe SentNotificationsController do
end
context
'when the force param is not passed'
do
render_views
before
do
get
(
:unsubscribe
,
params:
{
id:
sent_notification
.
reply_key
})
end
it
'does not unsubscribe the user'
do
expect
(
issue
.
subscribed?
(
user
,
project
)).
to
be_truthy
shared_examples
'unsubscribing as anonymous'
do
it
'does not unsubscribe the user'
do
expect
(
noteable
.
subscribed?
(
user
,
target_project
)).
to
be_truthy
end
it
'does not set the flash message'
do
expect
(
controller
).
not_to
set_flash
[
:notice
]
end
it
'renders unsubscribe page'
do
expect
(
response
.
status
).
to
eq
(
200
)
expect
(
response
).
to
render_template
:unsubscribe
end
end
it
'does not set the flash message'
do
expect
(
controller
).
not_to
set_flash
[
:notice
]
context
'when project is public'
do
context
'when unsubscribing from issue'
do
let
(
:noteable
)
{
issue
}
it
'shows issue title'
do
expect
(
response
.
body
).
to
include
(
issue
.
title
)
end
it_behaves_like
'unsubscribing as anonymous'
end
context
'when unsubscribing from confidential issue'
do
let
(
:noteable
)
{
confidential_issue
}
it
'does not show issue title'
do
expect
(
response
.
body
).
not_to
include
(
confidential_issue
.
title
)
expect
(
response
.
body
).
to
include
(
confidential_issue
.
to_reference
)
end
it_behaves_like
'unsubscribing as anonymous'
end
context
'when unsubscribing from merge request'
do
let
(
:noteable
)
{
merge_request
}
it
'shows merge request title'
do
expect
(
response
.
body
).
to
include
(
merge_request
.
title
)
end
it_behaves_like
'unsubscribing as anonymous'
end
end
it
'redirects to the login page'
do
expect
(
response
).
to
render_template
:unsubscribe
context
'when project is not public'
do
let
(
:target_project
)
{
private_project
}
context
'when unsubscribing from issue'
do
let
(
:noteable
)
{
issue
}
it
'shows issue title'
do
expect
(
response
.
body
).
not_to
include
(
issue
.
title
)
end
it_behaves_like
'unsubscribing as anonymous'
end
context
'when unsubscribing from confidential issue'
do
let
(
:noteable
)
{
confidential_issue
}
it
'does not show issue title'
do
expect
(
response
.
body
).
not_to
include
(
confidential_issue
.
title
)
expect
(
response
.
body
).
to
include
(
confidential_issue
.
to_reference
)
end
it_behaves_like
'unsubscribing as anonymous'
end
context
'when unsubscribing from merge request'
do
let
(
:noteable
)
{
merge_request
}
it
'shows merge request title'
do
expect
(
response
.
body
).
not_to
include
(
merge_request
.
title
)
end
it_behaves_like
'unsubscribing as anonymous'
end
end
end
end
...
...
spec/controllers/sessions_controller_spec.rb
View file @
fdcaeb38
...
...
@@ -58,7 +58,26 @@ describe SessionsController do
it
'authenticates user correctly'
do
post
(
:create
,
params:
{
user:
user_params
})
expect
(
subject
.
current_user
).
to
eq
user
expect
(
subject
.
current_user
).
to
eq
user
end
context
'with password authentication disabled'
do
before
do
stub_application_setting
(
password_authentication_enabled_for_web:
false
)
end
it
'does not sign in the user'
do
post
(
:create
,
params:
{
user:
user_params
})
expect
(
@request
.
env
[
'warden'
]).
not_to
be_authenticated
expect
(
subject
.
current_user
).
to
be_nil
end
it
'returns status 403'
do
post
(
:create
,
params:
{
user:
user_params
})
expect
(
response
.
status
).
to
eq
403
end
end
it
'creates an audit log record'
do
...
...
@@ -153,6 +172,19 @@ describe SessionsController do
end
end
context
'with password authentication disabled'
do
before
do
stub_application_setting
(
password_authentication_enabled_for_web:
false
)
end
it
'allows 2FA stage of non-password login'
do
authenticate_2fa
(
otp_attempt:
user
.
current_otp
)
expect
(
@request
.
env
[
'warden'
]).
to
be_authenticated
expect
(
subject
.
current_user
).
to
eq
user
end
end
##
# See #14900 issue
#
...
...
spec/features/admin/admin_settings_spec.rb
View file @
fdcaeb38
...
...
@@ -332,16 +332,19 @@ describe 'Admin updates settings' do
end
context
'Network page'
do
it
'
Enable outbound request
s'
do
it
'
Changes Outbound requests setting
s'
do
visit
network_admin_application_settings_path
page
.
within
(
'.as-outbound'
)
do
check
'Allow requests to the local network from hooks and services'
# Enabled by default
uncheck
'Enforce DNS rebinding attack protection'
click_button
'Save changes'
end
expect
(
page
).
to
have_content
"Application settings saved successfully"
expect
(
Gitlab
::
CurrentSettings
.
allow_local_requests_from_hooks_and_services
).
to
be
true
expect
(
Gitlab
::
CurrentSettings
.
dns_rebinding_protection_enabled
).
to
be
false
end
end
...
...
spec/features/issuables/issuable_list_spec.rb
View file @
fdcaeb38
...
...
@@ -76,7 +76,7 @@ describe 'issuable list' do
create
(
:issue
,
project:
project
,
author:
user
)
else
create
(
:merge_request
,
source_project:
project
,
source_branch:
generate
(
:branch
))
source_branch
=
FFaker
::
Name
.
name
source_branch
=
FFaker
::
Lorem
.
characters
(
8
)
pipeline
=
create
(
:ci_empty_pipeline
,
project:
project
,
ref:
source_branch
,
status:
%w(running failed success)
.
sample
,
sha:
'any'
)
create
(
:merge_request
,
title:
FFaker
::
Lorem
.
sentence
,
source_project:
project
,
source_branch:
source_branch
,
head_pipeline:
pipeline
)
end
...
...
spec/features/projects/import_export/export_file_spec.rb
View file @
fdcaeb38
...
...
@@ -12,7 +12,7 @@ describe 'Import/Export - project export integration test', :js do
let
(
:export_path
)
{
"
#{
Dir
.
tmpdir
}
/import_file_spec"
}
let
(
:config_hash
)
{
YAML
.
load_file
(
Gitlab
::
ImportExport
.
config_file
).
deep_stringify_keys
}
let
(
:sensitive_words
)
{
%w[pass secret token key encrypted]
}
let
(
:sensitive_words
)
{
%w[pass secret token key encrypted
html
]
}
let
(
:safe_list
)
do
{
token:
[
ProjectHook
,
Ci
::
Trigger
,
CommitStatus
],
...
...
spec/lib/banzai/redactor_spec.rb
View file @
fdcaeb38
...
...
@@ -13,10 +13,10 @@ describe Banzai::Redactor do
it
'redacts an array of documents'
do
doc1
=
Nokogiri
::
HTML
.
fragment
(
'<a class="gfm" data-reference-type="issue">foo</a>'
)
.
fragment
(
'<a class="gfm"
href="https://www.gitlab.com"
data-reference-type="issue">foo</a>'
)
doc2
=
Nokogiri
::
HTML
.
fragment
(
'<a class="gfm" data-reference-type="issue">bar</a>'
)
.
fragment
(
'<a class="gfm"
href="https://www.gitlab.com"
data-reference-type="issue">bar</a>'
)
redacted_data
=
redactor
.
redact
([
doc1
,
doc2
])
...
...
@@ -27,7 +27,7 @@ describe Banzai::Redactor do
end
it
'replaces redacted reference with inner HTML'
do
doc
=
Nokogiri
::
HTML
.
fragment
(
"<a class='gfm' data-reference-type='issue'>foo</a>"
)
doc
=
Nokogiri
::
HTML
.
fragment
(
"<a class='gfm'
href='https://www.gitlab.com'
data-reference-type='issue'>foo</a>"
)
redactor
.
redact
([
doc
])
expect
(
doc
.
to_html
).
to
eq
(
'foo'
)
end
...
...
@@ -35,20 +35,24 @@ describe Banzai::Redactor do
context
'when data-original attribute provided'
do
let
(
:original_content
)
{
'<code>foo</code>'
}
it
'replaces redacted reference with original content'
do
doc
=
Nokogiri
::
HTML
.
fragment
(
"<a class='gfm' data-reference-type='issue' data-original='
#{
original_content
}
'>bar</a>"
)
doc
=
Nokogiri
::
HTML
.
fragment
(
"<a class='gfm'
href='https://www.gitlab.com'
data-reference-type='issue' data-original='
#{
original_content
}
'>bar</a>"
)
redactor
.
redact
([
doc
])
expect
(
doc
.
to_html
).
to
eq
(
original_content
)
end
end
it
'returns <a> tag with original href if it is originally a link reference'
do
href
=
'http://localhost:3000'
doc
=
Nokogiri
::
HTML
.
fragment
(
"<a class='gfm' data-reference-type='issue' data-original=
#{
href
}
data-link-reference='true'>
#{
href
}
</a>"
)
redactor
.
redact
([
doc
])
it
'does not replace redacted reference with original content if href is given'
do
html
=
"<a href='https://www.gitlab.com' data-link-reference='true' class='gfm' data-reference-type='issue' data-reference-type='issue' data-original='Marge'>Marge</a>"
doc
=
Nokogiri
::
HTML
.
fragment
(
html
)
redactor
.
redact
([
doc
])
expect
(
doc
.
to_html
).
to
eq
(
'<a href="https://www.gitlab.com">Marge</a>'
)
end
expect
(
doc
.
to_html
).
to
eq
(
'<a href="http://localhost:3000">http://localhost:3000</a>'
)
it
'uses the original content as the link content if given'
do
html
=
"<a href='https://www.gitlab.com' data-link-reference='true' class='gfm' data-reference-type='issue' data-reference-type='issue' data-original='Homer'>Marge</a>"
doc
=
Nokogiri
::
HTML
.
fragment
(
html
)
redactor
.
redact
([
doc
])
expect
(
doc
.
to_html
).
to
eq
(
'<a href="https://www.gitlab.com">Homer</a>'
)
end
end
end
...
...
@@ -61,7 +65,7 @@ describe Banzai::Redactor do
end
it
'redacts an issue attached'
do
doc
=
Nokogiri
::
HTML
.
fragment
(
"<a class='gfm' data-reference-type='issue' data-issue='
#{
issue
.
id
}
'>foo</a>"
)
doc
=
Nokogiri
::
HTML
.
fragment
(
"<a class='gfm'
href='https://www.gitlab.com'
data-reference-type='issue' data-issue='
#{
issue
.
id
}
'>foo</a>"
)
redactor
.
redact
([
doc
])
...
...
@@ -69,7 +73,7 @@ describe Banzai::Redactor do
end
it
'redacts an external issue'
do
doc
=
Nokogiri
::
HTML
.
fragment
(
"<a class='gfm' data-reference-type='issue' data-external-issue='
#{
issue
.
id
}
' data-project='
#{
project
.
id
}
'>foo</a>"
)
doc
=
Nokogiri
::
HTML
.
fragment
(
"<a class='gfm'
href='https://www.gitlab.com'
data-reference-type='issue' data-external-issue='
#{
issue
.
id
}
' data-project='
#{
project
.
id
}
'>foo</a>"
)
redactor
.
redact
([
doc
])
...
...
spec/lib/gitlab/bitbucket_import/importer_spec.rb
View file @
fdcaeb38
...
...
@@ -5,6 +5,7 @@ describe Gitlab::BitbucketImport::Importer do
before
do
stub_omniauth_provider
(
'bitbucket'
)
stub_feature_flags
(
stricter_mr_branch_name:
false
)
end
let
(
:statuses
)
do
...
...
spec/lib/gitlab/ci/config/external/file/remote_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
Gitlab
::
Ci
::
Config
::
External
::
File
::
Remote
do
include
StubRequests
let
(
:context
)
{
described_class
::
Context
.
new
(
nil
,
'12345'
,
nil
,
Set
.
new
)
}
let
(
:params
)
{
{
remote:
location
}
}
let
(
:remote_file
)
{
described_class
.
new
(
params
,
context
)
}
...
...
@@ -46,7 +48,7 @@ describe Gitlab::Ci::Config::External::File::Remote do
describe
"#valid?"
do
context
'when is a valid remote url'
do
before
do
WebMock
.
stub_request
(
:get
,
location
).
to_return
(
body:
remote_file_content
)
stub_full_request
(
location
).
to_return
(
body:
remote_file_content
)
end
it
'returns true'
do
...
...
@@ -92,7 +94,7 @@ describe Gitlab::Ci::Config::External::File::Remote do
describe
"#content"
do
context
'with a valid remote file'
do
before
do
WebMock
.
stub_request
(
:get
,
location
).
to_return
(
body:
remote_file_content
)
stub_full_request
(
location
).
to_return
(
body:
remote_file_content
)
end
it
'returns the content of the file'
do
...
...
@@ -114,7 +116,7 @@ describe Gitlab::Ci::Config::External::File::Remote do
let
(
:location
)
{
'https://asdasdasdaj48ggerexample.com'
}
before
do
WebMock
.
stub_request
(
:get
,
location
).
to_raise
(
SocketError
.
new
(
'Some HTTP error'
))
stub_full_request
(
location
).
to_raise
(
SocketError
.
new
(
'Some HTTP error'
))
end
it
'is nil'
do
...
...
@@ -144,7 +146,7 @@ describe Gitlab::Ci::Config::External::File::Remote do
context
'when timeout error has been raised'
do
before
do
WebMock
.
stub_request
(
:get
,
location
).
to_timeout
stub_full_request
(
location
).
to_timeout
end
it
'returns error message about a timeout'
do
...
...
@@ -154,7 +156,7 @@ describe Gitlab::Ci::Config::External::File::Remote do
context
'when HTTP error has been raised'
do
before
do
WebMock
.
stub_request
(
:get
,
location
).
to_raise
(
Gitlab
::
HTTP
::
Error
)
stub_full_request
(
location
).
to_raise
(
Gitlab
::
HTTP
::
Error
)
end
it
'returns error message about a HTTP error'
do
...
...
@@ -164,7 +166,7 @@ describe Gitlab::Ci::Config::External::File::Remote do
context
'when response has 404 status'
do
before
do
WebMock
.
stub_request
(
:get
,
location
).
to_return
(
body:
remote_file_content
,
status:
404
)
stub_full_request
(
location
).
to_return
(
body:
remote_file_content
,
status:
404
)
end
it
'returns error message about a timeout'
do
...
...
spec/lib/gitlab/ci/config/external/mapper_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
Gitlab
::
Ci
::
Config
::
External
::
Mapper
do
include
StubRequests
set
(
:project
)
{
create
(
:project
,
:repository
)
}
set
(
:user
)
{
create
(
:user
)
}
...
...
@@ -18,7 +20,7 @@ describe Gitlab::Ci::Config::External::Mapper do
end
before
do
WebMock
.
stub_request
(
:get
,
remote_url
).
to_return
(
body:
file_content
)
stub_full_request
(
remote_url
).
to_return
(
body:
file_content
)
end
describe
'#process'
do
...
...
spec/lib/gitlab/ci/config/external/processor_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
Gitlab
::
Ci
::
Config
::
External
::
Processor
do
include
StubRequests
set
(
:project
)
{
create
(
:project
,
:repository
)
}
set
(
:another_project
)
{
create
(
:project
,
:repository
)
}
set
(
:user
)
{
create
(
:user
)
}
...
...
@@ -42,7 +44,7 @@ describe Gitlab::Ci::Config::External::Processor do
let
(
:values
)
{
{
include:
remote_file
,
image:
'ruby:2.2'
}
}
before
do
WebMock
.
stub_request
(
:get
,
remote_file
).
to
_raise
(
SocketError
.
new
(
'Some HTTP error'
))
stub_full_request
(
remote_file
).
and
_raise
(
SocketError
.
new
(
'Some HTTP error'
))
end
it
'raises an error'
do
...
...
@@ -75,7 +77,7 @@ describe Gitlab::Ci::Config::External::Processor do
end
before
do
WebMock
.
stub_request
(
:get
,
remote_file
).
to_return
(
body:
external_file_content
)
stub_full_request
(
remote_file
).
to_return
(
body:
external_file_content
)
end
it
'appends the file to the values'
do
...
...
@@ -145,7 +147,7 @@ describe Gitlab::Ci::Config::External::Processor do
allow_any_instance_of
(
Gitlab
::
Ci
::
Config
::
External
::
File
::
Local
)
.
to
receive
(
:fetch_local_content
).
and_return
(
local_file_content
)
WebMock
.
stub_request
(
:get
,
remote_file
).
to_return
(
body:
remote_file_content
)
stub_full_request
(
remote_file
).
to_return
(
body:
remote_file_content
)
end
it
'appends the files to the values'
do
...
...
@@ -191,7 +193,8 @@ describe Gitlab::Ci::Config::External::Processor do
end
it
'takes precedence'
do
WebMock
.
stub_request
(
:get
,
remote_file
).
to_return
(
body:
remote_file_content
)
stub_full_request
(
remote_file
).
to_return
(
body:
remote_file_content
)
expect
(
processor
.
perform
[
:image
]).
to
eq
(
'ruby:2.2'
)
end
end
...
...
@@ -231,7 +234,8 @@ describe Gitlab::Ci::Config::External::Processor do
HEREDOC
end
WebMock
.
stub_request
(
:get
,
'http://my.domain.com/config.yml'
).
to_return
(
body:
'remote_build: { script: echo Hello World }'
)
stub_full_request
(
'http://my.domain.com/config.yml'
)
.
to_return
(
body:
'remote_build: { script: echo Hello World }'
)
end
context
'when project is public'
do
...
...
@@ -273,8 +277,10 @@ describe Gitlab::Ci::Config::External::Processor do
context
'when config includes an external configuration file via SSL web request'
do
before
do
stub_request
(
:get
,
'https://sha256.badssl.com/fake.yml'
).
to_return
(
body:
'image: ruby:2.6'
,
status:
200
)
stub_request
(
:get
,
'https://self-signed.badssl.com/fake.yml'
)
stub_full_request
(
'https://sha256.badssl.com/fake.yml'
,
ip_address:
'8.8.8.8'
)
.
to_return
(
body:
'image: ruby:2.6'
,
status:
200
)
stub_full_request
(
'https://self-signed.badssl.com/fake.yml'
,
ip_address:
'8.8.8.9'
)
.
to_raise
(
OpenSSL
::
SSL
::
SSLError
.
new
(
'SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate)'
))
end
...
...
spec/lib/gitlab/ci/config_spec.rb
View file @
fdcaeb38
require
'spec_helper'
describe
Gitlab
::
Ci
::
Config
do
include
StubRequests
set
(
:user
)
{
create
(
:user
)
}
let
(
:config
)
do
...
...
@@ -216,8 +218,7 @@ describe Gitlab::Ci::Config do
end
before
do
WebMock
.
stub_request
(
:get
,
remote_location
)
.
to_return
(
body:
remote_file_content
)
stub_full_request
(
remote_location
).
to_return
(
body:
remote_file_content
)
allow
(
project
.
repository
)
.
to
receive
(
:blob_data_at
).
and_return
(
local_file_content
)
...
...
spec/lib/gitlab/ci/yaml_processor_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@ require 'spec_helper'
module
Gitlab
module
Ci
describe
YamlProcessor
do
include
StubRequests
subject
{
described_class
.
new
(
config
,
user:
nil
)
}
describe
'#build_attributes'
do
...
...
@@ -648,7 +650,7 @@ module Gitlab
end
before
do
WebMock
.
stub_request
(
:get
,
'https://gitlab.com/awesome-project/raw/master/.before-script-template.yml'
)
stub_full_request
(
'https://gitlab.com/awesome-project/raw/master/.before-script-template.yml'
)
.
to_return
(
status:
200
,
headers:
{
'Content-Type'
=>
'application/json'
},
...
...
spec/lib/gitlab/git_ref_validator_spec.rb
View file @
fdcaeb38
require
'spec_helper'
describe
Gitlab
::
GitRefValidator
do
it
{
expect
(
described_class
.
validate
(
'feature/new'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'implement_@all'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'my_new_feature'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'my-branch'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'#1'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'feature/refs/heads/foo'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'feature/~new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/^new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/:new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/?new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/*new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/[new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/new.'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature\@{'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature\new'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature//new'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature new'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'refs/heads/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'refs/remotes/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'refs/heads/feature'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'refs/remotes/origin'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'-'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'-branch'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'.tag'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'my branch'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
"
\xA0\u
0000
\xB0
"
)).
to
be_falsey
}
using
RSpec
::
Parameterized
::
TableSyntax
context
'.validate'
do
it
{
expect
(
described_class
.
validate
(
'feature/new'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'implement_@all'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'my_new_feature'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'my-branch'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'#1'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'feature/refs/heads/foo'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate
(
'feature/~new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/^new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/:new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/?new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/*new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/[new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature/new.'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature\@{'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature\new'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature//new'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'feature new'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'refs/heads/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'refs/remotes/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'refs/heads/feature'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'refs/remotes/origin'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'-'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'-branch'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'+foo:bar'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'foo:bar'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'.tag'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
'my branch'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate
(
"
\xA0\u
0000
\xB0
"
)).
to
be_falsey
}
end
context
'.validate_merge_request_branch'
do
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'HEAD'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/new'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'implement_@all'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'my_new_feature'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'my-branch'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'#1'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/refs/heads/foo'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/~new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/^new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/:new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/?new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/*new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/[new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/new/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature/new.'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature\@{'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature\new'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature//new'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'feature new'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'refs/heads/master'
)).
to
be_truthy
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'refs/heads/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'refs/remotes/'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'-'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'-branch'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'+foo:bar'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'foo:bar'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'.tag'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
'my branch'
)).
to
be_falsey
}
it
{
expect
(
described_class
.
validate_merge_request_branch
(
"
\xA0\u
0000
\xB0
"
)).
to
be_falsey
}
end
end
spec/lib/gitlab/http_connection_adapter_spec.rb
0 → 100644
View file @
fdcaeb38
# frozen_string_literal: true
require
'spec_helper'
describe
Gitlab
::
HTTPConnectionAdapter
do
describe
'#connection'
do
context
'when local requests are not allowed'
do
it
'sets up the connection'
do
uri
=
URI
(
'https://example.org'
)
connection
=
described_class
.
new
(
uri
).
connection
expect
(
connection
).
to
be_a
(
Net
::
HTTP
)
expect
(
connection
.
address
).
to
eq
(
'93.184.216.34'
)
expect
(
connection
.
hostname_override
).
to
eq
(
'example.org'
)
expect
(
connection
.
addr_port
).
to
eq
(
'example.org'
)
expect
(
connection
.
port
).
to
eq
(
443
)
end
it
'raises error when it is a request to local address'
do
uri
=
URI
(
'http://172.16.0.0/12'
)
expect
{
described_class
.
new
(
uri
).
connection
}
.
to
raise_error
(
Gitlab
::
HTTP
::
BlockedUrlError
,
"URL 'http://172.16.0.0/12' is blocked: Requests to the local network are not allowed"
)
end
it
'raises error when it is a request to localhost address'
do
uri
=
URI
(
'http://127.0.0.1'
)
expect
{
described_class
.
new
(
uri
).
connection
}
.
to
raise_error
(
Gitlab
::
HTTP
::
BlockedUrlError
,
"URL 'http://127.0.0.1' is blocked: Requests to localhost are not allowed"
)
end
context
'when port different from URL scheme is used'
do
it
'sets up the addr_port accordingly'
do
uri
=
URI
(
'https://example.org:8080'
)
connection
=
described_class
.
new
(
uri
).
connection
expect
(
connection
.
address
).
to
eq
(
'93.184.216.34'
)
expect
(
connection
.
hostname_override
).
to
eq
(
'example.org'
)
expect
(
connection
.
addr_port
).
to
eq
(
'example.org:8080'
)
expect
(
connection
.
port
).
to
eq
(
8080
)
end
end
end
context
'when DNS rebinding protection is disabled'
do
it
'sets up the connection'
do
stub_application_setting
(
dns_rebinding_protection_enabled:
false
)
uri
=
URI
(
'https://example.org'
)
connection
=
described_class
.
new
(
uri
).
connection
expect
(
connection
).
to
be_a
(
Net
::
HTTP
)
expect
(
connection
.
address
).
to
eq
(
'example.org'
)
expect
(
connection
.
hostname_override
).
to
eq
(
nil
)
expect
(
connection
.
addr_port
).
to
eq
(
'example.org'
)
expect
(
connection
.
port
).
to
eq
(
443
)
end
end
context
'when http(s) environment variable is set'
do
it
'sets up the connection'
do
stub_env
(
'https_proxy'
=>
'https://my.proxy'
)
uri
=
URI
(
'https://example.org'
)
connection
=
described_class
.
new
(
uri
).
connection
expect
(
connection
).
to
be_a
(
Net
::
HTTP
)
expect
(
connection
.
address
).
to
eq
(
'example.org'
)
expect
(
connection
.
hostname_override
).
to
eq
(
nil
)
expect
(
connection
.
addr_port
).
to
eq
(
'example.org'
)
expect
(
connection
.
port
).
to
eq
(
443
)
end
end
context
'when local requests are allowed'
do
it
'sets up the connection'
do
uri
=
URI
(
'https://example.org'
)
connection
=
described_class
.
new
(
uri
,
allow_local_requests:
true
).
connection
expect
(
connection
).
to
be_a
(
Net
::
HTTP
)
expect
(
connection
.
address
).
to
eq
(
'93.184.216.34'
)
expect
(
connection
.
hostname_override
).
to
eq
(
'example.org'
)
expect
(
connection
.
addr_port
).
to
eq
(
'example.org'
)
expect
(
connection
.
port
).
to
eq
(
443
)
end
it
'sets up the connection when it is a local network'
do
uri
=
URI
(
'http://172.16.0.0/12'
)
connection
=
described_class
.
new
(
uri
,
allow_local_requests:
true
).
connection
expect
(
connection
).
to
be_a
(
Net
::
HTTP
)
expect
(
connection
.
address
).
to
eq
(
'172.16.0.0'
)
expect
(
connection
.
hostname_override
).
to
be
(
nil
)
expect
(
connection
.
addr_port
).
to
eq
(
'172.16.0.0'
)
expect
(
connection
.
port
).
to
eq
(
80
)
end
it
'sets up the connection when it is localhost'
do
uri
=
URI
(
'http://127.0.0.1'
)
connection
=
described_class
.
new
(
uri
,
allow_local_requests:
true
).
connection
expect
(
connection
).
to
be_a
(
Net
::
HTTP
)
expect
(
connection
.
address
).
to
eq
(
'127.0.0.1'
)
expect
(
connection
.
hostname_override
).
to
be
(
nil
)
expect
(
connection
.
addr_port
).
to
eq
(
'127.0.0.1'
)
expect
(
connection
.
port
).
to
eq
(
80
)
end
end
end
end
spec/lib/gitlab/http_spec.rb
View file @
fdcaeb38
require
'spec_helper'
describe
Gitlab
::
HTTP
do
include
StubRequests
context
'when allow_local_requests'
do
it
'sends the request to the correct URI'
do
stub_full_request
(
'https://example.org:8080'
,
ip_address:
'8.8.8.8'
).
to_return
(
status:
200
)
described_class
.
get
(
'https://example.org:8080'
,
allow_local_requests:
false
)
expect
(
WebMock
).
to
have_requested
(
:get
,
'https://8.8.8.8:8080'
).
once
end
end
context
'when not allow_local_requests'
do
it
'sends the request to the correct URI'
do
stub_full_request
(
'https://example.org:8080'
)
described_class
.
get
(
'https://example.org:8080'
,
allow_local_requests:
true
)
expect
(
WebMock
).
to
have_requested
(
:get
,
'https://8.8.8.9:8080'
).
once
end
end
describe
'allow_local_requests_from_hooks_and_services is'
do
before
do
WebMock
.
stub_request
(
:get
,
/.*/
).
to_return
(
status:
200
,
body:
'Success'
)
...
...
@@ -21,6 +43,8 @@ describe Gitlab::HTTP do
context
'if allow_local_requests set to true'
do
it
'override the global value and allow requests to localhost or private network'
do
stub_full_request
(
'http://localhost:3003'
)
expect
{
described_class
.
get
(
'http://localhost:3003'
,
allow_local_requests:
true
)
}.
not_to
raise_error
end
end
...
...
@@ -32,6 +56,8 @@ describe Gitlab::HTTP do
end
it
'allow requests to localhost'
do
stub_full_request
(
'http://localhost:3003'
)
expect
{
described_class
.
get
(
'http://localhost:3003'
)
}.
not_to
raise_error
end
...
...
@@ -49,7 +75,7 @@ describe Gitlab::HTTP do
describe
'handle redirect loops'
do
before
do
WebMock
.
stub_request
(
:any
,
"http://example.org"
).
to_raise
(
HTTParty
::
RedirectionTooDeep
.
new
(
"Redirection Too Deep"
))
stub_full_request
(
"http://example.org"
,
method: :any
).
to_raise
(
HTTParty
::
RedirectionTooDeep
.
new
(
"Redirection Too Deep"
))
end
it
'handles GET requests'
do
...
...
spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb
View file @
fdcaeb38
require
'spec_helper'
describe
Gitlab
::
ImportExport
::
AfterExportStrategies
::
WebUploadStrategy
do
include
StubRequests
let
(
:example_url
)
{
'http://www.example.com'
}
let
(
:strategy
)
{
subject
.
new
(
url:
example_url
,
http_method:
'post'
)
}
let!
(
:project
)
{
create
(
:project
,
:with_export
)
}
...
...
@@ -35,7 +37,7 @@ describe Gitlab::ImportExport::AfterExportStrategies::WebUploadStrategy do
context
'when upload fails'
do
it
'stores the export error'
do
stub_
request
(
:post
,
example_url
).
to_return
(
status:
[
404
,
'Page not found'
])
stub_
full_request
(
example_url
,
method: :post
).
to_return
(
status:
[
404
,
'Page not found'
])
strategy
.
execute
(
user
,
project
)
...
...
spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
View file @
fdcaeb38
...
...
@@ -18,7 +18,11 @@ describe Gitlab::ImportExport::AttributeCleaner do
'notid'
=>
99
,
'import_source'
=>
'whatever'
,
'import_type'
=>
'whatever'
,
'non_existent_attr'
=>
'whatever'
'non_existent_attr'
=>
'whatever'
,
'some_html'
=>
'<p>dodgy html</p>'
,
'legit_html'
=>
'<p>legit html</p>'
,
'_html'
=>
'<p>perfectly ordinary html</p>'
,
'cached_markdown_version'
=>
12345
}
end
...
...
spec/lib/gitlab/import_export/project.json
View file @
fdcaeb38
...
...
@@ -158,6 +158,8 @@
{
"id"
:
351
,
"note"
:
"Quo reprehenderit aliquam qui dicta impedit cupiditate eligendi."
,
"note_html"
:
"<p>something else entirely</p>"
,
"cached_markdown_version"
:
917504
,
"noteable_type"
:
"Issue"
,
"author_id"
:
26
,
"created_at"
:
"2016-06-14T15:02:47.770Z"
,
...
...
@@ -2363,6 +2365,8 @@
{
"id"
:
671
,
"note"
:
"Sit voluptatibus eveniet architecto quidem."
,
"note_html"
:
"<p>something else entirely</p>"
,
"cached_markdown_version"
:
917504
,
"noteable_type"
:
"MergeRequest"
,
"author_id"
:
26
,
"created_at"
:
"2016-06-14T15:02:56.632Z"
,
...
...
spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
View file @
fdcaeb38
...
...
@@ -58,6 +58,26 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
expect
(
Milestone
.
find_by_description
(
'test milestone'
).
issues
.
count
).
to
eq
(
2
)
end
context
'when importing a project with cached_markdown_version and note_html'
do
context
'for an Issue'
do
it
'does not import note_html'
do
note_content
=
'Quo reprehenderit aliquam qui dicta impedit cupiditate eligendi'
issue_note
=
Issue
.
find_by
(
description:
'Aliquam enim illo et possimus.'
).
notes
.
select
{
|
n
|
n
.
note
.
match
(
/
#{
note_content
}
/
)}.
first
expect
(
issue_note
.
note_html
).
to
match
(
/
#{
note_content
}
/
)
end
end
context
'for a Merge Request'
do
it
'does not import note_html'
do
note_content
=
'Sit voluptatibus eveniet architecto quidem'
merge_request_note
=
MergeRequest
.
find_by
(
title:
'MR1'
).
notes
.
select
{
|
n
|
n
.
note
.
match
(
/
#{
note_content
}
/
)}.
first
expect
(
merge_request_note
.
note_html
).
to
match
(
/
#{
note_content
}
/
)
end
end
end
it
'creates a valid pipeline note'
do
expect
(
Ci
::
Pipeline
.
find_by_sha
(
'sha-notes'
).
notes
).
not_to
be_empty
end
...
...
spec/lib/gitlab/search_results_spec.rb
View file @
fdcaeb38
...
...
@@ -256,4 +256,27 @@ describe Gitlab::SearchResults do
expect
(
results
.
objects
(
'merge_requests'
)).
not_to
include
merge_request
end
context
'milestones'
do
it
'returns correct set of milestones'
do
private_project_1
=
create
(
:project
,
:private
)
private_project_2
=
create
(
:project
,
:private
)
internal_project
=
create
(
:project
,
:internal
)
public_project_1
=
create
(
:project
,
:public
)
public_project_2
=
create
(
:project
,
:public
,
:issues_disabled
,
:merge_requests_disabled
)
private_project_1
.
add_developer
(
user
)
# milestones that should not be visible
create
(
:milestone
,
project:
private_project_2
,
title:
'Private project without access milestone'
)
create
(
:milestone
,
project:
public_project_2
,
title:
'Public project with milestones disabled milestone'
)
# milestones that should be visible
milestone_1
=
create
(
:milestone
,
project:
private_project_1
,
title:
'Private project with access milestone'
,
state:
'closed'
)
milestone_2
=
create
(
:milestone
,
project:
internal_project
,
title:
'Internal project milestone'
)
milestone_3
=
create
(
:milestone
,
project:
public_project_1
,
title:
'Public project with milestones enabled milestone'
)
limit_projects
=
ProjectsFinder
.
new
(
current_user:
user
).
execute
milestones
=
described_class
.
new
(
user
,
limit_projects
,
'milestone'
).
objects
(
'milestones'
)
expect
(
milestones
).
to
match_array
([
milestone_1
,
milestone_2
,
milestone_3
])
end
end
end
spec/lib/gitlab/url_blocker_spec.rb
View file @
fdcaeb38
...
...
@@ -2,6 +2,87 @@
require
'spec_helper'
describe
Gitlab
::
UrlBlocker
do
describe
'#validate!'
do
context
'when URI is nil'
do
let
(
:import_url
)
{
nil
}
it
'returns no URI and hostname'
do
uri
,
hostname
=
described_class
.
validate!
(
import_url
)
expect
(
uri
).
to
be
(
nil
)
expect
(
hostname
).
to
be
(
nil
)
end
end
context
'when URI is internal'
do
let
(
:import_url
)
{
'http://localhost'
}
it
'returns URI and no hostname'
do
uri
,
hostname
=
described_class
.
validate!
(
import_url
)
expect
(
uri
).
to
eq
(
Addressable
::
URI
.
parse
(
'http://[::1]'
))
expect
(
hostname
).
to
eq
(
'localhost'
)
end
end
context
'when the URL hostname is a domain'
do
let
(
:import_url
)
{
'https://example.org'
}
it
'returns URI and hostname'
do
uri
,
hostname
=
described_class
.
validate!
(
import_url
)
expect
(
uri
).
to
eq
(
Addressable
::
URI
.
parse
(
'https://93.184.216.34'
))
expect
(
hostname
).
to
eq
(
'example.org'
)
end
end
context
'when the URL hostname is an IP address'
do
let
(
:import_url
)
{
'https://93.184.216.34'
}
it
'returns URI and no hostname'
do
uri
,
hostname
=
described_class
.
validate!
(
import_url
)
expect
(
uri
).
to
eq
(
Addressable
::
URI
.
parse
(
'https://93.184.216.34'
))
expect
(
hostname
).
to
be
(
nil
)
end
end
context
'disabled DNS rebinding protection'
do
context
'when URI is internal'
do
let
(
:import_url
)
{
'http://localhost'
}
it
'returns URI and no hostname'
do
uri
,
hostname
=
described_class
.
validate!
(
import_url
,
dns_rebind_protection:
false
)
expect
(
uri
).
to
eq
(
Addressable
::
URI
.
parse
(
'http://localhost'
))
expect
(
hostname
).
to
be
(
nil
)
end
end
context
'when the URL hostname is a domain'
do
let
(
:import_url
)
{
'https://example.org'
}
it
'returns URI and no hostname'
do
uri
,
hostname
=
described_class
.
validate!
(
import_url
,
dns_rebind_protection:
false
)
expect
(
uri
).
to
eq
(
Addressable
::
URI
.
parse
(
'https://example.org'
))
expect
(
hostname
).
to
eq
(
nil
)
end
end
context
'when the URL hostname is an IP address'
do
let
(
:import_url
)
{
'https://93.184.216.34'
}
it
'returns URI and no hostname'
do
uri
,
hostname
=
described_class
.
validate!
(
import_url
,
dns_rebind_protection:
false
)
expect
(
uri
).
to
eq
(
Addressable
::
URI
.
parse
(
'https://93.184.216.34'
))
expect
(
hostname
).
to
be
(
nil
)
end
end
end
end
describe
'#blocked_url?'
do
let
(
:ports
)
{
Project
::
VALID_IMPORT_PORTS
}
...
...
@@ -208,7 +289,7 @@ describe Gitlab::UrlBlocker do
end
def
stub_domain_resolv
(
domain
,
ip
)
address
=
double
(
ip_address:
ip
,
ipv4_private?:
true
,
ipv6_link_local?:
false
,
ipv4_loopback?:
false
,
ipv6_loopback?:
false
)
address
=
double
(
ip_address:
ip
,
ipv4_private?:
true
,
ipv6_link_local?:
false
,
ipv4_loopback?:
false
,
ipv6_loopback?:
false
,
ipv4?:
false
)
allow
(
Addrinfo
).
to
receive
(
:getaddrinfo
).
with
(
domain
,
any_args
).
and_return
([
address
])
allow
(
address
).
to
receive
(
:ipv6_v4mapped?
).
and_return
(
false
)
end
...
...
spec/lib/gitlab_spec.rb
View file @
fdcaeb38
...
...
@@ -109,4 +109,34 @@ describe Gitlab do
expect
(
described_class
.
ee?
).
to
eq
(
false
)
end
end
describe
'.http_proxy_env?'
do
it
'returns true when lower case https'
do
stub_env
(
'https_proxy'
,
'https://my.proxy'
)
expect
(
described_class
.
http_proxy_env?
).
to
eq
(
true
)
end
it
'returns true when upper case https'
do
stub_env
(
'HTTPS_PROXY'
,
'https://my.proxy'
)
expect
(
described_class
.
http_proxy_env?
).
to
eq
(
true
)
end
it
'returns true when lower case http'
do
stub_env
(
'http_proxy'
,
'http://my.proxy'
)
expect
(
described_class
.
http_proxy_env?
).
to
eq
(
true
)
end
it
'returns true when upper case http'
do
stub_env
(
'HTTP_PROXY'
,
'http://my.proxy'
)
expect
(
described_class
.
http_proxy_env?
).
to
eq
(
true
)
end
it
'returns false when not set'
do
expect
(
described_class
.
http_proxy_env?
).
to
eq
(
false
)
end
end
end
spec/lib/mattermost/session_spec.rb
View file @
fdcaeb38
...
...
@@ -2,6 +2,7 @@ require 'spec_helper'
describe
Mattermost
::
Session
,
type: :request
do
include
ExclusiveLeaseHelpers
include
StubRequests
let
(
:user
)
{
create
(
:user
)
}
...
...
@@ -24,7 +25,7 @@ describe Mattermost::Session, type: :request do
let
(
:location
)
{
'http://location.tld'
}
let
(
:cookie_header
)
{
'MMOAUTH=taskik8az7rq8k6rkpuas7htia; Path=/;'
}
let!
(
:stub
)
do
WebMock
.
stub_request
(
:get
,
"
#{
mattermost_url
}
/oauth/gitlab/login"
)
stub_full_request
(
"
#{
mattermost_url
}
/oauth/gitlab/login"
)
.
to_return
(
headers:
{
'location'
=>
location
,
'Set-Cookie'
=>
cookie_header
},
status:
302
)
end
...
...
@@ -63,7 +64,7 @@ describe Mattermost::Session, type: :request do
end
before
do
WebMock
.
stub_request
(
:get
,
"
#{
mattermost_url
}
/signup/gitlab/complete"
)
stub_full_request
(
"
#{
mattermost_url
}
/signup/gitlab/complete"
)
.
with
(
query:
hash_including
({
'state'
=>
state
}))
.
to_return
do
|
request
|
post
"/oauth/token"
,
...
...
@@ -80,7 +81,7 @@ describe Mattermost::Session, type: :request do
end
end
WebMock
.
stub_request
(
:post
,
"
#{
mattermost_url
}
/api/v4/users/logout"
)
stub_full_request
(
"
#{
mattermost_url
}
/api/v4/users/logout"
,
method: :post
)
.
to_return
(
headers:
{
Authorization
:
'token thisworksnow'
},
status:
200
)
end
...
...
spec/models/merge_request_spec.rb
View file @
fdcaeb38
...
...
@@ -173,6 +173,40 @@ describe MergeRequest do
end
end
context
'for branch'
do
before
do
stub_feature_flags
(
stricter_mr_branch_name:
false
)
end
using
RSpec
::
Parameterized
::
TableSyntax
where
(
:branch_name
,
:valid
)
do
'foo'
|
true
'foo:bar'
|
false
'+foo:bar'
|
false
'foo bar'
|
false
'-foo'
|
false
'HEAD'
|
true
'refs/heads/master'
|
true
end
with_them
do
it
"validates source_branch"
do
subject
=
build
(
:merge_request
,
source_branch:
branch_name
,
target_branch:
'master'
)
subject
.
valid?
expect
(
subject
.
errors
.
added?
(
:source_branch
)).
to
eq
(
!
valid
)
end
it
"validates target_branch"
do
subject
=
build
(
:merge_request
,
source_branch:
'master'
,
target_branch:
branch_name
)
subject
.
valid?
expect
(
subject
.
errors
.
added?
(
:target_branch
)).
to
eq
(
!
valid
)
end
end
end
context
'for forks'
do
let
(
:project
)
{
create
(
:project
)
}
let
(
:fork1
)
{
fork_project
(
project
)
}
...
...
spec/models/project_services/assembla_service_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
AssemblaService
do
include
StubRequests
describe
"Associations"
do
it
{
is_expected
.
to
belong_to
:project
}
it
{
is_expected
.
to
have_one
:service_hook
}
...
...
@@ -23,12 +25,12 @@ describe AssemblaService do
)
@sample_data
=
Gitlab
::
DataBuilder
::
Push
.
build_sample
(
project
,
user
)
@api_url
=
'https://atlas.assembla.com/spaces/project_name/github_tool?secret_key=verySecret'
WebMock
.
stub_request
(
:post
,
@api_url
)
stub_full_request
(
@api_url
,
method: :post
)
end
it
"calls Assembla API"
do
@assembla_service
.
execute
(
@sample_data
)
expect
(
WebMock
).
to
have_requested
(
:post
,
@api_url
).
with
(
expect
(
WebMock
).
to
have_requested
(
:post
,
stubbed_hostname
(
@api_url
)
).
with
(
body:
/
#{
@sample_data
[
:before
]
}
.*
#{
@sample_data
[
:after
]
}
.*
#{
project
.
path
}
/
).
once
end
...
...
spec/models/project_services/bamboo_service_spec.rb
View file @
fdcaeb38
...
...
@@ -4,6 +4,7 @@ require 'spec_helper'
describe
BambooService
,
:use_clean_rails_memory_store_caching
do
include
ReactiveCachingHelpers
include
StubRequests
let
(
:bamboo_url
)
{
'http://gitlab.com/bamboo'
}
...
...
@@ -257,7 +258,7 @@ describe BambooService, :use_clean_rails_memory_store_caching do
end
def
stub_bamboo_request
(
url
,
status
,
body
)
WebMock
.
stub_request
(
:get
,
url
).
to_return
(
stub_full_request
(
url
).
to_return
(
status:
status
,
headers:
{
'Content-Type'
=>
'application/json'
},
body:
body
...
...
spec/models/project_services/buildkite_service_spec.rb
View file @
fdcaeb38
...
...
@@ -4,6 +4,7 @@ require 'spec_helper'
describe
BuildkiteService
,
:use_clean_rails_memory_store_caching
do
include
ReactiveCachingHelpers
include
StubRequests
let
(
:project
)
{
create
(
:project
)
}
...
...
@@ -110,10 +111,9 @@ describe BuildkiteService, :use_clean_rails_memory_store_caching do
body
||=
%q({"status":"success"})
buildkite_full_url
=
'https://gitlab.buildkite.com/status/secret-sauce-status-token.json?commit=123'
WebMock
.
stub_request
(
:get
,
buildkite_full_url
).
to_return
(
status:
status
,
headers:
{
'Content-Type'
=>
'application/json'
},
body:
body
)
stub_full_request
(
buildkite_full_url
)
.
to_return
(
status:
status
,
headers:
{
'Content-Type'
=>
'application/json'
},
body:
body
)
end
end
spec/models/project_services/campfire_service_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
CampfireService
do
include
StubRequests
describe
'Associations'
do
it
{
is_expected
.
to
belong_to
:project
}
it
{
is_expected
.
to
have_one
:service_hook
}
...
...
@@ -49,39 +51,37 @@ describe CampfireService do
it
"calls Campfire API to get a list of rooms and speak in a room"
do
# make sure a valid list of rooms is returned
body
=
File
.
read
(
Rails
.
root
+
'spec/fixtures/project_services/campfire/rooms.json'
)
WebMock
.
stub_request
(
:get
,
@rooms_url
).
with
(
basic_auth:
@auth
).
to_return
(
stub_full_request
(
@rooms_url
).
with
(
basic_auth:
@auth
).
to_return
(
body:
body
,
status:
200
,
headers:
@headers
)
# stub the speak request with the room id found in the previous request's response
speak_url
=
'https://project-name.campfirenow.com/room/123/speak.json'
WebMock
.
stub_request
(
:post
,
speak_url
).
with
(
basic_auth:
@auth
)
stub_full_request
(
speak_url
,
method: :post
).
with
(
basic_auth:
@auth
)
@campfire_service
.
execute
(
@sample_data
)
expect
(
WebMock
).
to
have_requested
(
:get
,
@rooms_url
).
once
expect
(
WebMock
).
to
have_requested
(
:post
,
speak_url
).
with
(
body:
/
#{
project
.
path
}
.*
#{
@sample_data
[
:before
]
}
.*
#{
@sample_data
[
:after
]
}
/
).
once
expect
(
WebMock
).
to
have_requested
(
:get
,
stubbed_hostname
(
@rooms_url
)).
once
expect
(
WebMock
).
to
have_requested
(
:post
,
stubbed_hostname
(
speak_url
))
.
with
(
body:
/
#{
project
.
path
}
.*
#{
@sample_data
[
:before
]
}
.*
#{
@sample_data
[
:after
]
}
/
).
once
end
it
"calls Campfire API to get a list of rooms but shouldn't speak in a room"
do
# return a list of rooms that do not contain a room named 'test-room'
body
=
File
.
read
(
Rails
.
root
+
'spec/fixtures/project_services/campfire/rooms2.json'
)
WebMock
.
stub_request
(
:get
,
@rooms_url
).
with
(
basic_auth:
@auth
).
to_return
(
stub_full_request
(
@rooms_url
).
with
(
basic_auth:
@auth
).
to_return
(
body:
body
,
status:
200
,
headers:
@headers
)
# we want to make sure no request is sent to the /speak endpoint, here is a basic
# regexp that matches this endpoint
speak_url
=
'https://verySecret:X@project-name.campfirenow.com/room/.*/speak.json'
@campfire_service
.
execute
(
@sample_data
)
expect
(
WebMock
).
to
have_requested
(
:get
,
@rooms_url
).
once
expect
(
WebMock
).
not_to
have_requested
(
:post
,
/
#{
speak_url
}
/
)
expect
(
WebMock
).
to
have_requested
(
:get
,
'https://8.8.8.9/rooms.json'
).
once
expect
(
WebMock
).
not_to
have_requested
(
:post
,
'*/room/.*/speak.json'
)
end
end
end
spec/models/project_services/pivotaltracker_service_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
PivotaltrackerService
do
include
StubRequests
describe
'Associations'
do
it
{
is_expected
.
to
belong_to
:project
}
it
{
is_expected
.
to
have_one
:service_hook
}
...
...
@@ -53,12 +55,12 @@ describe PivotaltrackerService do
end
before
do
WebMock
.
stub_request
(
:post
,
url
)
stub_full_request
(
url
,
method: :post
)
end
it
'posts correct message'
do
service
.
execute
(
push_data
)
expect
(
WebMock
).
to
have_requested
(
:post
,
url
).
with
(
expect
(
WebMock
).
to
have_requested
(
:post
,
stubbed_hostname
(
url
)
).
with
(
body:
{
'source_commit'
=>
{
'commit_id'
=>
'21c12ea'
,
...
...
@@ -85,14 +87,14 @@ describe PivotaltrackerService do
service
.
execute
(
push_data
(
branch:
'master'
))
service
.
execute
(
push_data
(
branch:
'v10'
))
expect
(
WebMock
).
to
have_requested
(
:post
,
url
).
twice
expect
(
WebMock
).
to
have_requested
(
:post
,
stubbed_hostname
(
url
)
).
twice
end
it
'does not post message if branch is not in the list'
do
service
.
execute
(
push_data
(
branch:
'mas'
))
service
.
execute
(
push_data
(
branch:
'v11'
))
expect
(
WebMock
).
not_to
have_requested
(
:post
,
url
)
expect
(
WebMock
).
not_to
have_requested
(
:post
,
stubbed_hostname
(
url
)
)
end
end
end
...
...
spec/models/project_services/pushover_service_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
PushoverService
do
include
StubRequests
describe
'Associations'
do
it
{
is_expected
.
to
belong_to
:project
}
it
{
is_expected
.
to
have_one
:service_hook
}
...
...
@@ -57,13 +59,13 @@ describe PushoverService do
sound:
sound
)
WebMock
.
stub_request
(
:post
,
api_url
)
stub_full_request
(
api_url
,
method: :post
,
ip_address:
'8.8.8.8'
)
end
it
'calls Pushover API'
do
pushover
.
execute
(
sample_data
)
expect
(
WebMock
).
to
have_requested
(
:post
,
api_url
).
once
expect
(
WebMock
).
to
have_requested
(
:post
,
'https://8.8.8.8/1/messages.json'
).
once
end
end
end
spec/models/project_services/teamcity_service_spec.rb
View file @
fdcaeb38
...
...
@@ -4,6 +4,7 @@ require 'spec_helper'
describe
TeamcityService
,
:use_clean_rails_memory_store_caching
do
include
ReactiveCachingHelpers
include
StubRequests
let
(
:teamcity_url
)
{
'http://gitlab.com/teamcity'
}
...
...
@@ -212,7 +213,7 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do
body
||=
%Q({"build":{"status":"
#{
build_status
}
","id":"666"}})
WebMock
.
stub_request
(
:get
,
teamcity_full_url
).
with
(
basic_auth:
auth
).
to_return
(
stub_full_request
(
teamcity_full_url
).
with
(
basic_auth:
auth
).
to_return
(
status:
status
,
headers:
{
'Content-Type'
=>
'application/json'
},
body:
body
...
...
spec/models/project_spec.rb
View file @
fdcaeb38
...
...
@@ -3170,6 +3170,23 @@ describe Project do
end
end
describe
'.ids_with_milestone_available_for'
do
let!
(
:user
)
{
create
(
:user
)
}
it
'returns project ids with milestones available for user'
do
project_1
=
create
(
:project
,
:public
,
:merge_requests_disabled
,
:issues_disabled
)
project_2
=
create
(
:project
,
:public
,
:merge_requests_disabled
)
project_3
=
create
(
:project
,
:public
,
:issues_disabled
)
project_4
=
create
(
:project
,
:public
)
project_4
.
project_feature
.
update
(
issues_access_level:
ProjectFeature
::
PRIVATE
,
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
project_ids
=
described_class
.
ids_with_milestone_available_for
(
user
).
pluck
(
:id
)
expect
(
project_ids
).
to
include
(
project_2
.
id
,
project_3
.
id
)
expect
(
project_ids
).
not_to
include
(
project_1
.
id
,
project_4
.
id
)
end
end
describe
'.with_feature_available_for_user'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:feature
)
{
MergeRequest
}
...
...
spec/requests/api/search_spec.rb
View file @
fdcaeb38
...
...
@@ -70,11 +70,30 @@ describe API::Search do
context
'for milestones scope'
do
before
do
create
(
:milestone
,
project:
project
,
title:
'awesome milestone'
)
end
context
'when user can read project milestones'
do
before
do
get
api
(
'/search'
,
user
),
params:
{
scope:
'milestones'
,
search:
'awesome'
}
end
get
api
(
'/search'
,
user
),
params:
{
scope:
'milestones'
,
search:
'awesome'
}
it_behaves_like
'response is correct'
,
schema:
'public_api/v4/milestones'
end
it_behaves_like
'response is correct'
,
schema:
'public_api/v4/milestones'
context
'when user cannot read project milestones'
do
before
do
project
.
project_feature
.
update!
(
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
project
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
PRIVATE
)
end
it
'returns empty array'
do
get
api
(
'/search'
,
user
),
params:
{
scope:
'milestones'
,
search:
'awesome'
}
milestones
=
JSON
.
parse
(
response
.
body
)
expect
(
milestones
).
to
be_empty
end
end
end
context
'for users scope'
do
...
...
@@ -318,11 +337,30 @@ describe API::Search do
context
'for milestones scope'
do
before
do
create
(
:milestone
,
project:
project
,
title:
'awesome milestone'
)
end
context
'when user can read milestones'
do
before
do
get
api
(
"/projects/
#{
project
.
id
}
/search"
,
user
),
params:
{
scope:
'milestones'
,
search:
'awesome'
}
end
get
api
(
"/projects/
#{
project
.
id
}
/search"
,
user
),
params:
{
scope:
'milestones'
,
search:
'awesome'
}
it_behaves_like
'response is correct'
,
schema:
'public_api/v4/milestones'
end
it_behaves_like
'response is correct'
,
schema:
'public_api/v4/milestones'
context
'when user cannot read project milestones'
do
before
do
project
.
project_feature
.
update!
(
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
project
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
PRIVATE
)
end
it
'returns empty array'
do
get
api
(
"/projects/
#{
project
.
id
}
/search"
,
user
),
params:
{
scope:
'milestones'
,
search:
'awesome'
}
milestones
=
JSON
.
parse
(
response
.
body
)
expect
(
milestones
).
to
be_empty
end
end
end
context
'for users scope'
do
...
...
spec/requests/api/system_hooks_spec.rb
View file @
fdcaeb38
require
'spec_helper'
describe
API
::
SystemHooks
do
include
StubRequests
let
(
:user
)
{
create
(
:user
)
}
let
(
:admin
)
{
create
(
:admin
)
}
let!
(
:hook
)
{
create
(
:system_hook
,
url:
"http://example.com"
)
}
before
do
stub_
request
(
:post
,
hook
.
url
)
stub_
full_request
(
hook
.
url
,
method: :post
)
end
describe
"GET /hooks"
do
...
...
@@ -68,6 +70,8 @@ describe API::SystemHooks do
end
it
'sets default values for events'
do
stub_full_request
(
'http://mep.mep'
,
method: :post
)
post
api
(
'/hooks'
,
admin
),
params:
{
url:
'http://mep.mep'
}
expect
(
response
).
to
have_gitlab_http_status
(
201
)
...
...
@@ -78,6 +82,8 @@ describe API::SystemHooks do
end
it
'sets explicit values for events'
do
stub_full_request
(
'http://mep.mep'
,
method: :post
)
post
api
(
'/hooks'
,
admin
),
params:
{
url:
'http://mep.mep'
,
...
...
spec/services/ci/create_pipeline_service_spec.rb
View file @
fdcaeb38
...
...
@@ -973,7 +973,7 @@ describe Ci::CreatePipelineService do
let
(
:merge_request
)
do
create
(
:merge_request
,
source_project:
project
,
source_branch:
ref_name
,
source_branch:
Gitlab
::
Git
.
ref_name
(
ref_name
)
,
target_project:
project
,
target_branch:
'master'
)
end
...
...
@@ -1004,7 +1004,7 @@ describe Ci::CreatePipelineService do
let
(
:merge_request
)
do
create
(
:merge_request
,
source_project:
project
,
source_branch:
ref_name
,
source_branch:
Gitlab
::
Git
.
ref_name
(
ref_name
)
,
target_project:
project
,
target_branch:
'master'
)
end
...
...
@@ -1033,7 +1033,7 @@ describe Ci::CreatePipelineService do
let
(
:merge_request
)
do
create
(
:merge_request
,
source_project:
project
,
source_branch:
ref_name
,
source_branch:
Gitlab
::
Git
.
ref_name
(
ref_name
)
,
target_project:
project
,
target_branch:
'master'
)
end
...
...
spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
View file @
fdcaeb38
...
...
@@ -2,6 +2,8 @@
require
'spec_helper'
describe
Projects
::
LfsPointers
::
LfsDownloadService
do
include
StubRequests
let
(
:project
)
{
create
(
:project
)
}
let
(
:lfs_content
)
{
SecureRandom
.
random_bytes
(
10
)
}
let
(
:oid
)
{
Digest
::
SHA256
.
hexdigest
(
lfs_content
)
}
...
...
@@ -62,7 +64,7 @@ describe Projects::LfsPointers::LfsDownloadService do
describe
'#execute'
do
context
'when file download succeeds'
do
before
do
WebMock
.
stub_request
(
:get
,
download_link
).
to_return
(
body:
lfs_content
)
stub_full_request
(
download_link
).
to_return
(
body:
lfs_content
)
end
it_behaves_like
'lfs object is created'
...
...
@@ -104,7 +106,7 @@ describe Projects::LfsPointers::LfsDownloadService do
let
(
:size
)
{
1
}
before
do
WebMock
.
stub_request
(
:get
,
download_link
).
to_return
(
body:
lfs_content
)
stub_full_request
(
download_link
).
to_return
(
body:
lfs_content
)
end
it_behaves_like
'no lfs object is created'
...
...
@@ -118,7 +120,7 @@ describe Projects::LfsPointers::LfsDownloadService do
context
'when downloaded lfs file has a different oid'
do
before
do
WebMock
.
stub_request
(
:get
,
download_link
).
to_return
(
body:
lfs_content
)
stub_full_request
(
download_link
).
to_return
(
body:
lfs_content
)
allow_any_instance_of
(
Digest
::
SHA256
).
to
receive
(
:hexdigest
).
and_return
(
'foobar'
)
end
...
...
@@ -136,7 +138,7 @@ describe Projects::LfsPointers::LfsDownloadService do
let
(
:lfs_object
)
{
LfsDownloadObject
.
new
(
oid:
oid
,
size:
size
,
link:
download_link_with_credentials
)
}
before
do
WebMock
.
stub_request
(
:get
,
download_link
).
with
(
headers:
{
'Authorization'
=>
'Basic dXNlcjpwYXNzd29yZA=='
}).
to_return
(
body:
lfs_content
)
stub_full_request
(
download_link
).
with
(
headers:
{
'Authorization'
=>
'Basic dXNlcjpwYXNzd29yZA=='
}).
to_return
(
body:
lfs_content
)
end
it
'the request adds authorization headers'
do
...
...
@@ -149,7 +151,7 @@ describe Projects::LfsPointers::LfsDownloadService do
let
(
:local_request_setting
)
{
true
}
before
do
WebMock
.
stub_request
(
:get
,
download_link
).
to_return
(
body:
lfs_content
)
stub_full_request
(
download_link
,
ip_address:
'192.168.2.120'
).
to_return
(
body:
lfs_content
)
end
it_behaves_like
'lfs object is created'
...
...
@@ -173,7 +175,8 @@ describe Projects::LfsPointers::LfsDownloadService do
with_them
do
before
do
WebMock
.
stub_request
(
:get
,
download_link
).
to_return
(
status:
301
,
headers:
{
'Location'
=>
redirect_link
})
stub_full_request
(
download_link
,
ip_address:
'192.168.2.120'
)
.
to_return
(
status:
301
,
headers:
{
'Location'
=>
redirect_link
})
end
it_behaves_like
'no lfs object is created'
...
...
@@ -184,8 +187,8 @@ describe Projects::LfsPointers::LfsDownloadService do
let
(
:redirect_link
)
{
"http://example.com/"
}
before
do
WebMock
.
stub_request
(
:get
,
download_link
).
to_return
(
status:
301
,
headers:
{
'Location'
=>
redirect_link
})
WebMock
.
stub_request
(
:get
,
redirect_link
).
to_return
(
body:
lfs_content
)
stub_full_request
(
download_link
).
to_return
(
status:
301
,
headers:
{
'Location'
=>
redirect_link
})
stub_full_request
(
redirect_link
).
to_return
(
body:
lfs_content
)
end
it_behaves_like
'lfs object is created'
...
...
spec/services/submit_usage_ping_service_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
SubmitUsagePingService
do
include
StubRequests
context
'when usage ping is disabled'
do
before
do
stub_application_setting
(
usage_ping_enabled:
false
)
...
...
@@ -99,7 +101,7 @@ describe SubmitUsagePingService do
end
def
stub_response
(
body
)
stub_
request
(
:post
,
'https://version.gitlab.com/usage_data'
)
stub_
full_request
(
'https://version.gitlab.com/usage_data'
,
method: :post
)
.
to_return
(
headers:
{
'Content-Type'
=>
'application/json'
},
body:
body
.
to_json
...
...
spec/services/web_hook_service_spec.rb
View file @
fdcaeb38
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
describe
WebHookService
do
include
StubRequests
let
(
:project
)
{
create
(
:project
)
}
let
(
:project_hook
)
{
create
(
:project_hook
)
}
let
(
:headers
)
do
...
...
@@ -67,11 +69,11 @@ describe WebHookService do
let
(
:project_hook
)
{
create
(
:project_hook
,
url:
'https://demo:demo@example.org/'
)
}
it
'uses the credentials'
do
WebMock
.
stub_request
(
:post
,
url
)
stub_full_request
(
url
,
method: :post
)
service_instance
.
execute
expect
(
WebMock
).
to
have_requested
(
:post
,
url
).
with
(
expect
(
WebMock
).
to
have_requested
(
:post
,
stubbed_hostname
(
url
)
).
with
(
headers:
headers
.
merge
(
'Authorization'
=>
'Basic ZGVtbzpkZW1v'
)
).
once
end
...
...
@@ -82,11 +84,11 @@ describe WebHookService do
let
(
:project_hook
)
{
create
(
:project_hook
,
url:
'https://demo@example.org/'
)
}
it
'uses the credentials anyways'
do
WebMock
.
stub_request
(
:post
,
url
)
stub_full_request
(
url
,
method: :post
)
service_instance
.
execute
expect
(
WebMock
).
to
have_requested
(
:post
,
url
).
with
(
expect
(
WebMock
).
to
have_requested
(
:post
,
stubbed_hostname
(
url
)
).
with
(
headers:
headers
.
merge
(
'Authorization'
=>
'Basic ZGVtbzo='
)
).
once
end
...
...
spec/support/helpers/stub_requests.rb
0 → 100644
View file @
fdcaeb38
module
StubRequests
IP_ADDRESS_STUB
=
'8.8.8.9'
.
freeze
# Fully stubs a request using WebMock class. This class also
# stubs the IP address the URL is translated to (DNS lookup).
#
# It expects the final request to go to the `ip_address` instead the given url.
# That's primarily a DNS rebind attack prevention of Gitlab::HTTP
# (see: Gitlab::UrlBlocker).
#
def
stub_full_request
(
url
,
ip_address:
IP_ADDRESS_STUB
,
port:
80
,
method: :get
)
stub_dns
(
url
,
ip_address:
ip_address
,
port:
port
)
url
=
stubbed_hostname
(
url
,
hostname:
ip_address
)
WebMock
.
stub_request
(
method
,
url
)
end
def
stub_dns
(
url
,
ip_address
:,
port:
80
)
url
=
parse_url
(
url
)
socket
=
Socket
.
sockaddr_in
(
port
,
ip_address
)
addr
=
Addrinfo
.
new
(
socket
)
# See Gitlab::UrlBlocker
allow
(
Addrinfo
).
to
receive
(
:getaddrinfo
)
.
with
(
url
.
hostname
,
url
.
port
,
nil
,
:STREAM
)
.
and_return
([
addr
])
end
def
stubbed_hostname
(
url
,
hostname:
IP_ADDRESS_STUB
)
url
=
parse_url
(
url
)
url
.
hostname
=
hostname
url
.
to_s
end
private
def
parse_url
(
url
)
url
.
is_a?
(
URI
)
?
url
:
URI
(
url
)
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment