Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,16 @@ jobs:
with:
node-version: ${{ steps.shared-setup.outputs.node-version }}
cache: npm
cache-dependency-path: crates/trusted-server-integration-tests/browser/package-lock.json
cache-dependency-path: |
crates/trusted-server-integration-tests/browser/package-lock.json
crates/trusted-server-js/lib/package-lock.json

- name: Build TSJS browser fixtures
working-directory: crates/trusted-server-js/lib
run: |
npm ci
npm run build
npm run build:prebid-external

- name: Install Playwright
working-directory: crates/trusted-server-integration-tests/browser
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **Breaking** — Replaced the legacy APS contextual integration with APS OpenRTB at `/e/pb/bid`. APS configuration now uses canonical `account_id` (`pub_id` remains a compatibility alias), no longer requires APS-specific slot IDs, and defaults script creative eligibility off. Operators must update the endpoint, disable native APS demand for Trusted Server cohorts, and prepare GAM/Universal Creative targeting for `hb_bidder=aps` before rollout. APS renderer winners now preserve the upstream bid `id`, omit `crid` when APS omits it, and carry `ext.trusted_server.renderer` instead of `adm`; external `/auction` consumers must support this response shape.
- **Breaking** — `bid_param_zone_overrides` inner values must now be JSON objects; previously non-object or empty values (`"header" = "x"`, `"header" = {}`) were accepted and silently produced a dead rule at runtime. They now fail at startup with a configuration error. Operators upgrading should audit their `bid_param_zone_overrides` config for non-object zone entries.
- **Breaking** — Sourcepoint browser module inclusion now requires explicit `[integrations.sourcepoint].enabled = true`; operators relying on the previous unconditional Sourcepoint module should enable the integration before upgrading.
- Added optional APS `inventory_domain` and `inventory_page_origin` overrides for deployments whose edge hostname differs from the APS-authorized inventory identity.
- Preserved APS renderer capabilities through the client-side `trustedServer` Prebid adapter, allowing its generated `hb_adid` to render through GAM and Prebid Universal Creative instead of producing an empty creative.

### Security

- Validate synthetic ID format on inbound values from the `x-synthetic-id` header and `synthetic_id` cookie; values that do not match the expected format (`64-hex-hmac.6-alphanumeric-suffix`) are discarded and a fresh ID is generated rather than forwarded to response headers, cookies, or third-party APIs

### Added

- Added opt-in APS HTTP debug metadata for controlled test sites, exposing the direct request and response under `/auction` provider metadata using the Prebid Server `debug.httpcalls` shape.
- Added typed APS renderer transport for direct auctions and GAM/Prebid Universal Creative, using a minimized one-bid envelope, a fragment-bound nonce, and an opaque sandboxed renderer endpoint.
- Added Osano consent mirror integration docs and public enablement guidance.
- Implemented basic authentication for configurable endpoint paths (#73)
- Added integrations guide with example `testlight` integration
Expand Down
44 changes: 24 additions & 20 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ curl -X POST http://localhost:7676/auction \

**With Orchestrator Enabled** (`auction.enabled = true`):
- Logs showing: `"Using auction orchestrator"`
- Parallel execution of APS (mocked) and Prebid (real)
- GAM mediation (mocked) selecting winning bids
- Parallel execution of APS OpenRTB and Prebid Server
- Optional mock-adserver mediation selecting winning bids
- Final response with winning creatives

**With Orchestrator Disabled** (`auction.enabled = false`):
Expand All @@ -66,11 +66,13 @@ providers = ["prebid", "aps"]
mediator = "adserver_mock" # If set: mediation, if omitted: highest bid wins
timeout_ms = 2000

# Mock provider configs
# APS OpenRTB provider. The built-in production endpoint is used when
# endpoint is omitted; use only an account authorized for test traffic.
[integrations.aps]
enabled = true
mock = true
mock_price = 2.50
account_id = "example-account"
timeout_ms = 800
debug = false

[integrations.adserver_mock]
enabled = true
Expand All @@ -90,10 +92,10 @@ mediator = "adserver_mock" # Mediator configured = parallel mediation strategy
```

**Expected Flow:**
1. Prebid queries real SSPs
2. APS returns mock bids ($2.50 CPM)
3. AdServer Mock mediates between all bids
4. Winning creative returned
1. Prebid queries its configured bidders through Prebid Server
2. APS sends an OpenRTB request for eligible banner impressions
3. AdServer Mock mediates the provider responses
4. The winning creative or typed APS renderer is returned

### Scenario 2: Parallel Only (No Mediation)
**Config:**
Expand Down Expand Up @@ -131,8 +133,9 @@ INFO: Running 2 bidders in parallel
INFO: Requesting bids from: prebid
INFO: Prebid returned 2 bids (time: 120ms)
INFO: Requesting bids from: aps
INFO: APS (MOCK): returning 2 bids in 80ms
INFO: GAM mediation: slot 'header-banner' won by 'amazon-aps' at $2.50 CPM
INFO: APS requests bids for 2 impressions
Comment thread
ChristianPavilonis marked this conversation as resolved.
INFO: APS returns 2 accepted bids in 80ms
INFO: GAM mediation: slot 'header-banner' won by 'aps' at $2.50 CPM
```

### Verify Provider Registration
Expand All @@ -156,18 +159,19 @@ INFO: Registering auction provider: adserver_mock

## Next Steps

1. **Test with real Prebid Server** - Verify Prebid bids work correctly
2. **Implement real APS** - Replace mock with actual Amazon TAM API calls
3. **Implement real GAM** - Add Google Ad Manager API integration
4. **Add metrics** - Track bid rates, win rates, latency per provider
1. **Verify Prebid Server demand** - Confirm configured bidders return expected test bids
2. **Verify APS eligibility** - Confirm the test account, inventory identity, and `/e/pb/bid` endpoint are authorized
3. **Exercise renderer security** - Run the APS browser integration suite for iframe and script creatives
4. **Add metrics** - Track bid rates, win rates, latency, and aggregate drop reasons per provider

## Mock Provider Behavior
## Provider Behavior

### APS (Amazon)
- Returns bids for all slots
- Default mock price: $2.50 CPM
- Always returns 2 bids
- Response time: ~80ms (simulated)
- Sends real OpenRTB requests for eligible banner slots
- Safely drops malformed, unsupported, or unrenderable bids and reports aggregate reasons
- Reduces multiple APS candidates to one winner per impression
- Returns typed renderer descriptors rather than exposing `adm` outside the sandbox
- Automated tests intercept upstream traffic and use fictional response fixtures

### AdServer Mock
- Acts as mediator by calling mocktioneer's mediation endpoint
Expand Down
51 changes: 27 additions & 24 deletions crates/trusted-server-core/src/auction/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ When a request arrives at the `/auction` endpoint, it goes through the following
┌──────────────────────────────────────────────────────────────────────┐
│ 9. Each Provider Processes Request │
│ - Transform AuctionRequest → Provider format (e.g., APS TAM)
│ - Transform AuctionRequest → Provider OpenRTB request
│ - Send HTTP request to provider endpoint │
│ - Parse provider response │
│ - Transform → AuctionResponse with Bid[] │
Expand Down Expand Up @@ -188,30 +188,21 @@ AdSlot {

#### 3. Provider Execution
Each registered provider (APS, Prebid, etc.) receives the `AuctionRequest` and:
- Transforms it to their specific format (e.g., APS TAM, OpenRTB)
- Transforms it to the provider's OpenRTB request format
- Makes HTTP request to their endpoint
- Parses the response
- Returns `AuctionResponse` with `Bid[]`

For example, APS provider:
```rust
// Transform AuctionRequest → ApsBidRequest
let aps_request = ApsBidRequest {
pub_id: "5128",
slots: vec![
ApsSlot {
slot_id: "header-banner",
sizes: vec![[728, 90], [970, 250]],
slot_name: Some("header-banner"),
}
],
page_url: Some("https://example.com"),
ua: Some("Mozilla/5.0..."),
timeout: Some(800),
};

// HTTP POST to http://localhost:6767/e/dtb/bid
// Parse response → AuctionResponse
// Transform AuctionRequest → APS OpenRTB request
// - ext.account = configured account_id
// - ext.sdk = { source: "prebid", version: "2.2.0" }
// - banner slots become secure impressions with matching formats/floors
// - existing consent, identity, device, and geo privacy gates apply

// HTTP POST to https://aps.example.com/e/pb/bid
// Parse decoded-price response → AuctionResponse with a typed renderer
```

#### 4. Response Assembly
Expand All @@ -222,17 +213,29 @@ The orchestrator collects all bids and creates an OpenRTB response:
"id": "auction-response",
"seatbid": [
{
"seat": "amazon-aps",
"seat": "aps",
"bid": [
{
"id": "amazon-aps-header-banner",
"id": "fictional-selected-bid-id",
"impid": "header-banner",
"price": 2.5,
"adm": "<iframe src=\"/first-party/proxy?tsurl=...\">",
"w": 728,
"h": 90,
"crid": "amazon-aps-creative",
"adomain": ["amazon.com"]
"ext": {
"trusted_server": {
"renderer": {
"type": "aps",
"version": 1,
"accountId": "example-account",
"bidId": "fictional-selected-bid-id",
"tagType": "iframe",
"creativeUrl": "https://creative.example/render",
"aaxResponse": "<base64 minimized one-bid envelope>",
"width": 728,
"height": 90
}
}
}
}
]
}
Expand Down
Loading
Loading