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
4305f93e
Commit
4305f93e
authored
Feb 01, 2022
by
Bala Kumar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Permalink to the latest release
Changelog: added
parent
b1088a03
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
219 additions
and
2 deletions
+219
-2
app/controllers/projects/releases_controller.rb
app/controllers/projects/releases_controller.rb
+31
-2
config/routes/project.rb
config/routes/project.rb
+2
-0
spec/controllers/projects/releases_controller_spec.rb
spec/controllers/projects/releases_controller_spec.rb
+160
-0
spec/routing/project_routing_spec.rb
spec/routing/project_routing_spec.rb
+26
-0
No files found.
app/controllers/projects/releases_controller.rb
View file @
4305f93e
...
...
@@ -7,6 +7,7 @@ class Projects::ReleasesController < Projects::ApplicationController
before_action
:authorize_read_release!
before_action
:authorize_update_release!
,
only:
%i[edit update]
before_action
:authorize_create_release!
,
only: :new
before_action
:validate_suffix_path
,
:fetch_latest_tag
,
only: :latest_permalink
before_action
only: :index
do
push_frontend_feature_flag
(
:releases_index_apollo_client
,
project
,
default_enabled: :yaml
)
end
...
...
@@ -26,10 +27,24 @@ class Projects::ReleasesController < Projects::ApplicationController
redirect_to
link
.
url
end
def
latest_permalink
unless
@latest_tag
.
present?
return
render_404
end
query_parameters_except_order_by
=
request
.
query_parameters
.
except
(
:order_by
)
redirect_url
=
project_release_url
(
@project
,
@latest_tag
)
redirect_url
+=
"/
#{
params
[
:suffix_path
]
}
"
if
params
[
:suffix_path
]
redirect_url
+=
"?
#{
query_parameters_except_order_by
.
compact
.
to_param
}
"
if
query_parameters_except_order_by
.
present?
redirect_to
redirect_url
end
private
def
releases
ReleasesFinder
.
new
(
@project
,
current_user
).
execute
def
releases
(
params
=
{})
ReleasesFinder
.
new
(
@project
,
current_user
,
params
).
execute
end
def
authorize_update_release!
...
...
@@ -51,4 +66,18 @@ class Projects::ReleasesController < Projects::ApplicationController
def
sanitized_tag_name
CGI
.
unescape
(
params
[
:tag
])
end
# Default order_by is 'released_at', which is set in ReleasesFinder.
# Also if the passed order_by is invalid, we reject and default to 'released_at'.
def
fetch_latest_tag
allowed_values
=
[
'released_at'
]
params
.
reject!
{
|
key
,
value
|
key
.
to_sym
==
:order_by
&&
allowed_values
.
any?
(
value
)
}
@latest_tag
=
releases
(
order_by:
params
[
:order_by
]).
first
&
.
tag
end
def
validate_suffix_path
Gitlab
::
Utils
.
check_path_traversal!
(
params
[
:suffix_path
])
if
params
[
:suffix_path
]
end
end
config/routes/project.rb
View file @
4305f93e
...
...
@@ -241,6 +241,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
get
'releases/permalink/latest(/)(*suffix_path)'
,
to:
'releases#latest_permalink'
,
as: :latest_release_permalink
,
format:
false
resources
:logs
,
only:
[
:index
]
do
collection
do
get
:k8s
...
...
spec/controllers/projects/releases_controller_spec.rb
View file @
4305f93e
...
...
@@ -222,6 +222,166 @@ RSpec.describe Projects::ReleasesController do
end
end
describe
'GET #latest_permalink'
do
# Uses default order_by=released_at parameter.
subject
do
get
:latest_permalink
,
params:
{
namespace_id:
project
.
namespace
,
project_id:
project
}
end
before
do
sign_in
(
user
)
end
let
(
:release
)
{
create
(
:release
,
project:
project
)
}
let
(
:tag
)
{
CGI
.
escape
(
release
.
tag
)
}
context
'when user is a guest'
do
let
(
:project
)
{
private_project
}
let
(
:user
)
{
guest
}
it
'proceeds with the redirect'
do
subject
expect
(
response
).
to
have_gitlab_http_status
(
:redirect
)
end
end
context
'when user is an external user for the project'
do
let
(
:project
)
{
private_project
}
let
(
:user
)
{
create
(
:user
)
}
it
'behaves like not found'
do
subject
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
context
'when there are no releases for the project'
do
let
(
:project
)
{
create
(
:project
,
:repository
,
:public
)
}
let
(
:user
)
{
developer
}
before
do
project
.
releases
.
destroy_all
# rubocop: disable Cop/DestroyAll
end
it
'behaves like not found'
do
subject
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
end
context
'multiple releases'
do
let
(
:user
)
{
developer
}
it
'redirects to the latest release'
do
create
(
:release
,
project:
project
,
released_at:
1
.
day
.
ago
)
latest_release
=
create
(
:release
,
project:
project
,
released_at:
Time
.
current
)
subject
expect
(
response
).
to
redirect_to
(
"
#{
project_releases_path
(
project
)
}
/
#{
latest_release
.
tag
}
"
)
end
end
context
'suffix path redirection'
do
let
(
:user
)
{
developer
}
let
(
:suffix_path
)
{
'downloads/zips/helm-hello-world.zip'
}
let!
(
:latest_release
)
{
create
(
:release
,
project:
project
,
released_at:
Time
.
current
)
}
subject
do
get
:latest_permalink
,
params:
{
namespace_id:
project
.
namespace
,
project_id:
project
,
suffix_path:
suffix_path
}
end
it
'redirects to the latest release with suffix path and format'
do
subject
expect
(
response
).
to
redirect_to
(
"
#{
project_releases_path
(
project
)
}
/
#{
latest_release
.
tag
}
/
#{
suffix_path
}
"
)
end
context
'suffix path abuse'
do
let
(
:suffix_path
)
{
'downloads/zips/../../../../../../../robots.txt'
}
it
'raises attack error'
do
expect
do
subject
end
.
to
raise_error
(
Gitlab
::
Utils
::
PathTraversalAttackError
)
end
end
context
'url parameters'
do
let
(
:suffix_path
)
{
'downloads/zips/helm-hello-world.zip'
}
subject
do
get
:latest_permalink
,
params:
{
namespace_id:
project
.
namespace
,
project_id:
project
,
suffix_path:
suffix_path
,
order_by:
'released_at'
,
param_1:
1
,
param_2:
2
}
end
it
'carries over query parameters without order_by parameter in the redirect'
do
subject
expect
(
response
).
to
redirect_to
(
"
#{
project_releases_path
(
project
)
}
/
#{
latest_release
.
tag
}
/
#{
suffix_path
}
?param_1=1¶m_2=2"
)
end
end
end
context
'order_by parameter'
do
let!
(
:latest_release
)
{
create
(
:release
,
project:
project
,
released_at:
Time
.
current
)
}
shared_examples_for
'redirects to latest release ordered by using released_at'
do
it
do
subject
expect
(
response
).
to
redirect_to
(
"
#{
project_releases_path
(
project
)
}
/
#{
latest_release
.
tag
}
"
)
end
end
before
do
create
(
:release
,
project:
project
,
released_at:
1
.
day
.
ago
)
create
(
:release
,
project:
project
,
released_at:
2
.
days
.
ago
)
end
context
'invalid parameter'
do
let
(
:user
)
{
developer
}
subject
do
get
:latest_permalink
,
params:
{
namespace_id:
project
.
namespace
,
project_id:
project
,
order_by:
'unsupported'
}
end
it_behaves_like
'redirects to latest release ordered by using released_at'
end
context
'valid parameter'
do
subject
do
get
:latest_permalink
,
params:
{
namespace_id:
project
.
namespace
,
project_id:
project
,
order_by:
'released_at'
}
end
it_behaves_like
'redirects to latest release ordered by using released_at'
end
end
end
# `GET #downloads` is addressed in spec/requests/projects/releases_controller_spec.rb
private
...
...
spec/routing/project_routing_spec.rb
View file @
4305f93e
...
...
@@ -680,6 +680,32 @@ RSpec.describe 'project routing' do
end
end
describe
Projects
::
ReleasesController
,
'routing'
do
it
'to #latest_permalink with a valid permalink path'
do
expect
(
get
(
'/gitlab/gitlabhq/-/releases/permalink/latest/downloads/release-binary.zip'
)).
to
route_to
(
'projects/releases#latest_permalink'
,
namespace_id:
'gitlab'
,
project_id:
'gitlabhq'
,
suffix_path:
'downloads/release-binary.zip'
)
expect
(
get
(
'/gitlab/gitlabhq/-/releases/permalink/latest'
)).
to
route_to
(
'projects/releases#latest_permalink'
,
namespace_id:
'gitlab'
,
project_id:
'gitlabhq'
)
end
it
'to #show for the release with tag named permalink'
do
expect
(
get
(
'/gitlab/gitlabhq/-/releases/permalink'
)).
to
route_to
(
'projects/releases#show'
,
namespace_id:
'gitlab'
,
project_id:
'gitlabhq'
,
tag:
'permalink'
)
end
end
describe
Projects
::
Registry
::
TagsController
,
'routing'
do
describe
'#destroy'
do
it
'correctly routes to a destroy action'
do
...
...
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