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.
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)
## 13.5.1 (2020-10-22)
-
No changes.
-
No changes.
...
@@ -220,6 +230,16 @@ Please view this file on the master branch, on stable branches it's out of date.
...
@@ -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
-
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)
## 13.4.4 (2020-10-15)
### Fixed (1 change)
### Fixed (1 change)
...
@@ -493,6 +513,16 @@ Please view this file on the master branch, on stable branches it's out of date.
...
@@ -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
-
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)
## 13.3.8 (2020-10-21)
### Fixed (4 changes)
### Fixed (4 changes)
...
...
CHANGELOG.md
View file @
2cfd792a
...
@@ -2,6 +2,21 @@
...
@@ -2,6 +2,21 @@
documentation
](
doc/development/changelog.md
)
for instructions on adding your own
documentation
](
doc/development/changelog.md
)
for instructions on adding your own
entry.
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)
## 13.5.1 (2020-10-22)
### Other (1 change)
### Other (1 change)
...
@@ -583,6 +598,21 @@ entry.
...
@@ -583,6 +598,21 @@ entry.
-
Bump cluster applications CI template. !45472
-
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)
## 13.4.4 (2020-10-15)
### Fixed (2 changes)
### Fixed (2 changes)
...
@@ -1241,6 +1271,21 @@ entry.
...
@@ -1241,6 +1271,21 @@ entry.
-
Expand the visible highlight for collapsed diffs (re: !41393). !42343
-
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)
## 13.3.8 (2020-10-21)
### Fixed (2 changes)
### Fixed (2 changes)
...
...
app/assets/javascripts/jobs/components/job_app.vue
View file @
2cfd792a
<
script
>
<
script
>
/* eslint-disable vue/no-v-html */
import
{
throttle
,
isEmpty
}
from
'
lodash
'
;
import
{
throttle
,
isEmpty
}
from
'
lodash
'
;
import
{
mapGetters
,
mapState
,
mapActions
}
from
'
vuex
'
;
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
{
GlBreakpointInstance
as
bp
}
from
'
@gitlab/ui/dist/utils
'
;
import
{
isScrolledToBottom
}
from
'
~/lib/utils/scroll_utils
'
;
import
{
isScrolledToBottom
}
from
'
~/lib/utils/scroll_utils
'
;
import
{
polyfillSticky
}
from
'
~/lib/utils/sticky
'
;
import
{
polyfillSticky
}
from
'
~/lib/utils/sticky
'
;
...
@@ -36,6 +35,9 @@ export default {
...
@@ -36,6 +35,9 @@ export default {
GlLoadingIcon
,
GlLoadingIcon
,
SharedRunner
:
()
=>
import
(
'
ee_component/jobs/components/shared_runner_limit_block.vue
'
),
SharedRunner
:
()
=>
import
(
'
ee_component/jobs/components/shared_runner_limit_block.vue
'
),
},
},
directives
:
{
SafeHtml
,
},
mixins
:
[
delayedJobMixin
],
mixins
:
[
delayedJobMixin
],
props
:
{
props
:
{
artifactHelpUrl
:
{
artifactHelpUrl
:
{
...
@@ -223,7 +225,7 @@ export default {
...
@@ -223,7 +225,7 @@ export default {
</div>
</div>
<callout
v-if=
"shouldRenderHeaderCallout"
>
<callout
v-if=
"shouldRenderHeaderCallout"
>
<div
v-html=
"job.callout_message"
></div>
<div
v-
safe-
html=
"job.callout_message"
></div>
</callout>
</callout>
</header>
</header>
<!-- EO Header Section -->
<!-- EO Header Section -->
...
...
app/models/packages/package.rb
View file @
2cfd792a
...
@@ -37,6 +37,7 @@ class Packages::Package < ApplicationRecord
...
@@ -37,6 +37,7 @@ class Packages::Package < ApplicationRecord
validate
:package_already_taken
,
if: :npm?
validate
:package_already_taken
,
if: :npm?
validates
:name
,
format:
{
with:
Gitlab
::
Regex
.
conan_recipe_component_regex
},
if: :conan?
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
.
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
.
nuget_version_regex
},
if: :nuget?
validates
:version
,
format:
{
with:
Gitlab
::
Regex
.
conan_recipe_component_regex
},
if: :conan?
validates
:version
,
format:
{
with:
Gitlab
::
Regex
.
conan_recipe_component_regex
},
if: :conan?
validates
:version
,
format:
{
with:
Gitlab
::
Regex
.
maven_version_regex
},
if:
->
{
version?
&&
maven?
}
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
...
@@ -17,6 +17,7 @@ module Ci
rule
{
can?
(
:admin_pipeline
)
|
(
can?
(
:update_build
)
&
owner_of_schedule
)
}.
policy
do
rule
{
can?
(
:admin_pipeline
)
|
(
can?
(
:update_build
)
&
owner_of_schedule
)
}.
policy
do
enable
:update_pipeline_schedule
enable
:update_pipeline_schedule
enable
:admin_pipeline_schedule
enable
:admin_pipeline_schedule
enable
:read_pipeline_schedule_variables
end
end
rule
{
can?
(
:admin_pipeline_schedule
)
&
~
owner_of_schedule
}.
policy
do
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
...
@@ -136,7 +136,7 @@ class BuildDetailsEntity < JobEntity
docs_url
=
"https://docs.gitlab.com/ee/ci/yaml/README.html#dependencies"
docs_url
=
"https://docs.gitlab.com/ee/ci/yaml/README.html#dependencies"
[
[
failure_message
.
html_safe
,
failure_message
,
help_message
(
docs_url
).
html_safe
help_message
(
docs_url
).
html_safe
].
join
(
"<br />"
)
].
join
(
"<br />"
)
end
end
...
...
app/services/packages/nuget/update_package_from_metadata_service.rb
View file @
2cfd792a
...
@@ -32,6 +32,8 @@ module Packages
...
@@ -32,6 +32,8 @@ module Packages
)
)
end
end
end
end
rescue
ActiveRecord
::
RecordInvalid
=>
e
raise
InvalidMetadataError
.
new
(
e
.
message
)
end
end
private
private
...
...
app/services/projects/transfer_service.rb
View file @
2cfd792a
...
@@ -79,11 +79,7 @@ module Projects
...
@@ -79,11 +79,7 @@ module Projects
# Directories on disk
# Directories on disk
move_project_folders
(
project
)
move_project_folders
(
project
)
# Move missing group labels to project
transfer_missing_group_resources
(
@old_group
)
Labels
::
TransferService
.
new
(
current_user
,
@old_group
,
project
).
execute
# Move missing group milestones
Milestones
::
TransferService
.
new
(
current_user
,
@old_group
,
project
).
execute
# Move uploads
# Move uploads
move_project_uploads
(
project
)
move_project_uploads
(
project
)
...
@@ -107,6 +103,12 @@ module Projects
...
@@ -107,6 +103,12 @@ module Projects
refresh_permissions
refresh_permissions
end
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
)
def
allowed_transfer?
(
current_user
,
project
)
@new_namespace
&&
@new_namespace
&&
can?
(
current_user
,
:change_namespace
,
project
)
&&
can?
(
current_user
,
:change_namespace
,
project
)
&&
...
...
app/services/terraform/remote_state_handler.rb
View file @
2cfd792a
...
@@ -23,6 +23,8 @@ module Terraform
...
@@ -23,6 +23,8 @@ module Terraform
state
.
save!
unless
state
.
destroyed?
state
.
save!
unless
state
.
destroyed?
end
end
nil
end
end
def
lock!
def
lock!
...
...
app/uploaders/gitlab_uploader.rb
View file @
2cfd792a
...
@@ -5,6 +5,10 @@ class GitlabUploader < CarrierWave::Uploader::Base
...
@@ -5,6 +5,10 @@ class GitlabUploader < CarrierWave::Uploader::Base
class_attribute
:options
class_attribute
:options
PROTECTED_METHODS
=
%i(filename cache_dir work_dir store_dir)
.
freeze
ObjectNotReadyError
=
Class
.
new
(
StandardError
)
class
<<
self
class
<<
self
# DSL setter
# DSL setter
def
storage_options
(
options
)
def
storage_options
(
options
)
...
@@ -33,6 +37,8 @@ class GitlabUploader < CarrierWave::Uploader::Base
...
@@ -33,6 +37,8 @@ class GitlabUploader < CarrierWave::Uploader::Base
delegate
:base_dir
,
:file_storage?
,
to: :class
delegate
:base_dir
,
:file_storage?
,
to: :class
before
:cache
,
:protect_from_path_traversal!
def
initialize
(
model
,
mounted_as
=
nil
,
**
uploader_context
)
def
initialize
(
model
,
mounted_as
=
nil
,
**
uploader_context
)
super
(
model
,
mounted_as
)
super
(
model
,
mounted_as
)
end
end
...
@@ -121,6 +127,9 @@ class GitlabUploader < CarrierWave::Uploader::Base
...
@@ -121,6 +127,9 @@ class GitlabUploader < CarrierWave::Uploader::Base
# For example, `FileUploader` builds the storage path based on the associated
# For example, `FileUploader` builds the storage path based on the associated
# project model's `path_with_namespace` value, which can change when the
# project model's `path_with_namespace` value, which can change when the
# project or its containing namespace is moved or renamed.
# 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
def
dynamic_segment
raise
(
NotImplementedError
)
raise
(
NotImplementedError
)
end
end
...
@@ -138,4 +147,21 @@ class GitlabUploader < CarrierWave::Uploader::Base
...
@@ -138,4 +147,21 @@ class GitlabUploader < CarrierWave::Uploader::Base
def
pathname
def
pathname
@pathname
||=
Pathname
.
new
(
path
)
@pathname
||=
Pathname
.
new
(
path
)
end
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
end
app/uploaders/job_artifact_uploader.rb
View file @
2cfd792a
...
@@ -4,7 +4,6 @@ class JobArtifactUploader < GitlabUploader
...
@@ -4,7 +4,6 @@ class JobArtifactUploader < GitlabUploader
extend
Workhorse
::
UploadPath
extend
Workhorse
::
UploadPath
include
ObjectStorage
::
Concern
include
ObjectStorage
::
Concern
ObjectNotReadyError
=
Class
.
new
(
StandardError
)
UnknownFileLocationError
=
Class
.
new
(
StandardError
)
UnknownFileLocationError
=
Class
.
new
(
StandardError
)
storage_options
Gitlab
.
config
.
artifacts
storage_options
Gitlab
.
config
.
artifacts
...
@@ -24,7 +23,9 @@ class JobArtifactUploader < GitlabUploader
...
@@ -24,7 +23,9 @@ class JobArtifactUploader < GitlabUploader
private
private
def
dynamic_segment
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?
if
model
.
hashed_path?
hashed_path
hashed_path
...
...
app/uploaders/packages/package_file_uploader.rb
View file @
2cfd792a
...
@@ -20,6 +20,8 @@ class Packages::PackageFileUploader < GitlabUploader
...
@@ -20,6 +20,8 @@ class Packages::PackageFileUploader < GitlabUploader
private
private
def
dynamic_segment
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
)
Gitlab
::
HashedPath
.
new
(
'packages'
,
model
.
package
.
id
,
'files'
,
model
.
id
,
root_hash:
model
.
package
.
project_id
)
end
end
end
end
app/views/admin/runners/_runner.html.haml
View file @
2cfd792a
...
@@ -69,10 +69,10 @@
...
@@ -69,10 +69,10 @@
=
sprite_icon
(
'pencil'
)
=
sprite_icon
(
'pencil'
)
.btn-group
.btn-group
-
if
runner
.
active?
-
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'
)
=
sprite_icon
(
'pause'
)
-
else
-
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'
)
=
sprite_icon
(
'play'
)
.btn-group
.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
=
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
...
@@ -148,8 +148,8 @@ namespace :admin do
resources
:runners
,
only:
[
:index
,
:show
,
:update
,
:destroy
]
do
resources
:runners
,
only:
[
:index
,
:show
,
:update
,
:destroy
]
do
member
do
member
do
ge
t
:resume
pos
t
:resume
ge
t
:pause
pos
t
:pause
end
end
collection
do
collection
do
...
...
ee/app/graphql/ee/types/project_type.rb
View file @
2cfd792a
...
@@ -24,6 +24,8 @@ module EE
...
@@ -24,6 +24,8 @@ module EE
calls_gitaly:
true
,
calls_gitaly:
true
,
description:
'SAST CI configuration for the project'
,
description:
'SAST CI configuration for the project'
,
resolve:
->
(
project
,
args
,
ctx
)
do
resolve:
->
(
project
,
args
,
ctx
)
do
return
unless
Ability
.
allowed?
(
ctx
[
:current_user
],
:download_code
,
project
)
sast_ci_configuration
(
project
)
sast_ci_configuration
(
project
)
end
end
...
...
ee/app/services/ee/merge_requests/update_service.rb
View file @
2cfd792a
...
@@ -42,6 +42,13 @@ module EE
...
@@ -42,6 +42,13 @@ module EE
private
private
override
:after_update
def
after_update
(
merge_request
)
super
::
MergeRequests
::
SyncCodeOwnerApprovalRules
.
new
(
merge_request
).
execute
end
override
:create_branch_change_note
override
:create_branch_change_note
def
create_branch_change_note
(
merge_request
,
branch_type
,
old_branch
,
new_branch
)
def
create_branch_change_note
(
merge_request
,
branch_type
,
old_branch
,
new_branch
)
super
super
...
...
ee/app/services/ee/projects/transfer_service.rb
View file @
2cfd792a
...
@@ -19,6 +19,13 @@ module EE
...
@@ -19,6 +19,13 @@ module EE
old_path_with_namespace:
old_path
old_path_with_namespace:
old_path
).
create!
).
create!
end
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
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
...
@@ -133,8 +133,7 @@ module Gitlab
def
self
.
parse_search_result
(
result
,
project
)
def
self
.
parse_search_result
(
result
,
project
)
ref
=
result
[
"_source"
][
"blob"
][
"commit_sha"
]
ref
=
result
[
"_source"
][
"blob"
][
"commit_sha"
]
path
=
result
[
"_source"
][
"blob"
][
"path"
]
path
=
result
[
"_source"
][
"blob"
][
"path"
]
extname
=
File
.
extname
(
path
)
basename
=
File
.
join
(
File
.
dirname
(
path
),
File
.
basename
(
path
,
'.*'
))
basename
=
path
.
sub
(
/
#{
extname
}
$/
,
''
)
content
=
result
[
"_source"
][
"blob"
][
"content"
]
content
=
result
[
"_source"
][
"blob"
][
"content"
]
project_id
=
result
[
'_source'
][
'project_id'
].
to_i
project_id
=
result
[
'_source'
][
'project_id'
].
to_i
total_lines
=
content
.
lines
.
size
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
...
@@ -27,7 +27,7 @@ RSpec.describe GitlabSchema.types['Project'] do
describe
'sast_ci_configuration'
do
describe
'sast_ci_configuration'
do
include_context
'read ci configuration for sast enabled project'
include_context
'read ci configuration for sast enabled project'
let
_it_be
(
:query
)
do
let
(
:query
)
do
%(
%(
query {
query {
project(fullPath: "#{project.full_path}") {
project(fullPath: "#{project.full_path}") {
...
@@ -110,6 +110,72 @@ RSpec.describe GitlabSchema.types['Project'] do
...
@@ -110,6 +110,72 @@ RSpec.describe GitlabSchema.types['Project'] do
expect
(
analyzer
[
'label'
]).
to
eq
(
'Brakeman'
)
expect
(
analyzer
[
'label'
]).
to
eq
(
'Brakeman'
)
expect
(
analyzer
[
'enabled'
]).
to
eq
(
true
)
expect
(
analyzer
[
'enabled'
]).
to
eq
(
true
)
end
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
end
describe
'security_scanners'
do
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
...
@@ -85,12 +85,13 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
describe
'parse_search_result'
do
describe
'parse_search_result'
do
let
(
:project
)
{
double
(
:project
)
}
let
(
:project
)
{
double
(
:project
)
}
let
(
:content
)
{
"foo
\n
bar
\n
baz
\n
"
}
let
(
:content
)
{
"foo
\n
bar
\n
baz
\n
"
}
let
(
:path
)
{
'path/file.ext'
}
let
(
:blob
)
do
let
(
:blob
)
do
{
{
'blob'
=>
{
'blob'
=>
{
'commit_sha'
=>
'sha'
,
'commit_sha'
=>
'sha'
,
'content'
=>
content
,
'content'
=>
content
,
'path'
=>
'path/file.ext'
'path'
=>
path
}
}
}
}
end
end
...
@@ -184,6 +185,21 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
...
@@ -184,6 +185,21 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
)
)
end
end
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
end
describe
'issues'
do
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
...
@@ -322,5 +322,13 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
it_behaves_like
'undeletable existing approval rules'
it_behaves_like
'undeletable existing approval rules'
end
end
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
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
...
@@ -53,4 +53,14 @@ RSpec.describe Projects::TransferService do
end
end
end
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
end
lib/api/ci/pipeline_schedules.rb
View file @
2cfd792a
...
@@ -38,7 +38,7 @@ module API
...
@@ -38,7 +38,7 @@ module API
requires
:pipeline_schedule_id
,
type:
Integer
,
desc:
'The pipeline schedule id'
requires
:pipeline_schedule_id
,
type:
Integer
,
desc:
'The pipeline schedule id'
end
end
get
':id/pipeline_schedules/:pipeline_schedule_id'
do
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
end
desc
'Create a new pipeline schedule'
do
desc
'Create a new pipeline schedule'
do
...
...
lib/api/entities/ci/pipeline_schedule_details.rb
View file @
2cfd792a
...
@@ -5,7 +5,9 @@ module API
...
@@ -5,7 +5,9 @@ module API
module
Ci
module
Ci
class
PipelineScheduleDetails
<
PipelineSchedule
class
PipelineScheduleDetails
<
PipelineSchedule
expose
:last_pipeline
,
using:
::
API
::
Entities
::
Ci
::
PipelineBasic
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
end
end
end
...
...
lib/api/internal/kubernetes.rb
View file @
2cfd792a
...
@@ -87,7 +87,7 @@ module API
...
@@ -87,7 +87,7 @@ module API
# TODO sort out authorization for real
# TODO sort out authorization for real
# https://gitlab.com/gitlab-org/gitlab/-/issues/220912
# https://gitlab.com/gitlab-org/gitlab/-/issues/220912
if
!
project
||
!
project
.
public?
unless
Ability
.
allowed?
(
nil
,
:download_code
,
project
)
not_found!
not_found!
end
end
...
...
lib/api/terraform/state.rb
View file @
2cfd792a
...
@@ -41,7 +41,6 @@ module API
...
@@ -41,7 +41,6 @@ module API
env
[
'api.format'
]
=
:binary
# this bypasses json serialization
env
[
'api.format'
]
=
:binary
# this bypasses json serialization
body
state
.
latest_file
.
read
body
state
.
latest_file
.
read
status
:ok
end
end
end
end
...
@@ -55,8 +54,10 @@ module API
...
@@ -55,8 +54,10 @@ module API
remote_state_handler
.
handle_with_lock
do
|
state
|
remote_state_handler
.
handle_with_lock
do
|
state
|
state
.
update_file!
(
CarrierWaveStringFile
.
new
(
data
),
version:
params
[
:serial
],
build:
current_authenticated_job
)
state
.
update_file!
(
CarrierWaveStringFile
.
new
(
data
),
version:
params
[
:serial
],
build:
current_authenticated_job
)
status
:ok
end
end
body
false
status
:ok
end
end
desc
'Delete a terraform state of a certain name'
desc
'Delete a terraform state of a certain name'
...
@@ -66,8 +67,10 @@ module API
...
@@ -66,8 +67,10 @@ module API
remote_state_handler
.
handle_with_lock
do
|
state
|
remote_state_handler
.
handle_with_lock
do
|
state
|
state
.
destroy!
state
.
destroy!
status
:ok
end
end
body
false
status
:ok
end
end
desc
'Lock a terraform state of a certain name'
desc
'Lock a terraform state of a certain name'
...
...
lib/gitlab/middleware/multipart.rb
View file @
2cfd792a
...
@@ -31,6 +31,7 @@ module Gitlab
...
@@ -31,6 +31,7 @@ module Gitlab
RACK_ENV_KEY
=
'HTTP_GITLAB_WORKHORSE_MULTIPART_FIELDS'
RACK_ENV_KEY
=
'HTTP_GITLAB_WORKHORSE_MULTIPART_FIELDS'
JWT_PARAM_SUFFIX
=
'.gitlab-workhorse-upload'
JWT_PARAM_SUFFIX
=
'.gitlab-workhorse-upload'
JWT_PARAM_FIXED_KEY
=
'upload'
JWT_PARAM_FIXED_KEY
=
'upload'
REWRITTEN_FIELD_NAME_MAX_LENGTH
=
10000
.
freeze
class
Handler
class
Handler
def
initialize
(
env
,
message
)
def
initialize
(
env
,
message
)
...
@@ -41,6 +42,8 @@ module Gitlab
...
@@ -41,6 +42,8 @@ module Gitlab
def
with_open_files
def
with_open_files
@rewritten_fields
.
each
do
|
field
,
tmp_path
|
@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
)
parsed_field
=
Rack
::
Utils
.
parse_nested_query
(
field
)
raise
"unexpected field:
#{
field
.
inspect
}
"
unless
parsed_field
.
count
==
1
raise
"unexpected field:
#{
field
.
inspect
}
"
unless
parsed_field
.
count
==
1
...
@@ -108,6 +111,17 @@ module Gitlab
...
@@ -108,6 +111,17 @@ module Gitlab
private
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
def
package_allowed_paths
packages_config
=
::
Gitlab
.
config
.
packages
packages_config
=
::
Gitlab
.
config
.
packages
return
[]
unless
allow_packages_storage_path?
(
packages_config
)
return
[]
unless
allow_packages_storage_path?
(
packages_config
)
...
@@ -141,6 +155,8 @@ module Gitlab
...
@@ -141,6 +155,8 @@ module Gitlab
class
HandlerForJWTParams
<
Handler
class
HandlerForJWTParams
<
Handler
def
with_open_files
def
with_open_files
@rewritten_fields
.
keys
.
each
do
|
field
|
@rewritten_fields
.
keys
.
each
do
|
field
|
raise
"invalid field:
#{
field
.
inspect
}
"
unless
valid_field_name?
(
field
)
parsed_field
=
Rack
::
Utils
.
parse_nested_query
(
field
)
parsed_field
=
Rack
::
Utils
.
parse_nested_query
(
field
)
raise
"unexpected field:
#{
field
.
inspect
}
"
unless
parsed_field
.
count
==
1
raise
"unexpected field:
#{
field
.
inspect
}
"
unless
parsed_field
.
count
==
1
...
...
lib/gitlab/regex.rb
View file @
2cfd792a
...
@@ -50,6 +50,10 @@ module Gitlab
...
@@ -50,6 +50,10 @@ module Gitlab
maven_app_name_regex
maven_app_name_regex
end
end
def
nuget_package_name_regex
@nuget_package_name_regex
||=
%r{
\A
[-+
\.\_
a-zA-Z0-9]+
\z
}
.
freeze
end
def
nuget_version_regex
def
nuget_version_regex
@nuget_version_regex
||=
/
@nuget_version_regex
||=
/
\A
#{
_semver_major_minor_patch_regex
}
(\.\d*)?
#{
_semver_prerelease_build_regex
}
\z
\A
#{
_semver_major_minor_patch_regex
}
(\.\d*)?
#{
_semver_prerelease_build_regex
}
\z
...
@@ -208,7 +212,7 @@ module Gitlab
...
@@ -208,7 +212,7 @@ module Gitlab
# See https://github.com/docker/distribution/blob/master/reference/regexp.go.
# See https://github.com/docker/distribution/blob/master/reference/regexp.go.
#
#
def
container_repository_name_regex
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
end
##
##
...
...
lib/gitlab/utils.rb
View file @
2cfd792a
...
@@ -10,6 +10,8 @@ module Gitlab
...
@@ -10,6 +10,8 @@ module Gitlab
# Also see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24223#note_284122580
# Also see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24223#note_284122580
# It also checks for ALT_SEPARATOR aka '\' (forward slash)
# It also checks for ALT_SEPARATOR aka '\' (forward slash)
def
check_path_traversal!
(
path
)
def
check_path_traversal!
(
path
)
return
unless
path
.
is_a?
(
String
)
path
=
decode_path
(
path
)
path
=
decode_path
(
path
)
path_regex
=
/(\A(\.{1,2})\z|\A\.\.[\/\\]|[\/\\]\.\.\z|[\/\\]\.\.[\/\\]|\n)/
path_regex
=
/(\A(\.{1,2})\z|\A\.\.[\/\\]|[\/\\]\.\.\z|[\/\\]\.\.[\/\\]|\n)/
...
@@ -208,5 +210,33 @@ module Gitlab
...
@@ -208,5 +210,33 @@ module Gitlab
def
stable_sort_by
(
list
)
def
stable_sort_by
(
list
)
list
.
sort_by
.
with_index
{
|
x
,
idx
|
[
yield
(
x
),
idx
]
}
list
.
sort_by
.
with_index
{
|
x
,
idx
|
[
yield
(
x
),
idx
]
}
end
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
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
...
@@ -123,15 +123,46 @@ RSpec.describe Gitlab::Middleware::Multipart do
end
end
end
end
context
'with
invalid key in parameters
'
do
context
'with
an invalid upload key
'
do
include_context
'with one temporary file for multipart'
include_context
'with one temporary file for multipart'
let
(
:rewritten_fields
)
{
rewritten_fields_hash
(
'file'
=>
uploaded_filepath
)
}
RSpec
.
shared_examples
'rejecting the invalid key'
do
|
key_in_header
:,
key_in_upload_params
:,
error_message
:|
let
(
:params
)
{
upload_parameters_for
(
filepath:
uploaded_filepath
,
key:
'wrong_key'
,
filename:
filename
,
remote_id:
remote_id
)
}
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
it
'raises an error'
do
expect
{
subject
}.
to
raise_error
(
RuntimeError
,
'Empty JWT param: file.gitlab-workhorse-upload'
)
expect
{
subject
}.
to
raise_error
(
RuntimeError
,
error_message
)
end
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
end
context
'with a modified JWT payload'
do
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
...
@@ -139,6 +139,58 @@ RSpec.describe Gitlab::Middleware::Multipart do
subject
subject
end
end
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
end
end
end
spec/lib/gitlab/regex_spec.rb
View file @
2cfd792a
...
@@ -137,11 +137,16 @@ RSpec.describe Gitlab::Regex do
...
@@ -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-1'
)
}
it
{
is_expected
.
to
match
(
'my/awesome/image.test'
)
}
it
{
is_expected
.
to
match
(
'my/awesome/image.test'
)
}
it
{
is_expected
.
to
match
(
'my/awesome/image--test'
)
}
it
{
is_expected
.
to
match
(
'my/awesome/image--test'
)
}
# docker distribution allows for infinite `-`
it
{
is_expected
.
to
match
(
'my/image__test'
)
}
#
https://github.com/docker/distribution/blob/master/reference/regexp.go#L13
#
this example tests for catastrophic backtracking
# but we have a range of 0,10 to add a reasonable limit.
it
{
is_expected
.
to
match
(
'user1/project/a_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb------------x'
)
}
it
{
is_expected
.
not_to
match
(
'
my/image-----------test
'
)
}
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..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'
)
}
it
{
is_expected
.
not_to
match
(
'my/image.'
)
}
it
{
is_expected
.
not_to
match
(
'my/image.'
)
}
end
end
...
@@ -372,6 +377,21 @@ RSpec.describe Gitlab::Regex do
...
@@ -372,6 +377,21 @@ RSpec.describe Gitlab::Regex do
it
{
is_expected
.
not_to
match
(
'%2e%2e%2f1.2.3'
)
}
it
{
is_expected
.
not_to
match
(
'%2e%2e%2f1.2.3'
)
}
end
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
describe
'.pypi_version_regex'
do
subject
{
described_class
.
pypi_version_regex
}
subject
{
described_class
.
pypi_version_regex
}
...
...
spec/lib/gitlab/utils_spec.rb
View file @
2cfd792a
...
@@ -3,6 +3,8 @@
...
@@ -3,6 +3,8 @@
require
'spec_helper'
require
'spec_helper'
RSpec
.
describe
Gitlab
::
Utils
do
RSpec
.
describe
Gitlab
::
Utils
do
using
RSpec
::
Parameterized
::
TableSyntax
delegate
:to_boolean
,
:boolean_to_yes_no
,
:slugify
,
:random_string
,
:which
,
delegate
:to_boolean
,
:boolean_to_yes_no
,
:slugify
,
:random_string
,
:which
,
:ensure_array_from_string
,
:to_exclusive_sentence
,
:bytes_to_megabytes
,
: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
: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
...
@@ -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'
)
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
end
it
'does nothing for a non-string'
do
expect
(
check_path_traversal!
(
nil
)).
to
be_nil
end
end
end
describe
'.allowlisted?'
do
describe
'.allowlisted?'
do
...
@@ -448,4 +454,29 @@ RSpec.describe Gitlab::Utils do
...
@@ -448,4 +454,29 @@ RSpec.describe Gitlab::Utils do
end
end
end
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
end
spec/models/packages/package_spec.rb
View file @
2cfd792a
...
@@ -122,6 +122,21 @@ RSpec.describe Packages::Package, type: :model do
...
@@ -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
(
'my file name'
).
for
(
:name
)
}
it
{
is_expected
.
not_to
allow_value
(
'!!().for(:name)().for(:name)'
).
for
(
:name
)
}
it
{
is_expected
.
not_to
allow_value
(
'!!().for(:name)().for(:name)'
).
for
(
:name
)
}
end
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
end
describe
'#version'
do
describe
'#version'
do
...
...
spec/policies/project_policy_spec.rb
View file @
2cfd792a
...
@@ -137,7 +137,7 @@ RSpec.describe ProjectPolicy do
...
@@ -137,7 +137,7 @@ RSpec.describe ProjectPolicy do
it
'disallows all permissions except pipeline when the feature is disabled'
do
it
'disallows all permissions except pipeline when the feature is disabled'
do
builds_permissions
=
[
builds_permissions
=
[
:create_build
,
:read_build
,
:update_build
,
:admin_build
,
:destroy_build
,
: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_environment
,
:read_environment
,
:update_environment
,
:admin_environment
,
:destroy_environment
,
:create_cluster
,
:read_cluster
,
:update_cluster
,
:admin_cluster
,
:destroy_cluster
,
:create_cluster
,
:read_cluster
,
:update_cluster
,
:admin_cluster
,
:destroy_cluster
,
:create_deployment
,
:read_deployment
,
:update_deployment
,
:admin_deployment
,
:destroy_deployment
: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
...
@@ -97,46 +97,112 @@ RSpec.describe API::Ci::PipelineSchedules do
pipeline_schedule
.
pipelines
<<
build
(
:ci_pipeline
,
project:
project
)
pipeline_schedule
.
pipelines
<<
build
(
:ci_pipeline
,
project:
project
)
end
end
context
'authenticated user with valid permissions'
do
matcher
:return_pipeline_schedule_sucessfully
do
it
'returns pipeline_schedule details'
do
match_unless_raises
do
|
reponse
|
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
developer
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
response
).
to
match_response_schema
(
'pipeline_schedule'
)
expect
(
response
).
to
match_response_schema
(
'pipeline_schedule'
)
end
end
end
it
'responds with 404 Not Found if requesting non-existing pipeline_schedule'
do
shared_context
'request with project permissions'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/-5"
,
developer
)
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
end
end
context
'authenticated user with invalid permissions'
do
shared_examples
'request with schedule ownership'
do
it
'does not return pipeline_schedules list'
do
context
'authenticated user with pipeline schedule ownership'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
user
)
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
end
end
context
'authenticated user with insufficient permissions'
do
shared_examples
'request with unauthenticated user'
do
before
do
context
'with unauthenticated user'
do
project
.
add_guest
(
user
)
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
end
it
'does not return pipeline_schedules list'
do
shared_examples
'request with non-existing pipeline_schedule'
do
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
,
user
)
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
)
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
end
end
context
'unauthenticated user'
do
context
'with private project'
do
it
'does not return pipeline_schedules list'
do
it_behaves_like
'request with schedule ownership'
get
api
(
"/projects/
#{
project
.
id
}
/pipeline_schedules/
#{
pipeline_schedule
.
id
}
"
)
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
end
end
end
...
...
spec/requests/api/internal/kubernetes_spec.rb
View file @
2cfd792a
...
@@ -166,6 +166,16 @@ RSpec.describe API::Internal::Kubernetes do
...
@@ -166,6 +166,16 @@ RSpec.describe API::Internal::Kubernetes do
)
)
)
)
end
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
end
context
'project is private'
do
context
'project is private'
do
...
@@ -190,7 +200,7 @@ RSpec.describe API::Internal::Kubernetes do
...
@@ -190,7 +200,7 @@ RSpec.describe API::Internal::Kubernetes do
context
'project does not exist'
do
context
'project does not exist'
do
it
'returns 404'
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
)
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
...
...
spec/requests/api/terraform/state_spec.rb
View file @
2cfd792a
...
@@ -125,6 +125,7 @@ RSpec.describe API::Terraform::State do
...
@@ -125,6 +125,7 @@ RSpec.describe API::Terraform::State do
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
0
)
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
0
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
end
context
'on Unicorn'
,
:unicorn
do
context
'on Unicorn'
,
:unicorn
do
...
@@ -132,6 +133,7 @@ RSpec.describe API::Terraform::State do
...
@@ -132,6 +133,7 @@ RSpec.describe API::Terraform::State do
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
0
)
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
0
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
end
end
end
end
end
...
@@ -167,6 +169,7 @@ RSpec.describe API::Terraform::State do
...
@@ -167,6 +169,7 @@ RSpec.describe API::Terraform::State do
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
1
)
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
1
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
end
context
'on Unicorn'
,
:unicorn
do
context
'on Unicorn'
,
:unicorn
do
...
@@ -174,6 +177,7 @@ RSpec.describe API::Terraform::State do
...
@@ -174,6 +177,7 @@ RSpec.describe API::Terraform::State do
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
1
)
expect
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
1
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
end
end
end
end
end
...
@@ -218,10 +222,11 @@ RSpec.describe API::Terraform::State do
...
@@ -218,10 +222,11 @@ RSpec.describe API::Terraform::State do
context
'with maintainer permissions'
do
context
'with maintainer permissions'
do
let
(
:current_user
)
{
maintainer
}
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
{
request
}.
to
change
{
Terraform
::
State
.
count
}.
by
(
-
1
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
Gitlab
::
Json
.
parse
(
response
.
body
)).
to
be_empty
end
end
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_
...
@@ -198,24 +198,26 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
MetadataExtractionService
::
ExtractionError
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
MetadataExtractionService
::
ExtractionError
end
end
context
'with package file with a blank package name'
do
context
'with an invalid package name'
do
before
do
invalid_names
=
[
allow
(
service
).
to
receive
(
:package_name
).
and_return
(
''
)
''
,
end
'My/package'
,
'../../../my_package'
,
'%2e%2e%2fmy_package'
]
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
invalid_names
.
each
do
|
invalid_name
|
end
before
do
allow
(
service
).
to
receive
(
:package_name
).
and_return
(
invalid_name
)
end
context
'with package file with a blank package version'
do
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
before
do
allow
(
service
).
to
receive
(
:package_version
).
and_return
(
''
)
end
end
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
end
end
context
'with an invalid package version'
do
context
'with an invalid package version'
do
invalid_versions
=
[
invalid_versions
=
[
''
,
'555'
,
'555'
,
'1.2'
,
'1.2'
,
'1./2.3'
,
'1./2.3'
,
...
@@ -224,13 +226,11 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
...
@@ -224,13 +226,11 @@ RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_
]
]
invalid_versions
.
each
do
|
invalid_version
|
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
)
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
end
it_behaves_like
'raising an'
,
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
end
end
end
end
end
end
...
...
spec/services/terraform/remote_state_handler_spec.rb
View file @
2cfd792a
...
@@ -42,17 +42,17 @@ RSpec.describe Terraform::RemoteStateHandler do
...
@@ -42,17 +42,17 @@ RSpec.describe Terraform::RemoteStateHandler do
describe
'#handle_with_lock'
do
describe
'#handle_with_lock'
do
it
'allows to modify a state using database locking'
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'
state
.
name
=
'updated-name'
end
end
expect
(
state
.
name
).
to
eq
'updated-name'
expect
(
record
.
reload
.
name
).
to
eq
'updated-name'
end
end
it
'returns the state object itself'
do
it
'returns nil'
do
state
=
subject
.
handle_with_lock
expect
(
subject
.
handle_with_lock
).
to
be_nil
expect
(
state
.
name
).
to
eq
'my-state'
end
end
end
end
...
@@ -70,11 +70,13 @@ RSpec.describe Terraform::RemoteStateHandler do
...
@@ -70,11 +70,13 @@ RSpec.describe Terraform::RemoteStateHandler do
it
'handles a locked state using exclusive read lock'
do
it
'handles a locked state using exclusive read lock'
do
handler
.
lock!
handler
.
lock!
state
=
handler
.
handle_with_lock
do
|
state
|
record
=
nil
handler
.
handle_with_lock
do
|
state
|
record
=
state
state
.
name
=
'new-name'
state
.
name
=
'new-name'
end
end
expect
(
state
.
name
).
to
eq
'new-name'
expect
(
record
.
reload
.
name
).
to
eq
'new-name'
end
end
it
'raises exception if lock has not been acquired before'
do
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
...
@@ -14,6 +14,7 @@ end
RSpec
.
shared_examples
"builds correct paths"
do
|**
patterns
|
RSpec
.
shared_examples
"builds correct paths"
do
|**
patterns
|
let
(
:patterns
)
{
patterns
}
let
(
:patterns
)
{
patterns
}
let
(
:fixture
)
{
File
.
join
(
'spec'
,
'fixtures'
,
'rails_sample.jpg'
)
}
before
do
before
do
allow
(
subject
).
to
receive
(
:filename
).
and_return
(
'<filename>'
)
allow
(
subject
).
to
receive
(
:filename
).
and_return
(
'<filename>'
)
...
@@ -55,4 +56,15 @@ RSpec.shared_examples "builds correct paths" do |**patterns|
...
@@ -55,4 +56,15 @@ RSpec.shared_examples "builds correct paths" do |**patterns|
let
(
:target
)
{
subject
.
class
}
let
(
:target
)
{
subject
.
class
}
end
end
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
end
spec/uploaders/import_export_uploader_spec.rb
View file @
2cfd792a
...
@@ -24,9 +24,14 @@ RSpec.describe ImportExportUploader do
...
@@ -24,9 +24,14 @@ RSpec.describe ImportExportUploader do
include_context
'with storage'
,
described_class
::
Store
::
REMOTE
include_context
'with storage'
,
described_class
::
Store
::
REMOTE
it_behaves_like
'builds correct paths'
,
patterns
=
{
store_dir:
%r[import_export_upload/import_file/]
,
store_dir:
%r[import_export_upload/import_file/]
,
upload_path:
%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
describe
'#move_to_store'
do
it
'returns false'
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
...
@@ -13,6 +13,18 @@ RSpec.describe Packages::Nuget::ExtractionWorker, type: :worker do
subject
{
described_class
.
new
.
perform
(
package_file_id
)
}
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
context
'with valid package file'
do
it
'updates package and package file'
do
it
'updates package and package file'
do
expect
{
subject
}
expect
{
subject
}
...
@@ -48,46 +60,46 @@ RSpec.describe Packages::Nuget::ExtractionWorker, type: :worker do
...
@@ -48,46 +60,46 @@ RSpec.describe Packages::Nuget::ExtractionWorker, type: :worker do
allow_any_instance_of
(
Zip
::
File
).
to
receive
(
:glob
).
and_return
([])
allow_any_instance_of
(
Zip
::
File
).
to
receive
(
:glob
).
and_return
([])
end
end
it
'removes the package and the package file'
do
it_behaves_like
'handling the metadata error'
,
exception_class:
::
Packages
::
Nuget
::
MetadataExtractionService
::
ExtractionError
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
end
end
context
'with package file with a blank package name'
do
context
'with package with an invalid package name'
do
before
do
invalid_names
=
[
allow_any_instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
).
to
receive
(
:package_name
).
and_return
(
''
)
''
,
end
'My/package'
,
'../../../my_package'
,
'%2e%2e%2fmy_package'
]
i
t
'removes the package and the package file'
do
i
nvalid_names
.
each
do
|
invalid_name
|
expect
(
Gitlab
::
ErrorTracking
).
to
receive
(
:log_exception
).
with
(
before
do
instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
),
allow_next_instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
)
do
|
service
|
project_id:
package
.
project_id
allow
(
service
).
to
receive
(
:package_name
).
and_return
(
invalid_name
)
)
end
e
xpect
{
subject
}
e
nd
.
to
change
{
Packages
::
Package
.
count
}.
by
(
-
1
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
-
1
)
it_behaves_like
'handling the metadata error'
end
end
end
end
context
'with package file with a blank package version'
do
context
'with package with an invalid package version'
do
before
do
invalid_versions
=
[
allow_any_instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
).
to
receive
(
:package_version
).
and_return
(
''
)
''
,
end
'555'
,
'1.2'
,
'1./2.3'
,
'../../../../../1.2.3'
,
'%2e%2e%2f1.2.3'
]
i
t
'removes the package and the package file'
do
i
nvalid_versions
.
each
do
|
invalid_version
|
expect
(
Gitlab
::
ErrorTracking
).
to
receive
(
:log_exception
).
with
(
before
do
instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
::
InvalidMetadataError
),
allow_next_instance_of
(
::
Packages
::
Nuget
::
UpdatePackageFromMetadataService
)
do
|
service
|
project_id:
package
.
project_id
allow
(
service
).
to
receive
(
:package_version
).
and_return
(
invalid_version
)
)
end
e
xpect
{
subject
}
e
nd
.
to
change
{
Packages
::
Package
.
count
}.
by
(
-
1
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
-
1
)
it_behaves_like
'handling the metadata error'
end
end
end
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