From a6a4943f29a30f00bbd3e974f59218f857344a9f Mon Sep 17 00:00:00 2001 From: bsardo <1168933+bsardo@users.noreply.github.com> Date: Mon, 28 Jun 2021 22:54:11 -0400 Subject: [PATCH 1/2] Add GDPR host-level per-purpose enforce vendor signals config --- config/config.go | 13 +- config/config_test.go | 30 ++++ gdpr/impl.go | 36 ++++- gdpr/impl_test.go | 349 +++++++++++++++++++++++++----------------- 4 files changed, 288 insertions(+), 140 deletions(-) diff --git a/config/config.go b/config/config.go index 96e3c1f1e65..b64bab0006f 100644 --- a/config/config.go +++ b/config/config.go @@ -257,7 +257,8 @@ type TCF2 struct { // Making a purpose struct so purpose specific details can be added later. type TCF2Purpose struct { - Enabled bool `mapstructure:"enabled"` + Enabled bool `mapstructure:"enabled"` + EnforceVendors bool `mapstructure:"enforce_vendors"` // Array of vendor exceptions that is used to create the hash table VendorExceptionMap so vendor names can be instantly accessed VendorExceptions []openrtb_ext.BidderName `mapstructure:"vendor_exceptions"` VendorExceptionMap map[openrtb_ext.BidderName]struct{} @@ -999,6 +1000,16 @@ func SetupViper(v *viper.Viper, filename string) { v.SetDefault("gdpr.tcf2.purpose8.enabled", true) v.SetDefault("gdpr.tcf2.purpose9.enabled", true) v.SetDefault("gdpr.tcf2.purpose10.enabled", true) + v.SetDefault("gdpr.tcf2.purpose1.enforce_vendors", true) + v.SetDefault("gdpr.tcf2.purpose2.enforce_vendors", true) + v.SetDefault("gdpr.tcf2.purpose3.enforce_vendors", true) + v.SetDefault("gdpr.tcf2.purpose4.enforce_vendors", true) + v.SetDefault("gdpr.tcf2.purpose5.enforce_vendors", true) + v.SetDefault("gdpr.tcf2.purpose6.enforce_vendors", true) + v.SetDefault("gdpr.tcf2.purpose7.enforce_vendors", true) + v.SetDefault("gdpr.tcf2.purpose8.enforce_vendors", true) + v.SetDefault("gdpr.tcf2.purpose9.enforce_vendors", true) + v.SetDefault("gdpr.tcf2.purpose10.enforce_vendors", true) v.SetDefault("gdpr.tcf2.purpose1.vendor_exceptions", []openrtb_ext.BidderName{}) v.SetDefault("gdpr.tcf2.purpose2.vendor_exceptions", []openrtb_ext.BidderName{}) v.SetDefault("gdpr.tcf2.purpose3.vendor_exceptions", []openrtb_ext.BidderName{}) diff --git a/config/config_test.go b/config/config_test.go index c33a345c473..dfc880bf050 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -140,6 +140,16 @@ func TestDefaults(t *testing.T) { cmpBools(t, "generate_bid_id", cfg.GenerateBidID, false) cmpBools(t, "gdpr.tcf2.purpose_one_treatment.enabled", true, cfg.GDPR.TCF2.PurposeOneTreatment.Enabled) cmpBools(t, "gdpr.tcf2.purpose_one_treatment.access_allowed", true, cfg.GDPR.TCF2.PurposeOneTreatment.AccessAllowed) + cmpBools(t, "gdpr.tcf2.purpose1.enforce_vendors", cfg.GDPR.TCF2.Purpose1.EnforceVendors, true) + cmpBools(t, "gdpr.tcf2.purpose2.enforce_vendors", cfg.GDPR.TCF2.Purpose2.EnforceVendors, true) + cmpBools(t, "gdpr.tcf2.purpose3.enforce_vendors", cfg.GDPR.TCF2.Purpose3.EnforceVendors, true) + cmpBools(t, "gdpr.tcf2.purpose4.enforce_vendors", cfg.GDPR.TCF2.Purpose4.EnforceVendors, true) + cmpBools(t, "gdpr.tcf2.purpose5.enforce_vendors", cfg.GDPR.TCF2.Purpose5.EnforceVendors, true) + cmpBools(t, "gdpr.tcf2.purpose6.enforce_vendors", cfg.GDPR.TCF2.Purpose6.EnforceVendors, true) + cmpBools(t, "gdpr.tcf2.purpose7.enforce_vendors", cfg.GDPR.TCF2.Purpose7.EnforceVendors, true) + cmpBools(t, "gdpr.tcf2.purpose8.enforce_vendors", cfg.GDPR.TCF2.Purpose8.EnforceVendors, true) + cmpBools(t, "gdpr.tcf2.purpose9.enforce_vendors", cfg.GDPR.TCF2.Purpose9.EnforceVendors, true) + cmpBools(t, "gdpr.tcf2.purpose10.enforce_vendors", cfg.GDPR.TCF2.Purpose10.EnforceVendors, true) } var fullConfig = []byte(` @@ -149,25 +159,35 @@ gdpr: non_standard_publishers: ["siteID","fake-site-id","appID","agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA"] tcf2: purpose1: + enforce_vendors: false vendor_exceptions: ["foo1a", "foo1b"] purpose2: enabled: false + enforce_vendors: false vendor_exceptions: ["foo2"] purpose3: + enforce_vendors: false vendor_exceptions: ["foo3"] purpose4: + enforce_vendors: false vendor_exceptions: ["foo4"] purpose5: + enforce_vendors: false vendor_exceptions: ["foo5"] purpose6: + enforce_vendors: false vendor_exceptions: ["foo6"] purpose7: + enforce_vendors: false vendor_exceptions: ["foo7"] purpose8: + enforce_vendors: false vendor_exceptions: ["foo8"] purpose9: + enforce_vendors: false vendor_exceptions: ["foo9"] purpose10: + enforce_vendors: false vendor_exceptions: ["foo10"] special_purpose1: vendor_exceptions: ["fooSP1"] @@ -407,51 +427,61 @@ func TestFullConfig(t *testing.T) { Enabled: true, Purpose1: TCF2Purpose{ Enabled: true, // true by default + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo1a"), openrtb_ext.BidderName("foo1b")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo1a"): {}, openrtb_ext.BidderName("foo1b"): {}}, }, Purpose2: TCF2Purpose{ Enabled: false, + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo2")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo2"): {}}, }, Purpose3: TCF2Purpose{ Enabled: true, // true by default + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo3")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo3"): {}}, }, Purpose4: TCF2Purpose{ Enabled: true, // true by default + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo4")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo4"): {}}, }, Purpose5: TCF2Purpose{ Enabled: true, // true by default + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo5")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo5"): {}}, }, Purpose6: TCF2Purpose{ Enabled: true, // true by default + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo6")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo6"): {}}, }, Purpose7: TCF2Purpose{ Enabled: true, // true by default + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo7")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo7"): {}}, }, Purpose8: TCF2Purpose{ Enabled: true, // true by default + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo8")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo8"): {}}, }, Purpose9: TCF2Purpose{ Enabled: true, // true by default + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo9")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo9"): {}}, }, Purpose10: TCF2Purpose{ Enabled: true, // true by default + EnforceVendors: false, VendorExceptions: []openrtb_ext.BidderName{openrtb_ext.BidderName("foo10")}, VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderName("foo10"): {}}, }, diff --git a/gdpr/impl.go b/gdpr/impl.go index ac0bfefdba4..5f7e3e73fe2 100644 --- a/gdpr/impl.go +++ b/gdpr/impl.go @@ -210,8 +210,8 @@ func (p *permissionsImpl) checkPurpose(consent tcf2.ConsentMetadata, vendor api. return true } - purposeAllowed := consent.PurposeAllowed(purpose) && (weakVendorEnforcement || (vendor.Purpose(purpose) && consent.VendorConsent(vendorID))) - legitInterest := consent.PurposeLITransparency(purpose) && (weakVendorEnforcement || (vendor.LegitimateInterest(purpose) && consent.VendorLegitInterest(vendorID))) + purposeAllowed := p.consentEstablished(consent, vendor, vendorID, purpose, weakVendorEnforcement) + legitInterest := p.legitInterestEstablished(consent, vendor, vendorID, purpose, weakVendorEnforcement) if consent.CheckPubRestriction(uint8(purpose), pubRestrictRequireConsent, vendorID) { return purposeAllowed @@ -224,6 +224,38 @@ func (p *permissionsImpl) checkPurpose(consent tcf2.ConsentMetadata, vendor api. return purposeAllowed || legitInterest } +func (p *permissionsImpl) consentEstablished(consent tcf2.ConsentMetadata, vendor api.Vendor, vendorID uint16, purpose consentconstants.Purpose, weakVendorEnforcement bool) bool { + if !consent.PurposeAllowed(purpose) { + return false + } + if weakVendorEnforcement { + return true + } + if !p.purposeConfigs[purpose].EnforceVendors { + return true + } + if vendor.Purpose(purpose) && consent.VendorConsent(vendorID) { + return true + } + return false +} + +func (p *permissionsImpl) legitInterestEstablished(consent tcf2.ConsentMetadata, vendor api.Vendor, vendorID uint16, purpose consentconstants.Purpose, weakVendorEnforcement bool) bool { + if !consent.PurposeLITransparency(purpose) { + return false + } + if weakVendorEnforcement { + return true + } + if !p.purposeConfigs[purpose].EnforceVendors { + return true + } + if vendor.LegitimateInterest(purpose) && consent.VendorLegitInterest(vendorID) { + return true + } + return false +} + func (p *permissionsImpl) parseVendor(ctx context.Context, vendorID uint16, consent string) (parsedConsent api.VendorConsents, vendor api.Vendor, err error) { parsedConsent, err = vendorconsent.ParseString(consent) if err != nil { diff --git a/gdpr/impl_test.go b/gdpr/impl_test.go index 93d23c1acf6..f7d90f3673b 100644 --- a/gdpr/impl_test.go +++ b/gdpr/impl_test.go @@ -66,7 +66,8 @@ func TestAllowedSyncs(t *testing.T) { HostVendorID: 2, TCF2: config.TCF2{ Purpose1: config.TCF2Purpose{ - Enabled: true, + Enabled: true, + EnforceVendors: true, }, }, }, @@ -79,6 +80,9 @@ func TestAllowedSyncs(t *testing.T) { }), }, } + perms.purposeConfigs = map[consentconstants.Purpose]config.TCF2Purpose{ + consentconstants.Purpose(1): perms.cfg.TCF2.Purpose1, + } allowSync, err := perms.HostCookiesAllowed(context.Background(), SignalYes, vendor2AndPurpose1Consent) assertNilErr(t, err) @@ -145,7 +149,8 @@ func TestProhibitedVendors(t *testing.T) { HostVendorID: 2, TCF2: config.TCF2{ Purpose1: config.TCF2Purpose{ - Enabled: true, + Enabled: true, + EnforceVendors: true, }, }, }, @@ -158,6 +163,9 @@ func TestProhibitedVendors(t *testing.T) { }), }, } + perms.purposeConfigs = map[consentconstants.Purpose]config.TCF2Purpose{ + consentconstants.Purpose(1): perms.cfg.TCF2.Purpose1, + } allowSync, err := perms.HostCookiesAllowed(context.Background(), SignalYes, purpose1NoVendorConsent) assertNilErr(t, err) @@ -289,7 +297,8 @@ func TestAllowActivities(t *testing.T) { TCF2: config.TCF2{ Enabled: true, Purpose2: config.TCF2Purpose{ - Enabled: true, + Enabled: true, + EnforceVendors: true, }, }, }, @@ -302,6 +311,9 @@ func TestAllowActivities(t *testing.T) { }), }, } + perms.purposeConfigs = map[consentconstants.Purpose]config.TCF2Purpose{ + consentconstants.Purpose(2): perms.cfg.TCF2.Purpose2, + } for _, tt := range tests { perms.cfg.DefaultValue = tt.gdprDefaultValue @@ -357,15 +369,39 @@ func buildVendorList34() vendorList { } } -var gdprConfig = config.GDPR{ - HostVendorID: 2, - TCF2: config.TCF2{ - Enabled: true, - Purpose1: config.TCF2Purpose{Enabled: true}, - Purpose2: config.TCF2Purpose{Enabled: true}, - Purpose7: config.TCF2Purpose{Enabled: true}, - SpecialPurpose1: config.TCF2Purpose{Enabled: true}, - }, +func allPurposesEnabledPermissions() (perms permissionsImpl) { + perms = permissionsImpl{ + cfg: config.GDPR{ + HostVendorID: 2, + TCF2: config.TCF2{ + Enabled: true, + Purpose1: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + Purpose2: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + Purpose3: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + Purpose4: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + Purpose5: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + Purpose6: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + Purpose7: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + Purpose8: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + Purpose9: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + Purpose10: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + SpecialPurpose1: config.TCF2Purpose{Enabled: true, EnforceVendors: true}, + }, + }, + } + perms.purposeConfigs = map[consentconstants.Purpose]config.TCF2Purpose{ + consentconstants.Purpose(1): perms.cfg.TCF2.Purpose1, + consentconstants.Purpose(2): perms.cfg.TCF2.Purpose2, + consentconstants.Purpose(3): perms.cfg.TCF2.Purpose3, + consentconstants.Purpose(4): perms.cfg.TCF2.Purpose4, + consentconstants.Purpose(5): perms.cfg.TCF2.Purpose5, + consentconstants.Purpose(6): perms.cfg.TCF2.Purpose6, + consentconstants.Purpose(7): perms.cfg.TCF2.Purpose7, + consentconstants.Purpose(8): perms.cfg.TCF2.Purpose8, + consentconstants.Purpose(9): perms.cfg.TCF2.Purpose9, + consentconstants.Purpose(10): perms.cfg.TCF2.Purpose10, + } + return } type testDef struct { @@ -380,20 +416,20 @@ type testDef struct { func TestAllowActivitiesGeoAndID(t *testing.T) { vendorListData := MarshalVendorList(buildVendorList34()) - perms := permissionsImpl{ - cfg: gdprConfig, - vendorIDs: map[openrtb_ext.BidderName]uint16{ - openrtb_ext.BidderAppnexus: 2, - openrtb_ext.BidderPubmatic: 6, - openrtb_ext.BidderRubicon: 8, - openrtb_ext.BidderOpenx: 20, - }, - fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ - tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ - 34: parseVendorListDataV2(t, vendorListData), - 74: parseVendorListDataV2(t, vendorListData), - }), - }, + + perms := allPurposesEnabledPermissions() + perms.vendorIDs = map[openrtb_ext.BidderName]uint16{ + openrtb_ext.BidderAppnexus: 2, + openrtb_ext.BidderPubmatic: 6, + openrtb_ext.BidderRubicon: 8, + openrtb_ext.BidderOpenx: 20, + openrtb_ext.BidderAudienceNetwork: 55, + } + perms.fetchVendorList = map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ + tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ + 34: parseVendorListDataV2(t, vendorListData), + 74: parseVendorListDataV2(t, vendorListData), + }), } // COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA : full consents to purposes and vendors 2, 6, 8 @@ -464,19 +500,19 @@ func TestAllowActivitiesGeoAndID(t *testing.T) { func TestAllowActivitiesWhitelist(t *testing.T) { vendorListData := MarshalVendorList(buildVendorList34()) - perms := permissionsImpl{ - cfg: gdprConfig, - vendorIDs: map[openrtb_ext.BidderName]uint16{ - openrtb_ext.BidderAppnexus: 2, - openrtb_ext.BidderPubmatic: 6, - openrtb_ext.BidderRubicon: 8, - }, - fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ - tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ - 34: parseVendorListDataV2(t, vendorListData), - }), - }, + + perms := allPurposesEnabledPermissions() + perms.vendorIDs = map[openrtb_ext.BidderName]uint16{ + openrtb_ext.BidderAppnexus: 2, + openrtb_ext.BidderPubmatic: 6, + openrtb_ext.BidderRubicon: 8, } + perms.fetchVendorList = map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ + tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ + 34: parseVendorListDataV2(t, vendorListData), + }), + } + // Assert that an item that otherwise would not be allowed PI access, gets approved because it is found in the GDPR.NonStandardPublishers array perms.cfg.NonStandardPublisherMap = map[string]struct{}{"appNexusAppID": {}} _, passGeo, passID, err := perms.AuctionActivitiesAllowed(context.Background(), openrtb_ext.BidderAppnexus, "appNexusAppID", SignalYes, "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", false) @@ -487,18 +523,17 @@ func TestAllowActivitiesWhitelist(t *testing.T) { func TestAllowActivitiesPubRestrict(t *testing.T) { vendorListData := MarshalVendorList(buildVendorList34()) - perms := permissionsImpl{ - cfg: gdprConfig, - vendorIDs: map[openrtb_ext.BidderName]uint16{ - openrtb_ext.BidderAppnexus: 2, - openrtb_ext.BidderPubmatic: 32, - openrtb_ext.BidderRubicon: 8, - }, - fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ - tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ - 15: parseVendorListDataV2(t, vendorListData), - }), - }, + + perms := allPurposesEnabledPermissions() + perms.vendorIDs = map[openrtb_ext.BidderName]uint16{ + openrtb_ext.BidderAppnexus: 2, + openrtb_ext.BidderPubmatic: 32, + openrtb_ext.BidderRubicon: 8, + } + perms.fetchVendorList = map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ + tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ + 15: parseVendorListDataV2(t, vendorListData), + }), } // COwAdDhOwAdDhN4ABAENAPCgAAQAAv___wAAAFP_AAp_4AI6ACACAA - vendors 1-10 legit interest only, @@ -537,18 +572,17 @@ func TestAllowActivitiesPubRestrict(t *testing.T) { func TestAllowSync(t *testing.T) { vendorListData := MarshalVendorList(buildVendorList34()) - perms := permissionsImpl{ - cfg: gdprConfig, - vendorIDs: map[openrtb_ext.BidderName]uint16{ - openrtb_ext.BidderAppnexus: 2, - openrtb_ext.BidderPubmatic: 6, - openrtb_ext.BidderRubicon: 8, - }, - fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ - tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ - 34: parseVendorListDataV2(t, vendorListData), - }), - }, + + perms := allPurposesEnabledPermissions() + perms.vendorIDs = map[openrtb_ext.BidderName]uint16{ + openrtb_ext.BidderAppnexus: 2, + openrtb_ext.BidderPubmatic: 6, + openrtb_ext.BidderRubicon: 8, + } + perms.fetchVendorList = map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ + tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ + 34: parseVendorListDataV2(t, vendorListData), + }), } // COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA : full consensts to purposes and vendors 2, 6, 8 @@ -565,20 +599,19 @@ func TestProhibitedPurposeSync(t *testing.T) { vendorList34 := buildVendorList34() vendorList34.Vendors["8"].Purposes = []int{7} vendorListData := MarshalVendorList(vendorList34) - perms := permissionsImpl{ - cfg: gdprConfig, - vendorIDs: map[openrtb_ext.BidderName]uint16{ - openrtb_ext.BidderAppnexus: 2, - openrtb_ext.BidderPubmatic: 6, - openrtb_ext.BidderRubicon: 8, - }, - fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ - tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ - 34: parseVendorListDataV2(t, vendorListData), - }), - }, - } + + perms := allPurposesEnabledPermissions() perms.cfg.HostVendorID = 8 + perms.vendorIDs = map[openrtb_ext.BidderName]uint16{ + openrtb_ext.BidderAppnexus: 2, + openrtb_ext.BidderPubmatic: 6, + openrtb_ext.BidderRubicon: 8, + } + perms.fetchVendorList = map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ + tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ + 34: parseVendorListDataV2(t, vendorListData), + }), + } // COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA : full consents to purposes for vendors 2, 6, 8 allowSync, err := perms.HostCookiesAllowed(context.Background(), SignalYes, "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA") @@ -592,21 +625,20 @@ func TestProhibitedPurposeSync(t *testing.T) { func TestProhibitedVendorSync(t *testing.T) { vendorListData := MarshalVendorList(buildVendorList34()) - perms := permissionsImpl{ - cfg: gdprConfig, - vendorIDs: map[openrtb_ext.BidderName]uint16{ - openrtb_ext.BidderAppnexus: 2, - openrtb_ext.BidderPubmatic: 6, - openrtb_ext.BidderRubicon: 8, - openrtb_ext.BidderOpenx: 10, - }, - fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ - tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ - 34: parseVendorListDataV2(t, vendorListData), - }), - }, - } + + perms := allPurposesEnabledPermissions() perms.cfg.HostVendorID = 10 + perms.vendorIDs = map[openrtb_ext.BidderName]uint16{ + openrtb_ext.BidderAppnexus: 2, + openrtb_ext.BidderPubmatic: 6, + openrtb_ext.BidderRubicon: 8, + openrtb_ext.BidderOpenx: 10, + } + perms.fetchVendorList = map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ + tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ + 34: parseVendorListDataV2(t, vendorListData), + }), + } // COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA : full consents to purposes for vendors 2, 6, 8 allowSync, err := perms.HostCookiesAllowed(context.Background(), SignalYes, "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA") @@ -751,67 +783,110 @@ func TestAllowActivitiesBidRequests(t *testing.T) { purpose2AndVendorConsent := "CPF_61ePF_61eFxAAAENAiCAAEAAAAAAAAAAADAQAAAAAA" purpose2ConsentWithoutVendorConsent := "CPF_61ePF_61eFxAAAENAiCAAEAAAAAAAAAAABIAAAAA" + purpose2AndVendorLI := "CPF_61ePF_61eFxAAAENAiCAAAAAAEAAAAAAAAAAIAIAAA" + purpose2LIWithoutVendorLI := "CPF_61ePF_61eFxAAAENAiCAAAAAAEAAAAAAABIAAAAA" + testDefs := []struct { - description string - purpose2Enabled bool - bidder openrtb_ext.BidderName - consent string - allowBid bool - passGeo bool - passID bool - weakVendorEnforcement bool + description string + purpose2Enabled bool + purpose2EnforceVendors bool + bidder openrtb_ext.BidderName + consent string + allowBid bool + passGeo bool + passID bool + weakVendorEnforcement bool }{ { - description: "Bid blocked - p2 enabled, user consents to p2 but not vendor, vendor consents to p2", - purpose2Enabled: true, - bidder: openrtb_ext.BidderPubmatic, - consent: purpose2ConsentWithoutVendorConsent, - allowBid: false, - passGeo: false, - passID: false, + description: "Bid blocked - p2 enabled, user consents to p2 but not vendor, vendor consents to p2", + purpose2Enabled: true, + purpose2EnforceVendors: true, + bidder: openrtb_ext.BidderPubmatic, + consent: purpose2ConsentWithoutVendorConsent, + allowBid: false, + passGeo: false, + passID: false, + }, + { + description: "Bid allowed - p2 enabled not enforcing vendors, user consents to p2 but not vendor, vendor consents to p2", + purpose2Enabled: true, + purpose2EnforceVendors: false, + bidder: openrtb_ext.BidderPubmatic, + consent: purpose2ConsentWithoutVendorConsent, + allowBid: true, + passGeo: false, + passID: true, + }, + { + description: "Bid allowed - p2 disabled, user consents to p2 but not vendor, vendor consents to p2", + purpose2Enabled: false, + purpose2EnforceVendors: true, + bidder: openrtb_ext.BidderPubmatic, + consent: purpose2ConsentWithoutVendorConsent, + allowBid: true, + passGeo: false, + passID: false, + }, + { + description: "Bid allowed - p2 enabled, user consents to p2 and vendor, vendor consents to p2", + purpose2Enabled: true, + purpose2EnforceVendors: true, + bidder: openrtb_ext.BidderPubmatic, + consent: purpose2AndVendorConsent, + allowBid: true, + passGeo: false, + passID: true, + }, + { + description: "Bid blocked - p2 enabled, user consents to p2 LI but not vendor, vendor consents to p2", + purpose2Enabled: true, + purpose2EnforceVendors: true, + bidder: openrtb_ext.BidderRubicon, + consent: purpose2LIWithoutVendorLI, + allowBid: false, + passGeo: false, + passID: false, }, { - description: "Bid allowed - p2 disabled, user consents to p2 but not vendor, vendor consents to p2", - purpose2Enabled: false, - bidder: openrtb_ext.BidderPubmatic, - consent: purpose2ConsentWithoutVendorConsent, - allowBid: true, - passGeo: false, - passID: false, + description: "Bid allowed - p2 enabled, user consents to p2 LI and vendor, vendor consents to p2", + purpose2Enabled: true, + purpose2EnforceVendors: true, + bidder: openrtb_ext.BidderRubicon, + consent: purpose2AndVendorLI, + allowBid: true, + passGeo: false, + passID: true, }, { - description: "Bid allowed - p2 enabled, user consents to p2 and vendor, vendor consents to p2", - purpose2Enabled: true, - bidder: openrtb_ext.BidderPubmatic, - consent: purpose2AndVendorConsent, - allowBid: true, - passGeo: false, - passID: true, + description: "Bid allowed - p2 enabled not enforcing vendors, user consents to p2 LI but not vendor, vendor consents to p2", + purpose2Enabled: true, + purpose2EnforceVendors: false, + bidder: openrtb_ext.BidderPubmatic, + consent: purpose2AndVendorLI, + allowBid: true, + passGeo: false, + passID: true, }, } for _, td := range testDefs { vendorListData := MarshalVendorList(buildVendorList34()) - perms := permissionsImpl{ - cfg: config.GDPR{ - HostVendorID: 2, - TCF2: config.TCF2{ - Enabled: true, - Purpose1: config.TCF2Purpose{Enabled: true}, - Purpose2: config.TCF2Purpose{Enabled: td.purpose2Enabled}, - Purpose7: config.TCF2Purpose{Enabled: true}, - SpecialPurpose1: config.TCF2Purpose{Enabled: true}, - }, - }, - vendorIDs: map[openrtb_ext.BidderName]uint16{ - openrtb_ext.BidderPubmatic: 6, - }, - fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ - tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ - 34: parseVendorListDataV2(t, vendorListData), - }), - }, + + perms := allPurposesEnabledPermissions() + perms.vendorIDs = map[openrtb_ext.BidderName]uint16{ + openrtb_ext.BidderPubmatic: 6, + openrtb_ext.BidderRubicon: 8, + } + perms.fetchVendorList = map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){ + tcf2SpecVersion: listFetcher(map[uint16]vendorlist.VendorList{ + 34: parseVendorListDataV2(t, vendorListData), + }), } + perms.cfg.TCF2.Purpose2.Enabled = td.purpose2Enabled + p2Config := perms.purposeConfigs[consentconstants.Purpose(2)] + p2Config.Enabled = td.purpose2Enabled + p2Config.EnforceVendors = td.purpose2EnforceVendors + perms.purposeConfigs[consentconstants.Purpose(2)] = p2Config allowBid, passGeo, passID, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidder, "", SignalYes, td.consent, td.weakVendorEnforcement) assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description) From efd8dec292882cfcb06f28d6cb557197b2837edd Mon Sep 17 00:00:00 2001 From: bsardo <1168933+bsardo@users.noreply.github.com> Date: Tue, 13 Jul 2021 21:17:04 -0400 Subject: [PATCH 2/2] Update config defaults test with TCF2 object compare --- config/config_test.go | 87 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/config/config_test.go b/config/config_test.go index dfc880bf050..a87d65af359 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -138,18 +138,81 @@ func TestDefaults(t *testing.T) { cmpStrings(t, "stored_requests.filesystem.directorypath", "./stored_requests/data/by_id", cfg.StoredRequests.Files.Path) cmpBools(t, "auto_gen_source_tid", cfg.AutoGenSourceTID, true) cmpBools(t, "generate_bid_id", cfg.GenerateBidID, false) - cmpBools(t, "gdpr.tcf2.purpose_one_treatment.enabled", true, cfg.GDPR.TCF2.PurposeOneTreatment.Enabled) - cmpBools(t, "gdpr.tcf2.purpose_one_treatment.access_allowed", true, cfg.GDPR.TCF2.PurposeOneTreatment.AccessAllowed) - cmpBools(t, "gdpr.tcf2.purpose1.enforce_vendors", cfg.GDPR.TCF2.Purpose1.EnforceVendors, true) - cmpBools(t, "gdpr.tcf2.purpose2.enforce_vendors", cfg.GDPR.TCF2.Purpose2.EnforceVendors, true) - cmpBools(t, "gdpr.tcf2.purpose3.enforce_vendors", cfg.GDPR.TCF2.Purpose3.EnforceVendors, true) - cmpBools(t, "gdpr.tcf2.purpose4.enforce_vendors", cfg.GDPR.TCF2.Purpose4.EnforceVendors, true) - cmpBools(t, "gdpr.tcf2.purpose5.enforce_vendors", cfg.GDPR.TCF2.Purpose5.EnforceVendors, true) - cmpBools(t, "gdpr.tcf2.purpose6.enforce_vendors", cfg.GDPR.TCF2.Purpose6.EnforceVendors, true) - cmpBools(t, "gdpr.tcf2.purpose7.enforce_vendors", cfg.GDPR.TCF2.Purpose7.EnforceVendors, true) - cmpBools(t, "gdpr.tcf2.purpose8.enforce_vendors", cfg.GDPR.TCF2.Purpose8.EnforceVendors, true) - cmpBools(t, "gdpr.tcf2.purpose9.enforce_vendors", cfg.GDPR.TCF2.Purpose9.EnforceVendors, true) - cmpBools(t, "gdpr.tcf2.purpose10.enforce_vendors", cfg.GDPR.TCF2.Purpose10.EnforceVendors, true) + + //Assert purpose VendorExceptionMap hash tables were built correctly + expectedTCF2 := TCF2{ + Enabled: true, + Purpose1: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + Purpose2: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + Purpose3: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + Purpose4: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + Purpose5: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + Purpose6: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + Purpose7: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + Purpose8: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + Purpose9: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + Purpose10: TCF2Purpose{ + Enabled: true, + EnforceVendors: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + SpecialPurpose1: TCF2Purpose{ + Enabled: true, + VendorExceptions: []openrtb_ext.BidderName{}, + VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, + }, + PurposeOneTreatment: TCF2PurposeOneTreatment{ + Enabled: true, + AccessAllowed: true, + }, + } + assert.Equal(t, expectedTCF2, cfg.GDPR.TCF2, "gdpr.tcf2") } var fullConfig = []byte(`