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
2cfd792a
Commit
2cfd792a
authored
Nov 02, 2020
by
GitLab Release Tools Bot
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'dev/master'
parents
2b83aa8e
dd250391
Changes
46
Hide whitespace changes
Inline
Side-by-side
Showing
46 changed files
with
936 additions
and
118 deletions
+936
-118
CHANGELOG-EE.md
CHANGELOG-EE.md
+30
-0
CHANGELOG.md
CHANGELOG.md
+45
-0
app/assets/javascripts/jobs/components/job_app.vue
app/assets/javascripts/jobs/components/job_app.vue
+5
-3
app/models/packages/package.rb
app/models/packages/package.rb
+1
-0
app/policies/ci/pipeline_schedule_policy.rb
app/policies/ci/pipeline_schedule_policy.rb
+1
-0
app/serializers/build_details_entity.rb
app/serializers/build_details_entity.rb
+1
-1
app/services/packages/nuget/update_package_from_metadata_service.rb
...es/packages/nuget/update_package_from_metadata_service.rb
+2
-0
app/services/projects/transfer_service.rb
app/services/projects/transfer_service.rb
+7
-5
app/services/terraform/remote_state_handler.rb
app/services/terraform/remote_state_handler.rb
+2
-0
app/uploaders/gitlab_uploader.rb
app/uploaders/gitlab_uploader.rb
+26
-0
app/uploaders/job_artifact_uploader.rb
app/uploaders/job_artifact_uploader.rb
+3
-2
app/uploaders/packages/package_file_uploader.rb
app/uploaders/packages/package_file_uploader.rb
+2
-0
app/views/admin/runners/_runner.html.haml
app/views/admin/runners/_runner.html.haml
+2
-2
config/routes/admin.rb
config/routes/admin.rb
+2
-2
ee/app/graphql/ee/types/project_type.rb
ee/app/graphql/ee/types/project_type.rb
+2
-0
ee/app/services/ee/merge_requests/update_service.rb
ee/app/services/ee/merge_requests/update_service.rb
+7
-0
ee/app/services/ee/projects/transfer_service.rb
ee/app/services/ee/projects/transfer_service.rb
+7
-0
ee/app/services/epics/transfer_service.rb
ee/app/services/epics/transfer_service.rb
+78
-0
ee/lib/gitlab/elastic/search_results.rb
ee/lib/gitlab/elastic/search_results.rb
+1
-2
ee/spec/graphql/types/project_type_spec.rb
ee/spec/graphql/types/project_type_spec.rb
+67
-1
ee/spec/lib/gitlab/elastic/search_results_spec.rb
ee/spec/lib/gitlab/elastic/search_results_spec.rb
+17
-1
ee/spec/services/ee/merge_requests/update_service_spec.rb
ee/spec/services/ee/merge_requests/update_service_spec.rb
+8
-0
ee/spec/services/epics/transfer_service_spec.rb
ee/spec/services/epics/transfer_service_spec.rb
+143
-0
ee/spec/services/projects/transfer_service_spec.rb
ee/spec/services/projects/transfer_service_spec.rb
+10
-0
lib/api/ci/pipeline_schedules.rb
lib/api/ci/pipeline_schedules.rb
+1
-1
lib/api/entities/ci/pipeline_schedule_details.rb
lib/api/entities/ci/pipeline_schedule_details.rb
+3
-1
lib/api/internal/kubernetes.rb
lib/api/internal/kubernetes.rb
+1
-1
lib/api/terraform/state.rb
lib/api/terraform/state.rb
+6
-3
lib/gitlab/middleware/multipart.rb
lib/gitlab/middleware/multipart.rb
+16
-0
lib/gitlab/regex.rb
lib/gitlab/regex.rb
+5
-1
lib/gitlab/utils.rb
lib/gitlab/utils.rb
+30
-0
spec/features/file_uploads/multipart_invalid_uploads_spec.rb
spec/features/file_uploads/multipart_invalid_uploads_spec.rb
+52
-0
spec/lib/gitlab/middleware/multipart_with_handler_for_jwt_params_spec.rb
.../middleware/multipart_with_handler_for_jwt_params_spec.rb
+36
-5
spec/lib/gitlab/middleware/multipart_with_handler_spec.rb
spec/lib/gitlab/middleware/multipart_with_handler_spec.rb
+52
-0
spec/lib/gitlab/regex_spec.rb
spec/lib/gitlab/regex_spec.rb
+24
-4
spec/lib/gitlab/utils_spec.rb
spec/lib/gitlab/utils_spec.rb
+31
-0
spec/models/packages/package_spec.rb
spec/models/packages/package_spec.rb
+15
-0
spec/policies/project_policy_spec.rb
spec/policies/project_policy_spec.rb
+1
-1
spec/requests/api/ci/pipeline_schedules_spec.rb
spec/requests/api/ci/pipeline_schedules_spec.rb
+86
-20
spec/requests/api/internal/kubernetes_spec.rb
spec/requests/api/internal/kubernetes_spec.rb
+11
-1
spec/requests/api/terraform/state_spec.rb
spec/requests/api/terraform/state_spec.rb
+6
-1
spec/services/packages/nuget/update_package_from_metadata_service_spec.rb
...ckages/nuget/update_package_from_metadata_service_spec.rb
+16
-16
spec/services/terraform/remote_state_handler_spec.rb
spec/services/terraform/remote_state_handler_spec.rb
+10
-8
spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb
...red_examples/uploaders/gitlab_uploader_shared_examples.rb
+12
-0
spec/uploaders/import_export_uploader_spec.rb
spec/uploaders/import_export_uploader_spec.rb
+8
-3
spec/workers/packages/nuget/extraction_worker_spec.rb
spec/workers/packages/nuget/extraction_worker_spec.rb
+45
-33
No files found.
CHANGELOG-EE.md
View file @
2cfd792a
Please view this file on the master branch, on stable branches it's out of date.
## 13.5.2 (2020-11-02)
### Security (4 changes)
-
Sync code owners rules on MR update. !1003
-
Fix potential regex backtracking attack in path parsing in search result. !1027
-
Transfer missing epics when a project is transferred.
-
Tighten the RBAC for GraphQL in SAST CiConfiguration.
## 13.5.1 (2020-10-22)
-
No changes.
...
...
@@ -220,6 +230,16 @@ Please view this file on the master branch, on stable branches it's out of date.
-
Remove bootstrap class in licensed user count. !45443
## 13.4.5 (2020-11-02)
### Security (4 changes)
-
Sync code owners rules on MR update. !1003
-
Fix potential regex backtracking attack in path parsing in search result. !1023
-
Transfer missing epics when a project is transferred.
-
Tighten the RBAC for GraphQL in SAST CiConfiguration.
## 13.4.4 (2020-10-15)
### Fixed (1 change)
...
...
@@ -493,6 +513,16 @@ Please view this file on the master branch, on stable branches it's out of date.
-
Elasticsearch reindexing: add confirmation popup and change color scheme. !42209
## 13.3.9 (2020-11-02)
### Security (4 changes)
-
Sync code owners rules on MR update. !1003
-
Fix potential regex backtracking attack in path parsing in search result. !1024
-
Transfer missing epics when a project is transferred.
-
Tighten the RBAC for GraphQL in SAST CiConfiguration.
## 13.3.8 (2020-10-21)
### Fixed (4 changes)
...
...
CHANGELOG.md
View file @
2cfd792a
...
...
@@ -2,6 +2,21 @@
documentation
](
doc/development/changelog.md
)
for instructions on adding your own
entry.
## 13.5.2 (2020-11-02)
### Security (9 changes)
-
Add CSRF protection to runner pause and resume. !1021
-
Do not expose Terraform state record in API.
-
Path traversal to RCE via LFS upload.
-
Update container_repository_name_regex to prevent catastrophic backtracking.
-
Validate nuget package names.
-
Prevent private repo from being accessed via internal Kubernetes API.
-
Validate each upload param key in multipart.rb.
-
Fix XSS vulnerability for job build dependencies.
-
Fix unauthorized user is able to access schedule pipeline variables and values.
## 13.5.1 (2020-10-22)
### Other (1 change)
...
...
@@ -583,6 +598,21 @@ entry.
-
Bump cluster applications CI template. !45472
## 13.4.5 (2020-11-02)
### Security (9 changes)
-
Add CSRF protection to runner pause and resume. !1021
-
Do not expose Terraform state record in API.
-
Path traversal to RCE via LFS upload.
-
Update container_repository_name_regex to prevent catastrophic backtracking.
-
Validate nuget package names.
-
Prevent private repo from being accessed via internal Kubernetes API.
-
Validate each upload param key in multipart.rb.
-
Fix XSS vulnerability for job build dependencies.
-
Fix unauthorized user is able to access schedule pipeline variables and values.
## 13.4.4 (2020-10-15)
### Fixed (2 changes)
...
...
@@ -1241,6 +1271,21 @@ entry.
-
Expand the visible highlight for collapsed diffs (re: !41393). !42343
## 13.3.9 (2020-11-02)
### Security (9 changes)
-
Add CSRF protection to runner pause and resume. !1021
-
Do not expose Terraform state record in API.
-
Path traversal to RCE via LFS upload.
-
Update container_repository_name_regex to prevent catastrophic backtracking.
-
Validate nuget package names.
-
Prevent private repo from being accessed via internal Kubernetes API.
-
Validate each upload param key in multipart.rb.
-
Fix XSS vulnerability for job build dependencies.
-
Fix unauthorized user is able to access schedule pipeline variables and values.
## 13.3.8 (2020-10-21)
### Fixed (2 changes)
...
...
app/assets/javascripts/jobs/components/job_app.vue
View file @
2cfd792a
<
script
>
/* eslint-disable vue/no-v-html */
import
{
throttle
,
isEmpty
}
from
'
lodash
'
;
import
{
mapGetters
,
mapState
,
mapActions
}
from
'
vuex
'
;
import
{
GlLoadingIcon
,
GlIcon
}
from
'
@gitlab/ui
'
;
import
{
GlLoadingIcon
,
GlIcon
,
GlSafeHtmlDirective
as
SafeHtml
}
from
'
@gitlab/ui
'
;
import
{
GlBreakpointInstance
as
bp
}
from
'
@gitlab/ui/dist/utils
'
;
import
{
isScrolledToBottom
}
from
'
~/lib/utils/scroll_utils
'
;
import
{
polyfillSticky
}
from
'
~/lib/utils/sticky
'
;
...
...
@@ -36,6 +35,9 @@ export default {
GlLoadingIcon
,
SharedRunner
:
()
=>
import
(
'
ee_component/jobs/components/shared_runner_limit_block.vue
'
),
},
directives
:
{
SafeHtml
,
},
mixins
:
[
delayedJobMixin
],
props
:
{
artifactHelpUrl
:
{
...
...
@@ -223,7 +225,7 @@ export default {
</div>
<callout
v-if=
"shouldRenderHeaderCallout"
>
<div
v-html=
"job.callout_message"
></div>
<div
v-
safe-
html=
"job.callout_message"
></div>
</callout>
</header>
<!-- EO Header Section -->
...
...
app/models/packages/package.rb
View file @
2cfd792a
...
...
@@ -37,6 +37,7 @@ class Packages::Package < ApplicationRecord
validate
:package_already_taken
,
if: :npm?
validates
:name
,
format:
{
with:
Gitlab
::
Regex
.
conan_recipe_component_regex
},
if: :conan?
validates
:name
,
format:
{
with:
Gitlab
::
Regex
.
generic_package_name_regex
},
if: :generic?
validates
:name
,
format:
{
with:
Gitlab
::
Regex
.
nuget_package_name_regex
},
if: :nuget?
validates
:version
,
format:
{
with:
Gitlab
::
Regex
.
nuget_version_regex
},
if: :nuget?
validates
:version
,
format:
{
with:
Gitlab
::
Regex
.
conan_recipe_component_regex
},
if: :conan?
validates
:version
,
format:
{
with:
Gitlab
::
Regex
.
maven_version_regex
},
if:
->
{
version?
&&
maven?
}
...
...
app/policies/ci/pipeline_schedule_policy.rb
View file @
2cfd792a
...
...
@@ -17,6 +17,7 @@ module Ci
rule
{
can?
(
:admin_pipeline
)
|
(
can?
(
:update_build
)
&
owner_of_schedule
)
}.
policy
do
enable
:update_pipeline_schedule
enable
:admin_pipeline_schedule
enable
:read_pipeline_schedule_variables
end
rule
{
can?
(
:admin_pipeline_schedule
)
&
~
owner_of_schedule
}.
policy
do
...
...
app/serializers/build_details_entity.rb
View file @
2cfd792a
...
...
@@ -136,7 +136,7 @@ class BuildDetailsEntity < JobEntity
docs_url
=
"https://docs.gitlab.com/ee/ci/yaml/README.html#dependencies"
[
failure_message
.
html_safe
,
failure_message
,
help_message
(
docs_url
).
html_safe
].
join
(
"<br />"
)
end
...
...
app/services/packages/nuget/update_package_from_metadata_service.rb
View file @
2cfd792a
...
...
@@ -32,6 +32,8 @@ module Packages
)
end
end
rescue
ActiveRecord
::
RecordInvalid
=>
e
raise
InvalidMetadataError
.
new
(
e
.
message
)
end
private
...
...
app/services/projects/transfer_service.rb
View file @
2cfd792a
...
...
@@ -79,11 +79,7 @@ module Projects
# Directories on disk
move_project_folders
(
project
)
# Move missing group labels to project
Labels
::
TransferService
.
new
(
current_user
,
@old_group
,
project
).
execute
# Move missing group milestones
Milestones
::
TransferService
.
new
(
current_user
,
@old_group
,
project
).
execute
transfer_missing_group_resources
(
@old_group
)
# Move uploads
move_project_uploads
(
project
)
...
...
@@ -107,6 +103,12 @@ module Projects
refresh_permissions
end
def
transfer_missing_group_resources
(
group
)
Labels
::
TransferService
.
new
(
current_user
,
group
,
project
).
execute
Milestones
::
TransferService
.
new
(
current_user
,
group
,
project
).
execute
end
def
allowed_transfer?
(
current_user
,
project
)
@new_namespace
&&
can?
(
current_user
,
:change_namespace
,
project
)
&&
...
...
app/services/terraform/remote_state_handler.rb
View file @
2cfd792a
...
...
@@ -23,6 +23,8 @@ module Terraform
state
.
save!
unless
state
.
destroyed?
end
nil
end
def
lock!
...
...
app/uploaders/gitlab_uploader.rb
View file @
2cfd792a
...
...
@@ -5,6 +5,10 @@ class GitlabUploader < CarrierWave::Uploader::Base
class_attribute
:options
PROTECTED_METHODS
=
%i(filename cache_dir work_dir store_dir)
.
freeze
ObjectNotReadyError
=
Class
.
new
(
StandardError
)
class
<<
self
# DSL setter
def
storage_options
(
options
)
...
...
@@ -33,6 +37,8 @@ class GitlabUploader < CarrierWave::Uploader::Base
delegate
:base_dir
,
:file_storage?
,
to: :class
before
:cache
,
:protect_from_path_traversal!
def
initialize
(
model
,
mounted_as
=
nil
,
**
uploader_context
)
super
(
model
,
mounted_as
)
end
...
...
@@ -121,6 +127,9 @@ class GitlabUploader < CarrierWave::Uploader::Base
# For example, `FileUploader` builds the storage path based on the associated
# project model's `path_with_namespace` value, which can change when the
# project or its containing namespace is moved or renamed.
#
# When implementing this method, raise `ObjectNotReadyError` if the model
# does not yet exist, as it will be tested in `#protect_from_path_traversal!`
def
dynamic_segment
raise
(
NotImplementedError
)
end
...
...
@@ -138,4 +147,21 @@ class GitlabUploader < CarrierWave::Uploader::Base
def
pathname
@pathname
||=
Pathname
.
new
(
path
)
end
# Protect against path traversal attacks
# This takes a list of methods to test for path traversal, e.g. ../../
# and checks each of them. This uses `.send` so that any potential errors
# don't block the entire set from being tested.
#
# @param [CarrierWave::SanitizedFile]
# @return [Nil]
# @raise [Gitlab::Utils::PathTraversalAttackError]
def
protect_from_path_traversal!
(
file
)
PROTECTED_METHODS
.
each
do
|
method
|
Gitlab
::
Utils
.
check_path_traversal!
(
self
.
send
(
method
))
# rubocop: disable GitlabSecurity/PublicSend
rescue
ObjectNotReadyError
# Do nothing. This test was attempted before the file was ready for that method
end
end
end
app/uploaders/job_artifact_uploader.rb
View file @
2cfd792a
...
...
@@ -4,7 +4,6 @@ class JobArtifactUploader < GitlabUploader
extend
Workhorse
::
UploadPath
include
ObjectStorage
::
Concern
ObjectNotReadyError
=
Class
.
new
(
StandardError
)
UnknownFileLocationError
=
Class
.
new
(
StandardError
)
storage_options
Gitlab
.
config
.
artifacts
...
...
@@ -24,7 +23,9 @@ class JobArtifactUploader < GitlabUploader
private
def
dynamic_segment
raise
ObjectNotReadyError
,
'JobArtifact is not ready'
unless
model
.
id
# This now tests model.created_at because it can for some reason be nil in the test suite,
# and it's not clear if this is intentional or not
raise
ObjectNotReadyError
,
'JobArtifact is not ready'
unless
model
.
id
&&
model
.
created_at
if
model
.
hashed_path?
hashed_path
...
...
app/uploaders/packages/package_file_uploader.rb
View file @
2cfd792a
...
...
@@ -20,6 +20,8 @@ class Packages::PackageFileUploader < GitlabUploader
private
def
dynamic_segment
raise
ObjectNotReadyError
,
"Package model not ready"
unless
model
.
id
Gitlab
::
HashedPath
.
new
(
'packages'
,
model
.
package
.
id
,
'files'
,
model
.
id
,
root_hash:
model
.
package
.
project_id
)
end
end
app/views/admin/runners/_runner.html.haml
View file @
2cfd792a
...
...
@@ -69,10 +69,10 @@
=
sprite_icon
(
'pencil'
)
.btn-group
-
if
runner
.
active?
=
link_to
[
:pause
,
:admin
,
runner
],
method: :
ge
t
,
class:
'gl-button btn btn-default btn-svg has-tooltip'
,
title:
_
(
'Pause'
),
ref:
'tooltip'
,
aria:
{
label:
_
(
'Pause'
)
},
data:
{
placement:
'top'
,
container:
'body'
,
confirm:
_
(
'Are you sure?'
)
}
do
=
link_to
[
:pause
,
:admin
,
runner
],
method: :
pos
t
,
class:
'gl-button btn btn-default btn-svg has-tooltip'
,
title:
_
(
'Pause'
),
ref:
'tooltip'
,
aria:
{
label:
_
(
'Pause'
)
},
data:
{
placement:
'top'
,
container:
'body'
,
confirm:
_
(
'Are you sure?'
)
}
do
=
sprite_icon
(
'pause'
)
-
else
=
link_to
[
:resume
,
:admin
,
runner
],
method: :
ge
t
,
class:
'gl-button btn btn-default btn-svg has-tooltip gl-px-3'
,
title:
_
(
'Resume'
),
ref:
'tooltip'
,
aria:
{
label:
_
(
'Resume'
)
},
data:
{
placement:
'top'
,
container:
'body'
}
do
=
link_to
[
:resume
,
:admin
,
runner
],
method: :
pos
t
,
class:
'gl-button btn btn-default btn-svg has-tooltip gl-px-3'
,
title:
_
(
'Resume'
),
ref:
'tooltip'
,
aria:
{
label:
_
(
'Resume'
)
},
data:
{
placement:
'top'
,
container:
'body'
}
do
=
sprite_icon
(
'play'
)
.btn-group
=
link_to
[
:admin
,
runner
],
method: :delete
,
class:
'gl-button btn btn-danger has-tooltip'
,
title:
_
(
'Remove'
),
ref:
'tooltip'
,
aria:
{
label:
_
(
'Remove'
)
},
data:
{
placement:
'top'
,
container:
'body'
,
confirm:
_
(
'Are you sure?'
)
}
do
...
...
config/routes/admin.rb
View file @
2cfd792a
...
...
@@ -148,8 +148,8 @@ namespace :admin do
resources
:runners
,
only:
[
:index
,
:show
,
:update
,
:destroy
]
do
member
do
ge
t
:resume
ge
t
:pause
pos
t
:resume
pos
t
:pause
end
collection
do
...
...
ee/app/graphql/ee/types/project_type.rb
View file @
2cfd792a
...
...
@@ -24,6 +24,8 @@ module EE
calls_gitaly:
true
,
description:
'SAST CI configuration for the project'
,
resolve:
->
(
project
,
args
,
ctx
)
do
return
unless
Ability
.
allowed?
(
ctx
[
:current_user
],
:download_code
,
project
)
sast_ci_configuration
(
project
)
end
...
...
ee/app/services/ee/merge_requests/update_service.rb
View file @
2cfd792a
...
...
@@ -42,6 +42,13 @@ module EE
private
override
:after_update
def
after_update
(
merge_request
)
super
::
MergeRequests
::
SyncCodeOwnerApprovalRules
.
new
(
merge_request
).
execute
end
override
:create_branch_change_note
def
create_branch_change_note
(
merge_request
,
branch_type
,
old_branch
,
new_branch
)
super
...
...
ee/app/services/ee/projects/transfer_service.rb
View file @
2cfd792a
...
...
@@ -19,6 +19,13 @@ module EE
old_path_with_namespace:
old_path
).
create!
end
override
:transfer_missing_group_resources
def
transfer_missing_group_resources
(
group
)
super
::
Epics
::
TransferService
.
new
(
current_user
,
group
,
project
).
execute
end
end
end
end
ee/app/services/epics/transfer_service.rb
0 → 100644
View file @
2cfd792a
# frozen_string_literal: true
# Epics::TransferService class
#
# Used for recreating the missing epics when transferring a project to a new group
#
module
Epics
class
TransferService
attr_reader
:current_user
,
:old_group
,
:project
def
initialize
(
current_user
,
old_group
,
project
)
@current_user
=
current_user
@old_group
=
old_group
@project
=
project
end
def
execute
return
unless
old_group
.
present?
&&
project
.
group
.
present?
# If the old group is an ancestor of the new group the epic can remain assigned
return
if
project
.
group
.
ancestors
.
include?
(
old_group
)
Epic
.
transaction
do
epics_to_transfer
.
find_each
do
|
epic
|
new_epic
=
create_epic
(
epic
)
update_issues_epic
(
epic
,
new_epic
)
end
end
end
private
# rubocop: disable CodeReuse/ActiveRecord
def
epics_to_transfer
Epic
.
joins
(
:issues
)
.
where
(
issues:
{
project_id:
project
.
id
},
group_id:
old_group
.
self_and_descendants
)
end
# rubocop: enable CodeReuse/ActiveRecord
def
create_epic
(
epic
)
return
unless
current_user
.
can?
(
:create_epic
,
project
.
group
)
epic_params
=
epic
.
attributes
.
slice
(
'title'
,
'description'
,
'start_date'
,
'end_date'
,
'confidential'
)
CreateService
.
new
(
project
.
group
,
current_user
,
epic_params
).
execute
end
# rubocop: disable CodeReuse/ActiveRecord
def
update_issues_epic
(
old_epic
,
new_epic
)
issues
=
old_epic
.
issues
.
where
(
project:
project
)
issues
.
each
do
|
issue
|
if
new_epic
.
present?
create_epic_issue_link
(
issue
,
new_epic
)
else
destroy_epic_issue_link
(
issue
,
old_epic
)
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
def
create_epic_issue_link
(
issue
,
epic
)
link_params
=
{
target_issuable:
issue
,
skip_epic_dates_update:
true
}
EpicIssues
::
CreateService
.
new
(
epic
,
current_user
,
link_params
).
execute
end
def
destroy_epic_issue_link
(
issue
,
epic
)
link
=
EpicIssue
.
find_by_issue_id
(
issue
.
id
)
EpicIssues
::
DestroyService
.
new
(
link
,
current_user
).
execute
end
end
end
ee/lib/gitlab/elastic/search_results.rb
View file @
2cfd792a
...
...
@@ -133,8 +133,7 @@ module Gitlab
def
self
.
parse_search_result
(
result
,
project
)
ref
=
result
[
"_source"
][
"blob"
][
"commit_sha"
]
path
=
result
[
"_source"
][
"blob"
][
"path"
]
extname
=
File
.
extname
(
path
)
basename
=
path
.
sub
(
/
#{
extname
}
$/
,
''
)
basename
=
File
.
join
(
File
.
dirname
(
path
),
File
.
basename
(
path
,
'.*'
))
content
=
result
[
"_source"
][
"blob"
][
"content"
]
project_id
=
result
[
'_source'
][
'project_id'
].
to_i
total_lines
=
content
.
lines
.
size
...
...
ee/spec/graphql/types/project_type_spec.rb
View file @
2cfd792a
...
...
@@ -27,7 +27,7 @@ RSpec.describe GitlabSchema.types['Project'] do
describe
'sast_ci_configuration'
do
include_context
'read ci configuration for sast enabled project'
let
_it_be
(
:query
)
do
let
(
:query
)
do
%(
query {
project(fullPath: "#{project.full_path}") {
...
...
@@ -110,6 +110,72 @@ RSpec.describe GitlabSchema.types['Project'] do
expect
(
analyzer
[
'label'
]).
to
eq
(
'Brakeman'
)
expect
(
analyzer
[
'enabled'
]).
to
eq
(
true
)
end
context
"with guest user"
do
before
do
project
.
add_guest
(
user
)
end
context
'when project is private'
do
let
(
:project
)
{
create
(
:project
,
:private
,
:repository
)
}
it
"returns no configuration"
do
secure_analyzers_prefix
=
subject
.
dig
(
'data'
,
'project'
,
'sastCiConfiguration'
)
expect
(
secure_analyzers_prefix
).
to
be_nil
end
end
context
'when project is public'
do
let
(
:project
)
{
create
(
:project
,
:public
,
:repository
)
}
context
'when repository is accessible by everyone'
do
it
"returns the project's sast configuration for global variables"
do
secure_analyzers_prefix
=
subject
.
dig
(
'data'
,
'project'
,
'sastCiConfiguration'
,
'global'
,
'nodes'
).
first
expect
(
secure_analyzers_prefix
[
'type'
]).
to
eq
(
'string'
)
expect
(
secure_analyzers_prefix
[
'field'
]).
to
eq
(
'SECURE_ANALYZERS_PREFIX'
)
end
end
end
end
context
"with non-member user"
do
before
do
project
.
team
.
truncate
end
context
'when project is private'
do
let
(
:project
)
{
create
(
:project
,
:private
,
:repository
)
}
it
"returns no configuration"
do
secure_analyzers_prefix
=
subject
.
dig
(
'data'
,
'project'
,
'sastCiConfiguration'
)
expect
(
secure_analyzers_prefix
).
to
be_nil
end
end
context
'when project is public'
do
let
(
:project
)
{
create
(
:project
,
:public
,
:repository
)
}
context
'when repository is accessible by everyone'
do
it
"returns the project's sast configuration for global variables"
do
secure_analyzers_prefix
=
subject
.
dig
(
'data'
,
'project'
,
'sastCiConfiguration'
,
'global'
,
'nodes'
).
first
expect
(
secure_analyzers_prefix
[
'type'
]).
to
eq
(
'string'
)
expect
(
secure_analyzers_prefix
[
'field'
]).
to
eq
(
'SECURE_ANALYZERS_PREFIX'
)
end
end
context
'when repository is accessible only by team members'
do
it
"returns no configuration"
do
project
.
project_feature
.
update!
(
merge_requests_access_level:
ProjectFeature
::
DISABLED
,
builds_access_level:
ProjectFeature
::
DISABLED
,
repository_access_level:
ProjectFeature
::
PRIVATE
)
secure_analyzers_prefix
=
subject
.
dig
(
'data'
,
'project'
,
'sastCiConfiguration'
)
expect
(
secure_analyzers_prefix
).
to
be_nil
end
end
end
end
end
describe
'security_scanners'
do
...
...
ee/spec/lib/gitlab/elastic/search_results_spec.rb
View file @
2cfd792a
...
...
@@ -85,12 +85,13 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
describe
'parse_search_result'
do
let
(
:project
)
{
double
(
:project
)
}
let
(
:content
)
{
"foo
\n
bar
\n
baz
\n
"
}
let
(
:path
)
{
'path/file.ext'
}
let
(
:blob
)
do
{
'blob'
=>
{
'commit_sha'
=>
'sha'
,
'content'
=>
content
,
'path'
=>
'path/file.ext'
'path'
=>
path
}
}
end
...
...
@@ -184,6 +185,21 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
)
end
end
context
'file path in the blob contains potential backtracking regex attack pattern'
do
let
(
:path
)
{
'/group/project/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab.(a+)+$'
}
it
'still parses the basename from the path with reasonable amount of time'
do
Timeout
.
timeout
(
3
.
seconds
)
do
parsed
=
described_class
.
parse_search_result
({
'_source'
=>
blob
},
project
)
expect
(
parsed
).
to
be_kind_of
(
::
Gitlab
::
Search
::
FoundBlob
)
expect
(
parsed
).
to
have_attributes
(
basename:
'/group/project/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab'
)
end
end
end
end
describe
'issues'
do
...
...
ee/spec/services/ee/merge_requests/update_service_spec.rb
View file @
2cfd792a
...
...
@@ -322,5 +322,13 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
it_behaves_like
'undeletable existing approval rules'
end
end
it
'updates code owner approval rules'
do
expect_next_instance_of
(
::
MergeRequests
::
SyncCodeOwnerApprovalRules
)
do
|
instance
|
expect
(
instance
).
to
receive
(
:execute
)
end
update_merge_request
(
title:
'Title'
)
end
end
end
ee/spec/services/epics/transfer_service_spec.rb
0 → 100644
View file @
2cfd792a
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Epics
::
TransferService
do
describe
'#execute'
do
let_it_be
(
:user
)
{
create
(
:admin
)
}
let_it_be
(
:new_group
,
refind:
true
)
{
create
(
:group
)
}
let_it_be
(
:old_group
,
refind:
true
)
{
create
(
:group
)
}
subject
(
:service
)
{
described_class
.
new
(
user
,
old_group
,
project
)
}
context
'when old_group is present'
do
let_it_be
(
:project
)
{
create
(
:project
,
namespace:
old_group
)
}
let_it_be
(
:epic
)
{
create
(
:epic
,
group:
old_group
,
title:
'Epic 1'
)}
let_it_be
(
:issue_with_epic
)
{
create
(
:issue
,
project:
project
,
epic:
epic
)
}
before
do
stub_licensed_features
(
epics:
true
)
project
.
add_maintainer
(
user
)
# simulate project transfer
project
.
update!
(
group:
new_group
)
end
context
'when user can create epics in the new group'
do
before
do
new_group
.
add_maintainer
(
user
)
end
it
'recreates the missing group epics in the new group'
do
expect
{
service
.
execute
}.
to
change
(
project
.
group
.
epics
,
:count
).
by
(
1
)
new_epic
=
issue_with_epic
.
reload
.
epic
expect
(
new_epic
.
group
).
to
eq
(
new_group
)
expect
(
new_epic
.
title
).
to
eq
(
epic
.
title
)
expect
(
new_epic
.
description
).
to
eq
(
epic
.
description
)
expect
(
new_epic
.
start_date
).
to
eq
(
epic
.
start_date
)
expect
(
new_epic
.
end_date
).
to
eq
(
epic
.
end_date
)
expect
(
new_epic
.
confidential
).
to
eq
(
epic
.
confidential
)
end
it
'does not recreate missing epics that are not applied to issues'
do
unassigned_epic
=
create
(
:epic
,
group:
old_group
)
service
.
execute
new_epics_titles
=
project
.
group
.
reload
.
epics
.
pluck
(
:title
)
expect
(
new_epics_titles
).
to
include
(
epic
.
title
).
and
exclude
(
unassigned_epic
.
title
)
end
context
'when epic is from an descendant group'
do
let_it_be
(
:old_group_subgroup
)
{
create
(
:group
,
parent:
old_group
)
}
it
'recreates the missing epic in the new group'
do
create
(
:epic
,
group:
old_group_subgroup
)
expect
{
service
.
execute
}.
to
change
(
project
.
group
.
epics
,
:count
).
by
(
1
)
end
end
context
'when create_epic returns nil'
do
before
do
allow_next_instance_of
(
Epics
::
CreateService
)
do
|
instance
|
allow
(
instance
).
to
receive
(
:execute
).
and_return
(
nil
)
end
end
it
'removes issues epic'
do
service
.
execute
expect
(
issue_with_epic
.
reload
.
epic
).
to
be_nil
end
end
context
'when assigned epic is confidential'
do
before
do
[
issue_with_epic
,
epic
].
each
{
|
issuable
|
issuable
.
update!
(
confidential:
true
)
}
end
it
'creates a new confidential epic in the new group'
do
expect
{
service
.
execute
}.
to
change
(
project
.
group
.
epics
,
:count
).
by
(
1
)
new_epic
=
issue_with_epic
.
reload
.
epic
expect
(
new_epic
).
not_to
eq
(
epic
.
group
)
expect
(
new_epic
.
title
).
to
eq
(
epic
.
title
)
expect
(
new_epic
.
confidential
).
to
be_truthy
end
end
end
context
'when user is a guest of the new group'
do
let_it_be
(
:guest
)
{
create
(
:user
)
}
before
do
old_group
.
add_owner
(
guest
)
project
.
add_maintainer
(
user
)
new_group
.
add_guest
(
guest
)
end
it
'does not create a new epic but removes assigned epic'
do
service
=
described_class
.
new
(
guest
,
old_group
,
project
)
expect
{
service
.
execute
}.
not_to
change
(
project
.
group
.
epics
,
:count
)
expect
(
issue_with_epic
.
reload
.
epic
).
to
be_nil
end
end
context
'when epics are disabled'
do
before
do
stub_licensed_features
(
epics:
false
)
end
it
'does not create a new epic'
do
expect
{
service
.
execute
}.
not_to
change
(
project
.
group
.
epics
,
:count
)
end
end
end
context
'when old_group is not present'
do
let_it_be
(
:project
)
{
create
(
:project
,
namespace:
create
(
:namespace
))
}
let_it_be
(
:old_group
)
{
nil
}
before
do
project
.
update!
(
namespace:
new_group
)
end
it
'returns nil'
do
expect
(
described_class
.
new
(
user
,
old_group
,
project
).
execute
).
to
be_nil
end
end
context
'when project group is not present'
do
let_it_be
(
:project
)
{
create
(
:project
,
group:
old_group
)
}
before
do
project
.
update!
(
namespace:
user
.
namespace
)
end
it
'returns nil'
do
expect
(
described_class
.
new
(
user
,
old_group
,
project
).
execute
).
to
be_nil
end
end
end
end
ee/spec/services/projects/transfer_service_spec.rb
View file @
2cfd792a
...
...
@@ -53,4 +53,14 @@ RSpec.describe Projects::TransferService do
end
end
end
context
'missing epics applied to issues'
do
it
'delegates transfer to Epics::TransferService'
do
expect_next_instance_of
(
Epics
::
TransferService
,
user
,
project
.
group
,
project
)
do
|
epics_transfer_service
|
expect
(
epics_transfer_service
).
to
receive
(
:execute
).
once
.
and_call_original
end
subject
.
execute
(
group
)
end
end
end
lib/api/ci/pipeline_schedules.rb
View file @
2cfd792a
...
...
@@ -38,7 +38,7 @@ module API
requires
:pipeline_schedule_id
,
type:
Integer
,
desc:
'The pipeline schedule id'
end
get
':id/pipeline_schedules/:pipeline_schedule_id'
do
present
pipeline_schedule
,
with:
Entities
::
Ci
::
PipelineScheduleDetails
present
pipeline_schedule
,
with:
Entities
::
Ci
::
PipelineScheduleDetails
,
user:
current_user
end
desc
'Create a new pipeline schedule'
do
...
...
lib/api/entities/ci/pipeline_schedule_details.rb
View file @
2cfd792a
...
...
@@ -5,7 +5,9 @@ module API
module
Ci
class
PipelineScheduleDetails
<
PipelineSchedule
expose
:last_pipeline
,
using:
::
API
::
Entities
::
Ci
::
PipelineBasic
expose
:variables
,
using:
::
API
::
Entities
::
Ci
::
Variable
expose
:variables
,
using:
::
API
::
Entities
::
Ci
::
Variable
,
if:
->
(
schedule
,
options
)
{
Ability
.
allowed?
(
options
[
:user
],
:read_pipeline_schedule_variables
,
schedule
)
}
end
end
end
...
...
lib/api/internal/kubernetes.rb
View file @
2cfd792a
...
...
@@ -87,7 +87,7 @@ module API
# TODO sort out authorization for real
# https://gitlab.com/gitlab-org/gitlab/-/issues/220912
if
!
project
||
!
project
.
public?
unless
Ability
.
allowed?
(
nil
,
:download_code
,
project
)
not_found!
end
...
...
lib/api/terraform/state.rb
View file @
2cfd792a
...
...
@@ -41,7 +41,6 @@ module API
env
[
'api.format'
]
=
:binary
# this bypasses json serialization
body
state
.
latest_file
.
read
status
:ok
end
end
...
...
@@ -55,8 +54,10 @@ module API
remote_state_handler
.
handle_with_lock
do
|
state
|
state
.
update_file!
(
CarrierWaveStringFile
.
new
(
data
),
version:
params
[
:serial
],
build:
current_authenticated_job
)
status
:ok
end
body
false
status
:ok
end
desc
'Delete a terraform state of a certain name'
...
...
@@ -66,8 +67,10 @@ module API
remote_state_handler
.
handle_with_lock
do
|
state
|
state
.
destroy!
status
:ok
end
body
false
status
:ok
end
desc
'Lock a terraform state of a certain name'
...
...
lib/gitlab/middleware/multipart.rb
View file @
2cfd792a
...
...
@@ -31,6 +31,7 @@ module Gitlab
RACK_ENV_KEY
=
'HTTP_GITLAB_WORKHORSE_MULTIPART_FIELDS'
JWT_PARAM_SUFFIX
=
'.gitlab-workhorse-upload'
JWT_PARAM_FIXED_KEY
=
'upload'
REWRITTEN_FIELD_NAME_MAX_LENGTH
=
10000
.
freeze
class
Handler
def
initialize
(
env
,
message
)
...
...
@@ -41,6 +42,8 @@ module Gitlab
def
with_open_files
@rewritten_fields
.
each
do
|
field
,
tmp_path
|
raise
"invalid field:
#{
field
.
inspect
}
"
unless
valid_field_name?
(
field
)
parsed_field
=
Rack
::
Utils
.
parse_nested_query
(
field
)
raise
"unexpected field:
#{
field
.
inspect
}
"
unless
parsed_field
.
count
==
1
...
...
@@ -108,6 +111,17 @@ module Gitlab
private
def
valid_field_name?
(
name
)
# length validation
return
false
if
name
.
size
>=
REWRITTEN_FIELD_NAME_MAX_LENGTH
# brackets validation
return
false
if
name
.
include?
(
'[]'
)
||
name
.
start_with?
(
'['
,
']'
)
return
false
unless
::
Gitlab
::
Utils
.
valid_brackets?
(
name
,
allow_nested:
false
)
true
end
def
package_allowed_paths
packages_config
=
::
Gitlab
.
config
.
packages
return
[]
unless
allow_packages_storage_path?
(
packages_config
)
...
...
@@ -141,6 +155,8 @@ module Gitlab
class
HandlerForJWTParams
<
Handler
def
with_open_files
@rewritten_fields
.
keys
.
each
do
|
field
|
raise
"invalid field:
#{
field
.
inspect
}
"
unless
valid_field_name?
(
field
)
parsed_field
=
Rack
::
Utils
.
parse_nested_query
(
field
)
raise
"unexpected field:
#{
field
.
inspect
}
"
unless
parsed_field
.
count
==
1
...
...
lib/gitlab/regex.rb
View file @
2cfd792a
...
...
@@ -50,6 +50,10 @@ module Gitlab
maven_app_name_regex
end
def
nuget_package_name_regex
@nuget_package_name_regex
||=
%r{
\A
[-+
\.\_
a-zA-Z0-9]+
\z
}
.
freeze
end
def
nuget_version_regex
@nuget_version_regex
||=
/
\A
#{
_semver_major_minor_patch_regex
}
(\.\d*)?
#{
_semver_prerelease_build_regex
}
\z
...
...
@@ -208,7 +212,7 @@ module Gitlab
# See https://github.com/docker/distribution/blob/master/reference/regexp.go.
#
def
container_repository_name_regex
@container_repository_regex
||=
%r{
\A
[a-z0-9]+((
?:[._/]|__|[-]{0,10})[a-z0-9]+)*
\Z
}
@container_repository_regex
||=
%r{
\A
[a-z0-9]+((
[._/]|__|-*)[a-z0-9])*
\z
}
end
##
...
...
lib/gitlab/utils.rb
View file @
2cfd792a
...
...
@@ -10,6 +10,8 @@ module Gitlab
# Also see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24223#note_284122580
# It also checks for ALT_SEPARATOR aka '\' (forward slash)
def
check_path_traversal!
(
path
)
return
unless
path
.
is_a?
(
String
)
path
=
decode_path
(
path
)
path_regex
=
/(\A(\.{1,2})\z|\A\.\.[\/\\]|[\/\\]\.\.\z|[\/\\]\.\.[\/\\]|\n)/
...
...
@@ -208,5 +210,33 @@ module Gitlab
def
stable_sort_by
(
list
)
list
.
sort_by
.
with_index
{
|
x
,
idx
|
[
yield
(
x
),
idx
]
}
end
# Check for valid brackets (`[` and `]`) in a string using this aspects:
# * open brackets count == closed brackets count
# * (optionally) reject nested brackets via `allow_nested: false`
# * open / close brackets coherence, eg. ][[] -> invalid
def
valid_brackets?
(
string
=
''
,
allow_nested:
true
)
# remove everything except brackets
brackets
=
string
.
remove
(
/[^\[\]]/
)
return
true
if
brackets
.
empty?
# balanced counts check
return
false
if
brackets
.
size
.
odd?
unless
allow_nested
# nested brackets check
return
false
if
brackets
.
include?
(
'[['
)
||
brackets
.
include?
(
']]'
)
end
# open / close brackets coherence check
untrimmed
=
brackets
loop
do
trimmed
=
untrimmed
.
gsub
(
'[]'
,
''
)
return
true
if
trimmed
.
empty?
return
false
if
trimmed
==
untrimmed
untrimmed
=
trimmed
end
end
end
end
spec/features/file_uploads/multipart_invalid_uploads_spec.rb
0 → 100644
View file @
2cfd792a
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
'Invalid uploads that must be rejected'
,
:api
,
:js
do
include_context
'file upload requests helpers'
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:user
)
{
create
(
:user
,
:admin
)
}
let_it_be
(
:personal_access_token
)
{
create
(
:personal_access_token
,
user:
user
)
}
context
'invalid upload key'
,
:capybara_ignore_server_errors
do
let
(
:api_path
)
{
"/projects/
#{
project
.
id
}
/packages/nuget/"
}
let
(
:url
)
{
capybara_url
(
api
(
api_path
))
}
let
(
:file
)
{
fixture_file_upload
(
'spec/fixtures/dk.png'
)
}
subject
do
HTTParty
.
put
(
url
,
basic_auth:
{
user:
user
.
username
,
password:
personal_access_token
.
token
},
body:
body
)
end
RSpec
.
shared_examples
'rejecting invalid keys'
do
|
key_name
:,
message:
nil
|
context
"with invalid key
#{
key_name
}
"
do
let
(
:body
)
{
{
key_name
=>
file
,
'package[test][name]'
=>
'test'
}
}
it
{
expect
{
subject
}.
not_to
change
{
Packages
::
Package
.
nuget
.
count
}
}
it
{
expect
(
subject
.
code
).
to
eq
(
500
)
}
it
{
expect
(
subject
.
body
).
to
include
(
message
.
presence
||
"invalid field:
\"
#{
key_name
}
\"
"
)
}
end
end
RSpec
.
shared_examples
'by rejecting uploads with an invalid key'
do
it_behaves_like
'rejecting invalid keys'
,
key_name:
'package[test'
it_behaves_like
'rejecting invalid keys'
,
key_name:
'[]'
it_behaves_like
'rejecting invalid keys'
,
key_name:
'[package]test'
it_behaves_like
'rejecting invalid keys'
,
key_name:
'package][test]]'
it_behaves_like
'rejecting invalid keys'
,
key_name:
'package[test[nested]]'
end
# These keys are rejected directly by rack itself.
# The request will not be received by multipart.rb (can't use the 'handling file uploads' shared example)
it_behaves_like
'rejecting invalid keys'
,
key_name:
'x'
*
11000
,
message:
'Puma caught this error: exceeded available parameter key space (RangeError)'
it_behaves_like
'rejecting invalid keys'
,
key_name:
'package[]test'
,
message:
'Puma caught this error: expected Hash (got Array)'
it_behaves_like
'handling file uploads'
,
'by rejecting uploads with an invalid key'
end
end
spec/lib/gitlab/middleware/multipart_with_handler_for_jwt_params_spec.rb
View file @
2cfd792a
...
...
@@ -123,15 +123,46 @@ RSpec.describe Gitlab::Middleware::Multipart do
end
end
context
'with
invalid key in parameters
'
do
context
'with
an invalid upload key
'
do
include_context
'with one temporary file for multipart'
let
(
:rewritten_fields
)
{
rewritten_fields_hash
(
'file'
=>
uploaded_filepath
)
}
let
(
:params
)
{
upload_parameters_for
(
filepath:
uploaded_filepath
,
key:
'wrong_key'
,
filename:
filename
,
remote_id:
remote_id
)
}
RSpec
.
shared_examples
'rejecting the invalid key'
do
|
key_in_header
:,
key_in_upload_params
:,
error_message
:|
let
(
:rewritten_fields
)
{
rewritten_fields_hash
(
key_in_header
=>
uploaded_filepath
)
}
let
(
:params
)
{
upload_parameters_for
(
filepath:
uploaded_filepath
,
key:
key_in_upload_params
,
filename:
filename
,
remote_id:
remote_id
)
}
it
'raises an error'
do
expect
{
subject
}.
to
raise_error
(
RuntimeError
,
'Empty JWT param: file.gitlab-workhorse-upload'
)
it
'raises an error'
do
expect
{
subject
}.
to
raise_error
(
RuntimeError
,
error_message
)
end
end
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'file'
,
key_in_upload_params:
'wrong_key'
,
error_message:
'Empty JWT param: file.gitlab-workhorse-upload'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'user[avatar'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "user[avatar"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'[user]avatar'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "[user]avatar"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'user[]avatar'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "user[]avatar"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'user[avatar[image[url]]]'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "user[avatar[image[url]]]"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'[]'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "[]"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'x'
*
11000
,
key_in_upload_params:
'user[avatar]'
,
error_message:
"invalid field:
\"
#{
'x'
*
11000
}
\"
"
end
context
'with a modified JWT payload'
do
...
...
spec/lib/gitlab/middleware/multipart_with_handler_spec.rb
View file @
2cfd792a
...
...
@@ -139,6 +139,58 @@ RSpec.describe Gitlab::Middleware::Multipart do
subject
end
end
context
'with invalid key in header'
do
include_context
'with one temporary file for multipart'
RSpec
.
shared_examples
'rejecting the invalid key'
do
|
key_in_header
:,
key_in_upload_params
:,
error_message
:|
let
(
:rewritten_fields
)
{
rewritten_fields_hash
(
key_in_header
=>
uploaded_filepath
)
}
let
(
:params
)
{
upload_parameters_for
(
filepath:
uploaded_filepath
,
key:
key_in_upload_params
,
filename:
filename
,
remote_id:
remote_id
)
}
it
'raises an error'
do
expect
{
subject
}.
to
raise_error
(
RuntimeError
,
error_message
)
end
end
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'user[avatar'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "user[avatar"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'[user]avatar'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "[user]avatar"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'user[]avatar'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "user[]avatar"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'user[avatar[image[url]]]'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "user[avatar[image[url]]]"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'[]'
,
key_in_upload_params:
'user[avatar]'
,
error_message:
'invalid field: "[]"'
it_behaves_like
'rejecting the invalid key'
,
key_in_header:
'x'
*
11000
,
key_in_upload_params:
'user[avatar]'
,
error_message:
"invalid field:
\"
#{
'x'
*
11000
}
\"
"
end
context
'with key with unbalanced brackets in header'
do
include_context
'with one temporary file for multipart'
let
(
:invalid_key
)
{
'user[avatar'
}
let
(
:rewritten_fields
)
{
rewritten_fields_hash
(
invalid_key
=>
uploaded_filepath
)
}
let
(
:params
)
{
upload_parameters_for
(
filepath:
uploaded_filepath
,
key:
'user[avatar]'
,
filename:
filename
,
remote_id:
remote_id
)
}
it
'builds no UploadedFile'
do
expect
(
app
).
not_to
receive
(
:call
)
expect
{
subject
}.
to
raise_error
(
RuntimeError
,
"invalid field:
\"
#{
invalid_key
}
\"
"
)
end
end
end
end
end
spec/lib/gitlab/regex_spec.rb
View file @
2cfd792a
...
...
@@ -137,11 +137,16 @@ RSpec.describe Gitlab::Regex do
it
{
is_expected
.
to
match
(
'my/awesome/image-1'
)
}
it
{
is_expected
.
to
match
(
'my/awesome/image.test'
)
}
it
{
is_expected
.
to
match
(
'my/awesome/image--test'
)
}
# docker distribution allows for infinite `-`
#
https://github.com/docker/distribution/blob/master/reference/regexp.go#L13
# but we have a range of 0,10 to add a reasonable limit.
it
{
is_expected
.
not_to
match
(
'
my/image-----------test
'
)
}
it
{
is_expected
.
to
match
(
'my/image__test'
)
}
#
this example tests for catastrophic backtracking
it
{
is_expected
.
to
match
(
'user1/project/a_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb------------x'
)
}
it
{
is_expected
.
not_to
match
(
'
user1/project/a_bbbbb-------------
'
)
}
it
{
is_expected
.
not_to
match
(
'my/image-.test'
)
}
it
{
is_expected
.
not_to
match
(
'my/image___test'
)
}
it
{
is_expected
.
not_to
match
(
'my/image_.test'
)
}
it
{
is_expected
.
not_to
match
(
'my/image_-test'
)
}
it
{
is_expected
.
not_to
match
(
'my/image..test'
)
}
it
{
is_expected
.
not_to
match
(
'my/image\ntest'
)
}
it
{
is_expected
.
not_to
match
(
'.my/image'
)
}
it
{
is_expected
.
not_to
match
(
'my/image.'
)
}
end
...
...
@@ -372,6 +377,21 @@ RSpec.describe Gitlab::Regex do
it
{
is_expected
.
not_to
match
(
'%2e%2e%2f1.2.3'
)
}
end
describe
'.nuget_package_name_regex'
do
subject
{
described_class
.
nuget_package_name_regex
}
it
{
is_expected
.
to
match
(
'My.Package'
)
}
it
{
is_expected
.
to
match
(
'My.Package.Mvc'
)
}
it
{
is_expected
.
to
match
(
'MyPackage'
)
}
it
{
is_expected
.
to
match
(
'My.23.Package'
)
}
it
{
is_expected
.
to
match
(
'My23Package'
)
}
it
{
is_expected
.
to
match
(
'runtime.my-test64.runtime.package.Mvc'
)
}
it
{
is_expected
.
to
match
(
'my_package'
)
}
it
{
is_expected
.
not_to
match
(
'My/package'
)
}
it
{
is_expected
.
not_to
match
(
'../../../my_package'
)
}
it
{
is_expected
.
not_to
match
(
'%2e%2e%2fmy_package'
)
}
end
describe
'.pypi_version_regex'
do
subject
{
described_class
.
pypi_version_regex
}
...
...
spec/lib/gitlab/utils_spec.rb
View file @
2cfd792a
...
...
@@ -3,6 +3,8 @@
require
'spec_helper'
RSpec
.
describe
Gitlab
::
Utils
do
using
RSpec
::
Parameterized
::
TableSyntax
delegate
:to_boolean
,
:boolean_to_yes_no
,
:slugify
,
:random_string
,
:which
,
:ensure_array_from_string
,
:to_exclusive_sentence
,
:bytes_to_megabytes
,
:append_path
,
:check_path_traversal!
,
:allowlisted?
,
:check_allowed_absolute_path!
,
:decode_path
,
:ms_to_round_sec
,
to: :described_class
...
...
@@ -50,6 +52,10 @@ RSpec.describe Gitlab::Utils do
expect
(
check_path_traversal!
(
'dir/..foo.rb'
)).
to
eq
(
'dir/..foo.rb'
)
expect
(
check_path_traversal!
(
'dir/.foo.rb'
)).
to
eq
(
'dir/.foo.rb'
)
end
it
'does nothing for a non-string'
do
expect
(
check_path_traversal!
(
nil
)).
to
be_nil
end
end
describe
'.allowlisted?'
do
...
...
@@ -448,4 +454,29 @@ RSpec.describe Gitlab::Utils do
end
end
end
describe
'.valid_brackets?'
do
where
(
:input
,
:allow_nested
,
:valid
)
do
'no brackets'
|
true
|
true
'no brackets'
|
false
|
true
'user[avatar]'
|
true
|
true
'user[avatar]'
|
false
|
true
'user[avatar][friends]'
|
true
|
true
'user[avatar][friends]'
|
false
|
true
'user[avatar[image[url]]]'
|
true
|
true
'user[avatar[image[url]]]'
|
false
|
false
'user[avatar[]friends]'
|
true
|
true
'user[avatar[]friends]'
|
false
|
false
'user[avatar]]'
|
true
|
false
'user[avatar]]'
|
false
|
false
'user][avatar]]'
|
true
|
false
'user][avatar]]'
|
false
|
false
'user[avatar'
|
true
|
false
'user[avatar'
|
false
|
false
end
with_them
do
it
{
expect
(
described_class
.
valid_brackets?
(
input
,
allow_nested:
allow_nested
)).
to
eq
(
valid
)
}
end
end
end
spec/models/packages/package_spec.rb
View file @
2cfd792a
...
...
@@ -122,6 +122,21 @@ RSpec.describe Packages::Package, type: :model do
it
{
is_expected
.
not_to
allow_value
(
'my file name'
).
for
(
:name
)
}
it
{
is_expected
.
not_to
allow_value
(
'!!().for(:name)().for(:name)'
).
for
(
:name
)
}
end
context
'nuget package'
do
subject
{
build_stubbed
(
:nuget_package
)
}
it
{
is_expected
.
to
allow_value
(
'My.Package'
).
for
(
:name
)
}
it
{
is_expected
.
to
allow_value
(
'My.Package.Mvc'
).
for
(
:name
)
}
it
{
is_expected
.
to
allow_value
(
'MyPackage'
).
for
(
:name
)
}
it
{
is_expected
.
to
allow_value
(
'My.23.Package'
).
for
(
:name
)
}
it
{
is_expected
.
to
allow_value
(
'My23Package'
).
for
(
:name
)
}
it
{
is_expected
.
to
allow_value
(
'runtime.my-test64.runtime.package.Mvc'
).
for
(
:name
)
}
it
{
is_expected
.
to
allow_value
(
'my_package'
).
for
(
:name
)
}
it
{
is_expected
.
not_to
allow_value
(
'My/package'
).
for
(
:name
)
}
it
{
is_expected
.
not_to
allow_value
(
'../../../my_package'
).
for
(
:name
)
}
it
{
is_expected
.
not_to
allow_value
(
'%2e%2e%2fmy_package'
).
for
(
:name
)
}
end
end
describe
'#version'
do
...
...
spec/policies/project_policy_spec.rb
View file @
2cfd792a
...
...
@@ -137,7 +137,7 @@ RSpec.describe ProjectPolicy do
it
'disallows all permissions except pipeline when the feature is disabled'
do
builds_permissions
=
[
:create_build
,
:read_build
,
:update_build
,
:admin_build
,
:destroy_build
,
:create_pipeline_schedule
,
:read_pipeline_schedule
,
:update_pipeline_schedule
,
:admin_pipeline_schedule
,
:destroy_pipeline_schedule
,
:create_pipeline_schedule
,
:read_pipeline_schedule
_variables
,
:update_pipeline_schedule
,
:admin_pipeline_schedule
,
:destroy_pipeline_schedule
,
:create_environment
,
:read_environment
,
:update_environment
,
:admin_environment
,
:destroy_environment
,
:create_cluster
,
:read_cluster
,
:update_cluster
,
:admin_cluster
,
:destroy_cluster
,
:create_deployment
,
:read_deployment
,
:update_deployment
,
:admin_deployment
,
:destroy_deployment
...
...
spec/requests/api/ci/pipeline_schedules_spec.rb
View file @
2cfd792a
...
...
@@ -97,46 +97,112 @@ RSpec.describe API::Ci::PipelineSchedules do
pipeline_schedule
.
pipelines
<<
build
(
:ci_pipeline
,
project:
project
)
end
context
'authenticated user with valid permissions'
do
it
'returns pipeline_schedule details'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
developer
)
matcher
:return_pipeline_schedule_sucessfully
do
match_unless_raises
do
|
reponse
|
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
response
).
to
match_response_schema
(
'pipeline_schedule'
)
end
end
it
'responds with 404 Not Found if requesting non-existing pipeline_schedule'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/-5"
,
developer
)
shared_context
'request with project permissions'
do
context
'authenticated user with project permisions'
do
before
do
project
.
add_maintainer
(
user
)
end
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
it
'returns pipeline_schedule details'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
user
)
expect
(
response
).
to
return_pipeline_schedule_sucessfully
expect
(
json_response
).
to
have_key
(
'variables'
)
end
end
end
context
'authenticated user with invalid permissions'
do
it
'does not return pipeline_schedules list'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
user
)
shared_examples
'request with schedule ownership'
do
context
'authenticated user with pipeline schedule ownership'
do
it
'returns pipeline_schedule details'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
developer
)
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
expect
(
response
).
to
return_pipeline_schedule_sucessfully
expect
(
json_response
).
to
have_key
(
'variables'
)
end
end
end
context
'authenticated user with insufficient permissions'
do
before
do
project
.
add_guest
(
user
)
shared_examples
'request with unauthenticated user'
do
context
'with unauthenticated user'
do
it
'does not return pipeline_schedule'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
)
expect
(
response
).
to
have_gitlab_http_status
(
:unauthorized
)
end
end
end
it
'does not return pipeline_schedules list'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
user
)
shared_examples
'request with non-existing pipeline_schedule'
do
it
'responds with 404 Not Found if requesting non-existing pipeline_schedule'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/-5"
,
developer
)
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
context
'unauthenticated user'
do
it
'does not return pipeline_schedules list'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
)
context
'with private project'
do
it_behaves_like
'request with schedule ownership'
it_behaves_like
'request with project permissions'
it_behaves_like
'request with unauthenticated user'
it_behaves_like
'request with non-existing pipeline_schedule'
expect
(
response
).
to
have_gitlab_http_status
(
:unauthorized
)
context
'authenticated user with no project permissions'
do
it
'does not return pipeline_schedule'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
context
'authenticated user with insufficient project permissions'
do
before
do
project
.
add_guest
(
user
)
end
it
'does not return pipeline_schedule'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
end
context
'with public project'
do
let_it_be
(
:project
)
{
create
(
:project
,
:repository
,
:public
,
public_builds:
false
)
}
it_behaves_like
'request with schedule ownership'
it_behaves_like
'request with project permissions'
it_behaves_like
'request with unauthenticated user'
it_behaves_like
'request with non-existing pipeline_schedule'
context
'authenticated user with no project permissions'
do
it
'returns pipeline_schedule with no variables'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
user
)
expect
(
response
).
to
return_pipeline_schedule_sucessfully
expect
(
json_response
).
not_to
have_key
(
'variables'
)
end
end
context
'authenticated user with insufficient project permissions'
do
before
do
project
.
add_guest
(
user
)
end
it
'returns pipeline_schedule with no variables'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
user
)
expect
(
response
).
to
return_pipeline_schedule_sucessfully
expect
(
json_response
).
not_to
have_key
(
'variables'
)
end
end
end
end
...
...
spec/requests/api/internal/kubernetes_spec.rb
View file @
2cfd792a
...
...
@@ -166,6 +166,16 @@ RSpec.describe API::Internal::Kubernetes do
)
)
end
context
'repository is for project members only'
do
let
(
:project
)
{
create
(
:project
,
:public
,
:repository_private
)
}
it
'returns 404'
do
send_request
(
params:
{
id:
project
.
id
},
headers:
{
'Authorization'
=>
"Bearer
#{
agent_token
.
token
}
"
})
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
end
context
'project is private'
do
...
...
@@ -190,7 +200,7 @@ RSpec.describe API::Internal::Kubernetes do
context
'project does not exist'
do
it
'returns 404'
do
send_request
(
params:
{
id:
0
},
headers:
{
'Authorization'
=>
"Bearer
#{
agent_token
.
token
}
"
})
send_request
(
params:
{
id:
non_existing_record_id
},
headers:
{
'Authorization'
=>
"Bearer
#{
agent_token
.
token
}
"
})
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
...
...
spec/requests/api/terraform/state_spec.rb
View file @
2cfd792a
...
...
@@ -125,6 +125,7 @@ RSpec.describe API::Terraform::State do
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
0
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
context
'on Unicorn'
,
:unicorn
do
...
...
@@ -132,6 +133,7 @@ RSpec.describe API::Terraform::State do
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
0
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
end
end
...
...
@@ -167,6 +169,7 @@ RSpec.describe API::Terraform::State do
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
1
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
context
'on Unicorn'
,
:unicorn
do
...
...
@@ -174,6 +177,7 @@ RSpec.describe API::Terraform::State do
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
1
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
end
end
...
...
@@ -218,10 +222,11 @@ RSpec.describe API::Terraform::State do
context
'with maintainer permissions'
do
let
(
:current_user
)
{
maintainer
}
it
'deletes the state'
do
it
'deletes the state
and returns empty body
'
do
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
-
1
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
end
...
...
spec/services/packages/nuget/update_package_from_metadata_service_spec.rb
View file @
2cfd792a
...
...
@@ -198,24 +198,26 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
MetadataExtractionService
::
ExtractionError
end
context
'with package file with a blank package name'
do
before
do
allow
(
service
).
to
receive
(
:package_name
).
and_return
(
''
)
end
context
'with an invalid package name'
do
invalid_names
=
[
''
,
'My/package'
,
'../../../my_package'
,
'%2e%2e%2fmy_package'
]
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
end
invalid_names
.
each
do
|
invalid_name
|
before
do
allow
(
service
).
to
receive
(
:package_name
).
and_return
(
invalid_name
)
end
context
'with package file with a blank package version'
do
before
do
allow
(
service
).
to
receive
(
:package_version
).
and_return
(
''
)
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
end
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
end
context
'with an invalid package version'
do
invalid_versions
=
[
''
,
'555'
,
'1.2'
,
'1./2.3'
,
...
...
@@ -224,13 +226,11 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
]
invalid_versions
.
each
do
|
invalid_version
|
it
"raises an error for version
#{
invalid_version
}
"
do
before
do
allow
(
service
).
to
receive
(
:package_version
).
and_return
(
invalid_version
)
expect
{
subject
}.
to
raise_error
(
ActiveRecord
::
RecordInvalid
,
'Validation failed: Version is invalid'
)
expect
(
package_file
.
file_name
).
not_to
include
(
invalid_version
)
expect
(
package_file
.
file
.
file
.
path
).
not_to
include
(
invalid_version
)
end
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
end
end
end
...
...
spec/services/terraform/remote_state_handler_spec.rb
View file @
2cfd792a
...
...
@@ -42,17 +42,17 @@ RSpec.describe Terraform::RemoteStateHandler do
describe
'#handle_with_lock'
do
it
'allows to modify a state using database locking'
do
state
=
subject
.
handle_with_lock
do
|
state
|
record
=
nil
subject
.
handle_with_lock
do
|
state
|
record
=
state
state
.
name
=
'updated-name'
end
expect
(
state
.
name
).
to
eq
'updated-name'
expect
(
record
.
reload
.
name
).
to
eq
'updated-name'
end
it
'returns the state object itself'
do
state
=
subject
.
handle_with_lock
expect
(
state
.
name
).
to
eq
'my-state'
it
'returns nil'
do
expect
(
subject
.
handle_with_lock
).
to
be_nil
end
end
...
...
@@ -70,11 +70,13 @@ RSpec.describe Terraform::RemoteStateHandler do
it
'handles a locked state using exclusive read lock'
do
handler
.
lock!
state
=
handler
.
handle_with_lock
do
|
state
|
record
=
nil
handler
.
handle_with_lock
do
|
state
|
record
=
state
state
.
name
=
'new-name'
end
expect
(
state
.
name
).
to
eq
'new-name'
expect
(
record
.
reload
.
name
).
to
eq
'new-name'
end
it
'raises exception if lock has not been acquired before'
do
...
...
spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb
View file @
2cfd792a
...
...
@@ -14,6 +14,7 @@ end
RSpec
.
shared_examples
"builds correct paths"
do
|**
patterns
|
let
(
:patterns
)
{
patterns
}
let
(
:fixture
)
{
File
.
join
(
'spec'
,
'fixtures'
,
'rails_sample.jpg'
)
}
before
do
allow
(
subject
).
to
receive
(
:filename
).
and_return
(
'<filename>'
)
...
...
@@ -55,4 +56,15 @@ RSpec.shared_examples "builds correct paths" do |**patterns|
let
(
:target
)
{
subject
.
class
}
end
end
describe
"path traversal exploits"
do
before
do
allow
(
subject
).
to
receive
(
:filename
).
and_return
(
"3bc58d54542d6a5efffa9a87554faac0254f73f675b337899ea869f6d38b7371/122../../../../../../../../.ssh/authorized_keys"
)
end
it
"throws an exception"
do
expect
{
subject
.
cache!
(
fixture_file_upload
(
fixture
))
}.
to
raise_error
(
Gitlab
::
Utils
::
PathTraversalAttackError
)
expect
{
subject
.
store!
(
fixture_file_upload
(
fixture
))
}.
to
raise_error
(
Gitlab
::
Utils
::
PathTraversalAttackError
)
end
end
end
spec/uploaders/import_export_uploader_spec.rb
View file @
2cfd792a
...
...
@@ -24,9 +24,14 @@ RSpec.describe ImportExportUploader do
include_context
'with storage'
,
described_class
::
Store
::
REMOTE
it_behaves_like
'builds correct paths'
,
store_dir:
%r[import_export_upload/import_file/]
,
upload_path:
%r[import_export_upload/import_file/]
patterns
=
{
store_dir:
%r[import_export_upload/import_file/]
,
upload_path:
%r[import_export_upload/import_file/]
}
it_behaves_like
'builds correct paths'
,
patterns
do
let
(
:fixture
)
{
File
.
join
(
'spec'
,
'fixtures'
,
'group_export.tar.gz'
)
}
end
describe
'#move_to_store'
do
it
'returns false'
do
...
...
spec/workers/packages/nuget/extraction_worker_spec.rb
View file @
2cfd792a
...
...
@@ -13,6 +13,18 @@ RSpec.describe Packages::Nuget::ExtractionWorker, type: :worker do
subject
{
described_class
.
new
.
perform
(
package_file_id
)
}
shared_examples
'handling the metadata error'
do
|
exception_class:
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
|
it
'removes the package and the package file'
do
expect
(
Gitlab
::
ErrorTracking
).
to
receive
(
:log_exception
).
with
(
instance_of
(
exception_class
),
project_id:
package
.
project_id
)
expect
{
subject
}
.
to
change
{
Packages
::
Package
.
count
}.
by
(
-
1
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
-
1
)
end
end
context
'with valid package file'
do
it
'updates package and package file'
do
expect
{
subject
}
...
...
@@ -48,46 +60,46 @@ RSpec.describe Packages::Nuget::ExtractionWorker, type: :worker do
allow_any_instance_of
(
Zip
::
File
).
to
receive
(
:glob
).
and_return
([])
end
it
'removes the package and the package file'
do
expect
(
Gitlab
::
ErrorTracking
).
to
receive
(
:log_exception
).
with
(
instance_of
(
::
Packages
::
Nuget
::
MetadataExtractionService
::
ExtractionError
),
project_id:
package
.
project_id
)
expect
{
subject
}
.
to
change
{
Packages
::
Package
.
count
}.
by
(
-
1
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
-
1
)
end
it_behaves_like
'handling the metadata error'
,
exception_class:
::
Packages
::
Nuget
::
MetadataExtractionService
::
ExtractionError
end
context
'with package file with a blank package name'
do
before
do
allow_any_instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
).
to
receive
(
:package_name
).
and_return
(
''
)
end
context
'with package with an invalid package name'
do
invalid_names
=
[
''
,
'My/package'
,
'../../../my_package'
,
'%2e%2e%2fmy_package'
]
i
t
'removes the package and the package file'
do
expect
(
Gitlab
::
ErrorTracking
).
to
receive
(
:log_exception
).
with
(
instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
),
project_id:
package
.
project_id
)
e
xpect
{
subject
}
.
to
change
{
Packages
::
Package
.
count
}.
by
(
-
1
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
-
1
)
i
nvalid_names
.
each
do
|
invalid_name
|
before
do
allow_next_instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
)
do
|
service
|
allow
(
service
).
to
receive
(
:package_name
).
and_return
(
invalid_name
)
end
e
nd
it_behaves_like
'handling the metadata error'
end
end
context
'with package file with a blank package version'
do
before
do
allow_any_instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
).
to
receive
(
:package_version
).
and_return
(
''
)
end
context
'with package with an invalid package version'
do
invalid_versions
=
[
''
,
'555'
,
'1.2'
,
'1./2.3'
,
'../../../../../1.2.3'
,
'%2e%2e%2f1.2.3'
]
i
t
'removes the package and the package file'
do
expect
(
Gitlab
::
ErrorTracking
).
to
receive
(
:log_exception
).
with
(
instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
),
project_id:
package
.
project_id
)
e
xpect
{
subject
}
.
to
change
{
Packages
::
Package
.
count
}.
by
(
-
1
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
-
1
)
i
nvalid_versions
.
each
do
|
invalid_version
|
before
do
allow_next_instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
)
do
|
service
|
allow
(
service
).
to
receive
(
:package_version
).
and_return
(
invalid_version
)
end
e
nd
it_behaves_like
'handling the metadata error'
end
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