-
Notifications
You must be signed in to change notification settings - Fork 737
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
UserSync activity #2897
UserSync activity #2897
Conversation
endpoints/setuid.go
Outdated
w.WriteHeader(http.StatusBadRequest) | ||
return |
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.
We should probably record a metric and update the analytics object so
here as well.
Should the param passed to metricsEngine.RecordSetUid
be one of the account options (metrics.SetUidAccountConfigMalformed
or SetUidAccountInvalid
) or something more generic?
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 good point. We discussed this offline and decided to add metrics in a separate PR.
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 spec calls for us to only write to metrics / logs. In the case of error, we should continue with activities
set to nil
.
w.WriteHeader(http.StatusUnavailableForLegalReasons) | ||
return |
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.
We should probably record a metric and update the analytics object so
here as well.
For GDPR, the metric we use when the error is http.StatusUnavailableForLegalReasons
is metrics.SetUidGDPRHostCookieBlocked
. Maybe we need to add a more generic privacy related blocking metric like metrics.SetUidPrivacyHostCookieBlocked
?
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.
We discussed this offline and decided to add metrics in a separate PR.
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.
Using a generic metric is a good idea, especially as the number of privacy policies is expected to increase. IMHO the existign GDPR and CCPA metrics could use the new generalized privacy blocking metric.
7f0de64
to
ea46c83
Compare
endpoints/cookie_sync.go
Outdated
if errortypes.ContainsFatalError([]error{activitiesErr}) { | ||
return usersync.Request{}, privacy.Policies{}, err |
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 add tests to cover these lines?
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.
Added
endpoints/cookie_sync.go
Outdated
func (p usersyncPrivacy) ActivityAllowsUserSync(bidder string) privacy.ActivityResult { | ||
activityResult := p.activityControl.Allow(privacy.ActivitySyncUser, | ||
privacy.ScopedName{Scope: privacy.ScopeTypeBidder, Name: bidder}) | ||
return activityResult |
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 add tests to cover these lines?
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.
Added!
endpoints/cookie_sync_test.go
Outdated
@@ -1870,6 +1902,42 @@ func TestUsersyncPrivacyCCPAAllowsBidderSync(t *testing.T) { | |||
} | |||
} | |||
|
|||
func TestActivityDefaultToDefaultResult(t *testing.T) { | |||
|
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.
Nitpick: Could you remove this blank line?
usersync/chooser_test.go
Outdated
gdprAllowsHostCookie bool | ||
gdprAllowsBidderSync bool | ||
ccpaAllowsBidderSync bool | ||
activityAllowIUserSync privacy.ActivityResult |
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.
Is there a typo here with activityAllowIUserSync
? Should it be activityAllowsUserSync
?
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 a typo. Fixed
endpoints/cookie_sync_test.go
Outdated
@@ -972,6 +973,36 @@ func TestCookieSyncParseRequest(t *testing.T) { | |||
expectedError: errCookieSyncAccountBlocked.Error(), | |||
givenAccountRequired: true, | |||
}, | |||
|
|||
{ | |||
description: "Account Defaults - Invalid activities Activities", |
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.
Nitpick: Looks like you have activities twice in the test description.
endpoints/cookie_sync.go
Outdated
activityControl, activitiesErr := privacy.NewActivityControl(account.Privacy) | ||
if activitiesErr != nil { | ||
if errortypes.ContainsFatalError([]error{activitiesErr}) { | ||
return usersync.Request{}, privacy.Policies{}, err |
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.
We should ignore account config errors for activity control. Per the spec:
If a rule is invalid for any reason, skip it and emit an error at N% sampling.
I recommend proceeding with a nil activities control object if there's an error and emit metrics and logs so the host can know about the problem. I understand that metrics / logs are scoped for a follow-up PR.
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.
Done
endpoints/cookie_sync_test.go
Outdated
@@ -1870,6 +1902,41 @@ func TestUsersyncPrivacyCCPAAllowsBidderSync(t *testing.T) { | |||
} | |||
} | |||
|
|||
func TestActivityDefaultToDefaultResult(t *testing.T) { |
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 you're too specific with this test name. I suspect this is testing the activity control integration where the default value is not important. Consider renaming to something like TestCookieSyncActivityControlIntegration
.
privacy/enforcer.go
Outdated
@@ -33,9 +32,6 @@ func NewActivityControl(privacyConf *config.AccountPrivacy) (ActivityControl, er | |||
|
|||
if privacyConf == nil { | |||
return ac, err |
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.
Nitpick: Consider returning nil
for an error here to make it clear this a valid state.
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 was this turned back from nil
to err
?
endpoints/setuid.go
Outdated
w.WriteHeader(http.StatusBadRequest) | ||
return |
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 spec calls for us to only write to metrics / logs. In the case of error, we should continue with activities
set to nil
.
w.WriteHeader(http.StatusUnavailableForLegalReasons) | ||
return |
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.
Using a generic metric is a good idea, especially as the number of privacy policies is expected to increase. IMHO the existign GDPR and CCPA metrics could use the new generalized privacy blocking metric.
endpoints/setuid.go
Outdated
func getSyncer(query url.Values, syncersByKey map[string]usersync.Syncer) (usersync.Syncer, error) { | ||
key := query.Get("bidder") | ||
func getSyncer(query url.Values, syncersByKey map[string]usersync.Syncer) (usersync.Syncer, string, error) { | ||
bidderName := query.Get("bidder") |
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 don't believe this change is valid. The "bidder" parameter is actually the syncer key. There is often a 1:1 relationship between them, but it's possible to have a 1:many.
Let's discuss at our next meeting how to address this, since we need the proper bidder name now for activity rule matching. Since we only ever expect the setuid endpoint to be called as a redirect from a cookie sync, we should have the freedom to make this change.
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.
Good catch Scott, yeah this function gets passed a query from a cookie sync redirect, where "bidder" would actually grab the syncer key. Maybe that syncersByBidder
map that gets passed into NewSetUIDEndpoint()
can be used to get the proper bidder name?
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.
Good though. The problem is there is a 1:many relationship from the syncer key to the bidder name, so we can't be sure which bidder it is. We'll likely be fine if at least one of the linked bidders is allowed, but that's complicated to check. I think the easier approach would be to actually set bidder to the bidder name. SetUID would still need the syncersByBidder
map to get the syncer key.
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.
Wow! Let's discuss it in a team meeting. I'll follow your instructions 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 you closed your bidderNameBySyncer
PR. Will your changes be reflected in this PR or will you open a new one for this?
usersync/chooser.go
Outdated
@@ -1,5 +1,9 @@ | |||
package usersync | |||
|
|||
import ( | |||
privacyActivity "github.com/prebid/prebid-server/privacy" |
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 intent of the privacy interface in this package is to avoid adding a dependency / import. This is just needed for the ActivityResult, so please use a boolean there instead. When evaluating the result, both an Abstain and Allow result should map to true
.
All comments are addressed except of one. We need to find the right way to get a bidder name. |
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.
Left one comment! Also could you merge with master to fix conflicts!
endpoints/setuid.go
Outdated
func getSyncer(query url.Values, syncersByKey map[string]usersync.Syncer) (usersync.Syncer, error) { | ||
key := query.Get("bidder") | ||
func getSyncer(query url.Values, syncersByKey map[string]usersync.Syncer) (usersync.Syncer, string, error) { | ||
bidderName := query.Get("bidder") |
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 you closed your bidderNameBySyncer
PR. Will your changes be reflected in this PR or will you open a new one for this?
# Conflicts: # endpoints/setuid.go
Alex, good point! |
) | ||
|
||
// Privacy determines which privacy policies will be enforced for a user sync request. | ||
type Privacy interface { | ||
GDPRAllowsHostCookie() bool | ||
GDPRAllowsBidderSync(bidder string) bool | ||
CCPAAllowsBidderSync(bidder string) bool | ||
ActivityAllowsUserSync(bidder string) 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.
Should we rename to ActivityAllowsBidderSync
to match GDPRAllowsBidderSync
and CCPAAllowsBidderSync
?
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.
Gus, activity name we execute here is syncUser
:
prebid-server/privacy/activity.go
Line 19 in 5723674
case ActivitySyncUser: |
and this is how it is in configs:
prebid-server/config/activity.go
Line 4 in 5723674
SyncUser Activity `mapstructure:"syncUser" json:"syncUser"` |
I'm open to rename it if you think ActivityAllowsBidderSync
is better than ActivityAllowsUserSync
.
# Conflicts: # endpoints/setuid.go
endpoints/setuid.go
Outdated
if len(strSID) > 0 { | ||
gppSID, err := stringutil.StrToInt8Slice(strSID) | ||
if err != nil { | ||
return gdpr.SignalAmbiguous, fmt.Errorf("Error parsing gpp_sid %s", err.Error()) |
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.
For my own understanding is it okay to use fmt
when returning an error? I typically use something like errors.New()
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 use fmt.Error when I want to pass a parameter to error message. For instance when you want to build dynamic error messages and use %s
, %d
to format values. fmt.Error returns usual error, it just helps to format the message.
endpoints/setuid.go
Outdated
// first and the 'gdpr' and 'gdpr_consent' query params second. If found in both, throws a | ||
// warning. Can also throw a parsing or validation error | ||
func extractGDPRInfo(query url.Values) (reqInfo gdpr.RequestInfo, err error) { | ||
|
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.
Nitpick: Could you remove this blank line?
# Conflicts: # privacy/enforcer.go
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.
Very close to approval, just one last comment
privacy/enforcer.go
Outdated
@@ -33,9 +32,6 @@ func NewActivityControl(privacyConf *config.AccountPrivacy) (ActivityControl, er | |||
|
|||
if privacyConf == nil { | |||
return ac, err |
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 was this turned back from nil
to err
?
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.
LGTM
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.
LGTM
User sync activities for bidder.
In this PR I removed a statement that disables activities. If activities are not specified in config then nil plans will be returned. Default result is
Abstain
and it will not modify existing behavior.This is needed because more and more unit tests start to depend on
NewActivityControl
function as this is a part of auction logic.