Skip to content
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

Activities framework #2844

Merged
merged 14 commits into from
Jul 6, 2023
Merged

Activities framework #2844

merged 14 commits into from
Jul 6, 2023

Conversation

VeronikaSolovei9
Copy link
Contributor

Implementation for #2591
Added foundation for activities evaluation and execution.

@bsardo bsardo self-assigned this Jun 15, 2023
@VeronikaSolovei9 VeronikaSolovei9 marked this pull request as ready for review June 24, 2023 03:59
@hhhjort hhhjort self-assigned this Jun 26, 2023
}
for _, scope := range r.componentName {
if strings.EqualFold(scope.Scope, target.Scope) &&
(strings.EqualFold(scope.Name, target.Name) || scope.Name == "*") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler would hopefully optimize it anyway, but you could put the scope.Name == "*" first in the or since it is cheaper to compute than a longer string compare.

// skip the call to a bidder if fetchBids activity is not allowed
// do not add this bidder to allowedBidderRequests
continue
}
Copy link
Collaborator

@bsardo bsardo Jun 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes from offline discussion on how to use activities framework along with existing privacy packages as part of GPP phase 3:

if fetchBidsActivityAllowed == privacy.ActivityDeny {
    // skip the call to a bidder if fetchBids activity is not allowed
	// do not add this bidder to allowedBidderRequests
	continue
} else if fetchBidsActivityAllowed == privacy.ActivityAbstain and gdprEnforced == true {
    allowed, err := gdprPerms.FetchBidAllowed(ctx, bidderRequest.BidderCoreName, bidderRequest.BidderName)
        if !allowed {
            continue
        }
}
// proceed with processing ID and geo to see if needs to be scrubbed

@@ -8,16 +8,17 @@ type AllowActivities struct {
TransmitUserFPD Activity `mapstructure:"transmitUfpd" json:"transmitUfpd"`
TransmitPreciseGeo Activity `mapstructure:"transmitPreciseGeo" json:"transmitPreciseGeo"`
TransmitUniqueRequestIds Activity `mapstructure:"transmitUniqueRequestIds" json:"transmitUniqueRequestIds"`
TransmitTIds Activity `mapstructure:"transmitTid" json:"transmitTid"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Can we make the variable name match the name of the JSON field and follow go best practices on variable naming making this TransmitTID?

@@ -40,7 +40,7 @@ type Account struct {
Validations Validations `mapstructure:"validations" json:"validations"`
DefaultBidLimit int `mapstructure:"default_bid_limit" json:"default_bid_limit"`
BidAdjustments *openrtb_ext.ExtRequestPrebidBidAdjustments `mapstructure:"bidadjustments" json:"bidadjustments"`
Privacy AccountPrivacy `mapstructure:"privacy" json:"privacy"`
Privacy *AccountPrivacy `mapstructure:"privacy" json:"privacy"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we say this needed to be a pointer? I can't recall.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was changed to "short-circuit NewActivityControl call in auction for performance reasons".
Also we need this nil check, at least for the meantime to make sure we don't reject all requests if activities are not configured.

@@ -239,6 +247,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
HookExecutor: hookExecutor,
QueryParams: r.URL.Query(),
TCF2Config: tcf2Config,
Activitities: activities,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: Activitities --> Activities

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, renamed

Comment on lines 4303 to 4322
privacyConfig := getDefaultActivityConfig(test.componentName, test.allow)
activities, err := privacy.NewActivityControl(privacyConfig)
assert.NoError(t, err, "")
auctionReq := AuctionRequest{
BidRequestWrapper: &openrtb_ext.RequestWrapper{BidRequest: test.req},
UserSyncs: &emptyUsersync{},
Activitities: activities,
}

bidderToSyncerKey := map[string]string{}
reqSplitter := &requestSplitter{
bidderToSyncerKey: bidderToSyncerKey,
me: &metrics.MetricsEngineMock{},
hostSChainNode: nil,
bidderInfo: config.BidderInfos{},
}

bidderRequests, _, errs := reqSplitter.cleanOpenRTBRequests(context.Background(), auctionReq, nil, gdpr.SignalNo)
assert.Empty(t, errs, "unexpected error returned")
assert.Len(t, bidderRequests, test.expectedReqNumber, "incorrect number of requests")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest wrapping this in a t.Run(test.name, func(t *testing.T) { and changing description to name and using underscores to separate the words in name.

You can also probably get rid of the string parameters at the end of each assert statement since the test framework should tell you what the problem is.

}

func NewActivityControl(privacyConf *config.AccountPrivacy) (ActivityControl, error) {
ac := ActivityControl{plans: nil}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: isn't plans nil by default? You can probably omit that field in this instantiation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Activities are not configured, we need to return ActivityControl to avoid null pointer exception in future usage:

auctionReq.Activities.Allow(privacy.ActivityFetchBids, ...)

Plans should be set to nil, so it will handle undefined plan properly in Allow:

plan, planDefined := e.plans[activity]

if !planDefined {
	return ActivityAbstain
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I just meant that this can probably just be ac := ActivityControl{} because nil is the default value for plans.

expectedResult: ActivityAllow,
},
{
name: "activityDefault is nil",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"activity_default_is_true"

expectedResult: ActivityAllow,
},
{
name: "activityDefault is nil",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"activity_default_is_false"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I missed renaming these. Thank you.

for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
actualResult := activityDefaultToDefaultResult(test.activityDefault)
assert.Equal(t, actualResult, test.expectedResult, "result is incorrect")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove string and please reverse the actual and expected params to match the Equal signature.

ActivityFetchBids: getDefaultActivityPlan()}},
activity: ActivityFetchBids,
target: ScopedName{Scope: "bidder", Name: "bidderB"},
activityResult: ActivityAllow,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name says it shouldn't be allowed but the result here is allow. I think deny is what we should expect here right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case match is not found, but allowed by default value. I renamed it.

for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
actualResult := test.activityControl.Allow(test.activity, test.target)
assert.Equal(t, test.activityResult, actualResult, "incorrect allow activity result")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove the string param.

}

func NewActivityControl(privacyConf *config.AccountPrivacy) (ActivityControl, error) {
ac := ActivityControl{plans: nil}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I just meant that this can probably just be ac := ActivityControl{} because nil is the default value for plans.

return result
}
}
return p.defaultResult
Copy link
Collaborator

@bsardo bsardo Jun 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do see this requirement in the issue and this is ultimately the behavior we want when activities is complete with privacy reg rules interspersed with component name/type rules and such. However, for now, I don't see how we can have a default value if privacy regs are meant to run after the activity framework as part of phase 3. Having a default that can only ever be allow or deny and then triggering privacy regs only if the activity framework abstains would mean the privacy regs would never run. I'll confirm the desired behavior here.

return ac, err
} else {
//temporarily disable Activities if they are specified at the account level
return ac, errors.New("account.Privacy has no effect as the feature is under development.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we easily make this a warning reported back to the publisher so the request is still processed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, modified

config/config.go Outdated
@@ -155,6 +155,10 @@ func (cfg *Configuration) validate(v *viper.Viper) []error {
cfg.TmaxAdjustments.Enabled = false
}

if cfg.AccountDefaults.Privacy != nil {
errs = append(errs, errors.New("account_defaults.Privacy has no effect as the feature is under development."))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe using glog.Warning instead of recording an error might be better here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this to glog.Warning and there are no messages at the server startup. Instead I always see warning message in response debug logs, even if account config is correct.
I think it's ok for the meantime while this feature is disabled. Eventually both warnings will go away.

Comment on lines 162 to 164
if len(r.componentName) == 0 {
componentNameFound = true
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do see that the most recent change here works. However, I think my issue is more with the fact that we have two variable names componentNameFound and componentTypeFound that are sometimes set to true when in fact nothing has been found. I think for clarity we should find another way of representing when componentName and componentType clauses have been omitted from the rule which is why I suggested two additional variables with names that indicate presence.
It does mean that the matchFound statement is more verbose but I think it is more obvious what constitutes a match:
matchFound := (nameFound || !nameClauseExists) && (typeFound || !typeClauseExists)

We don't have to use this exact solution; it's just one way to address my concern.

Copy link
Collaborator

@hhhjort hhhjort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@bsardo bsardo merged commit 23fffa1 into master Jul 6, 2023
Peiling-Ding pushed a commit to ParticleMedia/prebid-server that referenced this pull request Jul 6, 2023
Peiling-Ding pushed a commit to ParticleMedia/prebid-server that referenced this pull request Jul 14, 2023
Peiling-Ding added a commit to ParticleMedia/prebid-server that referenced this pull request Jul 14, 2023
* Fix: deal tiers no longer ignored due to presence of tid (prebid#2829)

* CAPT-787: GPP support for imds bidder. (prebid#2867)

Co-authored-by: Timothy M. Ace <tace@imds.tv>

* Adsinteractive: change usersync endpoint to https (prebid#2861)


Co-authored-by: Balint Vargha <varghabalint@gmail.com>

* consumable adapter: add gpp support (prebid#2883)

* feat: IX Bid Adapter - gpp support for user sync urls (prebid#2873)

Co-authored-by: Chris Corbo <chris.corbo@indexexchange.com>

* fix: update links in readme (prebid#2888)

authored by @akkapur

* New Adapter: AIDEM (prebid#2824)


Co-authored-by: AndreaC <67786179+darkstarac@users.noreply.github.com>
Co-authored-by: Andrea Tumbarello <Wazabit@users.noreply.github.com>
Co-authored-by: darkstar <canazza@wazabit.it>

* Improve Digital adapter: Set currency in bid response (prebid#2886)

* Sharethrough: Support multiformat bid request impression (prebid#2866)

* Triplelift Bid Adapter: Adding GPP Support (prebid#2887)

* YahooAdvertising rebranding to Yahoo Ads. (prebid#2872)


Co-authored-by: oath-jac <dsp-supply-prebid@verizonmedia.com>

* IX: MultiImp Implementation (prebid#2779)


Co-authored-by: Chris Corbo <chris.corbo@indexexchange.com>
Co-authored-by: Oronno Mamun <oronno.mamun@indexexchange.com>

* Exchange unit test fix (prebid#2868)

* Semgrep rules for adapters (prebid#2833)

* IX: Remove glog statement (prebid#2909)

* Activities framework (prebid#2844)

* PWBID: Update Default Endpoint (prebid#2903)

* script to run semgrep tests against adapter PRs (prebid#2907)

authored by @onkarvhanumante

* semgrep rule to detect undesirable package imports in adapter code (prebid#2911)

* update package-import message (prebid#2913)

authored by @onkarvhanumante

* Bump google.golang.org/grpc from 1.46.2 to 1.53.0 (prebid#2905)

---------

Co-authored-by: Brian Sardo <1168933+bsardo@users.noreply.github.com>
Co-authored-by: Timothy Ace <github.com-1@timothyace.com>
Co-authored-by: Timothy M. Ace <tace@imds.tv>
Co-authored-by: balintvargha <122350182+balintvargha@users.noreply.github.com>
Co-authored-by: Balint Vargha <varghabalint@gmail.com>
Co-authored-by: Jason Piros <jasonpiros@gmail.com>
Co-authored-by: ccorbo <ccorbo2013@gmail.com>
Co-authored-by: Chris Corbo <chris.corbo@indexexchange.com>
Co-authored-by: Ankush <ankush.kapur@gmail.com>
Co-authored-by: Giovanni Sollazzo <gs@aidem.com>
Co-authored-by: AndreaC <67786179+darkstarac@users.noreply.github.com>
Co-authored-by: Andrea Tumbarello <Wazabit@users.noreply.github.com>
Co-authored-by: darkstar <canazza@wazabit.it>
Co-authored-by: Jozef Bartek <31618107+jbartek25@users.noreply.github.com>
Co-authored-by: Max Dupuis <118775839+maxime-dupuis@users.noreply.github.com>
Co-authored-by: Patrick Loughrey <ploughrey@triplelift.com>
Co-authored-by: radubarbos <raduiquest79@gmail.com>
Co-authored-by: oath-jac <dsp-supply-prebid@verizonmedia.com>
Co-authored-by: Oronno Mamun <oronno.mamun@indexexchange.com>
Co-authored-by: Veronika Solovei <kalypsonika@gmail.com>
Co-authored-by: Onkar Hanumante <onkar.hanumante@xandr.com>
Co-authored-by: Stephen Johnston <tiquortoo@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@SyntaxNode SyntaxNode deleted the activities branch October 2, 2023 17:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants