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
e1bc7c04
Commit
e1bc7c04
authored
Apr 29, 2019
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab-ce master
parents
156b7f3c
17e8e8d3
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
225 additions
and
183 deletions
+225
-183
app/views/notify/new_merge_request_email.html.haml
app/views/notify/new_merge_request_email.html.haml
+1
-1
changelogs/unreleased/secure-disallow-read-user-scope-to-read-project-events.yml
...ecure-disallow-read-user-scope-to-read-project-events.yml
+5
-0
lib/api/api.rb
lib/api/api.rb
+1
-0
lib/api/events.rb
lib/api/events.rb
+2
-47
lib/api/helpers/events_helpers.rb
lib/api/helpers/events_helpers.rb
+31
-0
lib/api/project_events.rb
lib/api/project_events.rb
+29
-0
spec/requests/api/events_spec.rb
spec/requests/api/events_spec.rb
+0
-135
spec/requests/api/project_events_spec.rb
spec/requests/api/project_events_spec.rb
+156
-0
No files found.
app/views/notify/new_merge_request_email.html.haml
View file @
e1bc7c04
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
#{
link_to
@merge_request
.
author_name
,
user_url
(
@merge_request
.
author
)
}
created a merge request:
#{
link_to
@merge_request
.
author_name
,
user_url
(
@merge_request
.
author
)
}
created a merge request:
%p
.details
%p
.details
!=
merge_path_description
(
@merge_request
,
'→
'
)
=
merge_path_description
(
@merge_request
,
'→
'
)
-
if
@merge_request
.
assignees
.
any?
-
if
@merge_request
.
assignees
.
any?
%p
%p
...
...
changelogs/unreleased/secure-disallow-read-user-scope-to-read-project-events.yml
0 → 100644
View file @
e1bc7c04
---
title
:
Allow to see project events only with api scope token
merge_request
:
author
:
type
:
security
lib/api/api.rb
View file @
e1bc7c04
...
@@ -134,6 +134,7 @@ module API
...
@@ -134,6 +134,7 @@ module API
mount
::
API
::
Pipelines
mount
::
API
::
Pipelines
mount
::
API
::
PipelineSchedules
mount
::
API
::
PipelineSchedules
mount
::
API
::
ProjectClusters
mount
::
API
::
ProjectClusters
mount
::
API
::
ProjectEvents
mount
::
API
::
ProjectExport
mount
::
API
::
ProjectExport
mount
::
API
::
ProjectImport
mount
::
API
::
ProjectImport
mount
::
API
::
ProjectHooks
mount
::
API
::
ProjectHooks
...
...
lib/api/events.rb
View file @
e1bc7c04
...
@@ -4,34 +4,11 @@ module API
...
@@ -4,34 +4,11 @@ module API
class
Events
<
Grape
::
API
class
Events
<
Grape
::
API
include
PaginationParams
include
PaginationParams
include
APIGuard
include
APIGuard
helpers
::
API
::
Helpers
::
EventsHelpers
helpers
do
allow_access_with_scope
:read_user
,
if:
->
(
request
)
{
request
.
get?
}
params
:event_filter_params
do
optional
:action
,
type:
String
,
values:
Event
.
actions
,
desc:
'Event action to filter on'
optional
:target_type
,
type:
String
,
values:
Event
.
target_types
,
desc:
'Event target type to filter on'
optional
:before
,
type:
Date
,
desc:
'Include only events created before this date'
optional
:after
,
type:
Date
,
desc:
'Include only events created after this date'
end
params
:sort_params
do
optional
:sort
,
type:
String
,
values:
%w[asc desc]
,
default:
'desc'
,
desc:
'Return events sorted in ascending and descending order'
end
def
present_events
(
events
)
events
=
paginate
(
events
)
present
events
,
with:
Entities
::
Event
end
def
find_events
(
source
)
EventsFinder
.
new
(
params
.
merge
(
source:
source
,
current_user:
current_user
,
with_associations:
true
)).
execute
end
end
resource
:events
do
resource
:events
do
allow_access_with_scope
:read_user
,
if:
->
(
request
)
{
request
.
get?
}
desc
"List currently authenticated user's events"
do
desc
"List currently authenticated user's events"
do
detail
'This feature was introduced in GitLab 9.3.'
detail
'This feature was introduced in GitLab 9.3.'
success
Entities
::
Event
success
Entities
::
Event
...
@@ -55,8 +32,6 @@ module API
...
@@ -55,8 +32,6 @@ module API
requires
:id
,
type:
String
,
desc:
'The ID or Username of the user'
requires
:id
,
type:
String
,
desc:
'The ID or Username of the user'
end
end
resource
:users
do
resource
:users
do
allow_access_with_scope
:read_user
,
if:
->
(
request
)
{
request
.
get?
}
desc
'Get the contribution events of a specified user'
do
desc
'Get the contribution events of a specified user'
do
detail
'This feature was introduced in GitLab 8.13.'
detail
'This feature was introduced in GitLab 8.13.'
success
Entities
::
Event
success
Entities
::
Event
...
@@ -76,25 +51,5 @@ module API
...
@@ -76,25 +51,5 @@ module API
present_events
(
events
)
present_events
(
events
)
end
end
end
end
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a project'
end
resource
:projects
,
requirements:
API
::
NAMESPACE_OR_PROJECT_REQUIREMENTS
do
desc
"List a Project's visible events"
do
success
Entities
::
Event
end
params
do
use
:pagination
use
:event_filter_params
use
:sort_params
end
get
":id/events"
do
events
=
find_events
(
user_project
)
present_events
(
events
)
end
end
end
end
end
end
lib/api/helpers/events_helpers.rb
0 → 100644
View file @
e1bc7c04
# frozen_string_literal: true
module
API
module
Helpers
module
EventsHelpers
extend
Grape
::
API
::
Helpers
params
:event_filter_params
do
optional
:action
,
type:
String
,
values:
Event
.
actions
,
desc:
'Event action to filter on'
optional
:target_type
,
type:
String
,
values:
Event
.
target_types
,
desc:
'Event target type to filter on'
optional
:before
,
type:
Date
,
desc:
'Include only events created before this date'
optional
:after
,
type:
Date
,
desc:
'Include only events created after this date'
end
params
:sort_params
do
optional
:sort
,
type:
String
,
values:
%w[asc desc]
,
default:
'desc'
,
desc:
'Return events sorted in ascending and descending order'
end
def
present_events
(
events
)
events
=
paginate
(
events
)
present
events
,
with:
Entities
::
Event
end
def
find_events
(
source
)
EventsFinder
.
new
(
params
.
merge
(
source:
source
,
current_user:
current_user
,
with_associations:
true
)).
execute
end
end
end
end
lib/api/project_events.rb
0 → 100644
View file @
e1bc7c04
# frozen_string_literal: true
module
API
class
ProjectEvents
<
Grape
::
API
include
PaginationParams
include
APIGuard
helpers
::
API
::
Helpers
::
EventsHelpers
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a project'
end
resource
:projects
,
requirements:
API
::
NAMESPACE_OR_PROJECT_REQUIREMENTS
do
desc
"List a Project's visible events"
do
success
Entities
::
Event
end
params
do
use
:pagination
use
:event_filter_params
use
:sort_params
end
get
":id/events"
do
events
=
find_events
(
user_project
)
present_events
(
events
)
end
end
end
end
spec/requests/api/events_spec.rb
View file @
e1bc7c04
...
@@ -164,139 +164,4 @@ describe API::Events do
...
@@ -164,139 +164,4 @@ describe API::Events do
expect
(
json_response
[
'message'
]).
to
eq
(
'404 User Not Found'
)
expect
(
json_response
[
'message'
]).
to
eq
(
'404 User Not Found'
)
end
end
end
end
describe
'GET /projects/:id/events'
do
context
'when unauthenticated '
do
it
'returns 404 for private project'
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events"
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
it
'returns 200 status for a public project'
do
public_project
=
create
(
:project
,
:public
)
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
end
end
context
'with inaccessible events'
do
let
(
:public_project
)
{
create
(
:project
,
:public
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let
(
:confidential_issue
)
{
create
(
:closed_issue
,
confidential:
true
,
project:
public_project
,
author:
user
)
}
let!
(
:confidential_event
)
{
create
(
:event
,
project:
public_project
,
author:
user
,
target:
confidential_issue
,
action:
Event
::
CLOSED
)
}
let
(
:public_issue
)
{
create
(
:closed_issue
,
project:
public_project
,
author:
user
)
}
let!
(
:public_event
)
{
create
(
:event
,
project:
public_project
,
author:
user
,
target:
public_issue
,
action:
Event
::
CLOSED
)
}
it
'returns only accessible events'
do
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
,
non_member
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
json_response
.
size
).
to
eq
(
1
)
end
it
'returns all events when the user has access'
do
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
json_response
.
size
).
to
eq
(
2
)
end
end
context
'pagination'
do
let
(
:public_project
)
{
create
(
:project
,
:public
)
}
before
do
create
(
:event
,
project:
public_project
,
target:
create
(
:issue
,
project:
public_project
,
title:
'Issue 1'
),
action:
Event
::
CLOSED
,
created_at:
Date
.
parse
(
'2018-12-10'
))
create
(
:event
,
project:
public_project
,
target:
create
(
:issue
,
confidential:
true
,
project:
public_project
,
title:
'Confidential event'
),
action:
Event
::
CLOSED
,
created_at:
Date
.
parse
(
'2018-12-11'
))
create
(
:event
,
project:
public_project
,
target:
create
(
:issue
,
project:
public_project
,
title:
'Issue 2'
),
action:
Event
::
CLOSED
,
created_at:
Date
.
parse
(
'2018-12-12'
))
end
it
'correctly returns the second page without inaccessible events'
do
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
,
user
),
params:
{
per_page:
2
,
page:
2
}
titles
=
json_response
.
map
{
|
event
|
event
[
'target_title'
]
}
expect
(
titles
.
first
).
to
eq
(
'Issue 1'
)
expect
(
titles
).
not_to
include
(
'Confidential event'
)
end
it
'correctly returns the first page without inaccessible events'
do
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
,
user
),
params:
{
per_page:
2
,
page:
1
}
titles
=
json_response
.
map
{
|
event
|
event
[
'target_title'
]
}
expect
(
titles
.
first
).
to
eq
(
'Issue 2'
)
expect
(
titles
).
not_to
include
(
'Confidential event'
)
end
end
context
'when not permitted to read'
do
it
'returns 404'
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events"
,
non_member
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
end
context
'when authenticated'
do
it
'returns project events'
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events?action=closed&target_type=issue&after=2016-12-1&before=2016-12-31"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
).
to
include_pagination_headers
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
size
).
to
eq
(
1
)
end
it
'returns 404 if project does not exist'
do
get
api
(
"/projects/1234/events"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
end
context
'when exists some events'
do
let
(
:merge_request1
)
{
create
(
:merge_request
,
:closed
,
author:
user
,
assignees:
[
user
],
source_project:
private_project
,
title:
'Test'
)
}
let
(
:merge_request2
)
{
create
(
:merge_request
,
:closed
,
author:
user
,
assignees:
[
user
],
source_project:
private_project
,
title:
'Test'
)
}
before
do
create_event
(
merge_request1
)
end
it
'avoids N+1 queries'
do
control_count
=
ActiveRecord
::
QueryRecorder
.
new
(
skip_cached:
false
)
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events"
,
user
),
params:
{
target_type: :merge_request
}
end
.
count
create_event
(
merge_request2
)
expect
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events"
,
user
),
params:
{
target_type: :merge_request
}
end
.
not_to
exceed_all_query_limit
(
control_count
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
).
to
include_pagination_headers
expect
(
json_response
.
size
).
to
eq
(
2
)
expect
(
json_response
.
map
{
|
r
|
r
[
'target_id'
]
}).
to
match_array
([
merge_request1
.
id
,
merge_request2
.
id
])
end
def
create_event
(
target
)
create
(
:event
,
project:
private_project
,
author:
user
,
target:
target
)
end
end
end
end
end
spec/requests/api/project_events_spec.rb
0 → 100644
View file @
e1bc7c04
require
'spec_helper'
describe
API
::
ProjectEvents
do
include
ApiHelpers
let
(
:user
)
{
create
(
:user
)
}
let
(
:non_member
)
{
create
(
:user
)
}
let
(
:private_project
)
{
create
(
:project
,
:private
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let
(
:closed_issue
)
{
create
(
:closed_issue
,
project:
private_project
,
author:
user
)
}
let!
(
:closed_issue_event
)
{
create
(
:event
,
project:
private_project
,
author:
user
,
target:
closed_issue
,
action:
Event
::
CLOSED
,
created_at:
Date
.
new
(
2016
,
12
,
30
))
}
describe
'GET /projects/:id/events'
do
context
'when unauthenticated '
do
it
'returns 404 for private project'
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events"
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
it
'returns 200 status for a public project'
do
public_project
=
create
(
:project
,
:public
)
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
end
end
context
'with inaccessible events'
do
let
(
:public_project
)
{
create
(
:project
,
:public
,
creator_id:
user
.
id
,
namespace:
user
.
namespace
)
}
let
(
:confidential_issue
)
{
create
(
:closed_issue
,
confidential:
true
,
project:
public_project
,
author:
user
)
}
let!
(
:confidential_event
)
{
create
(
:event
,
project:
public_project
,
author:
user
,
target:
confidential_issue
,
action:
Event
::
CLOSED
)
}
let
(
:public_issue
)
{
create
(
:closed_issue
,
project:
public_project
,
author:
user
)
}
let!
(
:public_event
)
{
create
(
:event
,
project:
public_project
,
author:
user
,
target:
public_issue
,
action:
Event
::
CLOSED
)
}
it
'returns only accessible events'
do
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
,
non_member
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
json_response
.
size
).
to
eq
(
1
)
end
it
'returns all events when the user has access'
do
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
json_response
.
size
).
to
eq
(
2
)
end
end
context
'pagination'
do
let
(
:public_project
)
{
create
(
:project
,
:public
)
}
before
do
create
(
:event
,
project:
public_project
,
target:
create
(
:issue
,
project:
public_project
,
title:
'Issue 1'
),
action:
Event
::
CLOSED
,
created_at:
Date
.
parse
(
'2018-12-10'
))
create
(
:event
,
project:
public_project
,
target:
create
(
:issue
,
confidential:
true
,
project:
public_project
,
title:
'Confidential event'
),
action:
Event
::
CLOSED
,
created_at:
Date
.
parse
(
'2018-12-11'
))
create
(
:event
,
project:
public_project
,
target:
create
(
:issue
,
project:
public_project
,
title:
'Issue 2'
),
action:
Event
::
CLOSED
,
created_at:
Date
.
parse
(
'2018-12-12'
))
end
it
'correctly returns the second page without inaccessible events'
do
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
,
user
),
params:
{
per_page:
2
,
page:
2
}
titles
=
json_response
.
map
{
|
event
|
event
[
'target_title'
]
}
expect
(
titles
.
first
).
to
eq
(
'Issue 1'
)
expect
(
titles
).
not_to
include
(
'Confidential event'
)
end
it
'correctly returns the first page without inaccessible events'
do
get
api
(
"/projects/
#{
public_project
.
id
}
/events"
,
user
),
params:
{
per_page:
2
,
page:
1
}
titles
=
json_response
.
map
{
|
event
|
event
[
'target_title'
]
}
expect
(
titles
.
first
).
to
eq
(
'Issue 2'
)
expect
(
titles
).
not_to
include
(
'Confidential event'
)
end
end
context
'when not permitted to read'
do
it
'returns 404'
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events"
,
non_member
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
end
context
'when authenticated'
do
it
'returns project events'
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events?action=closed&target_type=issue&after=2016-12-1&before=2016-12-31"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
).
to
include_pagination_headers
expect
(
json_response
).
to
be_an
Array
expect
(
json_response
.
size
).
to
eq
(
1
)
end
it
'returns 404 if project does not exist'
do
get
api
(
"/projects/1234/events"
,
user
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
context
'when the requesting token does not have "api" scope'
do
let
(
:token
)
{
create
(
:personal_access_token
,
scopes:
[
'read_user'
],
user:
user
)
}
it
'returns a "403" response'
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events"
,
personal_access_token:
token
)
expect
(
response
).
to
have_gitlab_http_status
(
403
)
end
end
end
context
'when exists some events'
do
let
(
:merge_request1
)
{
create
(
:merge_request
,
:closed
,
author:
user
,
assignees:
[
user
],
source_project:
private_project
,
title:
'Test'
)
}
let
(
:merge_request2
)
{
create
(
:merge_request
,
:closed
,
author:
user
,
assignees:
[
user
],
source_project:
private_project
,
title:
'Test'
)
}
before
do
create_event
(
merge_request1
)
end
it
'avoids N+1 queries'
do
control_count
=
ActiveRecord
::
QueryRecorder
.
new
(
skip_cached:
false
)
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events"
,
user
),
params:
{
target_type: :merge_request
}
end
.
count
create_event
(
merge_request2
)
expect
do
get
api
(
"/projects/
#{
private_project
.
id
}
/events"
,
user
),
params:
{
target_type: :merge_request
}
end
.
not_to
exceed_all_query_limit
(
control_count
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
).
to
include_pagination_headers
expect
(
json_response
.
size
).
to
eq
(
2
)
expect
(
json_response
.
map
{
|
r
|
r
[
'target_id'
]
}).
to
match_array
([
merge_request1
.
id
,
merge_request2
.
id
])
end
def
create_event
(
target
)
create
(
:event
,
project:
private_project
,
author:
user
,
target:
target
)
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