-
-
Notifications
You must be signed in to change notification settings - Fork 934
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add security event log #4367
Add security event log #4367
Conversation
f2d0ea1
to
8005337
Compare
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #4367 +/- ##
==========================================
+ Coverage 96.99% 97.06% +0.06%
==========================================
Files 349 383 +34
Lines 7695 8166 +471
==========================================
+ Hits 7464 7926 +462
- Misses 231 240 +9 ☔ View full report in Codecov by Sentry. |
07a43a9
to
f76d884
Compare
f76d884
to
b005e88
Compare
|
||
include Events::Tags | ||
|
||
VERSION_PUSHED = define_event "rubygem:version:pushed" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review: rubygem event definitions
|
||
include Events::Tags | ||
|
||
LOGIN_SUCCESS = define_event "user:login:success" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review: user event definitions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial review. Will come back soon.
@@ -24,7 +24,7 @@ def create | |||
|
|||
render "multifactor_auths/prompt" | |||
else | |||
do_login | |||
do_login(two_factor_label: nil, two_factor_method: nil, authentication_method: "password") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could use a constant for the magic strings in here to keep it consistent. Minor nitpick.
3a35c17
to
3420808
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me at a high level, I'm sure we'll discover things that need adjusting in the future but I'm happy to start here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm most focused on the way this is modeled, serialized and deserialized. I think the underlying storage is ok. I'm just thinking about ways we might be able to make the model a little simpler. However, I think it's possible to refactor this later. The storage structure seems simple enough, so not a blocker.
This is quite a feature. I didn't get to look at it all but we can adjust these parts after this is merged.
app/models/events/tags.rb
Outdated
def additional_type | ||
tags.fetch(tag, nil) | ||
end | ||
|
||
def additional | ||
additional_type&.new(super) || super | ||
end | ||
|
||
def additional=(value) | ||
super(value&.to_h) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest adding these methods to the module rather than in included do
. I think it's better for the method lookup table, so they can be shared by the module instead of unique per singleton.
app/models/events/tags.rb
Outdated
end | ||
|
||
class_methods do | ||
def define_event(string, &blk) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe some of this method would be more local in Event::Tag, since it's almost all about that class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really seeing what else can be pushed there, since we're dealing with the tags
method and setting consts on self
app/models/events/tags.rb
Outdated
tag = Events::Tag.new(string).freeze | ||
raise ArgumentError, "Tag #{tag.inspect} already defined" if tags.key?(tag) | ||
event = Events::Tag.to_struct(&blk) | ||
tags[tag] = event |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we shift to using the string as key? It's is actually the key since that's how we store and retrieve it from the database. Then deserializing might just be "look it up in the hash table" instead of reconstructing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
except we use the methods on it elsewhere, and then we have to write a custom active record serializer to handle the lookup into the map
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I misunderstood, the methods we use are string manipulations of the key. The code would not change much if they were class methods. It would certainly save complexity and remove a lot of low level code.
I could be totally wrong, you spent more time in this code than me. Just noting complexity where I see it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still approve as is, but I do think this is worth changing if you're willing.
app/models/events/tag.rb
Outdated
values = value.split(":") | ||
|
||
source_type = values[0] | ||
subject_type = values[1...-1]&.join(":").presence || source_type | ||
action = values[-1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the critical code from Tag, the rest is added to load and dump this class. (beside to_struct which is a pure function)
Without this complexity you add a few methods like Event.subject_type(tag) and then the tag can just be a string.
I think this is worthwhile, but I'm open to other approaches or happy to just let this slide. We could make this change even after it merges because this serializes back to the original string.
app/models/events/tags.rb
Outdated
event = Events::Tag.to_struct(&blk) | ||
tags[tag] = event | ||
|
||
const_name = [tag.subject_type == tag.source_type ? nil : tag.subject_type, tag.action].compact.join("_").upcase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Places where we use tag.
methods just become class methods for processing the tag string. It's like a global ID.
3420808
to
9fd9c6c
Compare
9fd9c6c
to
2552351
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏
@@ -0,0 +1,21 @@ | |||
module Events::Tag | |||
module_function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh neat. So this just turns the following functions into singleton functions?
end | ||
|
||
class_methods do | ||
def define_event(tag, &blk) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all looks great. Thanks for hearing me out. You got it even simpler than I had imagined.
Targets #4406
Implements https://docs.google.com/document/d/1ApREh07FzNFOtJnEkdvI1owWIQ-K2lIRML1z1jvs7eE/edit
Closes #4360