Repository: prebid/prebid-server
Pull request #3083 (2023-09-07 06:13:39)

New adapter: GreedyGame
Docs: https://github.com/prebid/prebid.github.io/pull/4850


Patch:
diff --git a/adapters/huaweiads/huaweiads.go b/adapters/huaweiads/huaweiads.go
index 071f0761..2b7c3c25 100644
--- a/adapters/huaweiads/huaweiads.go
+++ b/adapters/huaweiads/huaweiads.go
@@ -185,6 +185,7 @@ type metaData struct {
 	ApkInfo     apkInfo     `json:"apkInfo"`
 	Duration    int64       `json:"duration"`
 	MediaFile   mediaFile   `json:"mediaFile"`
+	Cta         string      `json:"cta"`
 }
 
 type imageInfo struct {
@@ -535,8 +536,7 @@ func getNativeFormat(adslot30 *adslot30, openRTBImp *openrtb2.Imp) error {
 	// only compute the main image number, type = native1.ImageAssetTypeMain
 	var numMainImage = 0
 	var numVideo = 0
-	var width int64
-	var height int64
+
 	for _, asset := range nativePayload.Assets {
 		// Only one of the {title,img,video,data} objects should be present in each object.
 		if asset.Video != nil {
@@ -547,19 +547,10 @@ func getNativeFormat(adslot30 *adslot30, openRTBImp *openrtb2.Imp) error {
 		if asset.Img != nil {
 			if asset.Img.Type == native1.ImageAssetTypeMain {
 				numMainImage++
-				if asset.Img.H != 0 && asset.Img.W != 0 {
-					width = asset.Img.W
-					height = asset.Img.H
-				} else if asset.Img.WMin != 0 && asset.Img.HMin != 0 {
-					width = asset.Img.WMin
-					height = asset.Img.HMin
-				}
 			}
 			continue
 		}
 	}
-	adslot30.W = width
-	adslot30.H = height
 
 	var detailedCreativeTypeList = make([]string, 0, 2)
 	if numVideo >= 1 {
@@ -1169,6 +1160,11 @@ func (a *adapter) extractAdmNative(adType int32, content *content, bidType openr
 				dataObject.Label = "desc"
 				dataObject.Value = getDecodeValue(content.MetaData.Description)
 			}
+
+			if asset.Data.Type == native1.DataAssetTypeCTAText {
+				dataObject.Type = native1.DataAssetTypeCTAText
+				dataObject.Value = getDecodeValue(content.MetaData.Cta)
+			}
 			responseAsset.Data = &dataObject
 		}
 		var id = asset.ID
diff --git a/adapters/response.go b/adapters/response.go
index 080f4627..8b7d59bd 100644
--- a/adapters/response.go
+++ b/adapters/response.go
@@ -15,7 +15,9 @@ func CheckResponseStatusCodeForErrors(response *ResponseData) error {
 	}
 
 	if response.StatusCode != http.StatusOK {
-		return fmt.Errorf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode)
+		return &errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode),
+		}
 	}
 
 	return nil
diff --git a/adapters/sovrn/sovrn.go b/adapters/sovrn/sovrn.go
index 24022490..405e5ebf 100644
--- a/adapters/sovrn/sovrn.go
+++ b/adapters/sovrn/sovrn.go
@@ -20,6 +20,11 @@ type SovrnAdapter struct {
 	URI string
 }
 
+type sovrnImpExt struct {
+	Bidder     openrtb_ext.ExtImpSovrn `json:"bidder"`
+	AdUnitCode string                  `json:"adunitcode,omitempty"`
+}
+
 func (s *SovrnAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
 	headers := http.Header{}
 	headers.Add("Content-Type", "application/json")
@@ -74,6 +79,20 @@ func (s *SovrnAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapt
 			imp.BidFloor = sovrnExt.BidFloor
 		}
 
+		var impExtBuffer []byte
+		impExtBuffer, err = json.Marshal(&sovrnImpExt{
+			Bidder:     sovrnExt,
+			AdUnitCode: sovrnExt.AdUnitCode,
+		})
+		if err != nil {
+			errs = append(errs, &errortypes.BadInput{
+				Message: err.Error(),
+			})
+			continue
+		}
+
+		imp.Ext = impExtBuffer
+
 		// Validate video params if appropriate
 		video := imp.Video
 		if video != nil {
diff --git a/adapters/undertone/undertone.go b/adapters/undertone/undertone.go
index 62934fa5..7f8dde35 100644
--- a/adapters/undertone/undertone.go
+++ b/adapters/undertone/undertone.go
@@ -26,6 +26,11 @@ type undertoneParams struct {
 	Version string `json:"version"`
 }
 
+type impExt struct {
+	Bidder *openrtb_ext.ExtImpUndertone `json:"bidder,omitempty"`
+	Gpid   string                       `json:"gpid,omitempty"`
+}
+
 func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
 	bidder := &adapter{
 		endpoint: config.Endpoint,
@@ -158,24 +163,29 @@ func getImpsAndPublisherId(bidRequest *openrtb2.BidRequest) ([]openrtb2.Imp, int
 	var validImps []openrtb2.Imp
 
 	for _, imp := range bidRequest.Imp {
-		var extImpBidder adapters.ExtImpBidder
-		if err := json.Unmarshal(imp.Ext, &extImpBidder); err != nil {
-			errs = append(errs, getInvalidImpErr(imp.ID, err))
-			continue
-		}
-
-		var extImpUndertone openrtb_ext.ExtImpUndertone
-		if err := json.Unmarshal(extImpBidder.Bidder, &extImpUndertone); err != nil {
+		var ext impExt
+		if err := json.Unmarshal(imp.Ext, &ext); err != nil {
 			errs = append(errs, getInvalidImpErr(imp.ID, err))
 			continue
 		}
 
 		if publisherId == 0 {
-			publisherId = extImpUndertone.PublisherID
+			publisherId = ext.Bidder.PublisherID
 		}
 
-		imp.TagID = strconv.Itoa(extImpUndertone.PlacementID)
+		imp.TagID = strconv.Itoa(ext.Bidder.PlacementID)
 		imp.Ext = nil
+
+		if ext.Gpid != "" {
+			ext.Bidder = nil
+			impExtJson, err := json.Marshal(&ext)
+			if err != nil {
+				errs = append(errs, getInvalidImpErr(imp.ID, err))
+				continue
+			}
+			imp.Ext = impExtJson
+		}
+
 		validImps = append(validImps, imp)
 	}
 
diff --git a/endpoints/cookie_sync.go b/endpoints/cookie_sync.go
index 50cb4491..0321fea3 100644
--- a/endpoints/cookie_sync.go
+++ b/endpoints/cookie_sync.go
@@ -149,12 +149,7 @@ func (c *cookieSyncEndpoint) parseRequest(r *http.Request) (usersync.Request, pr
 		}
 	}
 
-	activityControl, activitiesErr := privacy.NewActivityControl(&account.Privacy)
-	if activitiesErr != nil {
-		if errortypes.ContainsFatalError([]error{activitiesErr}) {
-			activityControl = privacy.ActivityControl{}
-		}
-	}
+	activityControl := privacy.NewActivityControl(&account.Privacy)
 
 	syncTypeFilter, err := parseTypeFilter(request.FilterSettings)
 	if err != nil {
diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go
index 142f7320..2879610d 100644
--- a/endpoints/openrtb2/amp_auction.go
+++ b/endpoints/openrtb2/amp_auction.go
@@ -6,12 +6,13 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"github.com/prebid/prebid-server/privacy"
 	"net/http"
 	"net/url"
 	"strings"
 	"time"
 
+	"github.com/prebid/prebid-server/privacy"
+
 	"github.com/buger/jsonparser"
 	"github.com/golang/glog"
 	"github.com/julienschmidt/httprouter"
@@ -229,12 +230,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
 
 	tcf2Config := gdpr.NewTCF2Config(deps.cfg.GDPR.TCF2, account.GDPR)
 
-	activities, activitiesErr := privacy.NewActivityControl(&account.Privacy)
-	if activitiesErr != nil {
-		errL = append(errL, activitiesErr)
-		writeError(errL, w, &labels)
-		return
-	}
+	activityControl := privacy.NewActivityControl(&account.Privacy)
 
 	secGPC := r.Header.Get("Sec-GPC")
 
@@ -253,7 +249,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h
 		HookExecutor:               hookExecutor,
 		QueryParams:                r.URL.Query(),
 		TCF2Config:                 tcf2Config,
-		Activities:                 activities,
+		Activities:                 activityControl,
 		TmaxAdjustments:            deps.tmaxAdjustments,
 	}
 
diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go
index 6fe5aab9..aeb5c20e 100644
--- a/endpoints/openrtb2/auction.go
+++ b/endpoints/openrtb2/auction.go
@@ -194,14 +194,7 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http
 
 	tcf2Config := gdpr.NewTCF2Config(deps.cfg.GDPR.TCF2, account.GDPR)
 
-	activities, activitiesErr := privacy.NewActivityControl(&account.Privacy)
-	if activitiesErr != nil {
-		errL = append(errL, activitiesErr)
-		if errortypes.ContainsFatalError(errL) {
-			writeError(errL, w, &labels)
-			return
-		}
-	}
+	activityControl := privacy.NewActivityControl(&account.Privacy)
 
 	ctx := context.Background()
 
@@ -252,7 +245,7 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http
 		PubID:                      labels.PubID,
 		HookExecutor:               hookExecutor,
 		TCF2Config:                 tcf2Config,
-		Activities:                 activities,
+		Activities:                 activityControl,
 		TmaxAdjustments:            deps.tmaxAdjustments,
 	}
 	auctionResponse, err := deps.ex.HoldAuction(ctx, auctionRequest, nil)
diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go
index 5f848446..a2a519fa 100644
--- a/endpoints/openrtb2/video_auction.go
+++ b/endpoints/openrtb2/video_auction.go
@@ -303,14 +303,7 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
 		return
 	}
 
-	activities, activitiesErr := privacy.NewActivityControl(&account.Privacy)
-	if activitiesErr != nil {
-		errL = append(errL, activitiesErr)
-		if errortypes.ContainsFatalError(errL) {
-			handleError(&labels, w, errL, &vo, &debugLog)
-			return
-		}
-	}
+	activityControl := privacy.NewActivityControl(&account.Privacy)
 
 	secGPC := r.Header.Get("Sec-GPC")
 	auctionRequest := &exchange.AuctionRequest{
@@ -324,7 +317,7 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re
 		PubID:                      labels.PubID,
 		HookExecutor:               hookexecution.EmptyHookExecutor{},
 		TmaxAdjustments:            deps.tmaxAdjustments,
-		Activities:                 activities,
+		Activities:                 activityControl,
 	}
 
 	auctionResponse, err := deps.ex.HoldAuction(ctx, auctionRequest, &debugLog)
diff --git a/endpoints/setuid.go b/endpoints/setuid.go
index 30a1cce2..b9023cfc 100644
--- a/endpoints/setuid.go
+++ b/endpoints/setuid.go
@@ -104,14 +104,9 @@ func NewSetUIDEndpoint(cfg *config.Configuration, syncersByBidder map[string]use
 			return
 		}
 
-		activities, activitiesErr := privacy.NewActivityControl(&account.Privacy)
-		if activitiesErr != nil {
-			if errortypes.ContainsFatalError([]error{activitiesErr}) {
-				activities = privacy.ActivityControl{}
-			}
-		}
+		activityControl := privacy.NewActivityControl(&account.Privacy)
 
-		userSyncActivityAllowed := activities.Allow(privacy.ActivitySyncUser,
+		userSyncActivityAllowed := activityControl.Allow(privacy.ActivitySyncUser,
 			privacy.Component{Type: privacy.ComponentTypeBidder, Name: bidderName})
 		if !userSyncActivityAllowed {
 			w.WriteHeader(http.StatusUnavailableForLegalReasons)
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index 84b1f1af..c5e9dc49 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -230,6 +230,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderApacdex:           apacdex.Builder,
 		openrtb_ext.BidderApplogy:           applogy.Builder,
 		openrtb_ext.BidderAppnexus:          appnexus.Builder,
+		openrtb_ext.BidderAppstock:          limelightDigital.Builder,
 		openrtb_ext.BidderAppush:            appush.Builder,
 		openrtb_ext.BidderAudienceNetwork:   audienceNetwork.Builder,
 		openrtb_ext.BidderAutomatad:         automatad.Builder,
@@ -286,6 +287,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderGamoshi:           gamoshi.Builder,
 		openrtb_ext.BidderGlobalsun:         globalsun.Builder,
 		openrtb_ext.BidderGothamads:         gothamads.Builder,
+		openrtb_ext.BidderGreedygame:        limelightDigital.Builder,
 		openrtb_ext.BidderGrid:              grid.Builder,
 		openrtb_ext.BidderGumGum:            gumgum.Builder,
 		openrtb_ext.BidderHuaweiAds:         huaweiads.Builder,
diff --git a/hooks/hookexecution/executor.go b/hooks/hookexecution/executor.go
index ce516630..5074d4b9 100644
--- a/hooks/hookexecution/executor.go
+++ b/hooks/hookexecution/executor.go
@@ -160,7 +160,7 @@ func (e *hookExecutor) ExecuteProcessedAuctionStage(request *openrtb_ext.Request
 
 	stageName := hooks.StageProcessedAuctionRequest.String()
 	executionCtx := e.newContext(stageName)
-	payload := hookstage.ProcessedAuctionRequestPayload{BidRequest: request.BidRequest}
+	payload := hookstage.ProcessedAuctionRequestPayload{RequestWrapper: request}
 
 	outcome, _, contexts, reject := executeStage(executionCtx, plan, payload, handler, e.metricEngine)
 	outcome.Entity = entityAuctionRequest
diff --git a/hooks/hookstage/processedauctionrequest.go b/hooks/hookstage/processedauctionrequest.go
index 30cb0dab..fe06bc6f 100644
--- a/hooks/hookstage/processedauctionrequest.go
+++ b/hooks/hookstage/processedauctionrequest.go
@@ -3,7 +3,7 @@ package hookstage
 import (
 	"context"
 
-	"github.com/prebid/openrtb/v19/openrtb2"
+	"github.com/prebid/prebid-server/openrtb_ext"
 )
 
 // ProcessedAuctionRequest hooks are invoked after the request is parsed
@@ -23,8 +23,8 @@ type ProcessedAuctionRequest interface {
 	) (HookResult[ProcessedAuctionRequestPayload], error)
 }
 
-// ProcessedAuctionRequestPayload consists of the openrtb2.BidRequest object.
-// Hooks are allowed to modify openrtb2.BidRequest using mutations.
+// ProcessedAuctionRequestPayload consists of the openrtb_ext.RequestWrapper object.
+// Hooks are allowed to modify openrtb_ext.RequestWrapper using mutations.
 type ProcessedAuctionRequestPayload struct {
-	BidRequest *openrtb2.BidRequest
+	RequestWrapper *openrtb_ext.RequestWrapper
 }
diff --git a/openrtb_ext/bid.go b/openrtb_ext/bid.go
index 85cfed5c..2e190389 100644
--- a/openrtb_ext/bid.go
+++ b/openrtb_ext/bid.go
@@ -67,6 +67,7 @@ type ExtBidPrebidMeta struct {
 	RendererName         string          `json:"rendererName,omitempty"`
 	RendererVersion      string          `json:"rendererVersion,omitempty"`
 	RendererData         json.RawMessage `json:"rendererData,omitempty"`
+	RendererUrl          string          `json:"rendererUrl,omitempty"`
 	SecondaryCategoryIDs []string        `json:"secondaryCatIds,omitempty"`
 }
 
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index c60058eb..11f01988 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -54,6 +54,7 @@ var coreBidderNames []BidderName = []BidderName{
 	BidderApacdex,
 	BidderApplogy,
 	BidderAppnexus,
+	BidderAppstock,
 	BidderAppush,
 	BidderAudienceNetwork,
 	BidderAutomatad,
@@ -110,6 +111,7 @@ var coreBidderNames []BidderName = []BidderName{
 	BidderGamoshi,
 	BidderGlobalsun,
 	BidderGothamads,
+	BidderGreedygame,
 	BidderGrid,
 	BidderGumGum,
 	BidderHuaweiAds,
@@ -345,6 +347,7 @@ const (
 	BidderApacdex           BidderName = "apacdex"
 	BidderApplogy           BidderName = "applogy"
 	BidderAppnexus          BidderName = "appnexus"
+	BidderAppstock          BidderName = "appstock"
 	BidderAppush            BidderName = "appush"
 	BidderAudienceNetwork   BidderName = "audienceNetwork"
 	BidderAutomatad         BidderName = "automatad"
@@ -401,6 +404,7 @@ const (
 	BidderGamoshi           BidderName = "gamoshi"
 	BidderGlobalsun         BidderName = "globalsun"
 	BidderGothamads         BidderName = "gothamads"
+	BidderGreedygame        BidderName = "greedygame"
 	BidderGrid              BidderName = "grid"
 	BidderGumGum            BidderName = "gumgum"
 	BidderHuaweiAds         BidderName = "huaweiads"
diff --git a/openrtb_ext/imp_sovrn.go b/openrtb_ext/imp_sovrn.go
index 38d2f785..362463f9 100644
--- a/openrtb_ext/imp_sovrn.go
+++ b/openrtb_ext/imp_sovrn.go
@@ -1,7 +1,8 @@
 package openrtb_ext
 
 type ExtImpSovrn struct {
-	TagId    string  `json:"tagId,omitempty"`
-	Tagid    string  `json:"tagid,omitempty"`
-	BidFloor float64 `json:"bidfloor"`
+	TagId      string  `json:"tagId,omitempty"`
+	Tagid      string  `json:"tagid,omitempty"`
+	BidFloor   float64 `json:"bidfloor,omitempty"`
+	AdUnitCode string  `json:"adunitcode,omitempty"`
 }
diff --git a/privacy/activitycontrol.go b/privacy/activitycontrol.go
index 5d68ce71..33c138f7 100644
--- a/privacy/activitycontrol.go
+++ b/privacy/activitycontrol.go
@@ -18,66 +18,35 @@ type ActivityControl struct {
 	plans map[Activity]ActivityPlan
 }
 
-func NewActivityControl(privacyConf *config.AccountPrivacy) (ActivityControl, error) {
+func NewActivityControl(cfg *config.AccountPrivacy) ActivityControl {
 	ac := ActivityControl{}
-	var err error
 
-	if privacyConf == nil || privacyConf.AllowActivities == nil {
-		return ac, nil
-	}
-
-	plans := make(map[Activity]ActivityPlan)
-
-	plans[ActivitySyncUser], err = buildEnforcementPlan(privacyConf.AllowActivities.SyncUser)
-	if err != nil {
-		return ac, err
-	}
-	plans[ActivityFetchBids], err = buildEnforcementPlan(privacyConf.AllowActivities.FetchBids)
-	if err != nil {
-		return ac, err
-	}
-	plans[ActivityEnrichUserFPD], err = buildEnforcementPlan(privacyConf.AllowActivities.EnrichUserFPD)
-	if err != nil {
-		return ac, err
-	}
-	plans[ActivityReportAnalytics], err = buildEnforcementPlan(privacyConf.AllowActivities.ReportAnalytics)
-	if err != nil {
-		return ac, err
-	}
-	plans[ActivityTransmitUserFPD], err = buildEnforcementPlan(privacyConf.AllowActivities.TransmitUserFPD)
-	if err != nil {
-		return ac, err
-	}
-	plans[ActivityTransmitPreciseGeo], err = buildEnforcementPlan(privacyConf.AllowActivities.TransmitPreciseGeo)
-	if err != nil {
-		return ac, err
-	}
-	plans[ActivityTransmitUniqueRequestIds], err = buildEnforcementPlan(privacyConf.AllowActivities.TransmitUniqueRequestIds)
-	if err != nil {
-		return ac, err
-	}
-	plans[ActivityTransmitTids], err = buildEnforcementPlan(privacyConf.AllowActivities.TransmitTids)
-	if err != nil {
-		return ac, err
+	if cfg == nil || cfg.AllowActivities == nil {
+		return ac
 	}
 
+	plans := make(map[Activity]ActivityPlan, 8)
+	plans[ActivitySyncUser] = buildPlan(cfg.AllowActivities.SyncUser)
+	plans[ActivityFetchBids] = buildPlan(cfg.AllowActivities.FetchBids)
+	plans[ActivityEnrichUserFPD] = buildPlan(cfg.AllowActivities.EnrichUserFPD)
+	plans[ActivityReportAnalytics] = buildPlan(cfg.AllowActivities.ReportAnalytics)
+	plans[ActivityTransmitUserFPD] = buildPlan(cfg.AllowActivities.TransmitUserFPD)
+	plans[ActivityTransmitPreciseGeo] = buildPlan(cfg.AllowActivities.TransmitPreciseGeo)
+	plans[ActivityTransmitUniqueRequestIds] = buildPlan(cfg.AllowActivities.TransmitUniqueRequestIds)
+	plans[ActivityTransmitTids] = buildPlan(cfg.AllowActivities.TransmitTids)
 	ac.plans = plans
 
-	return ac, nil
+	return ac
 }
 
-func buildEnforcementPlan(activity config.Activity) (ActivityPlan, error) {
-	ef := ActivityPlan{}
-	rules, err := activityRulesToEnforcementRules(activity.Rules)
-	if err != nil {
-		return ef, err
+func buildPlan(activity config.Activity) ActivityPlan {
+	return ActivityPlan{
+		rules:         cfgToRules(activity.Rules),
+		defaultResult: cfgToDefaultResult(activity.Default),
 	}
-	ef.defaultResult = activityDefaultToDefaultResult(activity.Default)
-	ef.rules = rules
-	return ef, nil
 }
 
-func activityRulesToEnforcementRules(rules []config.ActivityRule) ([]Rule, error) {
+func cfgToRules(rules []config.ActivityRule) []Rule {
 	var enfRules []Rule
 
 	for _, r := range rules {
@@ -88,34 +57,17 @@ func activityRulesToEnforcementRules(rules []config.ActivityRule) ([]Rule, error
 			result = ActivityDeny
 		}
 
-		componentName, err := conditionToRuleComponentNames(r.Condition.ComponentName)
-		if err != nil {
-			return nil, err
-		}
-
-		er := ComponentEnforcementRule{
+		er := ConditionRule{
 			result:        result,
-			componentName: componentName,
+			componentName: r.Condition.ComponentName,
 			componentType: r.Condition.ComponentType,
 		}
 		enfRules = append(enfRules, er)
 	}
-	return enfRules, nil
-}
-
-func conditionToRuleComponentNames(conditions []string) ([]Component, error) {
-	sn := make([]Component, 0)
-	for _, condition := range conditions {
-		scope, err := ParseComponent(condition)
-		if err != nil {
-			return nil, err
-		}
-		sn = append(sn, scope)
-	}
-	return sn, nil
+	return enfRules
 }
 
-func activityDefaultToDefaultResult(activityDefault *bool) bool {
+func cfgToDefaultResult(activityDefault *bool) bool {
 	if activityDefault == nil {
 		return defaultActivityResult
 	}
diff --git a/privacy/component.go b/privacy/component.go
index a203c6bd..33767938 100644
--- a/privacy/component.go
+++ b/privacy/component.go
@@ -1,8 +1,6 @@
 package privacy
 
 import (
-	"errors"
-	"fmt"
 	"strings"
 )
 
@@ -18,48 +16,10 @@ type Component struct {
 	Name string
 }
 
-func (c Component) Matches(target Component) bool {
-	return strings.EqualFold(c.Type, target.Type) && (c.Name == "*" || strings.EqualFold(c.Name, target.Name))
+func (c Component) MatchesName(v string) bool {
+	return strings.EqualFold(c.Name, v)
 }
 
-var ErrComponentEmpty = errors.New("unable to parse empty component")
-
-func ParseComponent(v string) (Component, error) {
-	if len(v) == 0 {
-		return Component{}, ErrComponentEmpty
-	}
-
-	split := strings.Split(v, ".")
-
-	if len(split) == 2 {
-		if !validComponentType(split[0]) {
-			return Component{}, fmt.Errorf("unable to parse component (invalid type): %s", v)
-		}
-		return Component{
-			Type: split[0],
-			Name: split[1],
-		}, nil
-	}
-
-	if len(split) == 1 {
-		return Component{
-			Type: ComponentTypeBidder,
-			Name: split[0],
-		}, nil
-	}
-
-	return Component{}, fmt.Errorf("unable to parse component: %s", v)
-}
-
-func validComponentType(t string) bool {
-	t = strings.ToLower(t)
-
-	if t == ComponentTypeBidder ||
-		t == ComponentTypeAnalytics ||
-		t == ComponentTypeRealTimeData ||
-		t == ComponentTypeGeneral {
-		return true
-	}
-
-	return false
+func (c Component) MatchesType(v string) bool {
+	return strings.EqualFold(c.Type, v)
 }
diff --git a/privacy/rule.go b/privacy/rule.go
new file mode 100644
index 00000000..47d0913c
--- /dev/null
+++ b/privacy/rule.go
@@ -0,0 +1,5 @@
+package privacy
+
+type Rule interface {
+	Evaluate(target Component) ActivityResult
+}
diff --git a/privacy/rules.go b/privacy/rule_condition.go
similarity index 64%
rename from privacy/rules.go
rename to privacy/rule_condition.go
index 502e10ef..705543e5 100644
--- a/privacy/rules.go
+++ b/privacy/rule_condition.go
@@ -1,20 +1,12 @@
 package privacy
 
-import (
-	"strings"
-)
-
-type Rule interface {
-	Evaluate(target Component) ActivityResult
-}
-
-type ComponentEnforcementRule struct {
+type ConditionRule struct {
 	result        ActivityResult
-	componentName []Component
+	componentName []string
 	componentType []string
 }
 
-func (r ComponentEnforcementRule) Evaluate(target Component) ActivityResult {
+func (r ConditionRule) Evaluate(target Component) ActivityResult {
 	if matched := evaluateComponentName(target, r.componentName); !matched {
 		return ActivityAbstain
 	}
@@ -26,7 +18,7 @@ func (r ComponentEnforcementRule) Evaluate(target Component) ActivityResult {
 	return r.result
 }
 
-func evaluateComponentName(target Component, componentNames []Component) bool {
+func evaluateComponentName(target Component, componentNames []string) bool {
 	// no clauses are considered a match
 	if len(componentNames) == 0 {
 		return true
@@ -34,7 +26,7 @@ func evaluateComponentName(target Component, componentNames []Component) bool {
 
 	// if there are clauses, at least one needs to match
 	for _, n := range componentNames {
-		if n.Matches(target) {
+		if target.MatchesName(n) {
 			return true
 		}
 	}
@@ -49,8 +41,8 @@ func evaluateComponentType(target Component, componentTypes []string) bool {
 	}
 
 	// if there are clauses, at least one needs to match
-	for _, s := range componentTypes {
-		if strings.EqualFold(s, target.Type) {
+	for _, t := range componentTypes {
+		if target.MatchesType(t) {
 			return true
 		}
 	}
diff --git a/static/bidder-info/appstock.yaml b/static/bidder-info/appstock.yaml
new file mode 100644
index 00000000..28f420e9
--- /dev/null
+++ b/static/bidder-info/appstock.yaml
@@ -0,0 +1,16 @@
+endpoint: "http://ads-pbs.pre.vr-tb.com/openrtb/{{.PublisherID}}?host={{.Host}}"
+maintainer:
+  email: "engineering@project-limelight.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - audio
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - audio
+      - native
diff --git a/static/bidder-info/greedygame.yaml b/static/bidder-info/greedygame.yaml
new file mode 100644
index 00000000..5e73e1fe
--- /dev/null
+++ b/static/bidder-info/greedygame.yaml
@@ -0,0 +1,16 @@
+endpoint: "http://ads-pbs.rtb-greedygame.com/openrtb/{{.PublisherID}}?host={{.Host}}"
+maintainer:
+  email: "engineering@project-limelight.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - audio
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - audio
+      - native
diff --git a/static/bidder-params/appstock.json b/static/bidder-params/appstock.json
new file mode 100644
index 00000000..eb2251e4
--- /dev/null
+++ b/static/bidder-params/appstock.json
@@ -0,0 +1,23 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Appstock Adapter Params",
+  "description": "A schema which validates params accepted by the Appstock adapter",
+  "type": "object",
+
+  "properties": {
+    "host": {
+      "type": "string",
+      "description": "Ad network's RTB host",
+      "format": "hostname",
+      "pattern": "^.+\\..+$"
+    },
+    "publisherId": {
+      "type": ["integer", "string"],
+      "description": "Publisher ID",
+      "minimum": 1,
+      "pattern": "^[1-9][0-9]*$"
+    }
+  },
+
+  "required": ["host", "publisherId"]
+}
diff --git a/static/bidder-params/greedygame.json b/static/bidder-params/greedygame.json
new file mode 100644
index 00000000..2057c147
--- /dev/null
+++ b/static/bidder-params/greedygame.json
@@ -0,0 +1,23 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "GreedyGame Adapter Params",
+  "description": "A schema which validates params accepted by the GreedyGame adapter",
+  "type": "object",
+
+  "properties": {
+    "host": {
+      "type": "string",
+      "description": "Ad network's RTB host",
+      "format": "hostname",
+      "pattern": "^.+\\..+$"
+    },
+    "publisherId": {
+      "type": ["integer", "string"],
+      "description": "Publisher ID",
+      "minimum": 1,
+      "pattern": "^[1-9][0-9]*$"
+    }
+  },
+
+  "required": ["host", "publisherId"]
+}
diff --git a/static/bidder-params/sovrn.json b/static/bidder-params/sovrn.json
index 6b345b55..d821a808 100644
--- a/static/bidder-params/sovrn.json
+++ b/static/bidder-params/sovrn.json
@@ -16,6 +16,10 @@
     "bidfloor": {
       "type": "number",
       "description": "The minimium acceptable bid, in CPM, using US Dollars"
+    },
+    "adunitcode": {
+      "type": "string",
+      "description": "The string which identifies Ad Unit"
     }
   },
   "oneOf": [


Test patch:
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json
index 8a7ca1b0..24aad066 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeIncludeVideo.json
@@ -95,9 +95,7 @@
               "detailedCreativeTypeList": [
                 "903"
               ],
-              "h": 200,
-              "test": 1,
-              "w": 200
+              "test": 1
             }
           ],
           "device": {
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json
index 240098e0..8e86675b 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeSingleImage.json
@@ -5,7 +5,7 @@
       {
         "id": "test-imp-id",
         "native": {
-          "request": "{\"context\":2,\"contextsubtype\":20,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"aurlsupport\":0,\"durlsupport\":0,\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}],\"privacy\":0,\"assets\":[{\"id\":100,\"title\":{\"len\":90},\"required\":1},{\"id\":103,\"img\":{\"type\":3,\"wmin\":200,\"hmin\":200},\"required\":1},{\"id\":105,\"data\":{\"type\":2,\"len\":90},\"required\":1}],\"ver\":\"1.2\"}",
+          "request": "{\"context\":2,\"contextsubtype\":20,\"plcmttype\":1,\"plcmtcnt\":1,\"seq\":0,\"aurlsupport\":0,\"durlsupport\":0,\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}],\"privacy\":0,\"assets\":[{\"id\":101,\"title\":{\"len\":90},\"required\":1},{\"id\":102,\"img\":{\"type\":3,\"wmin\":200,\"hmin\":200},\"required\":1},{\"id\":103,\"data\":{\"type\":2,\"len\":90},\"required\":1},{\"id\":105,\"data\":{\"type\":12,\"len\":90}}],\"ver\":\"1.2\"}",
           "ver": "1.2"
         },
         "ext": {
@@ -93,9 +93,7 @@
               "detailedCreativeTypeList": [
                 "901"
               ],
-              "h": 200,
-              "test": 1,
-              "w": 200
+              "test": 1
             }
           ],
           "device": {
@@ -166,6 +164,7 @@
                     "appId": "101219405",
                     "appPromotionChannel": "401721412",
                     "clickUrl": "https://ads.huawei.com/usermgtportal/home/index.html#/",
+                    "cta": "install",
                     "duration": 6038,
                     "description": "",
                     "icon": [
@@ -300,7 +299,7 @@
               "huaweiads"
             ],
             "crid": "58022259",
-            "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":100,\"title\":{\"text\":\"/test/\",\"len\":6}},{\"id\":103,\"img\":{\"type\":3,\"url\":\"http://image.jpg\",\"w\":720,\"h\":1280}},{\"id\":105,\"data\":{\"label\":\"desc\",\"value\":\"\"}}],\"link\":{\"url\":\"https://ads.huawei.com/usermgtportal/home/index.html#/\",\"clicktrackers\":[\"http://test/click\"]},\"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"http://test/imp\"}]}",
+            "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":101,\"title\":{\"text\":\"/test/\",\"len\":6}},{\"id\":102,\"img\":{\"type\":3,\"url\":\"http://image.jpg\",\"w\":720,\"h\":1280}},{\"id\":103,\"data\":{\"label\":\"desc\",\"value\":\"\"}},{\"id\":105,\"data\":{\"type\":12,\"value\":\"install\"}}],\"link\":{\"url\":\"https://ads.huawei.com/usermgtportal/home/index.html#/\",\"clicktrackers\":[\"http://test/click\"]},\"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"http://test/imp\"}]}",
             "id": "test-imp-id",
             "impid": "test-imp-id",
             "price": 2.8,
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json
index 9b46072d..c29b2352 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImage.json
@@ -92,9 +92,7 @@
               "detailedCreativeTypeList": [
                 "904"
               ],
-              "h": 200,
-              "test": 1,
-              "w": 200
+              "test": 1
             }
           ],
           "device": {
diff --git a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json
index f78f50e2..5d3af506 100644
--- a/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json
+++ b/adapters/huaweiads/huaweiadstest/exemplary/nativeThreeImageIncludeIcon.json
@@ -93,9 +93,7 @@
               "detailedCreativeTypeList": [
                 "904"
               ],
-              "h": 200,
-              "test": 1,
-              "w": 200
+              "test": 1
             }
           ],
           "device": {
diff --git a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_not_native.json b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_not_native.json
index c38bc9f6..14667370 100644
--- a/adapters/huaweiads/huaweiadstest/supplemental/bad_response_not_native.json
+++ b/adapters/huaweiads/huaweiadstest/supplemental/bad_response_not_native.json
@@ -93,9 +93,7 @@
               "test": 1,
               "detailedCreativeTypeList": [
                 "903"
-              ],
-              "h": 200,
-              "w": 200
+              ]
             }
           ],
           "device": {
diff --git a/adapters/response_test.go b/adapters/response_test.go
index 824a295e..0651ff26 100644
--- a/adapters/response_test.go
+++ b/adapters/response_test.go
@@ -8,17 +8,33 @@ import (
 )
 
 func TestCheckResponseStatusCodeForErrors(t *testing.T) {
-	t.Run("bad_input", func(t *testing.T) {
-		err := CheckResponseStatusCodeForErrors(&ResponseData{StatusCode: 400})
-		expectedErr := &errortypes.BadInput{Message: "Unexpected status code: 400. Run with request.debug = 1 for more info"}
-		assert.Equal(t, expectedErr.Error(), err.Error())
-	})
+	testCases := []struct {
+		name           string
+		responseStatus int
+		expectedErr    error
+	}{
+		{
+			name:           "bad_input",
+			responseStatus: 400,
+			expectedErr: &errortypes.BadInput{
+				Message: "Unexpected status code: 400. Run with request.debug = 1 for more info",
+			},
+		},
+		{
+			name:           "internal_server_error",
+			responseStatus: 500,
+			expectedErr: &errortypes.BadServerResponse{
+				Message: "Unexpected status code: 500. Run with request.debug = 1 for more info",
+			},
+		},
+	}
 
-	t.Run("internal_server_error", func(t *testing.T) {
-		err := CheckResponseStatusCodeForErrors(&ResponseData{StatusCode: 500})
-		expectedErrMessage := "Unexpected status code: 500. Run with request.debug = 1 for more info"
-		assert.Equal(t, expectedErrMessage, err.Error())
-	})
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			err := CheckResponseStatusCodeForErrors(&ResponseData{StatusCode: tc.responseStatus})
+			assert.Equal(t, tc.expectedErr, err)
+		})
+	}
 }
 
 func TestIsResponseStatusCodeNoContent(t *testing.T) {
diff --git a/adapters/sovrn/sovrntest/supplemental/adunitcode.json b/adapters/sovrn/sovrntest/supplemental/adunitcode.json
new file mode 100644
index 00000000..47197520
--- /dev/null
+++ b/adapters/sovrn/sovrntest/supplemental/adunitcode.json
@@ -0,0 +1,125 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "tagid": "123456",
+            "adunitcode": "sovrn_auc"
+          }
+        }
+      }
+    ],
+    "device": { },
+    "site": {
+      "domain": "www.publisher.com",
+      "page": "http://www.publisher.com/awesome/site"
+    },
+    "user": {
+      "buyeruid": "test_reader_id"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": ["application/json"],
+          "Cookie": ["ljt_reader=test_reader_id"]
+        },
+        "uri": "http://sovrn.com/test/endpoint",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "tagid": "123456",
+              "ext": {
+                "adunitcode": "sovrn_auc",
+                "bidder": {
+                  "tagid": "123456",
+                  "adunitcode": "sovrn_auc"
+                }
+              }
+            }
+          ],
+          "site": {
+            "domain": "www.publisher.com",
+            "page": "http://www.publisher.com/awesome/site"
+          },
+          "user": {
+            "buyeruid": "test_reader_id"
+          },
+          "device": { }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a_449642_554a13d3b9f348fba707cf83f0f63800",
+                  "impid": "test-imp-id",
+                  "price": 3.5,
+                  "nurl": "http://sovrn.com/rtb/impression?bannerid=138743&campaignid=3699&zoneid=449642&cb=69493397&tid=a_449642_554a13d3b9f348fba707cf83f0f63800",
+                  "adm": "some-test-ad",
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "a_449642_554a13d3b9f348fba707cf83f0f63800",
+            "impid": "test-imp-id",
+            "price": 3.5,
+            "adm": "some-test-ad",
+            "nurl": "http://sovrn.com/rtb/impression?bannerid=138743&campaignid=3699&zoneid=449642&cb=69493397&tid=a_449642_554a13d3b9f348fba707cf83f0f63800",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/sovrn/sovrntest/supplemental/fpd.json b/adapters/sovrn/sovrntest/supplemental/fpd.json
index 005d159d..e4368c13 100644
--- a/adapters/sovrn/sovrntest/supplemental/fpd.json
+++ b/adapters/sovrn/sovrntest/supplemental/fpd.json
@@ -86,8 +86,7 @@
               "tagid": "123456",
               "ext": {
                 "bidder": {
-                  "tagid": "123456",
-                  "anotherid": "654321"
+                  "tagid": "123456"
                 }
               }
             }
diff --git a/adapters/sovrn/sovrntest/supplemental/invalid-adunitcode.json b/adapters/sovrn/sovrntest/supplemental/invalid-adunitcode.json
new file mode 100644
index 00000000..fdb14371
--- /dev/null
+++ b/adapters/sovrn/sovrntest/supplemental/invalid-adunitcode.json
@@ -0,0 +1,123 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            },
+            {
+              "w": 300,
+              "h": 600
+            }
+          ]
+        },
+        "ext": {
+          "AdUnitCode": "sovrn_auc",
+          "bidder": {
+            "tagid": "123456"
+          }
+        }
+      }
+    ],
+    "device": { },
+    "site": {
+      "domain": "www.publisher.com",
+      "page": "http://www.publisher.com/awesome/site"
+    },
+    "user": {
+      "buyeruid": "test_reader_id"
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "headers": {
+          "Content-Type": ["application/json"],
+          "Cookie": ["ljt_reader=test_reader_id"]
+        },
+        "uri": "http://sovrn.com/test/endpoint",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  },
+                  {
+                    "w": 300,
+                    "h": 600
+                  }
+                ]
+              },
+              "tagid": "123456",
+              "ext": {
+                "bidder": {
+                  "tagid": "123456"
+                }
+              }
+            }
+          ],
+          "site": {
+            "domain": "www.publisher.com",
+            "page": "http://www.publisher.com/awesome/site"
+          },
+          "user": {
+            "buyeruid": "test_reader_id"
+          },
+          "device": { }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "a_449642_554a13d3b9f348fba707cf83f0f63800",
+                  "impid": "test-imp-id",
+                  "price": 3.5,
+                  "nurl": "http://sovrn.com/rtb/impression?bannerid=138743&campaignid=3699&zoneid=449642&cb=69493397&tid=a_449642_554a13d3b9f348fba707cf83f0f63800",
+                  "adm": "some-test-ad",
+                  "w": 300,
+                  "h": 250
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "a_449642_554a13d3b9f348fba707cf83f0f63800",
+            "impid": "test-imp-id",
+            "price": 3.5,
+            "adm": "some-test-ad",
+            "nurl": "http://sovrn.com/rtb/impression?bannerid=138743&campaignid=3699&zoneid=449642&cb=69493397&tid=a_449642_554a13d3b9f348fba707cf83f0f63800",
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/undertone/undertonetest/exemplary/multi-imp-app-request.json b/adapters/undertone/undertonetest/exemplary/multi-imp-app-request.json
index e6b4a83a..71ad2ae1 100644
--- a/adapters/undertone/undertonetest/exemplary/multi-imp-app-request.json
+++ b/adapters/undertone/undertonetest/exemplary/multi-imp-app-request.json
@@ -54,7 +54,8 @@
           "bidder": {
             "publisherId": 1234,
             "placementId": 123456
-          }
+          },
+          "gpid": "gpid-value"
         }
       }
     ],
@@ -116,7 +117,10 @@
                   4
                 ]
               },
-              "tagid": "123456"
+              "tagid": "123456",
+              "ext": {
+                "gpid": "gpid-value"
+              }
             }
           ],
           "app": {
diff --git a/adapters/undertone/undertonetest/exemplary/multi-imp-site-request.json b/adapters/undertone/undertonetest/exemplary/multi-imp-site-request.json
index 0de38caa..9e59ffbc 100644
--- a/adapters/undertone/undertonetest/exemplary/multi-imp-site-request.json
+++ b/adapters/undertone/undertonetest/exemplary/multi-imp-site-request.json
@@ -20,7 +20,8 @@
           "bidder": {
             "publisherId": 1234,
             "placementId": 12345
-          }
+          },
+          "gpid": "gpid-value"
         }
       },
       {
@@ -87,7 +88,10 @@
                   }
                 ]
               },
-              "tagid": "12345"
+              "tagid": "12345",
+              "ext": {
+                "gpid": "gpid-value"
+              }
             },
             {
               "id": "test-imp-video-id",
diff --git a/endpoints/cookie_sync_test.go b/endpoints/cookie_sync_test.go
index 45c27f0e..a674e9db 100644
--- a/endpoints/cookie_sync_test.go
+++ b/endpoints/cookie_sync_test.go
@@ -974,38 +974,6 @@ func TestCookieSyncParseRequest(t *testing.T) {
 			expectedError:        errCookieSyncAccountBlocked.Error(),
 			givenAccountRequired: true,
 		},
-
-		{
-			description: "Account Defaults - Invalid Activities",
-			givenBody: strings.NewReader(`{` +
-				`"bidders":["a", "b"],` +
-				`"account":"ValidAccountInvalidActivities"` +
-				`}`),
-			givenGDPRConfig:  config.GDPR{Enabled: true, DefaultValue: "0"},
-			givenCCPAEnabled: true,
-			givenConfig: config.UserSync{
-				Cooperative: config.UserSyncCooperative{
-					EnabledByDefault: false,
-					PriorityGroups:   [][]string{{"a", "b", "c"}},
-				},
-			},
-			expectedPrivacy: privacy.Policies{},
-			expectedRequest: usersync.Request{
-				Bidders: []string{"a", "b"},
-				Cooperative: usersync.Cooperative{
-					Enabled:        false,
-					PriorityGroups: [][]string{{"a", "b", "c"}},
-				},
-				Limit: 0,
-				Privacy: usersyncPrivacy{
-					gdprPermissions: &fakePermissions{},
-				},
-				SyncTypeFilter: usersync.SyncTypeFilter{
-					IFrame:   usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude),
-					Redirect: usersync.NewUniformBidderFilter(usersync.BidderFilterModeInclude),
-				},
-			},
-		},
 	}
 
 	for _, test := range testCases {
@@ -1934,8 +1902,7 @@ func TestCookieSyncActivityControlIntegration(t *testing.T) {
 
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			activities, err := privacy.NewActivityControl(test.accountPrivacy)
-			assert.NoError(t, err)
+			activities := privacy.NewActivityControl(test.accountPrivacy)
 			up := usersyncPrivacy{
 				activityControl: activities,
 			}
diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go
index 3c2528e2..da4522eb 100644
--- a/endpoints/openrtb2/video_auction_test.go
+++ b/endpoints/openrtb2/video_auction_test.go
@@ -65,20 +65,6 @@ func TestVideoEndpointImpressionsNumber(t *testing.T) {
 	assert.Equal(t, resp.AdPods[0].Targeting[0].HbDeal, "ABC_123", "If DealID exists in bid response, hb_deal targeting needs to be added to resp")
 }
 
-func TestVideoEndpointInvalidPrivacyConfig(t *testing.T) {
-	ex := &mockExchangeVideo{}
-	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample.json")
-	req := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader(reqBody))
-	recorder := httptest.NewRecorder()
-
-	deps := mockDepsInvalidPrivacy(t, ex)
-	deps.VideoAuctionEndpoint(recorder, req, nil)
-
-	respBytes := recorder.Body.Bytes()
-	expectedErrorMessage := "Critical error while running the video endpoint:  unable to parse component: bidderA.BidderB.bidderC"
-	assert.Equal(t, expectedErrorMessage, string(respBytes), "error message is incorrect")
-}
-
 func TestVideoEndpointImpressionsDuration(t *testing.T) {
 	ex := &mockExchangeVideo{}
 	reqBody := readVideoTestFile(t, "sample-requests/video/video_valid_sample_different_durations.json")
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 919f8dce..8ca96880 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -2352,10 +2352,7 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) {
 		impExtInfoMap[impID] = ImpExtInfo{}
 	}
 
-	activityControl, err := privacy.NewActivityControl(spec.AccountPrivacy)
-	if err != nil {
-		t.Errorf("%s: Exchange returned an unexpected error. Got %s", filename, err.Error())
-	}
+	activityControl := privacy.NewActivityControl(spec.AccountPrivacy)
 
 	auctionRequest := &AuctionRequest{
 		BidRequestWrapper: &openrtb_ext.RequestWrapper{BidRequest: &spec.IncomingRequest.OrtbRequest},
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index 1ab86fcd..a1ca0a60 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -4364,8 +4364,7 @@ func TestCleanOpenRTBRequestsActivities(t *testing.T) {
 	}
 
 	for _, test := range testCases {
-		activities, err := privacy.NewActivityControl(&test.privacyConfig)
-		assert.NoError(t, err, "")
+		activities := privacy.NewActivityControl(&test.privacyConfig)
 		auctionReq := AuctionRequest{
 			BidRequestWrapper: &openrtb_ext.RequestWrapper{BidRequest: test.req},
 			UserSyncs:         &emptyUsersync{},
diff --git a/hooks/hookexecution/mocks_test.go b/hooks/hookexecution/mocks_test.go
index e8670ff8..ff543c38 100644
--- a/hooks/hookexecution/mocks_test.go
+++ b/hooks/hookexecution/mocks_test.go
@@ -131,7 +131,7 @@ func (e mockTimeoutHook) HandleProcessedAuctionHook(_ context.Context, _ hooksta
 	time.Sleep(20 * time.Millisecond)
 	c := hookstage.ChangeSet[hookstage.ProcessedAuctionRequestPayload]{}
 	c.AddMutation(func(payload hookstage.ProcessedAuctionRequestPayload) (hookstage.ProcessedAuctionRequestPayload, error) {
-		payload.BidRequest.User.CustomData = "some-custom-data"
+		payload.RequestWrapper.User.CustomData = "some-custom-data"
 		return payload, nil
 	}, hookstage.MutationUpdate, "bidRequest", "user.customData")
 
@@ -305,12 +305,20 @@ func (e mockUpdateBidRequestHook) HandleProcessedAuctionHook(_ context.Context,
 	c := hookstage.ChangeSet[hookstage.ProcessedAuctionRequestPayload]{}
 	c.AddMutation(
 		func(payload hookstage.ProcessedAuctionRequestPayload) (hookstage.ProcessedAuctionRequestPayload, error) {
-			payload.BidRequest.User.Yob = 2000
+			payload.RequestWrapper.User.Yob = 2000
+			userExt, err := payload.RequestWrapper.GetUserExt()
+			if err != nil {
+				return payload, err
+			}
+			newPrebidExt := &openrtb_ext.ExtUserPrebid{
+				BuyerUIDs: map[string]string{"some": "id"},
+			}
+			userExt.SetPrebid(newPrebidExt)
 			return payload, nil
 		}, hookstage.MutationUpdate, "bidRequest", "user.yob",
 	).AddMutation(
 		func(payload hookstage.ProcessedAuctionRequestPayload) (hookstage.ProcessedAuctionRequestPayload, error) {
-			payload.BidRequest.User.Consent = "true"
+			payload.RequestWrapper.User.Consent = "true"
 			return payload, nil
 		}, hookstage.MutationUpdate, "bidRequest", "user.consent",
 	)
diff --git a/privacy/activitycontrol_test.go b/privacy/activitycontrol_test.go
index db5d588d..11a9bdc7 100644
--- a/privacy/activitycontrol_test.go
+++ b/privacy/activitycontrol_test.go
@@ -1,7 +1,6 @@
 package privacy
 
 import (
-	"errors"
 	"testing"
 
 	"github.com/prebid/prebid-server/config"
@@ -14,136 +13,48 @@ func TestNewActivityControl(t *testing.T) {
 		name            string
 		privacyConf     config.AccountPrivacy
 		activityControl ActivityControl
-		err             error
 	}{
 		{
-			name:            "privacy_config_is_empty",
+			name:            "empty",
 			privacyConf:     config.AccountPrivacy{},
 			activityControl: ActivityControl{plans: nil},
-			err:             nil,
 		},
 		{
-			name: "privacy_config_is_specified_and_correct",
+			name: "specified_and_correct",
 			privacyConf: config.AccountPrivacy{
 				AllowActivities: &config.AllowActivities{
-					SyncUser:                 getDefaultActivityConfig(),
-					FetchBids:                getDefaultActivityConfig(),
-					EnrichUserFPD:            getDefaultActivityConfig(),
-					ReportAnalytics:          getDefaultActivityConfig(),
-					TransmitUserFPD:          getDefaultActivityConfig(),
-					TransmitPreciseGeo:       getDefaultActivityConfig(),
-					TransmitUniqueRequestIds: getDefaultActivityConfig(),
-					TransmitTids:             getDefaultActivityConfig(),
+					SyncUser:                 getTestActivityConfig(true),
+					FetchBids:                getTestActivityConfig(true),
+					EnrichUserFPD:            getTestActivityConfig(true),
+					ReportAnalytics:          getTestActivityConfig(true),
+					TransmitUserFPD:          getTestActivityConfig(true),
+					TransmitPreciseGeo:       getTestActivityConfig(false),
+					TransmitUniqueRequestIds: getTestActivityConfig(true),
+					TransmitTids:             getTestActivityConfig(true),
 				},
 			},
 			activityControl: ActivityControl{plans: map[Activity]ActivityPlan{
-				ActivitySyncUser:                 getDefaultActivityPlan(),
-				ActivityFetchBids:                getDefaultActivityPlan(),
-				ActivityEnrichUserFPD:            getDefaultActivityPlan(),
-				ActivityReportAnalytics:          getDefaultActivityPlan(),
-				ActivityTransmitUserFPD:          getDefaultActivityPlan(),
-				ActivityTransmitPreciseGeo:       getDefaultActivityPlan(),
-				ActivityTransmitUniqueRequestIds: getDefaultActivityPlan(),
-				ActivityTransmitTids:             getDefaultActivityPlan(),
+				ActivitySyncUser:                 getTestActivityPlan(ActivityAllow),
+				ActivityFetchBids:                getTestActivityPlan(ActivityAllow),
+				ActivityEnrichUserFPD:            getTestActivityPlan(ActivityAllow),
+				ActivityReportAnalytics:          getTestActivityPlan(ActivityAllow),
+				ActivityTransmitUserFPD:          getTestActivityPlan(ActivityAllow),
+				ActivityTransmitPreciseGeo:       getTestActivityPlan(ActivityDeny),
+				ActivityTransmitUniqueRequestIds: getTestActivityPlan(ActivityAllow),
+				ActivityTransmitTids:             getTestActivityPlan(ActivityAllow),
 			}},
-			err: nil,
-		},
-		{
-			name: "privacy_config_is_specified_and_SyncUser_is_incorrect",
-			privacyConf: config.AccountPrivacy{
-				AllowActivities: &config.AllowActivities{
-					SyncUser: getIncorrectActivityConfig(),
-				},
-			},
-			activityControl: ActivityControl{plans: nil},
-			err:             errors.New("unable to parse component: bidder.bidderA.bidderB"),
-		},
-		{
-			name: "privacy_config_is_specified_and_FetchBids_is_incorrect",
-			privacyConf: config.AccountPrivacy{
-				AllowActivities: &config.AllowActivities{
-					FetchBids: getIncorrectActivityConfig(),
-				},
-			},
-			activityControl: ActivityControl{plans: nil},
-			err:             errors.New("unable to parse component: bidder.bidderA.bidderB"),
-		},
-		{
-			name: "privacy_config_is_specified_and_EnrichUserFPD_is_incorrect",
-			privacyConf: config.AccountPrivacy{
-				AllowActivities: &config.AllowActivities{
-					EnrichUserFPD: getIncorrectActivityConfig(),
-				},
-			},
-			activityControl: ActivityControl{plans: nil},
-			err:             errors.New("unable to parse component: bidder.bidderA.bidderB"),
-		},
-		{
-			name: "privacy_config_is_specified_and_ReportAnalytics_is_incorrect",
-			privacyConf: config.AccountPrivacy{
-				AllowActivities: &config.AllowActivities{
-					ReportAnalytics: getIncorrectActivityConfig(),
-				},
-			},
-			activityControl: ActivityControl{plans: nil},
-			err:             errors.New("unable to parse component: bidder.bidderA.bidderB"),
-		},
-		{
-			name: "privacy_config_is_specified_and_TransmitUserFPD_is_incorrect",
-			privacyConf: config.AccountPrivacy{
-				AllowActivities: &config.AllowActivities{
-					TransmitUserFPD: getIncorrectActivityConfig(),
-				},
-			},
-			activityControl: ActivityControl{plans: nil},
-			err:             errors.New("unable to parse component: bidder.bidderA.bidderB"),
-		},
-		{
-			name: "privacy_config_is_specified_and_TransmitPreciseGeo_is_incorrect",
-			privacyConf: config.AccountPrivacy{
-				AllowActivities: &config.AllowActivities{
-					TransmitPreciseGeo: getIncorrectActivityConfig(),
-				},
-			},
-			activityControl: ActivityControl{plans: nil},
-			err:             errors.New("unable to parse component: bidder.bidderA.bidderB"),
-		},
-		{
-			name: "privacy_config_is_specified_and_TransmitUniqueRequestIds_is_incorrect",
-			privacyConf: config.AccountPrivacy{
-				AllowActivities: &config.AllowActivities{
-					TransmitUniqueRequestIds: getIncorrectActivityConfig(),
-				},
-			},
-			activityControl: ActivityControl{plans: nil},
-			err:             errors.New("unable to parse component: bidder.bidderA.bidderB"),
-		},
-		{
-			name: "privacy_config_is_specified_and_TransmitTids_is_incorrect",
-			privacyConf: config.AccountPrivacy{
-				AllowActivities: &config.AllowActivities{
-					TransmitTids: getIncorrectActivityConfig(),
-				},
-			},
-			activityControl: ActivityControl{plans: nil},
-			err:             errors.New("unable to parse component: bidder.bidderA.bidderB"),
 		},
 	}
 
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			actualAC, actualErr := NewActivityControl(&test.privacyConf)
-			if test.err == nil {
-				assert.Equal(t, test.activityControl, actualAC)
-				assert.NoError(t, actualErr)
-			} else {
-				assert.EqualError(t, actualErr, test.err.Error())
-			}
+			actualAC := NewActivityControl(&test.privacyConf)
+			assert.Equal(t, test.activityControl, actualAC)
 		})
 	}
 }
 
-func TestActivityDefaultToDefaultResult(t *testing.T) {
+func TestCfgToDefaultResult(t *testing.T) {
 	testCases := []struct {
 		name            string
 		activityDefault *bool
@@ -168,14 +79,13 @@ func TestActivityDefaultToDefaultResult(t *testing.T) {
 
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			actualResult := activityDefaultToDefaultResult(test.activityDefault)
+			actualResult := cfgToDefaultResult(test.activityDefault)
 			assert.Equal(t, test.expectedResult, actualResult)
 		})
 	}
 }
 
-func TestAllowActivityControl(t *testing.T) {
-
+func TestActivityControlAllow(t *testing.T) {
 	testCases := []struct {
 		name            string
 		activityControl ActivityControl
@@ -193,7 +103,7 @@ func TestAllowActivityControl(t *testing.T) {
 		{
 			name: "activity_not_defined",
 			activityControl: ActivityControl{plans: map[Activity]ActivityPlan{
-				ActivitySyncUser: getDefaultActivityPlan()}},
+				ActivitySyncUser: getTestActivityPlan(ActivityAllow)}},
 			activity:       ActivityFetchBids,
 			target:         Component{Type: "bidder", Name: "bidderA"},
 			activityResult: true,
@@ -201,7 +111,7 @@ func TestAllowActivityControl(t *testing.T) {
 		{
 			name: "activity_defined_but_not_found_default_returned",
 			activityControl: ActivityControl{plans: map[Activity]ActivityPlan{
-				ActivityFetchBids: getDefaultActivityPlan()}},
+				ActivityFetchBids: getTestActivityPlan(ActivityAllow)}},
 			activity:       ActivityFetchBids,
 			target:         Component{Type: "bidder", Name: "bidderB"},
 			activityResult: true,
@@ -209,7 +119,7 @@ func TestAllowActivityControl(t *testing.T) {
 		{
 			name: "activity_defined_and_allowed",
 			activityControl: ActivityControl{plans: map[Activity]ActivityPlan{
-				ActivityFetchBids: getDefaultActivityPlan()}},
+				ActivityFetchBids: getTestActivityPlan(ActivityAllow)}},
 			activity:       ActivityFetchBids,
 			target:         Component{Type: "bidder", Name: "bidderA"},
 			activityResult: true,
@@ -225,13 +135,12 @@ func TestAllowActivityControl(t *testing.T) {
 	}
 }
 
-// constants
-func getDefaultActivityConfig() config.Activity {
+func getTestActivityConfig(allow bool) config.Activity {
 	return config.Activity{
 		Default: ptrutil.ToPtr(true),
 		Rules: []config.ActivityRule{
 			{
-				Allow: true,
+				Allow: allow,
 				Condition: config.ActivityCondition{
 					ComponentName: []string{"bidderA"},
 					ComponentType: []string{"bidder"},
@@ -241,32 +150,15 @@ func getDefaultActivityConfig() config.Activity {
 	}
 }
 
-func getDefaultActivityPlan() ActivityPlan {
+func getTestActivityPlan(result ActivityResult) ActivityPlan {
 	return ActivityPlan{
 		defaultResult: true,
 		rules: []Rule{
-			ComponentEnforcementRule{
-				result: ActivityAllow,
-				componentName: []Component{
-					{Type: "bidder", Name: "bidderA"},
-				},
+			ConditionRule{
+				result:        result,
+				componentName: []string{"bidderA"},
 				componentType: []string{"bidder"},
 			},
 		},
 	}
 }
-
-func getIncorrectActivityConfig() config.Activity {
-	return config.Activity{
-		Default: ptrutil.ToPtr(true),
-		Rules: []config.ActivityRule{
-			{
-				Allow: true,
-				Condition: config.ActivityCondition{
-					ComponentName: []string{"bidder.bidderA.bidderB"},
-					ComponentType: []string{"bidder"},
-				},
-			},
-		},
-	}
-}
diff --git a/privacy/component_test.go b/privacy/component_test.go
index 38aa105d..9d9d1644 100644
--- a/privacy/component_test.go
+++ b/privacy/component_test.go
@@ -1,124 +1,87 @@
 package privacy
 
 import (
-	"errors"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 )
 
-func TestComponentMatches(t *testing.T) {
+func TestComponentMatchesName(t *testing.T) {
 	testCases := []struct {
 		name   string
 		given  Component
-		target Component
+		target string
 		result bool
 	}{
 		{
-			name:   "full",
+			name:   "match",
 			given:  Component{Type: "a", Name: "b"},
-			target: Component{Type: "a", Name: "b"},
+			target: "b",
 			result: true,
 		},
 		{
-			name:   "name-wildcard",
-			given:  Component{Type: "a", Name: "*"},
-			target: Component{Type: "a", Name: "b"},
-			result: true,
-		},
-		{
-			name:   "different",
+			name:   "wrong-field",
 			given:  Component{Type: "a", Name: "b"},
-			target: Component{Type: "foo", Name: "bar"},
+			target: "a",
 			result: false,
 		},
 		{
-			name:   "different-type",
+			name:   "different-value",
 			given:  Component{Type: "a", Name: "b"},
-			target: Component{Type: "foo", Name: "b"},
+			target: "foo",
 			result: false,
 		},
 		{
-			name:   "different-name",
+			name:   "different-case",
 			given:  Component{Type: "a", Name: "b"},
-			target: Component{Type: "a", Name: "foo"},
-			result: false,
+			target: "B",
+			result: true,
 		},
 	}
 
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			assert.Equal(t, test.result, test.given.Matches(test.target))
+			assert.Equal(t, test.result, test.given.MatchesName(test.target))
 		})
 	}
 }
 
-func TestParseComponent(t *testing.T) {
+func TestComponentMatchesType(t *testing.T) {
 	testCases := []struct {
-		name          string
-		component     string
-		expected      Component
-		expectedError error
+		name   string
+		given  Component
+		target string
+		result bool
 	}{
 		{
-			name:          "empty",
-			component:     "",
-			expected:      Component{},
-			expectedError: errors.New("unable to parse empty component"),
-		},
-		{
-			name:          "too-many-parts",
-			component:     "bidder.bidderA.bidderB",
-			expected:      Component{},
-			expectedError: errors.New("unable to parse component: bidder.bidderA.bidderB"),
-		},
-		{
-			name:          "type-bidder",
-			component:     "bidder.bidderA",
-			expected:      Component{Type: "bidder", Name: "bidderA"},
-			expectedError: nil,
-		},
-		{
-			name:          "type-analytics",
-			component:     "analytics.bidderA",
-			expected:      Component{Type: "analytics", Name: "bidderA"},
-			expectedError: nil,
-		},
-		{
-			name:          "type-default",
-			component:     "bidderA",
-			expected:      Component{Type: "bidder", Name: "bidderA"},
-			expectedError: nil,
+			name:   "match",
+			given:  Component{Type: "a", Name: "b"},
+			target: "a",
+			result: true,
 		},
 		{
-			name:          "type-rtd",
-			component:     "rtd.test",
-			expected:      Component{Type: "rtd", Name: "test"},
-			expectedError: nil,
+			name:   "wrong-field",
+			given:  Component{Type: "a", Name: "b"},
+			target: "b",
+			result: false,
 		},
 		{
-			name:          "type-general",
-			component:     "general.test",
-			expected:      Component{Type: "general", Name: "test"},
-			expectedError: nil,
+			name:   "different-value",
+			given:  Component{Type: "a", Name: "b"},
+			target: "foo",
+			result: false,
 		},
 		{
-			name:          "type-invalid",
-			component:     "invalid.test",
-			expected:      Component{},
-			expectedError: errors.New("unable to parse component (invalid type): invalid.test"),
+			name:   "different-case",
+			given:  Component{Type: "a", Name: "b"},
+			target: "A",
+			result: true,
 		},
 	}
 
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
-			actualSN, actualErr := ParseComponent(test.component)
-			if test.expectedError == nil {
-				assert.Equal(t, test.expected, actualSN)
-				assert.NoError(t, actualErr)
-			} else {
-				assert.EqualError(t, actualErr, test.expectedError.Error())
-			}
+			assert.Equal(t, test.result, test.given.MatchesType(test.target))
 		})
 	}
 }
diff --git a/privacy/rules_test.go b/privacy/rule_condition_test.go
similarity index 69%
rename from privacy/rules_test.go
rename to privacy/rule_condition_test.go
index 7e80c9ce..3a09b365 100644
--- a/privacy/rules_test.go
+++ b/privacy/rule_condition_test.go
@@ -9,17 +9,15 @@ import (
 func TestComponentEnforcementRuleEvaluate(t *testing.T) {
 	testCases := []struct {
 		name           string
-		componentRule  ComponentEnforcementRule
+		componentRule  ConditionRule
 		target         Component
 		activityResult ActivityResult
 	}{
 		{
 			name: "activity_is_allowed",
-			componentRule: ComponentEnforcementRule{
-				result: ActivityAllow,
-				componentName: []Component{
-					{Type: "bidder", Name: "bidderA"},
-				},
+			componentRule: ConditionRule{
+				result:        ActivityAllow,
+				componentName: []string{"bidderA"},
 				componentType: []string{"bidder"},
 			},
 			target:         Component{Type: "bidder", Name: "bidderA"},
@@ -27,11 +25,9 @@ func TestComponentEnforcementRuleEvaluate(t *testing.T) {
 		},
 		{
 			name: "activity_is_not_allowed",
-			componentRule: ComponentEnforcementRule{
-				result: ActivityDeny,
-				componentName: []Component{
-					{Type: "bidder", Name: "bidderA"},
-				},
+			componentRule: ConditionRule{
+				result:        ActivityDeny,
+				componentName: []string{"bidderA"},
 				componentType: []string{"bidder"},
 			},
 			target:         Component{Type: "bidder", Name: "bidderA"},
@@ -39,11 +35,9 @@ func TestComponentEnforcementRuleEvaluate(t *testing.T) {
 		},
 		{
 			name: "abstain_both_clauses_do_not_match",
-			componentRule: ComponentEnforcementRule{
-				result: ActivityAllow,
-				componentName: []Component{
-					{Type: "bidder", Name: "bidderA"},
-				},
+			componentRule: ConditionRule{
+				result:        ActivityAllow,
+				componentName: []string{"bidderA"},
 				componentType: []string{"bidder"},
 			},
 			target:         Component{Type: "bidder", Name: "bidderB"},
@@ -51,18 +45,16 @@ func TestComponentEnforcementRuleEvaluate(t *testing.T) {
 		},
 		{
 			name: "activity_is_not_allowed_componentName_only",
-			componentRule: ComponentEnforcementRule{
-				result: ActivityAllow,
-				componentName: []Component{
-					{Type: "bidder", Name: "bidderA"},
-				},
+			componentRule: ConditionRule{
+				result:        ActivityAllow,
+				componentName: []string{"bidderA"},
 			},
 			target:         Component{Type: "bidder", Name: "bidderA"},
 			activityResult: ActivityAllow,
 		},
 		{
 			name: "activity_is_allowed_componentType_only",
-			componentRule: ComponentEnforcementRule{
+			componentRule: ConditionRule{
 				result:        ActivityAllow,
 				componentType: []string{"bidder"},
 			},
@@ -71,7 +63,7 @@ func TestComponentEnforcementRuleEvaluate(t *testing.T) {
 		},
 		{
 			name: "no-conditions-allow",
-			componentRule: ComponentEnforcementRule{
+			componentRule: ConditionRule{
 				result: ActivityAllow,
 			},
 			target:         Component{Type: "bidder", Name: "bidderA"},
@@ -79,7 +71,7 @@ func TestComponentEnforcementRuleEvaluate(t *testing.T) {
 		},
 		{
 			name: "no-conditions-deny",
-			componentRule: ComponentEnforcementRule{
+			componentRule: ConditionRule{
 				result: ActivityDeny,
 			},
 			target:         Component{Type: "bidder", Name: "bidderA"},