From e32eeec78d0e1aa8e9f7721b2ce19a9366e588ba Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Thu, 13 Mar 2025 20:30:10 +1100 Subject: [PATCH] fix(telemetry): correctly deserialise feature flags (#8425) Our Posthog integration was so lenient in regards to errors that I didn't even notice at all that we failed to deserialise them correctly. In Posthog, I configured the feature flags with `kebab-case` but we tried to deserialise them as `snake_case`. --- rust/telemetry/src/lib.rs | 41 +++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/rust/telemetry/src/lib.rs b/rust/telemetry/src/lib.rs index 84317936b..9e1c0e337 100644 --- a/rust/telemetry/src/lib.rs +++ b/rust/telemetry/src/lib.rs @@ -5,7 +5,7 @@ use std::{ time::Duration, }; -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use env::ON_PREM; use parking_lot::RwLock; use sentry::protocol::SessionStatus; @@ -210,30 +210,47 @@ fn set_current_user(user: Option) { sentry::Hub::main().configure_scope(|scope| scope.set_user(user)); } -fn evaluate_feature_flags(id: String) -> Result { - let json = reqwest::blocking::Client::new() +fn evaluate_feature_flags(distinct_id: String) -> Result { + let response = reqwest::blocking::ClientBuilder::new() + .connection_verbose(true) + .build()? .post("https://us.i.posthog.com/decide?v=3") - .body(format!( - r#"{{ - "api_key": "{POSTHOG_API_KEY}", - "distinct_id": "{id}" - }}"# - )) + .json(&DecideRequest { + api_key: POSTHOG_API_KEY.to_string(), + distinct_id, + }) .send() - .context("Failed to send POST request")? + .context("Failed to send POST request")?; + + let status = response.status(); + + if !status.is_success() { + let body = response.text().unwrap_or_default(); + + bail!("Failed to get feature flags; status={status}, body={body}") + } + + let json = response .json::() .context("Failed to deserialize response")?; Ok(json.feature_flags) } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize)] +struct DecideRequest { + api_key: String, + distinct_id: String, +} + +#[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct DecideResponse { feature_flags: FeatureFlags, } -#[derive(Debug, Serialize, Deserialize, Default, Clone, Copy)] +#[derive(Debug, Deserialize, Default, Clone, Copy)] +#[serde(rename_all = "kebab-case")] struct FeatureFlags { #[serde(default)] icmp_unreachable_instead_of_nat64: bool,