Skip to content

Commit 8492927

Browse files
Sync public snapshot from freebuff-private
1 parent e6b7f64 commit 8492927

2 files changed

Lines changed: 79 additions & 10 deletions

File tree

‎common/src/util/__tests__/axiom-only-log.test.ts‎

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
ADS_FIRST_PARTY_SETTLEMENT_EVENT,
1010
ADS_FIRST_PARTY_VIEW_ACK_EVENT,
1111
ADS_EXTERNAL_CONVERSION_CLICK_ID_SHAPES,
12+
ADS_EXTERNAL_CONVERSION_SELECTED_RAILS,
1213
ADS_EXTERNAL_CONVERSION_POSTBACK_EVENT,
1314
ADS_CAMPAIGN_INGRESS_EVIDENCE_EVENT,
1415
ADS_ADVERTISER_REPORTING_READ_EVENT,
@@ -1078,11 +1079,15 @@ describe('getAxiomOnlyLogEvent', () => {
10781079
)
10791080
})
10801081

1081-
test('keeps external conversion postbacks content- and identifier-free', () => {
1082+
test('keeps only advertiser correlation and content-free dimensions on conversion postbacks', () => {
10821083
expect(
10831084
getAxiomOnlyLogEvent({
10841085
axiomEvent: ADS_EXTERNAL_CONVERSION_POSTBACK_EVENT,
1085-
channel: 'client',
1086+
channel: 's2s',
1087+
selected_rail: 'identity_email',
1088+
email_present: false,
1089+
email_hash_present: true,
1090+
email_hash_valid: true,
10861091
outcome: 'accepted',
10871092
rejection_reason: 'none',
10881093
event_type: 'signup_completed',
@@ -1099,14 +1104,21 @@ describe('getAxiomOnlyLogEvent', () => {
10991104
advertiser_id: 'advertiser-private',
11001105
user_id: 'user-private',
11011106
email: 'private@example.com',
1107+
em: 'a'.repeat(64),
1108+
userData: { em: 'a'.repeat(64) },
11021109
url: 'https://partner.example/private',
11031110
body: { private: true },
11041111
error: new Error('private failure'),
11051112
}),
11061113
).toEqual({
11071114
event: ADS_EXTERNAL_CONVERSION_POSTBACK_EVENT,
11081115
data: {
1109-
channel: 'client',
1116+
channel: 's2s',
1117+
advertiser_id: 'advertiser-private',
1118+
selected_rail: 'identity_email',
1119+
email_present: false,
1120+
email_hash_present: true,
1121+
email_hash_valid: true,
11101122
outcome: 'accepted',
11111123
rejection_reason: 'none',
11121124
event_type: 'signup_completed',
@@ -1144,13 +1156,44 @@ describe('getAxiomOnlyLogEvent', () => {
11441156
const result = getAxiomOnlyLogEvent({
11451157
...base,
11461158
click_id_shape: 'bfc_1.private-raw-click-value',
1147-
advertiser_id: 'advertiser-private',
1159+
advertiser_id: 'advertiser-1',
11481160
api_key: 'fbadv_private',
11491161
})
11501162
expect(result?.data).not.toHaveProperty('click_id_shape')
11511163
expect(JSON.stringify(result)).not.toContain('private')
11521164
})
11531165

1166+
test('accepts only closed selected rails and boolean identity presence flags', () => {
1167+
const base = { axiomEvent: ADS_EXTERNAL_CONVERSION_POSTBACK_EVENT }
1168+
for (const selectedRail of ADS_EXTERNAL_CONVERSION_SELECTED_RAILS) {
1169+
expect(
1170+
getAxiomOnlyLogEvent({
1171+
...base,
1172+
selected_rail: selectedRail,
1173+
email_present: true,
1174+
email_hash_present: false,
1175+
email_hash_valid: false,
1176+
})?.data,
1177+
).toEqual({
1178+
selected_rail: selectedRail,
1179+
email_present: true,
1180+
email_hash_present: false,
1181+
email_hash_valid: false,
1182+
})
1183+
}
1184+
for (const invalid of ['private@example.com', 'a'.repeat(64), 42, null]) {
1185+
const result = getAxiomOnlyLogEvent({
1186+
...base,
1187+
selected_rail: invalid,
1188+
email_present: invalid,
1189+
email_hash_present: invalid,
1190+
email_hash_valid: invalid,
1191+
advertiser_id: { raw: 'private-id' },
1192+
})
1193+
expect(result?.data).toEqual({})
1194+
}
1195+
})
1196+
11541197
test('drops a non-string channel from the postback census', () => {
11551198
const result = getAxiomOnlyLogEvent({
11561199
axiomEvent: ADS_EXTERNAL_CONVERSION_POSTBACK_EVENT,

‎common/src/util/axiom-only-log.ts‎

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export const ADS_EXTERNAL_CONVERSION_POSTBACK_EVENT =
105105
/**
106106
* Why an authenticated S2S postback failed the click-id shape guard before
107107
* body validation. Values describe only the failed predicate; the presented
108-
* value, API key, advertiser, campaign, IP and request body stay out of Axiom.
108+
* value, API key, campaign, IP and request body stay out of Axiom.
109109
*/
110110
export const ADS_EXTERNAL_CONVERSION_CLICK_ID_SHAPES = [
111111
'missing',
@@ -116,9 +116,17 @@ export const ADS_EXTERNAL_CONVERSION_CLICK_ID_SHAPES = [
116116
] as const
117117
export type AdsExternalConversionClickIdShape =
118118
(typeof ADS_EXTERNAL_CONVERSION_CLICK_ID_SHAPES)[number]
119+
/** Selected ingress branch, including requests rejected before a lookup. */
120+
export const ADS_EXTERNAL_CONVERSION_SELECTED_RAILS = [
121+
'click_id',
122+
'identity_email',
123+
'none',
124+
] as const
125+
export type AdsExternalConversionSelectedRail =
126+
(typeof ADS_EXTERNAL_CONVERSION_SELECTED_RAILS)[number]
119127
/**
120-
* Durable campaign-health evidence. Unlike the content-free postback census,
121-
* this stream intentionally carries opaque advertiser/campaign identifiers so
128+
* Durable campaign-health evidence. This stream also carries an opaque
129+
* campaign identifier, beyond the postback census's authenticated advertiser, so
122130
* the health reader can distinguish independent ingress binding from a join
123131
* learned only after click resolution. Raw click ids, event ids, credentials,
124132
* email, IP and user-agent data are never fields on this event.
@@ -1067,13 +1075,23 @@ export function createFirstPartyViewAckTelemetry(
10671075
}
10681076
}
10691077

1070-
/** Keep the advertiser postback stream safe to aggregate. In particular this
1071-
* must not grow into an attribution/debugging record: the database owns that
1072-
* drill-down and Axiom receives only bounded operational dimensions. */
1078+
/** Keep the advertiser postback stream safe to aggregate. The authenticated
1079+
* advertiser id correlates integration health; all other fields describe
1080+
* bounded operational dimensions. Emails, hashes and click/event identifiers
1081+
* stay out of Axiom. */
10731082
const ADS_EXTERNAL_CONVERSION_POSTBACK_FIELDS = {
10741083
// Which ingress reported: 's2s' (key-authenticated postback) or 'client'
10751084
// (the keyless browser endpoint). Two-valued, never a partner identifier.
10761085
channel: 'string',
1086+
// Server-resolved after authentication, never a request-body field.
1087+
advertiser_id: 'string',
1088+
selected_rail: 'string',
1089+
// Raw canonical field presence, including fields ignored by click-id routing.
1090+
// Presence does not imply the supplied email or hash was valid.
1091+
email_present: 'boolean',
1092+
email_hash_present: 'boolean',
1093+
// Whether canonical `em` contains an accepted SHA-256 digest or digest array.
1094+
email_hash_valid: 'boolean',
10771095
outcome: 'string',
10781096
rejection_reason: 'string',
10791097
click_id_shape: 'string',
@@ -1105,6 +1123,14 @@ function sanitizeExternalConversionPostbackFields(
11051123
) {
11061124
delete data.click_id_shape
11071125
}
1126+
if (
1127+
typeof data.selected_rail === 'string' &&
1128+
!(ADS_EXTERNAL_CONVERSION_SELECTED_RAILS as readonly string[]).includes(
1129+
data.selected_rail,
1130+
)
1131+
) {
1132+
delete data.selected_rail
1133+
}
11081134
return data
11091135
}
11101136

0 commit comments

Comments
 (0)