-
Notifications
You must be signed in to change notification settings - Fork 882
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
Check SDK versions via version check call #2365
Conversation
5f4d0f3
to
9c761a0
Compare
service/frontend/workflowHandler.go
Outdated
@@ -247,7 +257,7 @@ func (wh *WorkflowHandler) RegisterNamespace(ctx context.Context, request *workf | |||
return nil, errShuttingDown | |||
} | |||
|
|||
if err := wh.versionChecker.ClientSupported(ctx, wh.config.EnableClientVersionCheck()); err != nil { | |||
if err := wh.RecordClientVersionAndCheckIfSupported(ctx); err != nil { |
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.
why not do this in interceptor?
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 was just following the pattern that we already had with the version checker, I'll look into moving it into an interceptor
service/frontend/versionChecker.go
Outdated
// Store if wasn't added racy | ||
valIface, _ = vc.sdkInfoCounter.LoadOrStore(info, &sdkCount{}) | ||
} | ||
atomic.AddInt64(&valIface.(*sdkCount).count, 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.
the counter will essentially be request count make by this type of sdk?
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 think we have decided not to collect any stats.
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.
yes, it is reset before we send the request
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 can change this to be a set instead of counting
8da885f
to
fde9b67
Compare
} | ||
|
||
func (vi *SDKVersionInterceptor) GetAndResetSDKInfo() []check.SDKInfo { | ||
sdkInfo := make([]check.SDKInfo, 0) |
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.
cap init to the same size as vi.sdkInfoCounter
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 was going to suggest this, but since it's not thread safe I figured meh.
Technically if you set the cap as 1000 and a then len changed in another thread making it 1001 before you ranged, once you attempted append
on the 1001st item, it'd create a new backing array of size 2002 ((cap + 1) * 2
). Granted that's not as likely in an expected-new-key-to-be-rare map like this.
But negligible either way I figured.
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 think it's negligible but don't mind adding it
de385c7
to
63eb27a
Compare
return &SDKVersionInterceptor{ | ||
sdkInfoSet: make(map[sdkNameVersion]bool), | ||
lock: sync.RWMutex{}, | ||
infoSetSizeCapGetter: infoSetSizeCapGetter, |
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.
What is the purpose of this getter? Can't you just have a fixed size? If the size doesn't change at runtime, then just accept a normal int 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 saw that I only had dynamic config available so that's what I used.
The getter here is to avoid using the frontend Config
struct directly because that causes an import cycle.
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.
Can you just pass in the result of the getter during construction instead of storing the getter?
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.
But then it wouldn't make sense to call this dynamic config
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.
Not sure such a config needs to be dynamic (such an "extreme max" value really is better as just a const IMO so as not to add noise to the pieces that actually deserve to be configurable). But 🤷 it matters little.
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'll address the comments soon
return &SDKVersionInterceptor{ | ||
sdkInfoSet: make(map[sdkNameVersion]bool), | ||
lock: sync.RWMutex{}, | ||
infoSetSizeCapGetter: infoSetSizeCapGetter, |
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 saw that I only had dynamic config available so that's what I used.
The getter here is to avoid using the frontend Config
struct directly because that causes an import cycle.
31c6e67
to
429cda1
Compare
} | ||
|
||
type SDKVersionInterceptor struct { | ||
sdkInfoSet map[sdkNameVersion]bool |
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.
nit, can use map[sdkNameVersion]struct{}
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.
Yup brought up at #2365 (comment) but figured it was inconsequential
429cda1
to
aea47c0
Compare
aea47c0
to
b01a99f
Compare
|
||
type SDKVersionInterceptor struct { | ||
sdkInfoSet map[sdkNameVersion]struct{} | ||
lock sync.RWMutex |
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.
lock
usually goes as embedded struct.
lock sync.RWMutex | |
sync.RWMutex |
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 nice, I can do that.
type sdkNameVersion struct { | ||
name string | ||
version string | ||
} | ||
|
||
type SDKVersionInterceptor struct { | ||
sdkInfoSet map[sdkNameVersion]struct{} | ||
lock sync.RWMutex | ||
maxSetSize int | ||
} |
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.
If there is more than one type
declaration they both should go inside single type
decalration:
type sdkNameVersion struct { | |
name string | |
version string | |
} | |
type SDKVersionInterceptor struct { | |
sdkInfoSet map[sdkNameVersion]struct{} | |
lock sync.RWMutex | |
maxSetSize int | |
} | |
type ( | |
sdkNameVersion struct { | |
name string | |
version string | |
} | |
SDKVersionInterceptor struct { | |
sdkInfoSet map[sdkNameVersion]struct{} | |
lock sync.RWMutex | |
maxSetSize int | |
} | |
) |
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.
Sure, can we get a lint rule that enforces this style?
|
||
// RecordSDKInfo records name and version tuple in memory | ||
func (vi *SDKVersionInterceptor) RecordSDKInfo(name, version string) { | ||
info := sdkNameVersion{name, version} |
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 would avoid nameless struct initialization. It is not possible to find references with 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.
I thought it'd be okay in this simple case, I don't mind fixing
vi.lock.RLock() | ||
overCap := len(vi.sdkInfoSet) >= vi.maxSetSize | ||
_, found := vi.sdkInfoSet[info] | ||
vi.lock.RUnlock() |
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.
Unlock
call usually is called with deffer
and it goes right after Lock
. I understand the here it would require 2 more funcs and probably doesn't worth it though.
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.
Yeah, it's not worth it here
|
||
sdkInfo := make([]check.SDKInfo, 0, len(currSet)) | ||
for k := range currSet { | ||
sdkInfo = append(sdkInfo, check.SDKInfo{Name: k.name, Version: k.version}) |
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.
k
is the struct
, right? You can use it directly, it will be copied by value:
sdkInfo = append(sdkInfo, check.SDKInfo{Name: k.name, Version: k.version}) | |
sdkInfo = append(sdkInfo, k) |
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 could have probably just used check.SDKInfo
here, in the first iteration of this PR this struct had a times_seen
field which we decided to drop.
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.
Thanks @alexshtin
|
||
sdkInfo := make([]check.SDKInfo, 0, len(currSet)) | ||
for k := range currSet { | ||
sdkInfo = append(sdkInfo, check.SDKInfo{Name: k.name, Version: k.version}) |
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 could have probably just used check.SDKInfo
here, in the first iteration of this PR this struct had a times_seen
field which we decided to drop.
vi.lock.RLock() | ||
overCap := len(vi.sdkInfoSet) >= vi.maxSetSize | ||
_, found := vi.sdkInfoSet[info] | ||
vi.lock.RUnlock() |
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.
Yeah, it's not worth it here
|
||
// RecordSDKInfo records name and version tuple in memory | ||
func (vi *SDKVersionInterceptor) RecordSDKInfo(name, version string) { | ||
info := sdkNameVersion{name, version} |
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 thought it'd be okay in this simple case, I don't mind fixing
type sdkNameVersion struct { | ||
name string | ||
version string | ||
} | ||
|
||
type SDKVersionInterceptor struct { | ||
sdkInfoSet map[sdkNameVersion]struct{} | ||
lock sync.RWMutex | ||
maxSetSize int | ||
} |
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.
Sure, can we get a lint rule that enforces this style?
|
||
type SDKVersionInterceptor struct { | ||
sdkInfoSet map[sdkNameVersion]struct{} | ||
lock sync.RWMutex |
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 nice, I can do that.
What changed?
Version check call now includes SDK versions
Why?
To be able to alert when they use an outdated or vulnerable SDK version
How did you test it?
Added unit tests
Potential risks
Is hotfix candidate?
No
Closes #2333