diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go index 7424d65005e..d00c8211993 100644 --- a/endpoints/cookie_sync_test.go +++ b/endpoints/cookie_sync_test.go @@ -2216,9 +2216,9 @@ func (m *MockGDPRPerms) BidderSyncAllowed(ctx context.Context, bidder openrtb_ex return args.Bool(0), args.Error(1) } -func (m *MockGDPRPerms) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (permissions gdpr.AuctionPermissions, err error) { +func (m *MockGDPRPerms) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) gdpr.AuctionPermissions { args := m.Called(ctx, bidderCoreName, bidder) - return args.Get(0).(gdpr.AuctionPermissions), args.Error(1) + return args.Get(0).(gdpr.AuctionPermissions) } type FakeAccountsFetcher struct { @@ -2248,10 +2248,10 @@ func (p *fakePermissions) BidderSyncAllowed(ctx context.Context, bidder openrtb_ return true, nil } -func (p *fakePermissions) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (permissions gdpr.AuctionPermissions, err error) { +func (p *fakePermissions) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) gdpr.AuctionPermissions { return gdpr.AuctionPermissions{ AllowBidRequest: true, - }, nil + } } func getDefaultActivityConfig(componentName string, allow bool) *config.AccountPrivacy { diff --git a/endpoints/openrtb2/test_utils.go b/endpoints/openrtb2/test_utils.go index b2f2826739f..331c0d57dfb 100644 --- a/endpoints/openrtb2/test_utils.go +++ b/endpoints/openrtb2/test_utils.go @@ -1429,10 +1429,10 @@ func (p *fakePermissions) BidderSyncAllowed(ctx context.Context, bidder openrtb_ return true, nil } -func (p *fakePermissions) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (permissions gdpr.AuctionPermissions, err error) { +func (p *fakePermissions) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) gdpr.AuctionPermissions { return gdpr.AuctionPermissions{ AllowBidRequest: true, - }, nil + } } type mockPlanBuilder struct { diff --git a/endpoints/setuid_test.go b/endpoints/setuid_test.go index d576b8a0093..87208a09114 100644 --- a/endpoints/setuid_test.go +++ b/endpoints/setuid_test.go @@ -1701,12 +1701,12 @@ func (g *fakePermsSetUID) BidderSyncAllowed(ctx context.Context, bidder openrtb_ return false, nil } -func (g *fakePermsSetUID) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (permissions gdpr.AuctionPermissions, err error) { +func (g *fakePermsSetUID) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) gdpr.AuctionPermissions { return gdpr.AuctionPermissions{ AllowBidRequest: g.personalInfoAllowed, PassGeo: g.personalInfoAllowed, PassID: g.personalInfoAllowed, - }, nil + } } type fakeSyncer struct { diff --git a/exchange/utils.go b/exchange/utils.go index 9b4ffd21f3e..f56a88151d9 100644 --- a/exchange/utils.go +++ b/exchange/utils.go @@ -71,8 +71,6 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context, return } - allowedBidderRequests = make([]BidderRequest, 0) - bidderImpWithBidResp := stored_responses.InitStoredBidResponses(req.BidRequest, auctionReq.StoredBidResponses) hasStoredAuctionResponses := len(auctionReq.StoredAuctionResponses) > 0 @@ -148,102 +146,110 @@ func (rs *requestSplitter) cleanOpenRTBRequests(ctx context.Context, gdprPerms = rs.gdprPermsBuilder(auctionReq.TCF2Config, gdprRequestInfo) } - // bidder level privacy policies + allowedBidderRequests = make([]BidderRequest, 0, len(allBidderRequests)) + for _, bidderRequest := range allBidderRequests { - // fetchBids activity - scopedName := privacy.Component{Type: privacy.ComponentTypeBidder, Name: bidderRequest.BidderName.String()} - fetchBidsActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityFetchBids, scopedName, privacy.NewRequestFromBidRequest(*req)) - if !fetchBidsActivityAllowed { - // skip the call to a bidder if fetchBids activity is not allowed - // do not add this bidder to allowedBidderRequests + auctionPermissions := gdprPerms.AuctionActivitiesAllowed(ctx, bidderRequest.BidderCoreName, bidderRequest.BidderName) + + // privacy blocking + if rs.isBidderBlockedByPrivacy(req, auctionReq.Activities, auctionPermissions, bidderRequest.BidderCoreName, bidderRequest.BidderName) { continue } - var auctionPermissions gdpr.AuctionPermissions - var gdprErr error + // fpd + applyFPD(auctionReq.FirstPartyData, bidderRequest) - if gdprEnforced { - auctionPermissions, gdprErr = gdprPerms.AuctionActivitiesAllowed(ctx, bidderRequest.BidderCoreName, bidderRequest.BidderName) - if !auctionPermissions.AllowBidRequest { - // auction request is not permitted by GDPR - // do not add this bidder to allowedBidderRequests - rs.me.RecordAdapterGDPRRequestBlocked(bidderRequest.BidderCoreName) - continue - } + // privacy scrubbing + if err := rs.applyPrivacy(&bidderRequest, auctionReq, auctionPermissions, ccpaEnforcer, lmt, coppa); err != nil { + errs = append(errs, err) + continue } - ipConf := privacy.IPConf{IPV6: auctionReq.Account.Privacy.IPv6Config, IPV4: auctionReq.Account.Privacy.IPv4Config} + // GPP downgrade: always downgrade unless we can confirm GPP is supported + if shouldSetLegacyPrivacy(rs.bidderInfo, string(bidderRequest.BidderCoreName)) { + setLegacyGDPRFromGPP(bidderRequest.BidRequest, gpp) + setLegacyUSPFromGPP(bidderRequest.BidRequest, gpp) + } - // FPD should be applied before policies, otherwise it overrides policies and activities restricted data - applyFPD(auctionReq.FirstPartyData, bidderRequest) + allowedBidderRequests = append(allowedBidderRequests, bidderRequest) + } - reqWrapper := &openrtb_ext.RequestWrapper{ - BidRequest: ortb.CloneBidRequestPartial(bidderRequest.BidRequest), - } + return +} + +func (rs *requestSplitter) isBidderBlockedByPrivacy(r *openrtb_ext.RequestWrapper, activities privacy.ActivityControl, auctionPermissions gdpr.AuctionPermissions, coreBidder, bidderName openrtb_ext.BidderName) bool { + // activities control + scope := privacy.Component{Type: privacy.ComponentTypeBidder, Name: bidderName.String()} + fetchBidsActivityAllowed := activities.Allow(privacy.ActivityFetchBids, scope, privacy.NewRequestFromBidRequest(*r)) + if !fetchBidsActivityAllowed { + return true + } + + // gdpr + if !auctionPermissions.AllowBidRequest { + rs.me.RecordAdapterGDPRRequestBlocked(coreBidder) + return true + } - passIDActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitUserFPD, scopedName, privacy.NewRequestFromBidRequest(*req)) - buyerUIDSet := reqWrapper.User != nil && reqWrapper.User.BuyerUID != "" - buyerUIDRemoved := false - if !passIDActivityAllowed { - privacy.ScrubUserFPD(reqWrapper) + return false +} + +func (rs *requestSplitter) applyPrivacy(bidderRequest *BidderRequest, auctionReq AuctionRequest, auctionPermissions gdpr.AuctionPermissions, ccpaEnforcer privacy.PolicyEnforcer, lmt bool, coppa bool) error { + scope := privacy.Component{Type: privacy.ComponentTypeBidder, Name: bidderRequest.BidderName.String()} + ipConf := privacy.IPConf{IPV6: auctionReq.Account.Privacy.IPv6Config, IPV4: auctionReq.Account.Privacy.IPv4Config} + + reqWrapper := &openrtb_ext.RequestWrapper{ + BidRequest: ortb.CloneBidRequestPartial(bidderRequest.BidRequest), + } + + passIDActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitUserFPD, scope, privacy.NewRequestFromBidRequest(*reqWrapper)) + buyerUIDSet := reqWrapper.User != nil && reqWrapper.User.BuyerUID != "" + buyerUIDRemoved := false + if !passIDActivityAllowed { + privacy.ScrubUserFPD(reqWrapper) + buyerUIDRemoved = true + } else { + if !auctionPermissions.PassID { + privacy.ScrubGdprID(reqWrapper) buyerUIDRemoved = true - } else { - // run existing policies (GDPR, CCPA, COPPA, LMT) - // potentially block passing IDs based on GDPR - if gdprEnforced && (gdprErr != nil || !auctionPermissions.PassID) { - privacy.ScrubGdprID(reqWrapper) - buyerUIDRemoved = true - } - // potentially block passing IDs based on CCPA - if ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String()) { - privacy.ScrubDeviceIDsIPsUserDemoExt(reqWrapper, ipConf, "eids", false) - buyerUIDRemoved = true - } - } - if buyerUIDSet && buyerUIDRemoved { - rs.me.RecordAdapterBuyerUIDScrubbed(bidderRequest.BidderCoreName) } - passGeoActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitPreciseGeo, scopedName, privacy.NewRequestFromBidRequest(*req)) - if !passGeoActivityAllowed { - privacy.ScrubGeoAndDeviceIP(reqWrapper, ipConf) - } else { - // run existing policies (GDPR, CCPA, COPPA, LMT) - // potentially block passing geo based on GDPR - if gdprEnforced && (gdprErr != nil || !auctionPermissions.PassGeo) { - privacy.ScrubGeoAndDeviceIP(reqWrapper, ipConf) - } - // potentially block passing geo based on CCPA - if ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String()) { - privacy.ScrubDeviceIDsIPsUserDemoExt(reqWrapper, ipConf, "eids", false) - } + if ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String()) { + privacy.ScrubDeviceIDsIPsUserDemoExt(reqWrapper, ipConf, "eids", false) + buyerUIDRemoved = true } + } + if buyerUIDSet && buyerUIDRemoved { + rs.me.RecordAdapterBuyerUIDScrubbed(bidderRequest.BidderCoreName) + } - if lmt || coppa { - privacy.ScrubDeviceIDsIPsUserDemoExt(reqWrapper, ipConf, "eids", coppa) + passGeoActivityAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitPreciseGeo, scope, privacy.NewRequestFromBidRequest(*reqWrapper)) + if !passGeoActivityAllowed { + privacy.ScrubGeoAndDeviceIP(reqWrapper, ipConf) + } else { + if !auctionPermissions.PassGeo { + privacy.ScrubGeoAndDeviceIP(reqWrapper, ipConf) } - - passTIDAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitTIDs, scopedName, privacy.NewRequestFromBidRequest(*req)) - if !passTIDAllowed { - privacy.ScrubTID(reqWrapper) + if ccpaEnforcer.ShouldEnforce(bidderRequest.BidderName.String()) { + privacy.ScrubDeviceIDsIPsUserDemoExt(reqWrapper, ipConf, "eids", false) } + } - err := reqWrapper.RebuildRequest() - if err != nil { - errs = append(errs, err) - } - bidderRequest.BidRequest = reqWrapper.BidRequest + if lmt || coppa { + privacy.ScrubDeviceIDsIPsUserDemoExt(reqWrapper, ipConf, "eids", coppa) + } - allowedBidderRequests = append(allowedBidderRequests, bidderRequest) + passTIDAllowed := auctionReq.Activities.Allow(privacy.ActivityTransmitTIDs, scope, privacy.NewRequestFromBidRequest(*reqWrapper)) + if !passTIDAllowed { + privacy.ScrubTID(reqWrapper) + } - // GPP downgrade: always downgrade unless we can confirm GPP is supported - if shouldSetLegacyPrivacy(rs.bidderInfo, string(bidderRequest.BidderCoreName)) { - setLegacyGDPRFromGPP(bidderRequest.BidRequest, gpp) - setLegacyUSPFromGPP(bidderRequest.BidRequest, gpp) - } + if err := reqWrapper.RebuildRequest(); err != nil { + return err } - return + bidderRequest.BidRequest = reqWrapper.BidRequest + return nil } func shouldSetLegacyPrivacy(bidderInfo config.BidderInfos, bidder string) bool { @@ -456,7 +462,6 @@ func buildRequestExtForBidder(bidder string, requestExt json.RawMessage, request } func buildRequestExtAlternateBidderCodes(bidder string, accABC *openrtb_ext.ExtAlternateBidderCodes, reqABC *openrtb_ext.ExtAlternateBidderCodes) *openrtb_ext.ExtAlternateBidderCodes { - if altBidderCodes := copyExtAlternateBidderCodes(bidder, reqABC); altBidderCodes != nil { return altBidderCodes } diff --git a/exchange/utils_test.go b/exchange/utils_test.go index 69cfdf70abf..5d2a83d5b49 100644 --- a/exchange/utils_test.go +++ b/exchange/utils_test.go @@ -46,7 +46,7 @@ func (p *permissionsMock) BidderSyncAllowed(ctx context.Context, bidder openrtb_ return true, nil } -func (p *permissionsMock) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (gdpr.AuctionPermissions, error) { +func (p *permissionsMock) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) gdpr.AuctionPermissions { permissions := gdpr.AuctionPermissions{ PassGeo: p.passGeo, PassID: p.passID, @@ -54,7 +54,7 @@ func (p *permissionsMock) AuctionActivitiesAllowed(ctx context.Context, bidderCo if p.allowAllBidders { permissions.AllowBidRequest = true - return permissions, p.activitiesError + return permissions } for _, allowedBidder := range p.allowedBidders { @@ -63,7 +63,7 @@ func (p *permissionsMock) AuctionActivitiesAllowed(ctx context.Context, bidderCo } } - return permissions, p.activitiesError + return permissions } type fakePermissionsBuilder struct { diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go index 1b4f6cb4680..4f7df2f3ab7 100644 --- a/gdpr/gdpr.go +++ b/gdpr/gdpr.go @@ -20,8 +20,8 @@ type Permissions interface { // Determines whether or not to send PI information to a bidder, or mask it out. // - // If the consent string was nonsensical, the returned error will be an ErrorMalformedConsent. - AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (permissions AuctionPermissions, err error) + // If the consent string was nonsensical, the no permissions are granted. + AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) AuctionPermissions } type PermissionsBuilder func(TCF2ConfigReader, RequestInfo) Permissions diff --git a/gdpr/impl.go b/gdpr/impl.go index 614c06d9a6a..27c10cf8fd5 100644 --- a/gdpr/impl.go +++ b/gdpr/impl.go @@ -56,33 +56,36 @@ func (p *permissionsImpl) BidderSyncAllowed(ctx context.Context, bidder openrtb_ } // AuctionActivitiesAllowed determines whether auction activities are permitted for a given bidder -func (p *permissionsImpl) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (permissions AuctionPermissions, err error) { +func (p *permissionsImpl) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) AuctionPermissions { if _, ok := p.nonStandardPublishers[p.publisherID]; ok { - return AllowAll, nil + return AllowAll } + if p.gdprSignal != SignalYes { - return AllowAll, nil + return AllowAll } + if p.consent == "" { - return p.defaultPermissions(), nil + return p.defaultPermissions() } + pc, err := parseConsent(p.consent) if err != nil { - return p.defaultPermissions(), err + return p.defaultPermissions() } + vendorID, _ := p.resolveVendorID(bidderCoreName, bidder) vendor, err := p.getVendor(ctx, vendorID, *pc) if err != nil { - return p.defaultPermissions(), err + return p.defaultPermissions() } - vendorInfo := VendorInfo{vendorID: vendorID, vendor: vendor} - - permissions = AuctionPermissions{} - permissions.AllowBidRequest = p.allowBidRequest(bidderCoreName, pc.consentMeta, vendorInfo) - permissions.PassGeo = p.allowGeo(bidderCoreName, pc.consentMeta, vendor) - permissions.PassID = p.allowID(bidderCoreName, pc.consentMeta, vendorInfo) - return permissions, nil + vendorInfo := VendorInfo{vendorID: vendorID, vendor: vendor} + return AuctionPermissions{ + AllowBidRequest: p.allowBidRequest(bidderCoreName, pc.consentMeta, vendorInfo), + PassGeo: p.allowGeo(bidderCoreName, pc.consentMeta, vendor), + PassID: p.allowID(bidderCoreName, pc.consentMeta, vendorInfo), + } } // defaultPermissions returns a permissions object that denies passing user IDs while @@ -222,6 +225,6 @@ func (a AlwaysAllow) HostCookiesAllowed(ctx context.Context) (bool, error) { func (a AlwaysAllow) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.BidderName) (bool, error) { return true, nil } -func (a AlwaysAllow) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) (permissions AuctionPermissions, err error) { - return AllowAll, nil +func (a AlwaysAllow) AuctionActivitiesAllowed(ctx context.Context, bidderCoreName openrtb_ext.BidderName, bidder openrtb_ext.BidderName) AuctionPermissions { + return AllowAll } diff --git a/gdpr/impl_test.go b/gdpr/impl_test.go index 64fa4434d4d..2a5826ad4cb 100644 --- a/gdpr/impl_test.go +++ b/gdpr/impl_test.go @@ -335,9 +335,8 @@ func TestAllowActivities(t *testing.T) { perms.gdprSignal = tt.gdpr perms.publisherID = tt.publisherID - permissions, err := perms.AuctionActivitiesAllowed(context.Background(), tt.bidderCoreName, tt.bidderName) + permissions := perms.AuctionActivitiesAllowed(context.Background(), tt.bidderCoreName, tt.bidderName) - assert.Nil(t, err, tt.description) assert.Equal(t, tt.passID, permissions.PassID, tt.description) } } @@ -437,8 +436,7 @@ func TestAllowActivitiesBidderWithoutGVLID(t *testing.T) { purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), } - permissions, err := perms.AuctionActivitiesAllowed(context.Background(), bidderWithoutGVLID, bidderWithoutGVLID) - assert.NoError(t, err) + permissions := perms.AuctionActivitiesAllowed(context.Background(), bidderWithoutGVLID, bidderWithoutGVLID) assert.Equal(t, tt.allowBidRequest, permissions.AllowBidRequest) assert.Equal(t, tt.passID, permissions.PassID) }) @@ -658,8 +656,7 @@ func TestAllowActivitiesGeoAndID(t *testing.T) { perms.consent = td.consent perms.purposeEnforcerBuilder = NewPurposeEnforcerBuilder(&tcf2AggConfig) - permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) - assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description) + permissions := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) assert.EqualValuesf(t, td.allowBidRequest, permissions.AllowBidRequest, "AllowBid failure on %s", td.description) assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description) assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description) @@ -695,8 +692,7 @@ func TestAllowActivitiesWhitelist(t *testing.T) { } // Assert that an item that otherwise would not be allowed PI access, gets approved because it is found in the GDPR.NonStandardPublishers array - permissions, err := perms.AuctionActivitiesAllowed(context.Background(), openrtb_ext.BidderAppnexus, openrtb_ext.BidderAppnexus) - assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed") + permissions := perms.AuctionActivitiesAllowed(context.Background(), openrtb_ext.BidderAppnexus, openrtb_ext.BidderAppnexus) assert.EqualValuesf(t, true, permissions.PassGeo, "PassGeo failure") assert.EqualValuesf(t, true, permissions.PassID, "PassID failure") } @@ -767,8 +763,7 @@ func TestAllowActivitiesPubRestrict(t *testing.T) { perms.aliasGVLIDs = td.aliasGVLIDs perms.consent = td.consent - permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) - assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description) + permissions := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description) assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description) } @@ -1101,8 +1096,7 @@ func TestAllowActivitiesBidRequests(t *testing.T) { perms.cfg = &tcf2AggConfig perms.purposeEnforcerBuilder = NewPurposeEnforcerBuilder(&tcf2AggConfig) - permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) - assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description) + permissions := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) assert.EqualValuesf(t, td.allowBidRequest, permissions.AllowBidRequest, "AllowBid failure on %s", td.description) assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description) assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description) @@ -1196,8 +1190,7 @@ func TestAllowActivitiesVendorException(t *testing.T) { perms.cfg = &tcf2AggConfig perms.purposeEnforcerBuilder = NewPurposeEnforcerBuilder(&tcf2AggConfig) - permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) - assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description) + permissions := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) assert.EqualValuesf(t, td.allowBidRequest, permissions.AllowBidRequest, "AllowBid failure on %s", td.description) assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description) assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description)