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
49d689fb
Commit
49d689fb
authored
Jul 03, 2019
by
Marin Jankovski
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq
parents
ab0c3e08
bebbb43f
Changes
85
Show whitespace changes
Inline
Side-by-side
Showing
85 changed files
with
1404 additions
and
298 deletions
+1404
-298
CHANGELOG.md
CHANGELOG.md
+38
-0
app/controllers/concerns/issuable_collections.rb
app/controllers/concerns/issuable_collections.rb
+1
-1
app/controllers/concerns/issuable_collections_action.rb
app/controllers/concerns/issuable_collections_action.rb
+2
-2
app/controllers/concerns/notes_actions.rb
app/controllers/concerns/notes_actions.rb
+7
-7
app/controllers/projects/application_controller.rb
app/controllers/projects/application_controller.rb
+5
-0
app/controllers/projects/templates_controller.rb
app/controllers/projects/templates_controller.rb
+15
-2
app/controllers/projects_controller.rb
app/controllers/projects_controller.rb
+1
-1
app/controllers/snippets/notes_controller.rb
app/controllers/snippets/notes_controller.rb
+6
-2
app/controllers/snippets_controller.rb
app/controllers/snippets_controller.rb
+1
-1
app/controllers/uploads_controller.rb
app/controllers/uploads_controller.rb
+16
-4
app/graphql/types/ci/detailed_status_type.rb
app/graphql/types/ci/detailed_status_type.rb
+3
-0
app/graphql/types/issue_state_enum.rb
app/graphql/types/issue_state_enum.rb
+3
-0
app/graphql/types/label_type.rb
app/graphql/types/label_type.rb
+2
-0
app/graphql/types/merge_request_state_enum.rb
app/graphql/types/merge_request_state_enum.rb
+3
-0
app/graphql/types/metadata_type.rb
app/graphql/types/metadata_type.rb
+2
-0
app/graphql/types/namespace_type.rb
app/graphql/types/namespace_type.rb
+2
-0
app/graphql/types/notes/diff_position_type.rb
app/graphql/types/notes/diff_position_type.rb
+3
-0
app/graphql/types/project_type.rb
app/graphql/types/project_type.rb
+2
-2
app/graphql/types/query_type.rb
app/graphql/types/query_type.rb
+1
-4
app/graphql/types/task_completion_status.rb
app/graphql/types/task_completion_status.rb
+4
-0
app/graphql/types/tree/blob_type.rb
app/graphql/types/tree/blob_type.rb
+3
-0
app/graphql/types/tree/submodule_type.rb
app/graphql/types/tree/submodule_type.rb
+3
-0
app/graphql/types/tree/tree_entry_type.rb
app/graphql/types/tree/tree_entry_type.rb
+3
-0
app/graphql/types/tree/tree_type.rb
app/graphql/types/tree/tree_type.rb
+3
-0
app/helpers/issuables_helper.rb
app/helpers/issuables_helper.rb
+1
-1
app/helpers/snippets_helper.rb
app/helpers/snippets_helper.rb
+10
-0
app/models/concerns/issuable.rb
app/models/concerns/issuable.rb
+5
-1
app/models/issue.rb
app/models/issue.rb
+2
-2
app/models/merge_requests_closing_issues.rb
app/models/merge_requests_closing_issues.rb
+31
-4
app/policies/repository_policy.rb
app/policies/repository_policy.rb
+5
-0
app/uploaders/file_mover.rb
app/uploaders/file_mover.rb
+57
-25
app/validators/color_validator.rb
app/validators/color_validator.rb
+1
-1
app/views/layouts/snippets.html.haml
app/views/layouts/snippets.html.haml
+3
-2
app/views/shared/_issuable_meta_data.html.haml
app/views/shared/_issuable_meta_data.html.haml
+1
-1
changelogs/unreleased/osw-persist-tmp-snippet-uploads.yml
changelogs/unreleased/osw-persist-tmp-snippet-uploads.yml
+5
-0
changelogs/unreleased/security-2858-fix-color-validation.yml
changelogs/unreleased/security-2858-fix-color-validation.yml
+5
-0
changelogs/unreleased/security-59581-related-merge-requests-count.yml
...nreleased/security-59581-related-merge-requests-count.yml
+5
-0
changelogs/unreleased/security-DOS_issue_comments_banzai.yml
changelogs/unreleased/security-DOS_issue_comments_banzai.yml
+5
-0
changelogs/unreleased/security-bvl-enforce-graphql-type-authorization.yml
...eased/security-bvl-enforce-graphql-type-authorization.yml
+5
-0
changelogs/unreleased/security-fp-prevent-billion-laughs-attack.yml
.../unreleased/security-fp-prevent-billion-laughs-attack.yml
+5
-0
changelogs/unreleased/security-mr-head-pipeline-leak.yml
changelogs/unreleased/security-mr-head-pipeline-leak.yml
+5
-0
changelogs/unreleased/security-notes-in-private-snippets.yml
changelogs/unreleased/security-notes-in-private-snippets.yml
+5
-0
changelogs/unreleased/security-prevent-detection-of-merge-request-template-name.yml
...rity-prevent-detection-of-merge-request-template-name.yml
+5
-0
config/routes/project.rb
config/routes/project.rb
+4
-1
config/routes/uploads.rb
config/routes/uploads.rb
+2
-2
lib/api/entities.rb
lib/api/entities.rb
+6
-4
lib/api/issues.rb
lib/api/issues.rb
+3
-3
lib/api/merge_requests.rb
lib/api/merge_requests.rb
+1
-1
lib/api/todos.rb
lib/api/todos.rb
+1
-1
lib/banzai/filter/relative_link_filter.rb
lib/banzai/filter/relative_link_filter.rb
+1
-1
lib/gitlab/ci/config.rb
lib/gitlab/ci/config.rb
+5
-0
lib/gitlab/config/loader/yaml.rb
lib/gitlab/config/loader/yaml.rb
+30
-4
lib/gitlab/graphql/authorize/authorize_field_service.rb
lib/gitlab/graphql/authorize/authorize_field_service.rb
+2
-0
lib/gitlab/issuable_metadata.rb
lib/gitlab/issuable_metadata.rb
+2
-2
lib/gitlab/utils/deep_size.rb
lib/gitlab/utils/deep_size.rb
+79
-0
rubocop/cop/graphql/authorize_types.rb
rubocop/cop/graphql/authorize_types.rb
+61
-0
rubocop/rubocop.rb
rubocop/rubocop.rb
+1
-0
spec/controllers/projects/notes_controller_spec.rb
spec/controllers/projects/notes_controller_spec.rb
+1
-1
spec/controllers/projects/templates_controller_spec.rb
spec/controllers/projects/templates_controller_spec.rb
+81
-29
spec/controllers/snippets/notes_controller_spec.rb
spec/controllers/snippets/notes_controller_spec.rb
+113
-0
spec/controllers/snippets_controller_spec.rb
spec/controllers/snippets_controller_spec.rb
+2
-2
spec/controllers/uploads_controller_spec.rb
spec/controllers/uploads_controller_spec.rb
+108
-69
spec/features/snippets/user_creates_snippet_spec.rb
spec/features/snippets/user_creates_snippet_spec.rb
+1
-1
spec/graphql/types/label_type_spec.rb
spec/graphql/types/label_type_spec.rb
+2
-0
spec/graphql/types/metadata_type_spec.rb
spec/graphql/types/metadata_type_spec.rb
+1
-0
spec/graphql/types/namespace_type_spec.rb
spec/graphql/types/namespace_type_spec.rb
+2
-0
spec/graphql/types/query_type_spec.rb
spec/graphql/types/query_type_spec.rb
+0
-4
spec/lib/banzai/filter/relative_link_filter_spec.rb
spec/lib/banzai/filter/relative_link_filter_spec.rb
+5
-0
spec/lib/gitlab/ci/config_spec.rb
spec/lib/gitlab/ci/config_spec.rb
+21
-0
spec/lib/gitlab/config/loader/yaml_spec.rb
spec/lib/gitlab/config/loader/yaml_spec.rb
+68
-4
spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
.../gitlab/graphql/authorize/authorize_field_service_spec.rb
+48
-34
spec/lib/gitlab/issuable_metadata_spec.rb
spec/lib/gitlab/issuable_metadata_spec.rb
+4
-4
spec/lib/gitlab/utils/deep_size_spec.rb
spec/lib/gitlab/utils/deep_size_spec.rb
+43
-0
spec/requests/api/graphql/namespace/projects_spec.rb
spec/requests/api/graphql/namespace/projects_spec.rb
+1
-3
spec/requests/api/graphql/project/repository_spec.rb
spec/requests/api/graphql/project/repository_spec.rb
+24
-0
spec/requests/api/issues/get_group_issues_spec.rb
spec/requests/api/issues/get_group_issues_spec.rb
+29
-1
spec/requests/api/issues/get_project_issues_spec.rb
spec/requests/api/issues/get_project_issues_spec.rb
+34
-24
spec/requests/api/issues/issues_spec.rb
spec/requests/api/issues/issues_spec.rb
+29
-2
spec/requests/api/merge_requests_spec.rb
spec/requests/api/merge_requests_spec.rb
+25
-0
spec/routing/project_routing_spec.rb
spec/routing/project_routing_spec.rb
+20
-0
spec/routing/uploads_routing_spec.rb
spec/routing/uploads_routing_spec.rb
+11
-2
spec/rubocop/cop/graphql/authorize_types_spec.rb
spec/rubocop/cop/graphql/authorize_types_spec.rb
+66
-0
spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
...quests/api/issues/merge_requests_count_shared_examples.rb
+37
-0
spec/uploaders/file_mover_spec.rb
spec/uploaders/file_mover_spec.rb
+97
-36
spec/validators/color_validator_spec.rb
spec/validators/color_validator_spec.rb
+43
-0
No files found.
CHANGELOG.md
View file @
49d689fb
...
@@ -2,6 +2,23 @@
...
@@ -2,6 +2,23 @@
documentation
](
doc/development/changelog.md
)
for instructions on adding your own
documentation
](
doc/development/changelog.md
)
for instructions on adding your own
entry.
entry.
## 12.0.3 (2019-06-27)
-
No changes.
### Security (10 changes)
-
Persist tmp snippet uploads at users.
-
Gate MR head_pipeline behind read_pipeline ability.
-
Fix DoS vulnerability in color validation regex.
-
Expose merge requests count based on user access.
-
Fix Denial of Service for comments when rendering issues/MR comments.
-
Add missing authorizations in GraphQL.
-
Disable Rails SQL query cache when applying service templates.
-
Prevent Billion Laughs attack.
-
Correctly check permissions when creating snippet notes.
-
Prevent the detection of merge request templates by unauthorized users.
## 12.0.2 (2019-06-25)
## 12.0.2 (2019-06-25)
### Fixed (7 changes, 1 of them is from the community)
### Fixed (7 changes, 1 of them is from the community)
...
@@ -555,6 +572,27 @@ entry.
...
@@ -555,6 +572,27 @@ entry.
-
Add some frozen string to spec/
**
/
*
.rb. (gfyoung)
-
Add some frozen string to spec/
**
/
*
.rb. (gfyoung)
## 11.10.8 (2019-06-27)
-
No changes.
### Security (10 changes)
-
Fix Denial of Service for comments when rendering issues/MR comments.
-
Gate MR head_pipeline behind read_pipeline ability.
-
Fix DoS vulnerability in color validation regex.
-
Expose merge requests count based on user access.
-
Persist tmp snippet uploads at users.
-
Add missing authorizations in GraphQL.
-
Disable Rails SQL query cache when applying service templates.
-
Prevent Billion Laughs attack.
-
Correctly check permissions when creating snippet notes.
-
Prevent the detection of merge request templates by unauthorized users.
### Performance (1 change)
-
Add improvements to global search of issues and merge requests. !27817
## 11.10.6 (2019-06-04)
## 11.10.6 (2019-06-04)
### Fixed (7 changes, 1 of them is from the community)
### Fixed (7 changes, 1 of them is from the community)
...
...
app/controllers/concerns/issuable_collections.rb
View file @
49d689fb
...
@@ -42,7 +42,7 @@ module IssuableCollections
...
@@ -42,7 +42,7 @@ module IssuableCollections
@issuables
=
@issuables
.
page
(
params
[
:page
])
@issuables
=
@issuables
.
page
(
params
[
:page
])
@issuables
=
per_page_for_relative_position
if
params
[
:sort
]
==
'relative_position'
@issuables
=
per_page_for_relative_position
if
params
[
:sort
]
==
'relative_position'
@issuable_meta_data
=
issuable_meta_data
(
@issuables
,
collection_type
)
@issuable_meta_data
=
issuable_meta_data
(
@issuables
,
collection_type
,
current_user
)
@total_pages
=
issuable_page_count
@total_pages
=
issuable_page_count
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
# rubocop:enable Gitlab/ModuleWithInstanceVariables
...
...
app/controllers/concerns/issuable_collections_action.rb
View file @
49d689fb
...
@@ -11,7 +11,7 @@ module IssuableCollectionsAction
...
@@ -11,7 +11,7 @@ module IssuableCollectionsAction
.
non_archived
.
non_archived
.
page
(
params
[
:page
])
.
page
(
params
[
:page
])
@issuable_meta_data
=
issuable_meta_data
(
@issues
,
collection_type
)
@issuable_meta_data
=
issuable_meta_data
(
@issues
,
collection_type
,
current_user
)
respond_to
do
|
format
|
respond_to
do
|
format
|
format
.
html
format
.
html
...
@@ -22,7 +22,7 @@ module IssuableCollectionsAction
...
@@ -22,7 +22,7 @@ module IssuableCollectionsAction
def
merge_requests
def
merge_requests
@merge_requests
=
issuables_collection
.
page
(
params
[
:page
])
@merge_requests
=
issuables_collection
.
page
(
params
[
:page
])
@issuable_meta_data
=
issuable_meta_data
(
@merge_requests
,
collection_type
)
@issuable_meta_data
=
issuable_meta_data
(
@merge_requests
,
collection_type
,
current_user
)
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
# rubocop:enable Gitlab/ModuleWithInstanceVariables
...
...
app/controllers/concerns/notes_actions.rb
View file @
49d689fb
...
@@ -203,17 +203,17 @@ module NotesActions
...
@@ -203,17 +203,17 @@ module NotesActions
# These params are also sent by the client but we need to set these based on
# These params are also sent by the client but we need to set these based on
# target_type and target_id because we're checking permissions based on that
# target_type and target_id because we're checking permissions based on that
create_params
[
:noteable_type
]
=
params
[
:target_type
].
classify
create_params
[
:noteable_type
]
=
noteable
.
class
.
name
case
params
[
:target_type
]
case
noteable
when
'commit'
when
Commit
create_params
[
:commit_id
]
=
params
[
:target_id
]
create_params
[
:commit_id
]
=
noteable
.
id
when
'merge_request'
when
MergeRequest
create_params
[
:noteable_id
]
=
params
[
:target_id
]
create_params
[
:noteable_id
]
=
noteable
.
id
# Notes on MergeRequest can have an extra `commit_id` context
# Notes on MergeRequest can have an extra `commit_id` context
create_params
[
:commit_id
]
=
params
.
dig
(
:note
,
:commit_id
)
create_params
[
:commit_id
]
=
params
.
dig
(
:note
,
:commit_id
)
else
else
create_params
[
:noteable_id
]
=
params
[
:target_id
]
create_params
[
:noteable_id
]
=
noteable
.
id
end
end
end
end
end
end
...
...
app/controllers/projects/application_controller.rb
View file @
49d689fb
...
@@ -12,6 +12,11 @@ class Projects::ApplicationController < ApplicationController
...
@@ -12,6 +12,11 @@ class Projects::ApplicationController < ApplicationController
helper_method
:repository
,
:can_collaborate_with_project?
,
:user_access
helper_method
:repository
,
:can_collaborate_with_project?
,
:user_access
rescue_from
Gitlab
::
Template
::
Finders
::
RepoTemplateFinder
::
FileNotFoundError
do
|
exception
|
log_exception
(
exception
)
render_404
end
private
private
def
project
def
project
...
...
app/controllers/projects/templates_controller.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
class
Projects::TemplatesController
<
Projects
::
ApplicationController
class
Projects::TemplatesController
<
Projects
::
ApplicationController
before_action
:authenticate_user!
,
:get_template_class
before_action
:authenticate_user!
before_action
:authorize_can_read_issuable!
before_action
:get_template_class
def
show
def
show
template
=
@template_type
.
find
(
params
[
:key
],
project
)
template
=
@template_type
.
find
(
params
[
:key
],
project
)
...
@@ -13,9 +15,20 @@ class Projects::TemplatesController < Projects::ApplicationController
...
@@ -13,9 +15,20 @@ class Projects::TemplatesController < Projects::ApplicationController
private
private
# User must have:
# - `read_merge_request` to see merge request templates, or
# - `read_issue` to see issue templates
#
# Note params[:template_type] has a route constraint to limit it to
# `merge_request` or `issue`
def
authorize_can_read_issuable!
action
=
[
:read_
,
params
[
:template_type
]].
join
authorize_action!
(
action
)
end
def
get_template_class
def
get_template_class
template_types
=
{
issue:
Gitlab
::
Template
::
IssueTemplate
,
merge_request:
Gitlab
::
Template
::
MergeRequestTemplate
}.
with_indifferent_access
template_types
=
{
issue:
Gitlab
::
Template
::
IssueTemplate
,
merge_request:
Gitlab
::
Template
::
MergeRequestTemplate
}.
with_indifferent_access
@template_type
=
template_types
[
params
[
:template_type
]]
@template_type
=
template_types
[
params
[
:template_type
]]
render
json:
[],
status: :not_found
unless
@template_type
end
end
end
end
app/controllers/projects_controller.rb
View file @
49d689fb
...
@@ -298,7 +298,7 @@ class ProjectsController < Projects::ApplicationController
...
@@ -298,7 +298,7 @@ class ProjectsController < Projects::ApplicationController
elsif
@project
.
feature_available?
(
:issues
,
current_user
)
elsif
@project
.
feature_available?
(
:issues
,
current_user
)
@issues
=
issuables_collection
.
page
(
params
[
:page
])
@issues
=
issuables_collection
.
page
(
params
[
:page
])
@collection_type
=
'Issue'
@collection_type
=
'Issue'
@issuable_meta_data
=
issuable_meta_data
(
@issues
,
@collection_type
)
@issuable_meta_data
=
issuable_meta_data
(
@issues
,
@collection_type
,
current_user
)
end
end
render
:show
render
:show
...
...
app/controllers/snippets/notes_controller.rb
View file @
49d689fb
...
@@ -5,8 +5,8 @@ class Snippets::NotesController < ApplicationController
...
@@ -5,8 +5,8 @@ class Snippets::NotesController < ApplicationController
include
ToggleAwardEmoji
include
ToggleAwardEmoji
skip_before_action
:authenticate_user!
,
only:
[
:index
]
skip_before_action
:authenticate_user!
,
only:
[
:index
]
before_action
:
snippet
before_action
:
authorize_read_snippet!
,
only:
[
:show
,
:index
]
before_action
:authorize_
read_snippet!
,
only:
[
:show
,
:index
,
:create
]
before_action
:authorize_
create_note!
,
only:
[
:create
]
private
private
...
@@ -33,4 +33,8 @@ class Snippets::NotesController < ApplicationController
...
@@ -33,4 +33,8 @@ class Snippets::NotesController < ApplicationController
def
authorize_read_snippet!
def
authorize_read_snippet!
return
render_404
unless
can?
(
current_user
,
:read_personal_snippet
,
snippet
)
return
render_404
unless
can?
(
current_user
,
:read_personal_snippet
,
snippet
)
end
end
def
authorize_create_note!
access_denied!
unless
can?
(
current_user
,
:create_note
,
noteable
)
end
end
end
app/controllers/snippets_controller.rb
View file @
49d689fb
...
@@ -137,7 +137,7 @@ class SnippetsController < ApplicationController
...
@@ -137,7 +137,7 @@ class SnippetsController < ApplicationController
def
move_temporary_files
def
move_temporary_files
params
[
:files
].
each
do
|
file
|
params
[
:files
].
each
do
|
file
|
FileMover
.
new
(
file
,
@snippet
).
execute
FileMover
.
new
(
file
,
from_model:
current_user
,
to_model:
@snippet
).
execute
end
end
end
end
end
end
app/controllers/uploads_controller.rb
View file @
49d689fb
...
@@ -41,7 +41,11 @@ class UploadsController < ApplicationController
...
@@ -41,7 +41,11 @@ class UploadsController < ApplicationController
when
Note
when
Note
can?
(
current_user
,
:read_project
,
model
.
project
)
can?
(
current_user
,
:read_project
,
model
.
project
)
when
User
when
User
true
# We validate the current user has enough (writing)
# access to itself when a secret is given.
# For instance, user avatars are readable by anyone,
# while temporary, user snippet uploads are not.
!
secret?
||
can?
(
current_user
,
:update_user
,
model
)
when
Appearance
when
Appearance
true
true
else
else
...
@@ -56,9 +60,13 @@ class UploadsController < ApplicationController
...
@@ -56,9 +60,13 @@ class UploadsController < ApplicationController
def
authorize_create_access!
def
authorize_create_access!
return
unless
model
return
unless
model
# for now we support only personal snippets comments. Only personal_snippet
authorized
=
# is allowed as a model to #create through routing.
case
model
authorized
=
can?
(
current_user
,
:create_note
,
model
)
when
User
can?
(
current_user
,
:update_user
,
model
)
else
can?
(
current_user
,
:create_note
,
model
)
end
render_unauthorized
unless
authorized
render_unauthorized
unless
authorized
end
end
...
@@ -75,6 +83,10 @@ class UploadsController < ApplicationController
...
@@ -75,6 +83,10 @@ class UploadsController < ApplicationController
User
===
model
||
Appearance
===
model
User
===
model
||
Appearance
===
model
end
end
def
secret?
params
[
:secret
].
present?
end
def
upload_model_class
def
upload_model_class
MODEL_CLASSES
[
params
[
:model
]]
||
raise
(
UnknownUploadModelError
)
MODEL_CLASSES
[
params
[
:model
]]
||
raise
(
UnknownUploadModelError
)
end
end
...
...
app/graphql/types/ci/detailed_status_type.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
module
Types
module
Types
module
Ci
module
Ci
# rubocop: disable Graphql/AuthorizeTypes
# This is presented through `PipelineType` that has its own authorization
class
DetailedStatusType
<
BaseObject
class
DetailedStatusType
<
BaseObject
graphql_name
'DetailedStatus'
graphql_name
'DetailedStatus'
...
@@ -13,5 +15,6 @@ module Types
...
@@ -13,5 +15,6 @@ module Types
field
:text
,
GraphQL
::
STRING_TYPE
,
null:
false
field
:text
,
GraphQL
::
STRING_TYPE
,
null:
false
field
:tooltip
,
GraphQL
::
STRING_TYPE
,
null:
false
,
method: :status_tooltip
field
:tooltip
,
GraphQL
::
STRING_TYPE
,
null:
false
,
method: :status_tooltip
end
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
end
end
app/graphql/types/issue_state_enum.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
module
Types
module
Types
# rubocop: disable Graphql/AuthorizeTypes
# This is a BaseEnum through IssuableEnum, so it does not need authorization
class
IssueStateEnum
<
IssuableStateEnum
class
IssueStateEnum
<
IssuableStateEnum
graphql_name
'IssueState'
graphql_name
'IssueState'
description
'State of a GitLab issue'
description
'State of a GitLab issue'
end
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
app/graphql/types/label_type.rb
View file @
49d689fb
...
@@ -4,6 +4,8 @@ module Types
...
@@ -4,6 +4,8 @@ module Types
class
LabelType
<
BaseObject
class
LabelType
<
BaseObject
graphql_name
'Label'
graphql_name
'Label'
authorize
:read_label
field
:description
,
GraphQL
::
STRING_TYPE
,
null:
true
field
:description
,
GraphQL
::
STRING_TYPE
,
null:
true
markdown_field
:description_html
,
null:
true
markdown_field
:description_html
,
null:
true
field
:title
,
GraphQL
::
STRING_TYPE
,
null:
false
field
:title
,
GraphQL
::
STRING_TYPE
,
null:
false
...
...
app/graphql/types/merge_request_state_enum.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
module
Types
module
Types
# rubocop: disable Graphql/AuthorizeTypes
# This is a BaseEnum through IssuableEnum, so it does not need authorization
class
MergeRequestStateEnum
<
IssuableStateEnum
class
MergeRequestStateEnum
<
IssuableStateEnum
graphql_name
'MergeRequestState'
graphql_name
'MergeRequestState'
description
'State of a GitLab merge request'
description
'State of a GitLab merge request'
value
'merged'
value
'merged'
end
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
app/graphql/types/metadata_type.rb
View file @
49d689fb
...
@@ -4,6 +4,8 @@ module Types
...
@@ -4,6 +4,8 @@ module Types
class
MetadataType
<
::
Types
::
BaseObject
class
MetadataType
<
::
Types
::
BaseObject
graphql_name
'Metadata'
graphql_name
'Metadata'
authorize
:read_instance_metadata
field
:version
,
GraphQL
::
STRING_TYPE
,
null:
false
field
:version
,
GraphQL
::
STRING_TYPE
,
null:
false
field
:revision
,
GraphQL
::
STRING_TYPE
,
null:
false
field
:revision
,
GraphQL
::
STRING_TYPE
,
null:
false
end
end
...
...
app/graphql/types/namespace_type.rb
View file @
49d689fb
...
@@ -4,6 +4,8 @@ module Types
...
@@ -4,6 +4,8 @@ module Types
class
NamespaceType
<
BaseObject
class
NamespaceType
<
BaseObject
graphql_name
'Namespace'
graphql_name
'Namespace'
authorize
:read_namespace
field
:id
,
GraphQL
::
ID_TYPE
,
null:
false
field
:id
,
GraphQL
::
ID_TYPE
,
null:
false
field
:name
,
GraphQL
::
STRING_TYPE
,
null:
false
field
:name
,
GraphQL
::
STRING_TYPE
,
null:
false
...
...
app/graphql/types/notes/diff_position_type.rb
View file @
49d689fb
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
module
Types
module
Types
module
Notes
module
Notes
# rubocop: disable Graphql/AuthorizeTypes
# This is presented through `NoteType` that has its own authorization
class
DiffPositionType
<
BaseObject
class
DiffPositionType
<
BaseObject
graphql_name
'DiffPosition'
graphql_name
'DiffPosition'
...
@@ -42,5 +44,6 @@ module Types
...
@@ -42,5 +44,6 @@ module Types
description:
"The total height of the image"
,
description:
"The total height of the image"
,
resolve:
->
(
position
,
_args
,
_ctx
)
{
position
.
height
if
position
.
on_image?
}
resolve:
->
(
position
,
_args
,
_ctx
)
{
position
.
height
if
position
.
on_image?
}
end
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
end
end
app/graphql/types/project_type.rb
View file @
49d689fb
...
@@ -67,14 +67,14 @@ module Types
...
@@ -67,14 +67,14 @@ module Types
field
:only_allow_merge_if_all_discussions_are_resolved
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
field
:only_allow_merge_if_all_discussions_are_resolved
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
field
:printing_merge_request_link_enabled
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
field
:printing_merge_request_link_enabled
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
field
:namespace
,
Types
::
NamespaceType
,
null:
fals
e
field
:namespace
,
Types
::
NamespaceType
,
null:
tru
e
field
:group
,
Types
::
GroupType
,
null:
true
field
:group
,
Types
::
GroupType
,
null:
true
field
:statistics
,
Types
::
ProjectStatisticsType
,
field
:statistics
,
Types
::
ProjectStatisticsType
,
null:
true
,
null:
true
,
resolve:
->
(
obj
,
_args
,
_ctx
)
{
Gitlab
::
Graphql
::
Loaders
::
BatchProjectStatisticsLoader
.
new
(
obj
.
id
).
find
}
resolve:
->
(
obj
,
_args
,
_ctx
)
{
Gitlab
::
Graphql
::
Loaders
::
BatchProjectStatisticsLoader
.
new
(
obj
.
id
).
find
}
field
:repository
,
Types
::
RepositoryType
,
null:
fals
e
field
:repository
,
Types
::
RepositoryType
,
null:
tru
e
field
:merge_requests
,
field
:merge_requests
,
Types
::
MergeRequestType
.
connection_type
,
Types
::
MergeRequestType
.
connection_type
,
...
...
app/graphql/types/query_type.rb
View file @
49d689fb
...
@@ -22,10 +22,7 @@ module Types
...
@@ -22,10 +22,7 @@ module Types
field
:metadata
,
Types
::
MetadataType
,
field
:metadata
,
Types
::
MetadataType
,
null:
true
,
null:
true
,
resolver:
Resolvers
::
MetadataResolver
,
resolver:
Resolvers
::
MetadataResolver
,
description:
'Metadata about GitLab'
do
|*
args
|
description:
'Metadata about GitLab'
authorize
:read_instance_metadata
end
field
:echo
,
GraphQL
::
STRING_TYPE
,
null:
false
,
function:
Functions
::
Echo
.
new
field
:echo
,
GraphQL
::
STRING_TYPE
,
null:
false
,
function:
Functions
::
Echo
.
new
end
end
...
...
app/graphql/types/task_completion_status.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
module
Types
module
Types
# rubocop: disable Graphql/AuthorizeTypes
# This is used in `IssueType` and `MergeRequestType` both of which have their
# own authorization
class
TaskCompletionStatus
<
BaseObject
class
TaskCompletionStatus
<
BaseObject
graphql_name
'TaskCompletionStatus'
graphql_name
'TaskCompletionStatus'
description
'Completion status of tasks'
description
'Completion status of tasks'
...
@@ -8,4 +11,5 @@ module Types
...
@@ -8,4 +11,5 @@ module Types
field
:count
,
GraphQL
::
INT_TYPE
,
null:
false
field
:count
,
GraphQL
::
INT_TYPE
,
null:
false
field
:completed_count
,
GraphQL
::
INT_TYPE
,
null:
false
field
:completed_count
,
GraphQL
::
INT_TYPE
,
null:
false
end
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
app/graphql/types/tree/blob_type.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
module
Types
module
Types
module
Tree
module
Tree
# rubocop: disable Graphql/AuthorizeTypes
# This is presented through `Repository` that has its own authorization
class
BlobType
<
BaseObject
class
BlobType
<
BaseObject
implements
Types
::
Tree
::
EntryType
implements
Types
::
Tree
::
EntryType
...
@@ -12,6 +14,7 @@ module Types
...
@@ -12,6 +14,7 @@ module Types
field
:lfs_oid
,
GraphQL
::
STRING_TYPE
,
null:
true
,
resolve:
->
(
blob
,
args
,
ctx
)
do
field
:lfs_oid
,
GraphQL
::
STRING_TYPE
,
null:
true
,
resolve:
->
(
blob
,
args
,
ctx
)
do
Gitlab
::
Graphql
::
Loaders
::
BatchLfsOidLoader
.
new
(
blob
.
repository
,
blob
.
id
).
find
Gitlab
::
Graphql
::
Loaders
::
BatchLfsOidLoader
.
new
(
blob
.
repository
,
blob
.
id
).
find
end
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
end
end
end
end
app/graphql/types/tree/submodule_type.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
module
Types
module
Types
module
Tree
module
Tree
# rubocop: disable Graphql/AuthorizeTypes
# This is presented through `Repository` that has its own authorization
class
SubmoduleType
<
BaseObject
class
SubmoduleType
<
BaseObject
implements
Types
::
Tree
::
EntryType
implements
Types
::
Tree
::
EntryType
graphql_name
'Submodule'
graphql_name
'Submodule'
end
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
end
end
app/graphql/types/tree/tree_entry_type.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
module
Types
module
Types
module
Tree
module
Tree
# rubocop: disable Graphql/AuthorizeTypes
# This is presented through `Repository` that has its own authorization
class
TreeEntryType
<
BaseObject
class
TreeEntryType
<
BaseObject
implements
Types
::
Tree
::
EntryType
implements
Types
::
Tree
::
EntryType
...
@@ -11,5 +13,6 @@ module Types
...
@@ -11,5 +13,6 @@ module Types
field
:web_url
,
GraphQL
::
STRING_TYPE
,
null:
true
field
:web_url
,
GraphQL
::
STRING_TYPE
,
null:
true
end
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
end
end
app/graphql/types/tree/tree_type.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
module
Types
module
Types
module
Tree
module
Tree
# rubocop: disable Graphql/AuthorizeTypes
# This is presented through `Repository` that has its own authorization
class
TreeType
<
BaseObject
class
TreeType
<
BaseObject
graphql_name
'Tree'
graphql_name
'Tree'
...
@@ -13,6 +15,7 @@ module Types
...
@@ -13,6 +15,7 @@ module Types
field
:blobs
,
Types
::
Tree
::
BlobType
.
connection_type
,
null:
false
,
resolve:
->
(
obj
,
args
,
ctx
)
do
field
:blobs
,
Types
::
Tree
::
BlobType
.
connection_type
,
null:
false
,
resolve:
->
(
obj
,
args
,
ctx
)
do
Gitlab
::
Graphql
::
Representation
::
TreeEntry
.
decorate
(
obj
.
blobs
,
obj
.
repository
)
Gitlab
::
Graphql
::
Representation
::
TreeEntry
.
decorate
(
obj
.
blobs
,
obj
.
repository
)
end
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
end
end
end
end
app/helpers/issuables_helper.rb
View file @
49d689fb
...
@@ -280,7 +280,7 @@ module IssuablesHelper
...
@@ -280,7 +280,7 @@ module IssuablesHelper
initialTaskStatus:
issuable
.
task_status
initialTaskStatus:
issuable
.
task_status
}
}
data
[
:hasClosingMergeRequest
]
=
issuable
.
merge_requests_count
!=
0
if
issuable
.
is_a?
(
Issue
)
data
[
:hasClosingMergeRequest
]
=
issuable
.
merge_requests_count
(
current_user
)
!=
0
if
issuable
.
is_a?
(
Issue
)
if
parent
.
is_a?
(
Group
)
if
parent
.
is_a?
(
Group
)
data
[
:groupPath
]
=
parent
.
path
data
[
:groupPath
]
=
parent
.
path
...
...
app/helpers/snippets_helper.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
module
SnippetsHelper
module
SnippetsHelper
def
snippets_upload_path
(
snippet
,
user
)
return
unless
user
if
snippet
&
.
persisted?
upload_path
(
'personal_snippet'
,
id:
snippet
.
id
)
else
upload_path
(
'user'
,
id:
user
.
id
)
end
end
def
reliable_snippet_path
(
snippet
,
opts
=
nil
)
def
reliable_snippet_path
(
snippet
,
opts
=
nil
)
if
snippet
.
project_id?
if
snippet
.
project_id?
project_snippet_path
(
snippet
.
project
,
snippet
,
opts
)
project_snippet_path
(
snippet
.
project
,
snippet
,
opts
)
...
...
app/models/concerns/issuable.rb
View file @
49d689fb
...
@@ -29,7 +29,11 @@ module Issuable
...
@@ -29,7 +29,11 @@ module Issuable
# This object is used to gather issuable meta data for displaying
# This object is used to gather issuable meta data for displaying
# upvotes, downvotes, notes and closing merge requests count for issues and merge requests
# upvotes, downvotes, notes and closing merge requests count for issues and merge requests
# lists avoiding n+1 queries and improving performance.
# lists avoiding n+1 queries and improving performance.
IssuableMeta
=
Struct
.
new
(
:upvotes
,
:downvotes
,
:user_notes_count
,
:merge_requests_count
)
IssuableMeta
=
Struct
.
new
(
:upvotes
,
:downvotes
,
:user_notes_count
,
:mrs_count
)
do
def
merge_requests_count
(
user
=
nil
)
mrs_count
end
end
included
do
included
do
cache_markdown_field
:title
,
pipeline: :single_line
cache_markdown_field
:title
,
pipeline: :single_line
...
...
app/models/issue.rb
View file @
49d689fb
...
@@ -250,8 +250,8 @@ class Issue < ApplicationRecord
...
@@ -250,8 +250,8 @@ class Issue < ApplicationRecord
end
end
# rubocop: enable CodeReuse/ServiceClass
# rubocop: enable CodeReuse/ServiceClass
def
merge_requests_count
def
merge_requests_count
(
user
=
nil
)
merge_requests_closing_issues
.
count
::
MergeRequestsClosingIssues
.
count_for_issue
(
self
.
id
,
user
)
end
end
def
labels_hook_attrs
def
labels_hook_attrs
...
...
app/models/merge_requests_closing_issues.rb
View file @
49d689fb
...
@@ -7,11 +7,38 @@ class MergeRequestsClosingIssues < ApplicationRecord
...
@@ -7,11 +7,38 @@ class MergeRequestsClosingIssues < ApplicationRecord
validates
:merge_request_id
,
uniqueness:
{
scope: :issue_id
},
presence:
true
validates
:merge_request_id
,
uniqueness:
{
scope: :issue_id
},
presence:
true
validates
:issue_id
,
presence:
true
validates
:issue_id
,
presence:
true
scope
:with_issues
,
->
(
ids
)
{
where
(
issue_id:
ids
)
}
scope
:with_merge_requests_enabled
,
->
do
joins
(
:merge_request
)
.
joins
(
'INNER JOIN project_features ON merge_requests.target_project_id = project_features.project_id'
)
.
where
(
'project_features.merge_requests_access_level >= :access'
,
access:
ProjectFeature
::
ENABLED
)
end
scope
:accessible_by
,
->
(
user
)
do
joins
(
:merge_request
)
.
joins
(
'INNER JOIN project_features ON merge_requests.target_project_id = project_features.project_id'
)
.
where
(
'project_features.merge_requests_access_level >= :access OR EXISTS(:authorizations)'
,
access:
ProjectFeature
::
ENABLED
,
authorizations:
user
.
authorizations_for_projects
(
min_access_level:
Gitlab
::
Access
::
REPORTER
,
related_project_column:
"merge_requests.target_project_id"
)
)
end
class
<<
self
class
<<
self
def
count_for_collection
(
ids
)
def
count_for_collection
(
ids
,
current_user
)
group
(
:issue_id
)
closing_merge_requests
(
ids
,
current_user
).
group
(
:issue_id
).
pluck
(
'issue_id'
,
'COUNT(*) as count'
)
.
where
(
issue_id:
ids
)
end
.
pluck
(
'issue_id'
,
'COUNT(*) as count'
)
def
count_for_issue
(
id
,
current_user
)
closing_merge_requests
(
id
,
current_user
).
count
end
private
def
closing_merge_requests
(
ids
,
current_user
)
return
with_issues
(
ids
)
if
current_user
&
.
admin?
return
with_issues
(
ids
).
with_merge_requests_enabled
if
current_user
.
blank?
with_issues
(
ids
).
accessible_by
(
current_user
)
end
end
end
end
end
end
app/policies/repository_policy.rb
0 → 100644
View file @
49d689fb
# frozen_string_literal: true
class
RepositoryPolicy
<
BasePolicy
delegate
{
@subject
.
project
}
end
app/uploaders/file_mover.rb
View file @
49d689fb
# frozen_string_literal: true
# frozen_string_literal: true
class
FileMover
class
FileMover
attr_reader
:secret
,
:file_name
,
:model
,
:update_field
include
Gitlab
::
Utils
::
StrongMemoize
def
initialize
(
file_path
,
model
,
update_field
=
:description
)
attr_reader
:secret
,
:file_name
,
:from_model
,
:to_model
,
:update_field
def
initialize
(
file_path
,
update_field
=
:description
,
from_model
:,
to_model
:)
@secret
=
File
.
split
(
File
.
dirname
(
file_path
)).
last
@secret
=
File
.
split
(
File
.
dirname
(
file_path
)).
last
@file_name
=
File
.
basename
(
file_path
)
@file_name
=
File
.
basename
(
file_path
)
@model
=
model
@from_model
=
from_model
@to_model
=
to_model
@update_field
=
update_field
@update_field
=
update_field
end
end
def
execute
def
execute
temp_file_uploader
.
retrieve_from_store!
(
file_name
)
return
unless
valid?
return
unless
valid?
uploader
.
retrieve_from_store!
(
file_name
)
move
move
if
update_markdown
if
update_markdown
up
loader
.
record_upload
up
date_upload_model
uploader
.
schedule_background_upload
uploader
.
schedule_background_upload
end
end
end
end
...
@@ -24,52 +31,77 @@ class FileMover
...
@@ -24,52 +31,77 @@ class FileMover
private
private
def
valid?
def
valid?
if
temp_file_uploader
.
file_storage?
Pathname
.
new
(
temp_file_path
).
realpath
.
to_path
.
start_with?
(
Pathname
.
new
(
temp_file_path
).
realpath
.
to_path
.
start_with?
(
(
Pathname
(
temp_file_uploader
.
root
)
+
temp_file_uploader
.
base_dir
).
to_path
(
Pathname
(
temp_file_uploader
.
root
)
+
temp_file_uploader
.
base_dir
).
to_path
)
)
else
temp_file_uploader
.
exists?
end
end
end
def
move
def
move
if
temp_file_uploader
.
file_storage?
FileUtils
.
mkdir_p
(
File
.
dirname
(
file_path
))
FileUtils
.
mkdir_p
(
File
.
dirname
(
file_path
))
FileUtils
.
move
(
temp_file_path
,
file_path
)
FileUtils
.
move
(
temp_file_path
,
file_path
)
else
uploader
.
copy_file
(
temp_file_uploader
.
file
)
temp_file_uploader
.
upload
.
destroy!
end
end
end
def
update_markdown
def
update_markdown
updated_text
=
model
.
read_attribute
(
update_field
)
updated_text
=
to_
model
.
read_attribute
(
update_field
)
.
gsub
(
temp_file_uploader
.
markdown_link
,
uploader
.
markdown_link
)
.
gsub
(
temp_file_uploader
.
markdown_link
,
uploader
.
markdown_link
)
model
.
update_attribute
(
update_field
,
updated_text
)
to_
model
.
update_attribute
(
update_field
,
updated_text
)
rescue
rescue
revert
revert
false
false
end
end
def
temp_file_path
def
update_upload_model
return
@temp_file_path
if
@temp_file_path
return
unless
upload
=
temp_file_uploader
.
upload
return
if
upload
.
destroyed?
temp_file_uploader
.
retrieve_from_store!
(
file_name
)
upload
.
update!
(
model:
to_model
)
end
@temp_file_path
=
temp_file_uploader
.
file
.
path
def
temp_file_path
strong_memoize
(
:temp_file_path
)
do
temp_file_uploader
.
file
.
path
end
end
end
def
file_path
def
file_path
return
@file_path
if
@file_path
strong_memoize
(
:file_path
)
do
uploader
.
file
.
path
uploader
.
retrieve_from_store!
(
file_name
)
end
@file_path
=
uploader
.
file
.
path
end
end
def
uploader
def
uploader
@uploader
||=
PersonalFileUploader
.
new
(
model
,
secret:
secret
)
@uploader
||=
begin
uploader
=
PersonalFileUploader
.
new
(
to_model
,
secret:
secret
)
# Enforcing a REMOTE object storage given FileUploader#retrieve_from_store! won't do it
# (there's no upload at the target yet).
if
uploader
.
class
.
object_store_enabled?
uploader
.
object_store
=
::
ObjectStorage
::
Store
::
REMOTE
end
uploader
end
end
end
def
temp_file_uploader
def
temp_file_uploader
@temp_file_uploader
||=
PersonalFileUploader
.
new
(
ni
l
,
secret:
secret
)
@temp_file_uploader
||=
PersonalFileUploader
.
new
(
from_mode
l
,
secret:
secret
)
end
end
def
revert
def
revert
Rails
.
logger
.
warn
(
"Markdown not updated, file move reverted for
#{
model
}
"
)
Rails
.
logger
.
warn
(
"Markdown not updated, file move reverted for
#{
to_
model
}
"
)
if
temp_file_uploader
.
file_storage?
FileUtils
.
move
(
file_path
,
temp_file_path
)
FileUtils
.
move
(
file_path
,
temp_file_path
)
end
end
end
end
end
app/validators/color_validator.rb
View file @
49d689fb
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
# end
# end
#
#
class
ColorValidator
<
ActiveModel
::
EachValidator
class
ColorValidator
<
ActiveModel
::
EachValidator
PATTERN
=
/\A\#
[0-9A-Fa-f]{3}{1,2}+
\Z/
.
freeze
PATTERN
=
/\A\#
(?:[0-9A-Fa-f]{3}){1,2}
\Z/
.
freeze
def
validate_each
(
record
,
attribute
,
value
)
def
validate_each
(
record
,
attribute
,
value
)
unless
value
=~
PATTERN
unless
value
=~
PATTERN
...
...
app/views/layouts/snippets.html.haml
View file @
49d689fb
-
header_title
_
(
"Snippets"
),
snippets_path
-
header_title
_
(
"Snippets"
),
snippets_path
-
snippets_upload_path
=
snippets_upload_path
(
@snippet
,
current_user
)
-
content_for
:page_specific_javascripts
do
-
content_for
:page_specific_javascripts
do
-
if
@snippet
&&
current_user
-
if
snippets_upload_path
-# haml-lint:disable InlineJavaScript
-# haml-lint:disable InlineJavaScript
:javascript
:javascript
window
.
uploads_path
=
"
#{
upload_path
(
'personal_snippet'
,
id:
@snippet
.
id
)
}
"
;
window
.
uploads_path
=
"
#{
snippets_upload_path
}
"
;
=
render
template:
"layouts/application"
=
render
template:
"layouts/application"
app/views/shared/_issuable_meta_data.html.haml
View file @
49d689fb
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
-
issue_votes
=
@issuable_meta_data
[
issuable
.
id
]
-
issue_votes
=
@issuable_meta_data
[
issuable
.
id
]
-
upvotes
,
downvotes
=
issue_votes
.
upvotes
,
issue_votes
.
downvotes
-
upvotes
,
downvotes
=
issue_votes
.
upvotes
,
issue_votes
.
downvotes
-
issuable_url
=
@collection_type
==
"Issue"
?
issue_path
(
issuable
,
anchor:
'notes'
)
:
merge_request_path
(
issuable
,
anchor:
'notes'
)
-
issuable_url
=
@collection_type
==
"Issue"
?
issue_path
(
issuable
,
anchor:
'notes'
)
:
merge_request_path
(
issuable
,
anchor:
'notes'
)
-
issuable_mr
=
@issuable_meta_data
[
issuable
.
id
].
merge_requests_count
-
issuable_mr
=
@issuable_meta_data
[
issuable
.
id
].
merge_requests_count
(
current_user
)
-
if
issuable_mr
>
0
-
if
issuable_mr
>
0
%li
.issuable-mr.d-none.d-sm-block.has-tooltip
{
title:
_
(
'Related merge requests'
)
}
%li
.issuable-mr.d-none.d-sm-block.has-tooltip
{
title:
_
(
'Related merge requests'
)
}
...
...
changelogs/unreleased/osw-persist-tmp-snippet-uploads.yml
0 → 100644
View file @
49d689fb
---
title
:
Persist tmp snippet uploads at users
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-2858-fix-color-validation.yml
0 → 100644
View file @
49d689fb
---
title
:
Fix DoS vulnerability in color validation regex
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-59581-related-merge-requests-count.yml
0 → 100644
View file @
49d689fb
---
title
:
Expose merge requests count based on user access
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-DOS_issue_comments_banzai.yml
0 → 100644
View file @
49d689fb
---
title
:
Fix Denial of Service for comments when rendering issues/MR comments
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-bvl-enforce-graphql-type-authorization.yml
0 → 100644
View file @
49d689fb
---
title
:
Add missing authorizations in GraphQL
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-fp-prevent-billion-laughs-attack.yml
0 → 100644
View file @
49d689fb
---
title
:
Prevent Billion Laughs attack
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-mr-head-pipeline-leak.yml
0 → 100644
View file @
49d689fb
---
title
:
Gate MR head_pipeline behind read_pipeline ability.
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-notes-in-private-snippets.yml
0 → 100644
View file @
49d689fb
---
title
:
Correctly check permissions when creating snippet notes
merge_request
:
author
:
type
:
security
changelogs/unreleased/security-prevent-detection-of-merge-request-template-name.yml
0 → 100644
View file @
49d689fb
---
title
:
Prevent the detection of merge request templates by unauthorized users
merge_request
:
author
:
type
:
security
config/routes/project.rb
View file @
49d689fb
...
@@ -182,7 +182,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
...
@@ -182,7 +182,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
#
#
# Templates
# Templates
#
#
get
'/templates/:template_type/:key'
=>
'templates#show'
,
as: :template
,
constraints:
{
key:
%r{[^/]+}
}
get
'/templates/:template_type/:key'
=>
'templates#show'
,
as: :template
,
defaults:
{
format:
'json'
},
constraints:
{
key:
%r{[^/]+}
,
template_type:
%r{issue|merge_request}
,
format:
'json'
}
resources
:commit
,
only:
[
:show
],
constraints:
{
id:
/\h{7,40}/
}
do
resources
:commit
,
only:
[
:show
],
constraints:
{
id:
/\h{7,40}/
}
do
member
do
member
do
...
...
config/routes/uploads.rb
View file @
49d689fb
...
@@ -7,7 +7,7 @@ scope path: :uploads do
...
@@ -7,7 +7,7 @@ scope path: :uploads do
# show uploads for models, snippets (notes) available for now
# show uploads for models, snippets (notes) available for now
get
'-/system/:model/:id/:secret/:filename'
,
get
'-/system/:model/:id/:secret/:filename'
,
to:
'uploads#show'
,
to:
'uploads#show'
,
constraints:
{
model:
/personal_snippet/
,
id:
/\d+/
,
filename:
%r{[^/]+}
}
constraints:
{
model:
/personal_snippet
|user
/
,
id:
/\d+/
,
filename:
%r{[^/]+}
}
# show temporary uploads
# show temporary uploads
get
'-/system/temp/:secret/:filename'
,
get
'-/system/temp/:secret/:filename'
,
...
@@ -28,7 +28,7 @@ scope path: :uploads do
...
@@ -28,7 +28,7 @@ scope path: :uploads do
# create uploads for models, snippets (notes) available for now
# create uploads for models, snippets (notes) available for now
post
':model'
,
post
':model'
,
to:
'uploads#create'
,
to:
'uploads#create'
,
constraints:
{
model:
/personal_snippet/
,
id:
/\d+/
},
constraints:
{
model:
/personal_snippet
|user
/
,
id:
/\d+/
},
as:
'upload'
as:
'upload'
end
end
...
...
lib/api/entities.rb
View file @
49d689fb
...
@@ -498,9 +498,9 @@ module API
...
@@ -498,9 +498,9 @@ module API
expose
:state
,
:created_at
,
:updated_at
expose
:state
,
:created_at
,
:updated_at
# Avoids an N+1 query when metadata is included
# Avoids an N+1 query when metadata is included
def
issuable_metadata
(
subject
,
options
,
method
)
def
issuable_metadata
(
subject
,
options
,
method
,
args
=
nil
)
cached_subject
=
options
.
dig
(
:issuable_metadata
,
subject
.
id
)
cached_subject
=
options
.
dig
(
:issuable_metadata
,
subject
.
id
)
(
cached_subject
||
subject
).
public_send
(
method
)
# rubocop: disable GitlabSecurity/PublicSend
(
cached_subject
||
subject
).
public_send
(
method
,
*
args
)
# rubocop: disable GitlabSecurity/PublicSend
end
end
end
end
...
@@ -564,7 +564,7 @@ module API
...
@@ -564,7 +564,7 @@ module API
end
end
expose
(
:user_notes_count
)
{
|
issue
,
options
|
issuable_metadata
(
issue
,
options
,
:user_notes_count
)
}
expose
(
:user_notes_count
)
{
|
issue
,
options
|
issuable_metadata
(
issue
,
options
,
:user_notes_count
)
}
expose
(
:merge_requests_count
)
{
|
issue
,
options
|
issuable_metadata
(
issue
,
options
,
:merge_requests_count
)
}
expose
(
:merge_requests_count
)
{
|
issue
,
options
|
issuable_metadata
(
issue
,
options
,
:merge_requests_count
,
options
[
:current_user
]
)
}
expose
(
:upvotes
)
{
|
issue
,
options
|
issuable_metadata
(
issue
,
options
,
:upvotes
)
}
expose
(
:upvotes
)
{
|
issue
,
options
|
issuable_metadata
(
issue
,
options
,
:upvotes
)
}
expose
(
:downvotes
)
{
|
issue
,
options
|
issuable_metadata
(
issue
,
options
,
:downvotes
)
}
expose
(
:downvotes
)
{
|
issue
,
options
|
issuable_metadata
(
issue
,
options
,
:downvotes
)
}
expose
:due_date
expose
:due_date
...
@@ -757,7 +757,9 @@ module API
...
@@ -757,7 +757,9 @@ module API
merge_request
.
metrics
&
.
pipeline
merge_request
.
metrics
&
.
pipeline
end
end
expose
:head_pipeline
,
using:
'API::Entities::Pipeline'
expose
:head_pipeline
,
using:
'API::Entities::Pipeline'
,
if:
->
(
_
,
options
)
do
Ability
.
allowed?
(
options
[
:current_user
],
:read_pipeline
,
options
[
:project
])
end
expose
:diff_refs
,
using:
Entities
::
DiffRefs
expose
:diff_refs
,
using:
Entities
::
DiffRefs
...
...
lib/api/issues.rb
View file @
49d689fb
...
@@ -96,7 +96,7 @@ module API
...
@@ -96,7 +96,7 @@ module API
with:
Entities
::
Issue
,
with:
Entities
::
Issue
,
with_labels_details:
declared_params
[
:with_labels_details
],
with_labels_details:
declared_params
[
:with_labels_details
],
current_user:
current_user
,
current_user:
current_user
,
issuable_metadata:
issuable_meta_data
(
issues
,
'Issue'
)
issuable_metadata:
issuable_meta_data
(
issues
,
'Issue'
,
current_user
)
}
}
present
issues
,
options
present
issues
,
options
...
@@ -122,7 +122,7 @@ module API
...
@@ -122,7 +122,7 @@ module API
with:
Entities
::
Issue
,
with:
Entities
::
Issue
,
with_labels_details:
declared_params
[
:with_labels_details
],
with_labels_details:
declared_params
[
:with_labels_details
],
current_user:
current_user
,
current_user:
current_user
,
issuable_metadata:
issuable_meta_data
(
issues
,
'Issue'
)
issuable_metadata:
issuable_meta_data
(
issues
,
'Issue'
,
current_user
)
}
}
present
issues
,
options
present
issues
,
options
...
@@ -161,7 +161,7 @@ module API
...
@@ -161,7 +161,7 @@ module API
with_labels_details:
declared_params
[
:with_labels_details
],
with_labels_details:
declared_params
[
:with_labels_details
],
current_user:
current_user
,
current_user:
current_user
,
project:
user_project
,
project:
user_project
,
issuable_metadata:
issuable_meta_data
(
issues
,
'Issue'
)
issuable_metadata:
issuable_meta_data
(
issues
,
'Issue'
,
current_user
)
}
}
present
issues
,
options
present
issues
,
options
...
...
lib/api/merge_requests.rb
View file @
49d689fb
...
@@ -72,7 +72,7 @@ module API
...
@@ -72,7 +72,7 @@ module API
if
params
[
:view
]
==
'simple'
if
params
[
:view
]
==
'simple'
options
[
:with
]
=
Entities
::
MergeRequestSimple
options
[
:with
]
=
Entities
::
MergeRequestSimple
else
else
options
[
:issuable_metadata
]
=
issuable_meta_data
(
merge_requests
,
'MergeRequest'
)
options
[
:issuable_metadata
]
=
issuable_meta_data
(
merge_requests
,
'MergeRequest'
,
current_user
)
end
end
options
options
...
...
lib/api/todos.rb
View file @
49d689fb
...
@@ -65,7 +65,7 @@ module API
...
@@ -65,7 +65,7 @@ module API
next
unless
collection
next
unless
collection
targets
=
collection
.
map
(
&
:target
)
targets
=
collection
.
map
(
&
:target
)
options
[
type
]
=
{
issuable_metadata:
issuable_meta_data
(
targets
,
type
)
}
options
[
type
]
=
{
issuable_metadata:
issuable_meta_data
(
targets
,
type
,
current_user
)
}
end
end
end
end
end
end
...
...
lib/banzai/filter/relative_link_filter.rb
View file @
49d689fb
...
@@ -102,7 +102,7 @@ module Banzai
...
@@ -102,7 +102,7 @@ module Banzai
end
end
def
relative_file_path
(
uri
)
def
relative_file_path
(
uri
)
path
=
Addressable
::
URI
.
unescape
(
uri
.
path
)
path
=
Addressable
::
URI
.
unescape
(
uri
.
path
)
.
delete
(
"
\0
"
)
request_path
=
Addressable
::
URI
.
unescape
(
context
[
:requested_path
])
request_path
=
Addressable
::
URI
.
unescape
(
context
[
:requested_path
])
nested_path
=
build_relative_path
(
path
,
request_path
)
nested_path
=
build_relative_path
(
path
,
request_path
)
file_exists?
(
nested_path
)
?
nested_path
:
path
file_exists?
(
nested_path
)
?
nested_path
:
path
...
...
lib/gitlab/ci/config.rb
View file @
49d689fb
...
@@ -23,6 +23,11 @@ module Gitlab
...
@@ -23,6 +23,11 @@ module Gitlab
@root
=
Entry
::
Root
.
new
(
@config
)
@root
=
Entry
::
Root
.
new
(
@config
)
@root
.
compose!
@root
.
compose!
rescue
Gitlab
::
Config
::
Loader
::
Yaml
::
DataTooLargeError
=>
e
Gitlab
::
Sentry
.
track_exception
(
e
,
extra:
{
user:
user
.
inspect
,
project:
project
.
inspect
})
raise
Config
::
ConfigError
,
e
.
message
rescue
*
rescue_errors
=>
e
rescue
*
rescue_errors
=>
e
raise
Config
::
ConfigError
,
e
.
message
raise
Config
::
ConfigError
,
e
.
message
end
end
...
...
lib/gitlab/config/loader/yaml.rb
View file @
49d689fb
...
@@ -4,6 +4,13 @@ module Gitlab
...
@@ -4,6 +4,13 @@ module Gitlab
module
Config
module
Config
module
Loader
module
Loader
class
Yaml
class
Yaml
DataTooLargeError
=
Class
.
new
(
Loader
::
FormatError
)
include
Gitlab
::
Utils
::
StrongMemoize
MAX_YAML_SIZE
=
1
.
megabyte
MAX_YAML_DEPTH
=
100
def
initialize
(
config
)
def
initialize
(
config
)
@config
=
YAML
.
safe_load
(
config
,
[
Symbol
],
[],
true
)
@config
=
YAML
.
safe_load
(
config
,
[
Symbol
],
[],
true
)
rescue
Psych
::
Exception
=>
e
rescue
Psych
::
Exception
=>
e
...
@@ -11,16 +18,35 @@ module Gitlab
...
@@ -11,16 +18,35 @@ module Gitlab
end
end
def
valid?
def
valid?
@config
.
is_a?
(
Hash
)
hash
?
&&
!
too_big?
end
end
def
load!
def
load!
unless
valid?
raise
DataTooLargeError
,
'The parsed YAML is too big'
if
too_big?
raise
Loader
::
FormatError
,
'Invalid configuration format'
raise
Loader
::
FormatError
,
'Invalid configuration format'
unless
hash
?
end
@config
.
deep_symbolize_keys
@config
.
deep_symbolize_keys
end
end
private
def
hash?
@config
.
is_a?
(
Hash
)
end
def
too_big?
return
false
unless
Feature
.
enabled?
(
:ci_yaml_limit_size
,
default_enabled:
true
)
!
deep_size
.
valid?
end
def
deep_size
strong_memoize
(:
deep_size
)
do
Gitlab
::
Utils
::
DeepSize
.
new
(
@config
,
max_size:
MAX_YAML_SIZE
,
max_depth:
MAX_YAML_DEPTH
)
end
end
end
end
end
end
end
end
...
...
lib/gitlab/graphql/authorize/authorize_field_service.rb
View file @
49d689fb
...
@@ -39,6 +39,8 @@ module Gitlab
...
@@ -39,6 +39,8 @@ module Gitlab
type
=
node_type_for_basic_connection
(
type
)
type
=
node_type_for_basic_connection
(
type
)
end
end
type
=
type
.
unwrap
if
type
.
kind
.
non_null?
Array
.
wrap
(
type
.
metadata
[
:authorize
])
Array
.
wrap
(
type
.
metadata
[
:authorize
])
end
end
...
...
lib/gitlab/issuable_metadata.rb
View file @
49d689fb
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
module
Gitlab
module
Gitlab
module
IssuableMetadata
module
IssuableMetadata
def
issuable_meta_data
(
issuable_collection
,
collection_type
)
def
issuable_meta_data
(
issuable_collection
,
collection_type
,
user
=
nil
)
# ActiveRecord uses Object#extend for null relations.
# ActiveRecord uses Object#extend for null relations.
if
!
(
issuable_collection
.
singleton_class
<
ActiveRecord
::
NullRelation
)
&&
if
!
(
issuable_collection
.
singleton_class
<
ActiveRecord
::
NullRelation
)
&&
issuable_collection
.
respond_to?
(
:limit_value
)
&&
issuable_collection
.
respond_to?
(
:limit_value
)
&&
...
@@ -23,7 +23,7 @@ module Gitlab
...
@@ -23,7 +23,7 @@ module Gitlab
issuable_votes_count
=
::
AwardEmoji
.
votes_for_collection
(
issuable_ids
,
collection_type
)
issuable_votes_count
=
::
AwardEmoji
.
votes_for_collection
(
issuable_ids
,
collection_type
)
issuable_merge_requests_count
=
issuable_merge_requests_count
=
if
collection_type
==
'Issue'
if
collection_type
==
'Issue'
::
MergeRequestsClosingIssues
.
count_for_collection
(
issuable_ids
)
::
MergeRequestsClosingIssues
.
count_for_collection
(
issuable_ids
,
user
)
else
else
[]
[]
end
end
...
...
lib/gitlab/utils/deep_size.rb
0 → 100644
View file @
49d689fb
# frozen_string_literal: true
require
'objspace'
module
Gitlab
module
Utils
class
DeepSize
Error
=
Class
.
new
(
StandardError
)
TooMuchDataError
=
Class
.
new
(
Error
)
DEFAULT_MAX_SIZE
=
1
.
megabyte
DEFAULT_MAX_DEPTH
=
100
def
initialize
(
root
,
max_size:
DEFAULT_MAX_SIZE
,
max_depth:
DEFAULT_MAX_DEPTH
)
@root
=
root
@max_size
=
max_size
@max_depth
=
max_depth
@size
=
0
@depth
=
0
evaluate
end
def
valid?
!
too_big?
&&
!
too_deep?
end
private
def
evaluate
add_object
(
@root
)
rescue
Error
# NOOP
end
def
too_big?
@size
>
@max_size
end
def
too_deep?
@depth
>
@max_depth
end
def
add_object
(
object
)
@size
+=
ObjectSpace
.
memsize_of
(
object
)
raise
TooMuchDataError
if
@size
>
@max_size
add_array
(
object
)
if
object
.
is_a?
(
Array
)
add_hash
(
object
)
if
object
.
is_a?
(
Hash
)
end
def
add_array
(
object
)
with_nesting
do
object
.
each
do
|
n
|
add_object
(
n
)
end
end
end
def
add_hash
(
object
)
with_nesting
do
object
.
each
do
|
key
,
value
|
add_object
(
key
)
add_object
(
value
)
end
end
end
def
with_nesting
@depth
+=
1
raise
TooMuchDataError
if
too_deep?
yield
@depth
-=
1
end
end
end
end
rubocop/cop/graphql/authorize_types.rb
0 → 100644
View file @
49d689fb
# frozen_string_literal: true
require_relative
'../../spec_helpers'
module
RuboCop
module
Cop
module
Graphql
class
AuthorizeTypes
<
RuboCop
::
Cop
::
Cop
include
SpecHelpers
MSG
=
'Add an `authorize :ability` call to the type: '
\
'https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#type-authorization'
TYPES_DIR
=
'app/graphql/types'
# We want to exclude our own basetypes and scalars
WHITELISTED_TYPES
=
%w[BaseEnum BaseScalar BasePermissionType MutationType
QueryType GraphQL::Schema BaseUnion]
.
freeze
def_node_search
:authorize?
,
<<~
PATTERN
(send nil? :authorize ...)
PATTERN
def
on_class
(
node
)
return
unless
in_type?
(
node
)
return
if
whitelisted?
(
class_constant
(
node
))
return
if
whitelisted?
(
superclass_constant
(
node
))
add_offense
(
node
,
location: :expression
)
unless
authorize?
(
node
)
end
private
def
in_type?
(
node
)
return
if
in_spec?
(
node
)
path
=
node
.
location
.
expression
.
source_buffer
.
name
path
.
include?
(
TYPES_DIR
)
end
def
whitelisted?
(
class_node
)
return
false
unless
class_node
&
.
const_name
WHITELISTED_TYPES
.
any?
{
|
whitelisted
|
class_node
.
const_name
.
include?
(
whitelisted
)
}
end
def
class_constant
(
node
)
node
.
descendants
.
first
end
def
superclass_constant
(
class_node
)
# First one is the class name itself, second is it's superclass
_class_constant
,
*
others
=
class_node
.
descendants
others
.
find
{
|
node
|
node
.
const_type?
&&
node
&
.
const_name
!=
'Types'
}
end
end
end
end
end
rubocop/rubocop.rb
View file @
49d689fb
...
@@ -43,3 +43,4 @@ require_relative 'cop/code_reuse/serializer'
...
@@ -43,3 +43,4 @@ require_relative 'cop/code_reuse/serializer'
require_relative
'cop/code_reuse/active_record'
require_relative
'cop/code_reuse/active_record'
require_relative
'cop/group_public_or_visible_to_user'
require_relative
'cop/group_public_or_visible_to_user'
require_relative
'cop/inject_enterprise_edition_module'
require_relative
'cop/inject_enterprise_edition_module'
require_relative
'cop/graphql/authorize_types'
spec/controllers/projects/notes_controller_spec.rb
View file @
49d689fb
...
@@ -252,7 +252,7 @@ describe Projects::NotesController do
...
@@ -252,7 +252,7 @@ describe Projects::NotesController do
before
do
before
do
service_params
=
ActionController
::
Parameters
.
new
({
service_params
=
ActionController
::
Parameters
.
new
({
note:
'some note'
,
note:
'some note'
,
noteable_id:
merge_request
.
id
.
to_s
,
noteable_id:
merge_request
.
id
,
noteable_type:
'MergeRequest'
,
noteable_type:
'MergeRequest'
,
commit_id:
nil
,
commit_id:
nil
,
merge_request_diff_head_sha:
'sha'
merge_request_diff_head_sha:
'sha'
...
...
spec/controllers/projects/templates_controller_spec.rb
View file @
49d689fb
...
@@ -3,49 +3,101 @@
...
@@ -3,49 +3,101 @@
require
'spec_helper'
require
'spec_helper'
describe
Projects
::
TemplatesController
do
describe
Projects
::
TemplatesController
do
let
(
:project
)
{
create
(
:project
,
:repository
)
}
let
(
:project
)
{
create
(
:project
,
:repository
,
:private
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:
user2
)
{
create
(
:user
)
}
let
(
:
file_path_1
)
{
'.gitlab/issue_templates/issue_template.md'
}
let
(
:file_path_
1
)
{
'.gitlab/issue_templates/bug
.md'
}
let
(
:file_path_
2
)
{
'.gitlab/merge_request_templates/merge_request_template
.md'
}
let
(
:body
)
{
JSON
.
parse
(
response
.
body
)
}
let
(
:body
)
{
JSON
.
parse
(
response
.
body
)
}
let!
(
:file_1
)
{
project
.
repository
.
create_file
(
user
,
file_path_1
,
'issue content'
,
message:
'message'
,
branch_name:
'master'
)
}
let!
(
:file_2
)
{
project
.
repository
.
create_file
(
user
,
file_path_2
,
'merge request content'
,
message:
'message'
,
branch_name:
'master'
)
}
before
do
describe
'#show'
do
project
.
add_developer
(
user
)
shared_examples
'renders issue templates as json'
do
sign_in
(
user
)
it
do
end
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
,
template_type:
'issue'
,
key:
'issue_template'
,
project_id:
project
},
format: :json
)
before
do
expect
(
response
.
status
).
to
eq
(
200
)
project
.
add_user
(
user
,
Gitlab
::
Access
::
MAINTAINER
)
expect
(
body
[
'name'
]).
to
eq
(
'issue_template'
)
project
.
repository
.
create_file
(
user
,
file_path_1
,
'something valid'
,
expect
(
body
[
'content'
]).
to
eq
(
'issue content'
)
message:
'test 3'
,
branch_name:
'master'
)
end
end
end
describe
'#show
'
do
shared_examples
'renders merge request templates as json
'
do
it
'renders template name and content as json'
do
it
do
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
.
to_param
,
template_type:
"issue"
,
key:
"bug"
,
project_id:
project
},
format: :json
)
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
,
template_type:
'merge_request'
,
key:
'merge_request_template'
,
project_id:
project
},
format: :json
)
expect
(
response
.
status
).
to
eq
(
200
)
expect
(
response
.
status
).
to
eq
(
200
)
expect
(
body
[
"name"
]).
to
eq
(
"bug"
)
expect
(
body
[
'name'
]).
to
eq
(
'merge_request_template'
)
expect
(
body
[
"content"
]).
to
eq
(
"something valid"
)
expect
(
body
[
'content'
]).
to
eq
(
'merge request content'
)
end
end
end
it
'renders 404 when unauthorized
'
do
shared_examples
'renders 404 when requesting an issue template
'
do
sign_in
(
user2
)
it
do
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
.
to_param
,
template_type:
"issue"
,
key:
"bug"
,
project_id:
project
},
format: :json
)
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
,
template_type:
'issue'
,
key:
'issue_template'
,
project_id:
project
},
format: :json
)
expect
(
response
.
status
).
to
eq
(
404
)
expect
(
response
.
status
).
to
eq
(
404
)
end
end
end
it
'renders 404 when template type is not found'
do
shared_examples
'renders 404 when requesting a merge request template'
do
sign_in
(
user
)
it
do
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
.
to_param
,
template_type:
"dont_exist"
,
key:
"bug"
,
project_id:
project
},
format: :json
)
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
,
template_type:
'merge_request'
,
key:
'merge_request_template'
,
project_id:
project
},
format: :json
)
expect
(
response
.
status
).
to
eq
(
404
)
end
end
shared_examples
'renders 404 when params are invalid'
do
it
'does not route when the template type is invalid'
do
expect
do
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
,
template_type:
'invalid_type'
,
key:
'issue_template'
,
project_id:
project
},
format: :json
)
end
.
to
raise_error
(
ActionController
::
UrlGenerationError
)
end
it
'renders 404 when the format type is invalid'
do
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
,
template_type:
'issue'
,
key:
'issue_template'
,
project_id:
project
},
format: :html
)
expect
(
response
.
status
).
to
eq
(
404
)
end
it
'renders 404 when the key is unknown'
do
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
,
template_type:
'issue'
,
key:
'unknown_template'
,
project_id:
project
},
format: :json
)
expect
(
response
.
status
).
to
eq
(
404
)
expect
(
response
.
status
).
to
eq
(
404
)
end
end
end
context
'when the user is not a member of the project'
do
before
do
sign_in
(
user
)
end
include_examples
'renders 404 when requesting an issue template'
include_examples
'renders 404 when requesting a merge request template'
include_examples
'renders 404 when params are invalid'
end
it
'renders 404 without errors'
do
context
'when user is a member of the project'
do
before
do
project
.
add_developer
(
user
)
sign_in
(
user
)
end
include_examples
'renders issue templates as json'
include_examples
'renders merge request templates as json'
include_examples
'renders 404 when params are invalid'
end
context
'when user is a guest of the project'
do
before
do
project
.
add_guest
(
user
)
sign_in
(
user
)
sign_in
(
user
)
expect
{
get
(
:show
,
params:
{
namespace_id:
project
.
namespace
.
to_param
,
template_type:
"dont_exist"
,
key:
"bug"
,
project_id:
project
},
format: :json
)
}.
not_to
raise_error
end
include_examples
'renders issue templates as json'
include_examples
'renders 404 when requesting a merge request template'
include_examples
'renders 404 when params are invalid'
end
end
end
end
end
end
spec/controllers/snippets/notes_controller_spec.rb
View file @
49d689fb
...
@@ -119,6 +119,119 @@ describe Snippets::NotesController do
...
@@ -119,6 +119,119 @@ describe Snippets::NotesController do
end
end
end
end
describe
'POST create'
do
context
'when a snippet is public'
do
let
(
:request_params
)
do
{
note:
attributes_for
(
:note_on_personal_snippet
,
noteable:
public_snippet
),
snippet_id:
public_snippet
.
id
}
end
before
do
sign_in
user
end
it
'returns status 302'
do
post
:create
,
params:
request_params
expect
(
response
).
to
have_gitlab_http_status
(
302
)
end
it
'creates the note'
do
expect
{
post
:create
,
params:
request_params
}.
to
change
{
Note
.
count
}.
by
(
1
)
end
end
context
'when a snippet is internal'
do
let
(
:request_params
)
do
{
note:
attributes_for
(
:note_on_personal_snippet
,
noteable:
internal_snippet
),
snippet_id:
internal_snippet
.
id
}
end
before
do
sign_in
user
end
it
'returns status 302'
do
post
:create
,
params:
request_params
expect
(
response
).
to
have_gitlab_http_status
(
302
)
end
it
'creates the note'
do
expect
{
post
:create
,
params:
request_params
}.
to
change
{
Note
.
count
}.
by
(
1
)
end
end
context
'when a snippet is private'
do
let
(
:request_params
)
do
{
note:
attributes_for
(
:note_on_personal_snippet
,
noteable:
private_snippet
),
snippet_id:
private_snippet
.
id
}
end
before
do
sign_in
user
end
context
'when user is not the author'
do
before
do
sign_in
(
user
)
end
it
'returns status 404'
do
post
:create
,
params:
request_params
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
it
'does not create the note'
do
expect
{
post
:create
,
params:
request_params
}.
not_to
change
{
Note
.
count
}
end
context
'when user sends a snippet_id for a public snippet'
do
let
(
:request_params
)
do
{
note:
attributes_for
(
:note_on_personal_snippet
,
noteable:
private_snippet
),
snippet_id:
public_snippet
.
id
}
end
it
'returns status 302'
do
post
:create
,
params:
request_params
expect
(
response
).
to
have_gitlab_http_status
(
302
)
end
it
'creates the note on the public snippet'
do
expect
{
post
:create
,
params:
request_params
}.
to
change
{
Note
.
count
}.
by
(
1
)
expect
(
Note
.
last
.
noteable
).
to
eq
public_snippet
end
end
end
context
'when user is the author'
do
before
do
sign_in
(
private_snippet
.
author
)
end
it
'returns status 302'
do
post
:create
,
params:
request_params
expect
(
response
).
to
have_gitlab_http_status
(
302
)
end
it
'creates the note'
do
expect
{
post
:create
,
params:
request_params
}.
to
change
{
Note
.
count
}.
by
(
1
)
end
end
end
end
describe
'DELETE destroy'
do
describe
'DELETE destroy'
do
let
(
:request_params
)
do
let
(
:request_params
)
do
{
{
...
...
spec/controllers/snippets_controller_spec.rb
View file @
49d689fb
...
@@ -209,8 +209,8 @@ describe SnippetsController do
...
@@ -209,8 +209,8 @@ describe SnippetsController do
context
'when the snippet description contains a file'
do
context
'when the snippet description contains a file'
do
include
FileMoverHelpers
include
FileMoverHelpers
let
(
:picture_file
)
{
'/-/system/temp/secret56/picture.jpg'
}
let
(
:picture_file
)
{
"/-/system/user/
#{
user
.
id
}
/secret56/picture.jpg"
}
let
(
:text_file
)
{
'/-/system/temp/secret78/text.txt'
}
let
(
:text_file
)
{
"/-/system/user/
#{
user
.
id
}
/secret78/text.txt"
}
let
(
:description
)
do
let
(
:description
)
do
"Description with picture: ![picture](/uploads
#{
picture_file
}
) and "
\
"Description with picture: ![picture](/uploads
#{
picture_file
}
) and "
\
"text: [text.txt](/uploads
#{
text_file
}
)"
"text: [text.txt](/uploads
#{
text_file
}
)"
...
...
spec/controllers/uploads_controller_spec.rb
View file @
49d689fb
...
@@ -24,11 +24,13 @@ describe UploadsController do
...
@@ -24,11 +24,13 @@ describe UploadsController do
let!
(
:user
)
{
create
(
:user
,
avatar:
fixture_file_upload
(
"spec/fixtures/dk.png"
,
"image/png"
))
}
let!
(
:user
)
{
create
(
:user
,
avatar:
fixture_file_upload
(
"spec/fixtures/dk.png"
,
"image/png"
))
}
describe
'POST create'
do
describe
'POST create'
do
let
(
:model
)
{
'personal_snippet'
}
let
(
:snippet
)
{
create
(
:personal_snippet
,
:public
)
}
let
(
:jpg
)
{
fixture_file_upload
(
'spec/fixtures/rails_sample.jpg'
,
'image/jpg'
)
}
let
(
:jpg
)
{
fixture_file_upload
(
'spec/fixtures/rails_sample.jpg'
,
'image/jpg'
)
}
let
(
:txt
)
{
fixture_file_upload
(
'spec/fixtures/doc_sample.txt'
,
'text/plain'
)
}
let
(
:txt
)
{
fixture_file_upload
(
'spec/fixtures/doc_sample.txt'
,
'text/plain'
)
}
context
'snippet uploads'
do
let
(
:model
)
{
'personal_snippet'
}
let
(
:snippet
)
{
create
(
:personal_snippet
,
:public
)
}
context
'when a user does not have permissions to upload a file'
do
context
'when a user does not have permissions to upload a file'
do
it
"returns 401 when the user is not logged in"
do
it
"returns 401 when the user is not logged in"
do
post
:create
,
params:
{
model:
model
,
id:
snippet
.
id
},
format: :json
post
:create
,
params:
{
model:
model
,
id:
snippet
.
id
},
format: :json
...
@@ -107,38 +109,75 @@ describe UploadsController do
...
@@ -107,38 +109,75 @@ describe UploadsController do
end
end
end
end
end
end
end
end
context
'user uploads'
do
let
(
:model
)
{
'user'
}
it
'returns 401 when the user has no access'
do
post
:create
,
params:
{
model:
'user'
,
id:
user
.
id
},
format: :json
expect
(
response
).
to
have_gitlab_http_status
(
401
)
end
context
'when user is logged in'
do
before
do
sign_in
(
user
)
end
context
'temporal with valid image'
do
subject
do
subject
do
post
:create
,
params:
{
model:
'personal_snippet'
,
file:
jpg
},
format: :json
post
:create
,
params:
{
model:
model
,
id:
user
.
id
,
file:
jpg
},
format: :json
end
end
it
'returns a content with original filename, new link, and correct type.'
do
it
'returns a content with original filename, new link, and correct type.'
do
subject
subject
expect
(
response
.
body
).
to
match
'\"alt\":\"rails_sample\"'
expect
(
response
.
body
).
to
match
'\"alt\":\"rails_sample\"'
expect
(
response
.
body
).
to
match
"
\"
url
\"
:
\"
/uploads/-/system/
temp
"
expect
(
response
.
body
).
to
match
"
\"
url
\"
:
\"
/uploads/-/system/
user/
#{
user
.
id
}
/
"
end
end
it
'does not create an Upload record'
do
it
'creates a corresponding Upload record'
do
expect
{
subject
}.
not_to
change
{
Upload
.
count
}
expect
{
subject
}.
to
change
{
Upload
.
count
}
upload
=
Upload
.
last
aggregate_failures
do
expect
(
upload
).
to
exist
expect
(
upload
.
model
).
to
eq
user
end
end
end
end
context
'temporal
with valid non-image file'
do
context
'
with valid non-image file'
do
subject
do
subject
do
post
:create
,
params:
{
model:
'personal_snippet'
,
file:
txt
},
format: :json
post
:create
,
params:
{
model:
model
,
id:
user
.
id
,
file:
txt
},
format: :json
end
end
it
'returns a content with original filename, new link, and correct type.'
do
it
'returns a content with original filename, new link, and correct type.'
do
subject
subject
expect
(
response
.
body
).
to
match
'\"alt\":\"doc_sample.txt\"'
expect
(
response
.
body
).
to
match
'\"alt\":\"doc_sample.txt\"'
expect
(
response
.
body
).
to
match
"
\"
url
\"
:
\"
/uploads/-/system/temp"
expect
(
response
.
body
).
to
match
"
\"
url
\"
:
\"
/uploads/-/system/user/
#{
user
.
id
}
/"
end
it
'creates a corresponding Upload record'
do
expect
{
subject
}.
to
change
{
Upload
.
count
}
upload
=
Upload
.
last
aggregate_failures
do
expect
(
upload
).
to
exist
expect
(
upload
.
model
).
to
eq
user
end
end
end
end
it
'returns 404 when given user is not the logged in one'
do
another_user
=
create
(
:user
)
it
'does not create an Upload record'
do
post
:create
,
params:
{
model:
model
,
id:
another_user
.
id
,
file:
txt
},
format: :json
expect
{
subject
}.
not_to
change
{
Upload
.
count
}
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
end
end
end
end
end
...
...
spec/features/snippets/user_creates_snippet_spec.rb
View file @
49d689fb
...
@@ -41,7 +41,7 @@ describe 'User creates snippet', :js do
...
@@ -41,7 +41,7 @@ describe 'User creates snippet', :js do
expect
(
page
).
to
have_content
(
'My Snippet'
)
expect
(
page
).
to
have_content
(
'My Snippet'
)
link
=
find
(
'a.no-attachment-icon img[alt="banana_sample"]'
)[
'src'
]
link
=
find
(
'a.no-attachment-icon img[alt="banana_sample"]'
)[
'src'
]
expect
(
link
).
to
match
(
%r{/uploads/-/system/
temp
/
\h
{32}/banana_sample
\.
gif
\z
}
)
expect
(
link
).
to
match
(
%r{/uploads/-/system/
user/
#{
user
.
id
}
/
\h
{32}/banana_sample
\.
gif
\z
}
)
reqs
=
inspect_requests
{
visit
(
link
)
}
reqs
=
inspect_requests
{
visit
(
link
)
}
expect
(
reqs
.
first
.
status_code
).
to
eq
(
200
)
expect
(
reqs
.
first
.
status_code
).
to
eq
(
200
)
...
...
spec/graphql/types/label_type_spec.rb
View file @
49d689fb
...
@@ -7,4 +7,6 @@ describe GitlabSchema.types['Label'] do
...
@@ -7,4 +7,6 @@ describe GitlabSchema.types['Label'] do
is_expected
.
to
have_graphql_fields
(
*
expected_fields
)
is_expected
.
to
have_graphql_fields
(
*
expected_fields
)
end
end
it
{
is_expected
.
to
require_graphql_authorizations
(
:read_label
)
}
end
end
spec/graphql/types/metadata_type_spec.rb
View file @
49d689fb
...
@@ -2,4 +2,5 @@ require 'spec_helper'
...
@@ -2,4 +2,5 @@ require 'spec_helper'
describe
GitlabSchema
.
types
[
'Metadata'
]
do
describe
GitlabSchema
.
types
[
'Metadata'
]
do
it
{
expect
(
described_class
.
graphql_name
).
to
eq
(
'Metadata'
)
}
it
{
expect
(
described_class
.
graphql_name
).
to
eq
(
'Metadata'
)
}
it
{
is_expected
.
to
require_graphql_authorizations
(
:read_instance_metadata
)
}
end
end
spec/graphql/types/namespace_type_spec.rb
View file @
49d689fb
...
@@ -13,4 +13,6 @@ describe GitlabSchema.types['Namespace'] do
...
@@ -13,4 +13,6 @@ describe GitlabSchema.types['Namespace'] do
is_expected
.
to
have_graphql_fields
(
*
expected_fields
)
is_expected
.
to
have_graphql_fields
(
*
expected_fields
)
end
end
it
{
is_expected
.
to
require_graphql_authorizations
(
:read_namespace
)
}
end
end
spec/graphql/types/query_type_spec.rb
View file @
49d689fb
...
@@ -34,9 +34,5 @@ describe GitlabSchema.types['Query'] do
...
@@ -34,9 +34,5 @@ describe GitlabSchema.types['Query'] do
is_expected
.
to
have_graphql_type
(
Types
::
MetadataType
)
is_expected
.
to
have_graphql_type
(
Types
::
MetadataType
)
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
MetadataResolver
)
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
MetadataResolver
)
end
end
it
'authorizes with read_instance_metadata'
do
is_expected
.
to
require_graphql_authorizations
(
:read_instance_metadata
)
end
end
end
end
end
spec/lib/banzai/filter/relative_link_filter_spec.rb
View file @
49d689fb
...
@@ -83,6 +83,11 @@ describe Banzai::Filter::RelativeLinkFilter do
...
@@ -83,6 +83,11 @@ describe Banzai::Filter::RelativeLinkFilter do
expect
{
filter
(
act
)
}.
not_to
raise_error
expect
{
filter
(
act
)
}.
not_to
raise_error
end
end
it
'does not explode with an escaped null byte'
do
act
=
link
(
"/%00"
)
expect
{
filter
(
act
)
}.
not_to
raise_error
end
it
'does not raise an exception with a space in the path'
do
it
'does not raise an exception with a space in the path'
do
act
=
link
(
"/uploads/d18213acd3732630991986120e167e3d/Landscape_8.jpg
\n
But here's some more unexpected text :smile:)"
)
act
=
link
(
"/uploads/d18213acd3732630991986120e167e3d/Landscape_8.jpg
\n
But here's some more unexpected text :smile:)"
)
expect
{
filter
(
act
)
}.
not_to
raise_error
expect
{
filter
(
act
)
}.
not_to
raise_error
...
...
spec/lib/gitlab/ci/config_spec.rb
View file @
49d689fb
...
@@ -90,6 +90,27 @@ describe Gitlab::Ci::Config do
...
@@ -90,6 +90,27 @@ describe Gitlab::Ci::Config do
end
end
end
end
context
'when yml is too big'
do
let
(
:yml
)
do
<<~
YAML
--- &1
- hi
- *1
YAML
end
describe
'.new'
do
it
'raises error'
do
expect
(
Gitlab
::
Sentry
).
to
receive
(
:track_exception
)
expect
{
config
}.
to
raise_error
(
described_class
::
ConfigError
,
/The parsed YAML is too big/
)
end
end
end
context
'when config logic is incorrect'
do
context
'when config logic is incorrect'
do
let
(
:yml
)
{
'before_script: "ls"'
}
let
(
:yml
)
{
'before_script: "ls"'
}
...
...
spec/lib/gitlab/config/loader/yaml_spec.rb
View file @
49d689fb
...
@@ -8,7 +8,7 @@ describe Gitlab::Config::Loader::Yaml do
...
@@ -8,7 +8,7 @@ describe Gitlab::Config::Loader::Yaml do
describe
'#valid?'
do
describe
'#valid?'
do
it
'returns true'
do
it
'returns true'
do
expect
(
loader
.
valid?
).
to
be
true
expect
(
loader
).
to
be_valid
end
end
end
end
...
@@ -24,7 +24,7 @@ describe Gitlab::Config::Loader::Yaml do
...
@@ -24,7 +24,7 @@ describe Gitlab::Config::Loader::Yaml do
describe
'#valid?'
do
describe
'#valid?'
do
it
'returns false'
do
it
'returns false'
do
expect
(
loader
.
valid?
).
to
be
false
expect
(
loader
).
not_to
be_valid
end
end
end
end
...
@@ -43,7 +43,10 @@ describe Gitlab::Config::Loader::Yaml do
...
@@ -43,7 +43,10 @@ describe Gitlab::Config::Loader::Yaml do
describe
'#initialize'
do
describe
'#initialize'
do
it
'raises FormatError'
do
it
'raises FormatError'
do
expect
{
loader
}.
to
raise_error
(
Gitlab
::
Config
::
Loader
::
FormatError
,
'Unknown alias: bad_alias'
)
expect
{
loader
}.
to
raise_error
(
Gitlab
::
Config
::
Loader
::
FormatError
,
'Unknown alias: bad_alias'
)
end
end
end
end
end
end
...
@@ -53,7 +56,68 @@ describe Gitlab::Config::Loader::Yaml do
...
@@ -53,7 +56,68 @@ describe Gitlab::Config::Loader::Yaml do
describe
'#valid?'
do
describe
'#valid?'
do
it
'returns false'
do
it
'returns false'
do
expect
(
loader
.
valid?
).
to
be
false
expect
(
loader
).
not_to
be_valid
end
end
end
# Prevent Billion Laughs attack: https://gitlab.com/gitlab-org/gitlab-ce/issues/56018
context
'when yaml size is too large'
do
let
(
:yml
)
do
<<~
YAML
a: &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"]
b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
YAML
end
describe
'#valid?'
do
it
'returns false'
do
expect
(
loader
).
not_to
be_valid
end
it
'returns true if "ci_yaml_limit_size" feature flag is disabled'
do
stub_feature_flags
(
ci_yaml_limit_size:
false
)
expect
(
loader
).
to
be_valid
end
end
describe
'#load!'
do
it
'raises FormatError'
do
expect
{
loader
.
load!
}.
to
raise_error
(
Gitlab
::
Config
::
Loader
::
FormatError
,
'The parsed YAML is too big'
)
end
end
end
# Prevent Billion Laughs attack: https://gitlab.com/gitlab-org/gitlab-ce/issues/56018
context
'when yaml has cyclic data structure'
do
let
(
:yml
)
do
<<~
YAML
--- &1
- hi
- *1
YAML
end
describe
'#valid?'
do
it
'returns false'
do
expect
(
loader
.
valid?
).
to
be
(
false
)
end
end
describe
'#load!'
do
it
'raises FormatError'
do
expect
{
loader
.
load!
}.
to
raise_error
(
Gitlab
::
Config
::
Loader
::
FormatError
,
'The parsed YAML is too big'
)
end
end
end
end
end
end
...
...
spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
View file @
49d689fb
...
@@ -7,35 +7,39 @@ require 'spec_helper'
...
@@ -7,35 +7,39 @@ require 'spec_helper'
describe
Gitlab
::
Graphql
::
Authorize
::
AuthorizeFieldService
do
describe
Gitlab
::
Graphql
::
Authorize
::
AuthorizeFieldService
do
def
type
(
type_authorizations
=
[])
def
type
(
type_authorizations
=
[])
Class
.
new
(
Types
::
BaseObject
)
do
Class
.
new
(
Types
::
BaseObject
)
do
graphql_name
"TestType"
graphql_name
'TestType'
authorize
type_authorizations
authorize
type_authorizations
end
end
end
end
def
type_with_field
(
field_type
,
field_authorizations
=
[],
resolved_value
=
"Resolved value"
)
def
type_with_field
(
field_type
,
field_authorizations
=
[],
resolved_value
=
'Resolved value'
,
**
options
)
Class
.
new
(
Types
::
BaseObject
)
do
Class
.
new
(
Types
::
BaseObject
)
do
graphql_name
"TestTypeWithField"
graphql_name
'TestTypeWithField'
field
:test_field
,
field_type
,
null:
true
,
authorize:
field_authorizations
,
resolve:
->
(
_
,
_
,
_
)
{
resolved_value
}
options
.
reverse_merge!
(
null:
true
)
field
:test_field
,
field_type
,
authorize:
field_authorizations
,
resolve:
->
(
_
,
_
,
_
)
{
resolved_value
},
**
options
end
end
end
end
let
(
:current_user
)
{
double
(
:current_user
)
}
let
(
:current_user
)
{
double
(
:current_user
)
}
subject
(
:service
)
{
described_class
.
new
(
field
)
}
subject
(
:service
)
{
described_class
.
new
(
field
)
}
describe
"#authorized_resolve"
do
describe
'#authorized_resolve'
do
let
(
:presented_object
)
{
double
(
"presented object"
)
}
let
(
:presented_object
)
{
double
(
'presented object'
)
}
let
(
:presented_type
)
{
double
(
"parent type"
,
object:
presented_object
)
}
let
(
:presented_type
)
{
double
(
'parent type'
,
object:
presented_object
)
}
subject
(
:resolved
)
{
service
.
authorized_resolve
.
call
(
presented_type
,
{},
{
current_user:
current_user
})
}
subject
(
:resolved
)
{
service
.
authorized_resolve
.
call
(
presented_type
,
{},
{
current_user:
current_user
})
}
context
"scalar types"
do
context
'scalar types'
do
shared_examples
"checking permissions on the presented object"
do
shared_examples
'checking permissions on the presented object'
do
it
"checks the abilities on the object being presented and returns the value"
do
it
'checks the abilities on the object being presented and returns the value'
do
expected_permissions
.
each
do
|
permission
|
expected_permissions
.
each
do
|
permission
|
spy_ability_check_for
(
permission
,
presented_object
,
passed:
true
)
spy_ability_check_for
(
permission
,
presented_object
,
passed:
true
)
end
end
expect
(
resolved
).
to
eq
(
"Resolved value"
)
expect
(
resolved
).
to
eq
(
'Resolved value'
)
end
end
it
"returns nil if the value wasn't authorized"
do
it
"returns nil if the value wasn't authorized"
do
...
@@ -45,61 +49,71 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
...
@@ -45,61 +49,71 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
end
end
end
end
context
"when the field is a built-in scalar type"
do
context
'when the field is a built-in scalar type'
do
let
(
:field
)
{
type_with_field
(
GraphQL
::
STRING_TYPE
,
:read_field
).
fields
[
"testField"
].
to_graphql
}
let
(
:field
)
{
type_with_field
(
GraphQL
::
STRING_TYPE
,
:read_field
).
fields
[
'testField'
].
to_graphql
}
let
(
:expected_permissions
)
{
[
:read_field
]
}
let
(
:expected_permissions
)
{
[
:read_field
]
}
it_behaves_like
"checking permissions on the presented object"
it_behaves_like
'checking permissions on the presented object'
end
end
context
"when the field is a list of scalar types"
do
context
'when the field is a list of scalar types'
do
let
(
:field
)
{
type_with_field
([
GraphQL
::
STRING_TYPE
],
:read_field
).
fields
[
"testField"
].
to_graphql
}
let
(
:field
)
{
type_with_field
([
GraphQL
::
STRING_TYPE
],
:read_field
).
fields
[
'testField'
].
to_graphql
}
let
(
:expected_permissions
)
{
[
:read_field
]
}
let
(
:expected_permissions
)
{
[
:read_field
]
}
it_behaves_like
"checking permissions on the presented object"
it_behaves_like
'checking permissions on the presented object'
end
end
context
"when the field is sub-classed scalar type"
do
context
'when the field is sub-classed scalar type'
do
let
(
:field
)
{
type_with_field
(
Types
::
TimeType
,
:read_field
).
fields
[
"testField"
].
to_graphql
}
let
(
:field
)
{
type_with_field
(
Types
::
TimeType
,
:read_field
).
fields
[
'testField'
].
to_graphql
}
let
(
:expected_permissions
)
{
[
:read_field
]
}
let
(
:expected_permissions
)
{
[
:read_field
]
}
it_behaves_like
"checking permissions on the presented object"
it_behaves_like
'checking permissions on the presented object'
end
end
context
"when the field is a list of sub-classed scalar types"
do
context
'when the field is a list of sub-classed scalar types'
do
let
(
:field
)
{
type_with_field
([
Types
::
TimeType
],
:read_field
).
fields
[
"testField"
].
to_graphql
}
let
(
:field
)
{
type_with_field
([
Types
::
TimeType
],
:read_field
).
fields
[
'testField'
].
to_graphql
}
let
(
:expected_permissions
)
{
[
:read_field
]
}
let
(
:expected_permissions
)
{
[
:read_field
]
}
it_behaves_like
"checking permissions on the presented object"
it_behaves_like
'checking permissions on the presented object'
end
end
end
end
context
"when the field is a specific type"
do
context
'when the field is a specific type'
do
let
(
:custom_type
)
{
type
(
:read_type
)
}
let
(
:custom_type
)
{
type
(
:read_type
)
}
let
(
:object_in_field
)
{
double
(
"presented in field"
)
}
let
(
:object_in_field
)
{
double
(
'presented in field'
)
}
let
(
:field
)
{
type_with_field
(
custom_type
,
:read_field
,
object_in_field
).
fields
[
"testField"
].
to_graphql
}
let
(
:field
)
{
type_with_field
(
custom_type
,
:read_field
,
object_in_field
).
fields
[
'testField'
].
to_graphql
}
it
"checks both field & type permissions"
do
it
'checks both field & type permissions'
do
spy_ability_check_for
(
:read_field
,
object_in_field
,
passed:
true
)
spy_ability_check_for
(
:read_field
,
object_in_field
,
passed:
true
)
spy_ability_check_for
(
:read_type
,
object_in_field
,
passed:
true
)
spy_ability_check_for
(
:read_type
,
object_in_field
,
passed:
true
)
expect
(
resolved
).
to
eq
(
object_in_field
)
expect
(
resolved
).
to
eq
(
object_in_field
)
end
end
it
"returns nil if viewing was not allowed"
do
it
'returns nil if viewing was not allowed'
do
spy_ability_check_for
(
:read_field
,
object_in_field
,
passed:
false
)
spy_ability_check_for
(
:read_field
,
object_in_field
,
passed:
false
)
spy_ability_check_for
(
:read_type
,
object_in_field
,
passed:
true
)
spy_ability_check_for
(
:read_type
,
object_in_field
,
passed:
true
)
expect
(
resolved
).
to
be_nil
expect
(
resolved
).
to
be_nil
end
end
context
"when the field is a list"
do
context
'when the field is not nullable'
do
let
(
:object_1
)
{
double
(
"presented in field 1"
)
}
let
(
:field
)
{
type_with_field
(
custom_type
,
[],
object_in_field
,
null:
false
).
fields
[
'testField'
].
to_graphql
}
let
(
:object_2
)
{
double
(
"presented in field 2"
)
}
it
'returns nil when viewing is not allowed'
do
spy_ability_check_for
(
:read_type
,
object_in_field
,
passed:
false
)
expect
(
resolved
).
to
be_nil
end
end
context
'when the field is a list'
do
let
(
:object_1
)
{
double
(
'presented in field 1'
)
}
let
(
:object_2
)
{
double
(
'presented in field 2'
)
}
let
(
:presented_types
)
{
[
double
(
object:
object_1
),
double
(
object:
object_2
)]
}
let
(
:presented_types
)
{
[
double
(
object:
object_1
),
double
(
object:
object_2
)]
}
let
(
:field
)
{
type_with_field
([
custom_type
],
:read_field
,
presented_types
).
fields
[
"testField"
].
to_graphql
}
let
(
:field
)
{
type_with_field
([
custom_type
],
:read_field
,
presented_types
).
fields
[
'testField'
].
to_graphql
}
it
"checks all permissions"
do
it
'checks all permissions'
do
allow
(
Ability
).
to
receive
(
:allowed?
)
{
true
}
allow
(
Ability
).
to
receive
(
:allowed?
)
{
true
}
spy_ability_check_for
(
:read_field
,
object_1
,
passed:
true
)
spy_ability_check_for
(
:read_field
,
object_1
,
passed:
true
)
...
@@ -110,7 +124,7 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
...
@@ -110,7 +124,7 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
expect
(
resolved
).
to
eq
(
presented_types
)
expect
(
resolved
).
to
eq
(
presented_types
)
end
end
it
"filters out objects that the user cannot see"
do
it
'filters out objects that the user cannot see'
do
allow
(
Ability
).
to
receive
(
:allowed?
)
{
true
}
allow
(
Ability
).
to
receive
(
:allowed?
)
{
true
}
spy_ability_check_for
(
:read_type
,
object_1
,
passed:
false
)
spy_ability_check_for
(
:read_type
,
object_1
,
passed:
false
)
...
...
spec/lib/gitlab/issuable_metadata_spec.rb
View file @
49d689fb
...
@@ -7,11 +7,11 @@ describe Gitlab::IssuableMetadata do
...
@@ -7,11 +7,11 @@ describe Gitlab::IssuableMetadata do
subject
{
Class
.
new
{
include
Gitlab
::
IssuableMetadata
}.
new
}
subject
{
Class
.
new
{
include
Gitlab
::
IssuableMetadata
}.
new
}
it
'returns an empty Hash if an empty collection is provided'
do
it
'returns an empty Hash if an empty collection is provided'
do
expect
(
subject
.
issuable_meta_data
(
Issue
.
none
,
'Issue'
)).
to
eq
({})
expect
(
subject
.
issuable_meta_data
(
Issue
.
none
,
'Issue'
,
user
)).
to
eq
({})
end
end
it
'raises an error when given a collection with no limit'
do
it
'raises an error when given a collection with no limit'
do
expect
{
subject
.
issuable_meta_data
(
Issue
.
all
,
'Issue'
)
}.
to
raise_error
(
/must have a limit/
)
expect
{
subject
.
issuable_meta_data
(
Issue
.
all
,
'Issue'
,
user
)
}.
to
raise_error
(
/must have a limit/
)
end
end
context
'issues'
do
context
'issues'
do
...
@@ -23,7 +23,7 @@ describe Gitlab::IssuableMetadata do
...
@@ -23,7 +23,7 @@ describe Gitlab::IssuableMetadata do
let!
(
:closing_issues
)
{
create
(
:merge_requests_closing_issues
,
issue:
issue
,
merge_request:
merge_request
)
}
let!
(
:closing_issues
)
{
create
(
:merge_requests_closing_issues
,
issue:
issue
,
merge_request:
merge_request
)
}
it
'aggregates stats on issues'
do
it
'aggregates stats on issues'
do
data
=
subject
.
issuable_meta_data
(
Issue
.
all
.
limit
(
10
),
'Issue'
)
data
=
subject
.
issuable_meta_data
(
Issue
.
all
.
limit
(
10
),
'Issue'
,
user
)
expect
(
data
.
count
).
to
eq
(
2
)
expect
(
data
.
count
).
to
eq
(
2
)
expect
(
data
[
issue
.
id
].
upvotes
).
to
eq
(
1
)
expect
(
data
[
issue
.
id
].
upvotes
).
to
eq
(
1
)
...
@@ -46,7 +46,7 @@ describe Gitlab::IssuableMetadata do
...
@@ -46,7 +46,7 @@ describe Gitlab::IssuableMetadata do
let!
(
:note
)
{
create
(
:note_on_merge_request
,
author:
user
,
project:
project
,
noteable:
merge_request
,
note:
"a comment on a MR"
)
}
let!
(
:note
)
{
create
(
:note_on_merge_request
,
author:
user
,
project:
project
,
noteable:
merge_request
,
note:
"a comment on a MR"
)
}
it
'aggregates stats on merge requests'
do
it
'aggregates stats on merge requests'
do
data
=
subject
.
issuable_meta_data
(
MergeRequest
.
all
.
limit
(
10
),
'MergeRequest'
)
data
=
subject
.
issuable_meta_data
(
MergeRequest
.
all
.
limit
(
10
),
'MergeRequest'
,
user
)
expect
(
data
.
count
).
to
eq
(
2
)
expect
(
data
.
count
).
to
eq
(
2
)
expect
(
data
[
merge_request
.
id
].
upvotes
).
to
eq
(
1
)
expect
(
data
[
merge_request
.
id
].
upvotes
).
to
eq
(
1
)
...
...
spec/lib/gitlab/utils/deep_size_spec.rb
0 → 100644
View file @
49d689fb
require
'spec_helper'
describe
Gitlab
::
Utils
::
DeepSize
do
let
(
:data
)
do
{
a:
[
1
,
2
,
3
],
b:
{
c:
[
4
,
5
],
d:
[
{
e:
[[
6
],
[
7
]]
}
]
}
}
end
let
(
:max_size
)
{
1
.
kilobyte
}
let
(
:max_depth
)
{
10
}
let
(
:deep_size
)
{
described_class
.
new
(
data
,
max_size:
max_size
,
max_depth:
max_depth
)
}
describe
'#evaluate'
do
context
'when data within size and depth limits'
do
it
'returns true'
do
expect
(
deep_size
).
to
be_valid
end
end
context
'when data not within size limit'
do
let
(
:max_size
)
{
200
.
bytes
}
it
'returns false'
do
expect
(
deep_size
).
not_to
be_valid
end
end
context
'when data not within depth limit'
do
let
(
:max_depth
)
{
2
}
it
'returns false'
do
expect
(
deep_size
).
not_to
be_valid
end
end
end
end
spec/requests/api/graphql/namespace/projects_spec.rb
View file @
49d689fb
...
@@ -58,9 +58,7 @@ describe 'getting projects', :nested_groups do
...
@@ -58,9 +58,7 @@ describe 'getting projects', :nested_groups do
it
'finds only public projects'
do
it
'finds only public projects'
do
post_graphql
(
query
,
current_user:
nil
)
post_graphql
(
query
,
current_user:
nil
)
expect
(
graphql_data
[
'namespace'
][
'projects'
][
'edges'
].
size
).
to
eq
(
1
)
expect
(
graphql_data
[
'namespace'
]).
to
be_nil
project
=
graphql_data
[
'namespace'
][
'projects'
][
'edges'
][
0
][
'node'
]
expect
(
project
[
'id'
]).
to
eq
(
public_project
.
to_global_id
.
to_s
)
end
end
end
end
end
end
...
...
spec/requests/api/graphql/project/repository_spec.rb
View file @
49d689fb
...
@@ -34,4 +34,28 @@ describe 'getting a repository in a project' do
...
@@ -34,4 +34,28 @@ describe 'getting a repository in a project' do
expect
(
graphql_data
[
'project'
]).
to
be
(
nil
)
expect
(
graphql_data
[
'project'
]).
to
be
(
nil
)
end
end
end
end
context
'when the repository is only accessible to members'
do
let
(
:project
)
do
create
(
:project
,
:public
,
:repository
,
repository_access_level:
ProjectFeature
::
PRIVATE
)
end
it
'returns a repository for the owner'
do
post_graphql
(
query
,
current_user:
current_user
)
expect
(
graphql_data
[
'project'
][
'repository'
]).
not_to
be_nil
end
it
'returns nil for the repository for other users'
do
post_graphql
(
query
,
current_user:
create
(
:user
))
expect
(
graphql_data
[
'project'
][
'repository'
]).
to
be_nil
end
it
'returns nil for the repository for other users'
do
post_graphql
(
query
,
current_user:
nil
)
expect
(
graphql_data
[
'project'
][
'repository'
]).
to
be_nil
end
end
end
end
spec/requests/api/issues/get_group_issues_spec.rb
View file @
49d689fb
...
@@ -23,7 +23,11 @@ describe API::Issues do
...
@@ -23,7 +23,11 @@ describe API::Issues do
describe
'GET /groups/:id/issues'
do
describe
'GET /groups/:id/issues'
do
let!
(
:group
)
{
create
(
:group
)
}
let!
(
:group
)
{
create
(
:group
)
}
let!
(
:group_project
)
{
create
(
:project
,
:public
,
creator_id:
user
.
id
,
namespace:
group
)
}
let!
(
:group_project
)
{
create
(
:project
,
:public
,
:repository
,
creator_id:
user
.
id
,
namespace:
group
)
}
let!
(
:private_mrs_project
)
do
create
(
:project
,
:public
,
:repository
,
creator_id:
user
.
id
,
namespace:
group
,
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
end
let!
(
:group_closed_issue
)
do
let!
(
:group_closed_issue
)
do
create
:closed_issue
,
create
:closed_issue
,
author:
user
,
author:
user
,
...
@@ -234,6 +238,30 @@ describe API::Issues do
...
@@ -234,6 +238,30 @@ describe API::Issues do
it_behaves_like
'group issues statistics'
it_behaves_like
'group issues statistics'
end
end
end
end
context
"when returns issue merge_requests_count for different access levels"
do
let!
(
:merge_request1
)
do
create
(
:merge_request
,
:simple
,
author:
user
,
source_project:
private_mrs_project
,
target_project:
private_mrs_project
,
description:
"closes
#{
group_issue
.
to_reference
(
private_mrs_project
)
}
"
)
end
let!
(
:merge_request2
)
do
create
(
:merge_request
,
:simple
,
author:
user
,
source_project:
group_project
,
target_project:
group_project
,
description:
"closes
#{
group_issue
.
to_reference
}
"
)
end
it_behaves_like
'accessible merge requests count'
do
let
(
:api_url
)
{
base_url
}
let
(
:target_issue
)
{
group_issue
}
end
end
end
end
end
end
...
...
spec/requests/api/issues/get_project_issues_spec.rb
View file @
49d689fb
...
@@ -4,8 +4,9 @@ require 'spec_helper'
...
@@ -4,8 +4,9 @@ require 'spec_helper'
describe
API
::
Issues
do
describe
API
::
Issues
do
set
(
:user
)
{
create
(
:user
)
}
set
(
:user
)
{
create
(
:user
)
}
set
(
:project
)
do
set
(
:project
)
{
create
(
:project
,
:public
,
:repository
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
create
(
:project
,
:public
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
set
(
:private_mrs_project
)
do
create
(
:project
,
:public
,
:repository
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
,
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
end
end
let
(
:user2
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
...
@@ -60,9 +61,28 @@ describe API::Issues do
...
@@ -60,9 +61,28 @@ describe API::Issues do
let
(
:no_milestone_title
)
{
'None'
}
let
(
:no_milestone_title
)
{
'None'
}
let
(
:any_milestone_title
)
{
'Any'
}
let
(
:any_milestone_title
)
{
'Any'
}
let!
(
:merge_request1
)
do
create
(
:merge_request
,
:simple
,
author:
user
,
source_project:
project
,
target_project:
project
,
description:
"closes
#{
issue
.
to_reference
}
"
)
end
let!
(
:merge_request2
)
do
create
(
:merge_request
,
:simple
,
author:
user
,
source_project:
private_mrs_project
,
target_project:
private_mrs_project
,
description:
"closes
#{
issue
.
to_reference
(
private_mrs_project
)
}
"
)
end
before
(
:all
)
do
before
(
:all
)
do
project
.
add_reporter
(
user
)
project
.
add_reporter
(
user
)
project
.
add_guest
(
guest
)
project
.
add_guest
(
guest
)
private_mrs_project
.
add_reporter
(
user
)
private_mrs_project
.
add_guest
(
guest
)
end
end
before
do
before
do
...
@@ -257,6 +277,11 @@ describe API::Issues do
...
@@ -257,6 +277,11 @@ describe API::Issues do
expect_paginated_array_response
(
issue
.
id
)
expect_paginated_array_response
(
issue
.
id
)
end
end
it_behaves_like
'accessible merge requests count'
do
let
(
:api_url
)
{
"/projects/
#{
project
.
id
}
/issues"
}
let
(
:target_issue
)
{
issue
}
end
context
'with labeled issues'
do
context
'with labeled issues'
do
let
(
:label_b
)
{
create
(
:label
,
title:
'foo'
,
project:
project
)
}
let
(
:label_b
)
{
create
(
:label
,
title:
'foo'
,
project:
project
)
}
let
(
:label_c
)
{
create
(
:label
,
title:
'bar'
,
project:
project
)
}
let
(
:label_c
)
{
create
(
:label
,
title:
'bar'
,
project:
project
)
}
...
@@ -636,34 +661,26 @@ describe API::Issues do
...
@@ -636,34 +661,26 @@ describe API::Issues do
expect
(
json_response
[
'iid'
]).
to
eq
(
confidential_issue
.
iid
)
expect
(
json_response
[
'iid'
]).
to
eq
(
confidential_issue
.
iid
)
end
end
end
end
end
describe
'GET :id/issues/:issue_iid/closed_by'
do
it_behaves_like
'accessible merge requests count'
do
let
(
:merge_request
)
do
let
(
:api_url
)
{
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
iid
}
"
}
create
(
:merge_request
,
let
(
:target_issue
)
{
issue
}
:simple
,
author:
user
,
source_project:
project
,
target_project:
project
,
description:
"closes
#{
issue
.
to_reference
}
"
)
end
end
before
do
create
(
:merge_requests_closing_issues
,
issue:
issue
,
merge_request:
merge_request
)
end
end
describe
'GET :id/issues/:issue_iid/closed_by'
do
context
'when unauthenticated'
do
context
'when unauthenticated'
do
it
'return public project issues'
do
it
'return public project issues'
do
get
api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
iid
}
/closed_by"
)
get
api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
iid
}
/closed_by"
)
expect_paginated_array_response
(
merge_request
.
id
)
expect_paginated_array_response
(
merge_request
1
.
id
)
end
end
end
end
it
'returns merge requests that will close issue on merge'
do
it
'returns merge requests that will close issue on merge'
do
get
api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
iid
}
/closed_by"
,
user
)
get
api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
iid
}
/closed_by"
,
user
)
expect_paginated_array_response
(
merge_request
.
id
)
expect_paginated_array_response
(
merge_request
1
.
id
)
end
end
context
'when no merge requests will close issue'
do
context
'when no merge requests will close issue'
do
...
@@ -721,13 +738,6 @@ describe API::Issues do
...
@@ -721,13 +738,6 @@ describe API::Issues do
end
end
it
'returns merge requests that mentioned a issue'
do
it
'returns merge requests that mentioned a issue'
do
create
(
:merge_request
,
:simple
,
author:
user
,
source_project:
project
,
target_project:
project
,
description:
'Some description'
)
get_related_merge_requests
(
project
.
id
,
issue
.
iid
,
user
)
get_related_merge_requests
(
project
.
id
,
issue
.
iid
,
user
)
expect_paginated_array_response
(
related_mr
.
id
)
expect_paginated_array_response
(
related_mr
.
id
)
...
...
spec/requests/api/issues/issues_spec.rb
View file @
49d689fb
...
@@ -4,8 +4,9 @@ require 'spec_helper'
...
@@ -4,8 +4,9 @@ require 'spec_helper'
describe
API
::
Issues
do
describe
API
::
Issues
do
set
(
:user
)
{
create
(
:user
)
}
set
(
:user
)
{
create
(
:user
)
}
set
(
:project
)
do
set
(
:project
)
{
create
(
:project
,
:public
,
:repository
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
create
(
:project
,
:public
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
set
(
:private_mrs_project
)
do
create
(
:project
,
:public
,
:repository
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
,
merge_requests_access_level:
ProjectFeature
::
PRIVATE
)
end
end
let
(
:user2
)
{
create
(
:user
)
}
let
(
:user2
)
{
create
(
:user
)
}
...
@@ -63,6 +64,8 @@ describe API::Issues do
...
@@ -63,6 +64,8 @@ describe API::Issues do
before
(
:all
)
do
before
(
:all
)
do
project
.
add_reporter
(
user
)
project
.
add_reporter
(
user
)
project
.
add_guest
(
guest
)
project
.
add_guest
(
guest
)
private_mrs_project
.
add_reporter
(
user
)
private_mrs_project
.
add_guest
(
guest
)
end
end
before
do
before
do
...
@@ -725,6 +728,30 @@ describe API::Issues do
...
@@ -725,6 +728,30 @@ describe API::Issues do
end
end
end
end
end
end
context
"when returns issue merge_requests_count for different access levels"
do
let!
(
:merge_request1
)
do
create
(
:merge_request
,
:simple
,
author:
user
,
source_project:
private_mrs_project
,
target_project:
private_mrs_project
,
description:
"closes
#{
issue
.
to_reference
(
private_mrs_project
)
}
"
)
end
let!
(
:merge_request2
)
do
create
(
:merge_request
,
:simple
,
author:
user
,
source_project:
project
,
target_project:
project
,
description:
"closes
#{
issue
.
to_reference
}
"
)
end
it_behaves_like
'accessible merge requests count'
do
let
(
:api_url
)
{
"/issues"
}
let
(
:target_issue
)
{
issue
}
end
end
end
end
describe
'DELETE /projects/:id/issues/:issue_iid'
do
describe
'DELETE /projects/:id/issues/:issue_iid'
do
...
...
spec/requests/api/merge_requests_spec.rb
View file @
49d689fb
...
@@ -834,6 +834,31 @@ describe API::MergeRequests do
...
@@ -834,6 +834,31 @@ describe API::MergeRequests do
end
end
end
end
context
'head_pipeline'
do
before
do
merge_request
.
update
(
head_pipeline:
create
(
:ci_pipeline
))
merge_request
.
project
.
project_feature
.
update
(
builds_access_level:
10
)
end
context
'when user can read the pipeline'
do
it
'exposes pipeline information'
do
get
api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
iid
}
"
,
user
)
expect
(
json_response
).
to
include
(
'head_pipeline'
)
end
end
context
'when user can not read the pipeline'
do
let
(
:guest
)
{
create
(
:user
)
}
it
'does not expose pipeline information'
do
get
api
(
"/projects/
#{
project
.
id
}
/merge_requests/
#{
merge_request
.
iid
}
"
,
guest
)
expect
(
json_response
).
not_to
include
(
'head_pipeline'
)
end
end
end
it
'returns the commits behind the target branch when include_diverged_commits_count is present'
do
it
'returns the commits behind the target branch when include_diverged_commits_count is present'
do
allow_any_instance_of
(
merge_request
.
class
).
to
receive
(
:diverged_commits_count
).
and_return
(
1
)
allow_any_instance_of
(
merge_request
.
class
).
to
receive
(
:diverged_commits_count
).
and_return
(
1
)
...
...
spec/routing/project_routing_spec.rb
View file @
49d689fb
...
@@ -693,4 +693,24 @@ describe 'project routing' do
...
@@ -693,4 +693,24 @@ describe 'project routing' do
it_behaves_like
'redirecting a legacy project path'
,
"/gitlab/gitlabhq/settings/repository"
,
"/gitlab/gitlabhq/-/settings/repository"
it_behaves_like
'redirecting a legacy project path'
,
"/gitlab/gitlabhq/settings/repository"
,
"/gitlab/gitlabhq/-/settings/repository"
end
end
describe
Projects
::
TemplatesController
,
'routing'
do
describe
'#show'
do
def
show_with_template_type
(
template_type
)
"/gitlab/gitlabhq/templates/
#{
template_type
}
/template_name"
end
it
'routes when :template_type is `merge_request`'
do
expect
(
get
(
show_with_template_type
(
'merge_request'
))).
to
route_to
(
'projects/templates#show'
,
namespace_id:
'gitlab'
,
project_id:
'gitlabhq'
,
template_type:
'merge_request'
,
key:
'template_name'
,
format:
'json'
)
end
it
'routes when :template_type is `issue`'
do
expect
(
get
(
show_with_template_type
(
'issue'
))).
to
route_to
(
'projects/templates#show'
,
namespace_id:
'gitlab'
,
project_id:
'gitlabhq'
,
template_type:
'issue'
,
key:
'template_name'
,
format:
'json'
)
end
it
'routes to application#route_not_found when :template_type is unknown'
do
expect
(
get
(
show_with_template_type
(
'invalid'
))).
to
route_to
(
'application#route_not_found'
,
unmatched_route:
'gitlab/gitlabhq/templates/invalid/template_name'
)
end
end
end
end
end
spec/routing/uploads_routing_spec.rb
View file @
49d689fb
...
@@ -12,10 +12,19 @@ describe 'Uploads', 'routing' do
...
@@ -12,10 +12,19 @@ describe 'Uploads', 'routing' do
)
)
end
end
it
'allows creating uploads for users'
do
expect
(
post
(
'/uploads/user?id=1'
)).
to
route_to
(
controller:
'uploads'
,
action:
'create'
,
model:
'user'
,
id:
'1'
)
end
it
'does not allow creating uploads for other models'
do
it
'does not allow creating uploads for other models'
do
UploadsController
::
MODEL_CLASSES
.
keys
.
compact
.
each
do
|
model
|
unroutable_models
=
UploadsController
::
MODEL_CLASSES
.
keys
.
compact
-
%w(personal_snippet user)
next
if
model
==
'personal_snippet'
unroutable_models
.
each
do
|
model
|
expect
(
post
(
"/uploads/
#{
model
}
?id=1"
)).
not_to
be_routable
expect
(
post
(
"/uploads/
#{
model
}
?id=1"
)).
not_to
be_routable
end
end
end
end
...
...
spec/rubocop/cop/graphql/authorize_types_spec.rb
0 → 100644
View file @
49d689fb
# frozen_string_literal: true
require
'fast_spec_helper'
require
'rubocop'
require
'rubocop/rspec/support'
require_relative
'../../../../rubocop/cop/graphql/authorize_types'
describe
RuboCop
::
Cop
::
Graphql
::
AuthorizeTypes
do
include
RuboCop
::
RSpec
::
ExpectOffense
include
CopHelper
subject
(
:cop
)
{
described_class
.
new
}
context
'when in a type folder'
do
before
do
allow
(
cop
).
to
receive
(
:in_type?
).
and_return
(
true
)
end
it
'adds an offense when there is no authorize call'
do
inspect_source
(
<<~
TYPE
)
module Types
class AType < BaseObject
field :a_thing
field :another_thing
end
end
TYPE
expect
(
cop
.
offenses
.
size
).
to
eq
1
end
it
'does not add an offense for classes that have an authorize call'
do
expect_no_offenses
(
<<~
TYPE
.
strip
)
module Types
class AType < BaseObject
graphql_name 'ATypeName'
authorize :an_ability, :second_ability
field :a_thing
end
end
TYPE
end
it
'does not add an offense for classes that only have an authorize call'
do
expect_no_offenses
(
<<~
TYPE
.
strip
)
module Types
class AType < SuperClassWithFields
authorize :an_ability
end
end
TYPE
end
it
'does not add an offense for base types'
do
expect_no_offenses
(
<<~
TYPE
)
module Types
class AType < BaseEnum
field :a_thing
end
end
TYPE
end
end
end
spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
0 → 100644
View file @
49d689fb
def
get_issue
json_response
.
is_a?
(
Array
)
?
json_response
.
detect
{
|
issue
|
issue
[
'id'
]
==
target_issue
.
id
}
:
json_response
end
shared_examples
'accessible merge requests count'
do
it
'returns anonymous accessible merge requests count'
do
get
api
(
api_url
),
params:
{
scope:
'all'
}
issue
=
get_issue
expect
(
issue
).
not_to
be_nil
expect
(
issue
[
'merge_requests_count'
]).
to
eq
(
1
)
end
it
'returns guest accessible merge requests count'
do
get
api
(
api_url
,
guest
),
params:
{
scope:
'all'
}
issue
=
get_issue
expect
(
issue
).
not_to
be_nil
expect
(
issue
[
'merge_requests_count'
]).
to
eq
(
1
)
end
it
'returns reporter accessible merge requests count'
do
get
api
(
api_url
,
user
),
params:
{
scope:
'all'
}
issue
=
get_issue
expect
(
issue
).
not_to
be_nil
expect
(
issue
[
'merge_requests_count'
]).
to
eq
(
2
)
end
it
'returns admin accessible merge requests count'
do
get
api
(
api_url
,
admin
),
params:
{
scope:
'all'
}
issue
=
get_issue
expect
(
issue
).
not_to
be_nil
expect
(
issue
[
'merge_requests_count'
]).
to
eq
(
2
)
end
end
spec/uploaders/file_mover_spec.rb
View file @
49d689fb
...
@@ -3,22 +3,36 @@ require 'spec_helper'
...
@@ -3,22 +3,36 @@ require 'spec_helper'
describe
FileMover
do
describe
FileMover
do
include
FileMoverHelpers
include
FileMoverHelpers
let
(
:user
)
{
create
(
:user
)
}
let
(
:filename
)
{
'banana_sample.gif'
}
let
(
:filename
)
{
'banana_sample.gif'
}
let
(
:temp_file_path
)
{
File
.
join
(
'uploads/-/system/temp'
,
'secret55'
,
filename
)
}
let
(
:secret
)
{
'secret55'
}
let
(
:temp_file_path
)
{
File
.
join
(
"uploads/-/system/user/
#{
user
.
id
}
"
,
secret
,
filename
)
}
let
(
:temp_description
)
do
let
(
:temp_description
)
do
"test ![banana_sample](/
#{
temp_file_path
}
) "
\
"test ![banana_sample](/
#{
temp_file_path
}
) "
\
"same ![banana_sample](/
#{
temp_file_path
}
) "
"same ![banana_sample](/
#{
temp_file_path
}
) "
end
end
let
(
:file_path
)
{
File
.
join
(
'uploads/-/system/personal_snippet'
,
snippet
.
id
.
to_s
,
'secret55'
,
filename
)
}
let
(
:file_path
)
{
File
.
join
(
'uploads/-/system/personal_snippet'
,
snippet
.
id
.
to_s
,
secret
,
filename
)
}
let
(
:snippet
)
{
create
(
:personal_snippet
,
description:
temp_description
)
}
let
(
:snippet
)
{
create
(
:personal_snippet
,
description:
temp_description
)
}
subject
{
described_class
.
new
(
temp_file_path
,
snippet
).
execute
}
let
(
:tmp_uploader
)
do
PersonalFileUploader
.
new
(
user
,
secret:
secret
)
end
let
(
:file
)
{
fixture_file_upload
(
'spec/fixtures/banana_sample.gif'
)
}
subject
{
described_class
.
new
(
temp_file_path
,
from_model:
user
,
to_model:
snippet
).
execute
}
describe
'#execute'
do
describe
'#execute'
do
let
(
:tmp_upload
)
{
tmp_uploader
.
upload
}
before
do
before
do
expect
(
FileUtils
).
to
receive
(
:mkdir_p
).
with
(
a_string_including
(
File
.
dirname
(
file_path
)))
tmp_uploader
.
store!
(
file
)
expect
(
FileUtils
).
to
receive
(
:move
).
with
(
a_string_including
(
temp_file_path
),
a_string_including
(
file_path
))
end
context
'local storage'
do
before
do
allow
(
FileUtils
).
to
receive
(
:mkdir_p
).
with
(
a_string_including
(
File
.
dirname
(
file_path
)))
allow
(
FileUtils
).
to
receive
(
:move
).
with
(
a_string_including
(
temp_file_path
),
a_string_including
(
file_path
))
allow_any_instance_of
(
CarrierWave
::
SanitizedFile
).
to
receive
(
:exists?
).
and_return
(
true
)
allow_any_instance_of
(
CarrierWave
::
SanitizedFile
).
to
receive
(
:exists?
).
and_return
(
true
)
allow_any_instance_of
(
CarrierWave
::
SanitizedFile
).
to
receive
(
:size
).
and_return
(
10
)
allow_any_instance_of
(
CarrierWave
::
SanitizedFile
).
to
receive
(
:size
).
and_return
(
10
)
...
@@ -30,14 +44,14 @@ describe FileMover do
...
@@ -30,14 +44,14 @@ describe FileMover do
subject
subject
expect
(
snippet
.
reload
.
description
)
expect
(
snippet
.
reload
.
description
)
.
to
eq
(
.
to
eq
(
"test ![banana_sample](/uploads/-/system/personal_snippet/
#{
snippet
.
id
}
/secret55/banana_sample.gif) "
\
"test ![banana_sample](/uploads/-/system/personal_snippet/
#{
snippet
.
id
}
/secret55/banana_sample.gif) "
\
"same ![banana_sample](/uploads/-/system/personal_snippet/
#{
snippet
.
id
}
/secret55/banana_sample.gif) "
)
"same ![banana_sample](/uploads/-/system/personal_snippet/
#{
snippet
.
id
}
/secret55/banana_sample.gif) "
)
end
end
it
'creates a new update record'
do
it
'updates existing upload record'
do
expect
{
subject
}.
to
change
{
Upload
.
count
}.
by
(
1
)
expect
{
subject
}
.
to
change
{
tmp_upload
.
reload
.
attributes
.
values_at
(
'model_id'
,
'model_type'
)
}
.
from
([
user
.
id
,
'User'
]).
to
([
snippet
.
id
,
'Snippet'
])
end
end
it
'schedules a background migration'
do
it
'schedules a background migration'
do
...
@@ -52,30 +66,77 @@ describe FileMover do
...
@@ -52,30 +66,77 @@ describe FileMover do
expect
(
FileUtils
).
to
receive
(
:move
).
with
(
a_string_including
(
file_path
),
a_string_including
(
temp_file_path
))
expect
(
FileUtils
).
to
receive
(
:move
).
with
(
a_string_including
(
file_path
),
a_string_including
(
temp_file_path
))
end
end
subject
{
described_class
.
new
(
file_path
,
snippet
,
:non_existing_field
).
execute
}
subject
{
described_class
.
new
(
file_path
,
:non_existing_field
,
from_model:
user
,
to_model:
snippet
).
execute
}
it
'does not update the description'
do
it
'does not update the description'
do
subject
subject
expect
(
snippet
.
reload
.
description
)
expect
(
snippet
.
reload
.
description
)
.
to
eq
(
.
to
eq
(
"test ![banana_sample](/uploads/-/system/user/
#{
user
.
id
}
/secret55/banana_sample.gif) "
\
"test ![banana_sample](/uploads/-/system/temp/secret55/banana_sample.gif) "
\
"same ![banana_sample](/uploads/-/system/user/
#{
user
.
id
}
/secret55/banana_sample.gif) "
)
"same ![banana_sample](/uploads/-/system/temp/secret55/banana_sample.gif) "
end
)
it
'does not change the upload record'
do
expect
{
subject
}
.
not_to
change
{
tmp_upload
.
reload
.
attributes
.
values_at
(
'model_id'
,
'model_type'
)
}
end
end
end
end
it
'does not create a new update record'
do
context
'when tmp uploader is not local storage'
do
expect
{
subject
}.
not_to
change
{
Upload
.
count
}
before
do
allow
(
PersonalFileUploader
).
to
receive
(
:object_store_enabled?
)
{
true
}
tmp_uploader
.
object_store
=
ObjectStorage
::
Store
::
REMOTE
allow_any_instance_of
(
PersonalFileUploader
).
to
receive
(
:file_storage?
)
{
false
}
end
after
do
FileUtils
.
rm_f
(
File
.
join
(
'personal_snippet'
,
snippet
.
id
.
to_s
,
secret
,
filename
))
end
context
'when move and field update successful'
do
it
'updates the description correctly'
do
subject
expect
(
snippet
.
reload
.
description
)
.
to
eq
(
"test ![banana_sample](/uploads/-/system/personal_snippet/
#{
snippet
.
id
}
/secret55/banana_sample.gif) "
\
"same ![banana_sample](/uploads/-/system/personal_snippet/
#{
snippet
.
id
}
/secret55/banana_sample.gif) "
)
end
it
'creates new target upload record an delete the old upload'
do
expect
{
subject
}
.
to
change
{
Upload
.
last
.
attributes
.
values_at
(
'model_id'
,
'model_type'
)
}
.
from
([
user
.
id
,
'User'
]).
to
([
snippet
.
id
,
'Snippet'
])
expect
(
Upload
.
count
).
to
eq
(
1
)
end
end
context
'when update_markdown fails'
do
subject
{
described_class
.
new
(
file_path
,
:non_existing_field
,
from_model:
user
,
to_model:
snippet
).
execute
}
it
'does not update the description'
do
subject
expect
(
snippet
.
reload
.
description
)
.
to
eq
(
"test ![banana_sample](/uploads/-/system/user/
#{
user
.
id
}
/secret55/banana_sample.gif) "
\
"same ![banana_sample](/uploads/-/system/user/
#{
user
.
id
}
/secret55/banana_sample.gif) "
)
end
it
'does not change the upload record'
do
expect
{
subject
}
.
to
change
{
Upload
.
last
.
attributes
.
values_at
(
'model_id'
,
'model_type'
)
}.
from
([
user
.
id
,
'User'
])
end
end
end
end
end
end
end
context
'security'
do
context
'security'
do
context
'when relative path is involved'
do
context
'when relative path is involved'
do
let
(
:temp_file_path
)
{
File
.
join
(
'uploads/-/system/temp'
,
'..'
,
'another_subdir_of_temp'
)
}
let
(
:temp_file_path
)
{
File
.
join
(
"uploads/-/system/user/
#{
user
.
id
}
"
,
'..'
,
'another_subdir_of_temp'
)
}
it
'does not trigger move if path is outside designated directory'
do
it
'does not trigger move if path is outside designated directory'
do
stub_file_mover
(
'uploads/-/system/another_subdir_of_temp'
)
stub_file_mover
(
"uploads/-/system/user/
#{
user
.
id
}
/another_subdir_of_temp"
)
expect
(
FileUtils
).
not_to
receive
(
:move
)
expect
(
FileUtils
).
not_to
receive
(
:move
)
subject
subject
...
...
spec/validators/color_validator_spec.rb
0 → 100644
View file @
49d689fb
# frozen_string_literal: true
require
'spec_helper'
describe
ColorValidator
do
using
RSpec
::
Parameterized
::
TableSyntax
subject
do
Class
.
new
do
include
ActiveModel
::
Model
include
ActiveModel
::
Validations
attr_accessor
:color
validates
:color
,
color:
true
end
.
new
end
where
(
:color
,
:is_valid
)
do
'#000abc'
|
true
'#aaa'
|
true
'#BBB'
|
true
'#cCc'
|
true
'#ffff'
|
false
'#000111222'
|
false
'invalid'
|
false
'000'
|
false
end
with_them
do
it
'only accepts valid colors'
do
subject
.
color
=
color
expect
(
subject
.
valid?
).
to
eq
(
is_valid
)
end
end
it
'fails fast for long invalid string'
do
subject
.
color
=
'#'
+
(
'0'
*
50_000
)
+
'xxx'
expect
do
Timeout
.
timeout
(
5
.
seconds
)
{
subject
.
valid?
}
end
.
not_to
raise_error
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