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
7d35fa3e
Commit
7d35fa3e
authored
Nov 15, 2021
by
Jiaan Louw
Committed by
Etienne Baqué
Nov 15, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Backend] Update audit events to allow filtering by username
parent
0e500835
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
147 additions
and
6 deletions
+147
-6
app/models/audit_event.rb
app/models/audit_event.rb
+6
-0
ee/app/controllers/admin/audit_logs_controller.rb
ee/app/controllers/admin/audit_logs_controller.rb
+9
-1
ee/app/controllers/concerns/audit_events/audit_logs_params.rb
...pp/controllers/concerns/audit_events/audit_logs_params.rb
+1
-1
ee/app/finders/audit_log_finder.rb
ee/app/finders/audit_log_finder.rb
+21
-3
ee/spec/controllers/admin/audit_logs_controller_spec.rb
ee/spec/controllers/admin/audit_logs_controller_spec.rb
+23
-0
ee/spec/finders/audit_log_finder_spec.rb
ee/spec/finders/audit_log_finder_spec.rb
+87
-1
No files found.
app/models/audit_event.rb
View file @
7d35fa3e
...
@@ -30,6 +30,8 @@ class AuditEvent < ApplicationRecord
...
@@ -30,6 +30,8 @@ class AuditEvent < ApplicationRecord
scope
:by_entity_type
,
->
(
entity_type
)
{
where
(
entity_type:
entity_type
)
}
scope
:by_entity_type
,
->
(
entity_type
)
{
where
(
entity_type:
entity_type
)
}
scope
:by_entity_id
,
->
(
entity_id
)
{
where
(
entity_id:
entity_id
)
}
scope
:by_entity_id
,
->
(
entity_id
)
{
where
(
entity_id:
entity_id
)
}
scope
:by_author_id
,
->
(
author_id
)
{
where
(
author_id:
author_id
)
}
scope
:by_author_id
,
->
(
author_id
)
{
where
(
author_id:
author_id
)
}
scope
:by_entity_username
,
->
(
username
)
{
where
(
entity_id:
find_user_id
(
username
))
}
scope
:by_author_username
,
->
(
username
)
{
where
(
author_id:
find_user_id
(
username
))
}
after_initialize
:initialize_details
after_initialize
:initialize_details
...
@@ -106,6 +108,10 @@ class AuditEvent < ApplicationRecord
...
@@ -106,6 +108,10 @@ class AuditEvent < ApplicationRecord
self
[
name
]
=
self
.
details
[
name
]
=
original
self
[
name
]
=
self
.
details
[
name
]
=
original
end
end
end
end
def
self
.
find_user_id
(
username
)
User
.
find_by_username
(
username
)
&
.
id
end
end
end
AuditEvent
.
prepend_mod_with
(
'AuditEvent'
)
AuditEvent
.
prepend_mod_with
(
'AuditEvent'
)
ee/app/controllers/admin/audit_logs_controller.rb
View file @
7d35fa3e
...
@@ -23,7 +23,7 @@ class Admin::AuditLogsController < Admin::ApplicationController
...
@@ -23,7 +23,7 @@ class Admin::AuditLogsController < Admin::ApplicationController
@entity
=
case
audit_logs_params
[
:entity_type
]
@entity
=
case
audit_logs_params
[
:entity_type
]
when
'User'
when
'User'
User
.
find_by_id
(
audit_logs_params
[
:entity_id
])
user_entity
when
'Project'
when
'Project'
Project
.
find_by_id
(
audit_logs_params
[
:entity_id
])
Project
.
find_by_id
(
audit_logs_params
[
:entity_id
])
when
'Group'
when
'Group'
...
@@ -54,4 +54,12 @@ class Admin::AuditLogsController < Admin::ApplicationController
...
@@ -54,4 +54,12 @@ class Admin::AuditLogsController < Admin::ApplicationController
def
check_license_admin_audit_log_available!
def
check_license_admin_audit_log_available!
render_404
unless
License
.
feature_available?
(
:admin_audit_log
)
render_404
unless
License
.
feature_available?
(
:admin_audit_log
)
end
end
def
user_entity
if
audit_logs_params
[
:entity_username
].
present?
return
User
.
find_by_username
(
audit_logs_params
[
:entity_username
])
end
User
.
find_by_id
(
audit_logs_params
[
:entity_id
])
end
end
end
ee/app/controllers/concerns/audit_events/audit_logs_params.rb
View file @
7d35fa3e
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
module
AuditEvents
module
AuditEvents
module
AuditLogsParams
module
AuditLogsParams
def
audit_logs_params
def
audit_logs_params
params
.
permit
(
:entity_type
,
:entity_id
,
:created_before
,
:created_after
,
:sort
,
:author_id
)
params
.
permit
(
:entity_type
,
:entity_id
,
:created_before
,
:created_after
,
:sort
,
:author_id
,
:entity_username
,
:author_username
)
end
end
def
audit_params
def
audit_params
...
...
ee/app/finders/audit_log_finder.rb
View file @
7d35fa3e
...
@@ -55,7 +55,9 @@ class AuditLogFinder
...
@@ -55,7 +55,9 @@ class AuditLogFinder
audit_events
=
audit_events
.
by_entity_type
(
params
[
:entity_type
])
audit_events
=
audit_events
.
by_entity_type
(
params
[
:entity_type
])
if
valid_entity_id?
if
valid_entity_username?
audit_events
=
audit_events
.
by_entity_username
(
params
[
:entity_username
])
elsif
valid_entity_id?
audit_events
=
audit_events
.
by_entity_id
(
params
[
:entity_id
])
audit_events
=
audit_events
.
by_entity_id
(
params
[
:entity_id
])
end
end
...
@@ -63,9 +65,13 @@ class AuditLogFinder
...
@@ -63,9 +65,13 @@ class AuditLogFinder
end
end
def
by_author
(
audit_events
)
def
by_author
(
audit_events
)
return
audit_events
unless
valid_author_id?
if
valid_author_username?
audit_events
=
audit_events
.
by_author_username
(
params
[
:author_username
])
elsif
valid_author_id?
audit_events
=
audit_events
.
by_author_id
(
params
[
:author_id
])
end
audit_events
.
by_author_id
(
params
[
:author_id
])
audit_events
end
end
def
sort
(
audit_events
)
def
sort
(
audit_events
)
...
@@ -83,4 +89,16 @@ class AuditLogFinder
...
@@ -83,4 +89,16 @@ class AuditLogFinder
def
valid_author_id?
def
valid_author_id?
params
[
:author_id
].
to_i
.
nonzero?
params
[
:author_id
].
to_i
.
nonzero?
end
end
def
valid_username?
(
username
)
username
.
present?
&&
username
.
length
>=
User
::
MIN_USERNAME_LENGTH
&&
username
.
length
<=
User
::
MAX_USERNAME_LENGTH
end
def
valid_entity_username?
valid_username?
(
params
[
:entity_username
])
end
def
valid_author_username?
valid_username?
(
params
[
:author_username
])
end
end
end
ee/spec/controllers/admin/audit_logs_controller_spec.rb
View file @
7d35fa3e
...
@@ -43,5 +43,28 @@ RSpec.describe Admin::AuditLogsController do
...
@@ -43,5 +43,28 @@ RSpec.describe Admin::AuditLogsController do
)
)
end
end
end
end
context
'by user'
do
before
do
stub_licensed_features
(
admin_audit_log:
true
)
end
it
'finds the user by id when provided with a entity_id'
do
allow
(
User
).
to
receive
(
:find_by_id
).
and_return
(
admin
)
get
:index
,
params:
{
'entity_type'
:
'User'
,
'entity_id'
:
'1'
}
expect
(
User
).
to
have_received
(
:find_by_id
).
with
(
'1'
)
end
it
'finds the user by username when provided with a entity_username'
do
allow
(
User
).
to
receive
(
:find_by_username
).
and_return
(
admin
)
get
:index
,
params:
{
'entity_type'
:
'User'
,
'entity_username'
:
'abc'
}
# find_by_username gets called in thee controller and in the AuditEvent model
expect
(
User
).
to
have_received
(
:find_by_username
).
twice
.
with
(
'abc'
)
end
end
end
end
end
end
ee/spec/finders/audit_log_finder_spec.rb
View file @
7d35fa3e
...
@@ -9,7 +9,7 @@ RSpec.describe AuditLogFinder do
...
@@ -9,7 +9,7 @@ RSpec.describe AuditLogFinder do
let_it_be
(
:project
)
{
create
(
:project
,
namespace:
group
)
}
let_it_be
(
:project
)
{
create
(
:project
,
namespace:
group
)
}
let_it_be
(
:subproject
)
{
create
(
:project
,
namespace:
subgroup
)
}
let_it_be
(
:subproject
)
{
create
(
:project
,
namespace:
subgroup
)
}
let_it_be
(
:user_audit_event
)
{
create
(
:user_audit_event
,
created_at:
3
.
days
.
ago
)
}
let_it_be
(
:user_audit_event
)
{
create
(
:user_audit_event
,
created_at:
3
.
days
.
ago
,
entity_id:
user
.
id
)
}
let_it_be
(
:project_audit_event
)
{
create
(
:project_audit_event
,
entity_id:
project
.
id
,
author_id:
user
.
id
,
created_at:
2
.
days
.
ago
)
}
let_it_be
(
:project_audit_event
)
{
create
(
:project_audit_event
,
entity_id:
project
.
id
,
author_id:
user
.
id
,
created_at:
2
.
days
.
ago
)
}
let_it_be
(
:subproject_audit_event
)
{
create
(
:project_audit_event
,
entity_id:
subproject
.
id
,
created_at:
2
.
days
.
ago
)
}
let_it_be
(
:subproject_audit_event
)
{
create
(
:project_audit_event
,
entity_id:
subproject
.
id
,
created_at:
2
.
days
.
ago
)
}
let_it_be
(
:group_audit_event
)
{
create
(
:group_audit_event
,
entity_id:
group
.
id
,
author_id:
user
.
id
,
created_at:
1
.
day
.
ago
)
}
let_it_be
(
:group_audit_event
)
{
create
(
:group_audit_event
,
entity_id:
group
.
id
,
author_id:
user
.
id
,
created_at:
1
.
day
.
ago
)
}
...
@@ -259,6 +259,92 @@ RSpec.describe AuditLogFinder do
...
@@ -259,6 +259,92 @@ RSpec.describe AuditLogFinder do
end
end
end
end
end
end
context
'filtering by entity_username'
do
context
'User Event'
do
let
(
:params
)
{
{
entity_type:
'User'
,
entity_username:
user
.
username
}
}
let
(
:entity_type
)
{
'User'
}
let
(
:audit_event
)
{
user_audit_event
}
it
'finds the right event'
do
expect
(
subject
.
count
).
to
eq
(
1
)
entity
=
subject
.
first
expect
(
entity
.
entity_type
).
to
eq
(
entity_type
)
expect
(
entity
.
id
).
to
eq
(
audit_event
.
id
)
expect
(
entity
.
entity_id
).
to
eq
(
user
.
id
)
end
end
end
context
'filtering by author_username'
do
context
'username is too short'
do
let
(
:params
)
{
{
author_username:
'a'
*
(
User
::
MIN_USERNAME_LENGTH
-
1
)
}
}
it
'ignores author_username and returns all events irrespective of entity_type'
do
expect
(
subject
.
count
).
to
eq
(
4
)
end
end
context
'username is too long'
do
let
(
:params
)
{
{
author_username:
'a'
*
(
User
::
MAX_USERNAME_LENGTH
+
1
)
}
}
it
'ignores author_username and returns all events irrespective of entity_type'
do
expect
(
subject
.
count
).
to
eq
(
4
)
end
end
shared_examples
'finds the right event'
do
it
'finds the right event'
do
expect
(
subject
.
count
).
to
eq
(
1
)
entity
=
subject
.
first
expect
(
entity
.
entity_type
).
to
eq
(
entity_type
)
expect
(
entity
.
id
).
to
eq
(
audit_event
.
id
)
expect
(
entity
.
author_id
).
to
eq
(
audit_event
.
author_id
)
end
end
context
'Instance Event'
do
let
(
:level
)
{
Gitlab
::
Audit
::
Levels
::
Instance
.
new
}
let
(
:params
)
{
{
author_username:
user
.
username
}
}
it
'finds all the events the user authored'
,
:aggregate_failures
do
expect
(
subject
.
count
).
to
eq
(
2
)
subject
.
each
do
|
entity
|
expect
(
entity
.
author_id
).
to
eq
(
user
.
id
)
end
end
end
context
'Group Event'
do
let
(
:level
)
{
Gitlab
::
Audit
::
Levels
::
Group
.
new
(
group:
group
)
}
let
(
:params
)
{
{
author_username:
user
.
username
}
}
before
do
# Only looking for group event, with this on it tests Group and Project events
stub_feature_flags
(
audit_log_group_level:
false
)
end
it_behaves_like
'finds the right event'
do
let
(
:entity_type
)
{
'Group'
}
let
(
:audit_event
)
{
group_audit_event
}
end
end
context
'Project Event'
do
let
(
:level
)
{
Gitlab
::
Audit
::
Levels
::
Project
.
new
(
project:
project
)
}
let
(
:params
)
{
{
author_username:
user
.
username
}
}
it_behaves_like
'finds the right event'
do
let
(
:entity_type
)
{
'Project'
}
let
(
:audit_event
)
{
project_audit_event
}
end
end
end
end
end
describe
'#find_by!'
do
describe
'#find_by!'
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