From 006194c34e467d32900eb69ec45a2282a6318aea Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Fri, 10 Oct 2025 13:41:54 -0400 Subject: [PATCH 1/8] feat: Support periodic reload for api key --- bottlecap/Cargo.lock | 19 +++------------ bottlecap/Cargo.toml | 4 +-- bottlecap/src/bin/bottlecap/main.rs | 14 +++++++---- bottlecap/src/config/env.rs | 7 ++++++ bottlecap/src/config/mod.rs | 35 +++++++++++++++++++++++++++ bottlecap/src/config/yaml.rs | 5 ++++ bottlecap/src/logs/flusher.rs | 2 +- bottlecap/src/traces/proxy_flusher.rs | 2 +- bottlecap/src/traces/stats_flusher.rs | 3 ++- bottlecap/src/traces/trace_flusher.rs | 3 ++- 10 files changed, 68 insertions(+), 26 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 61efeaa54..6b7f98131 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -513,7 +513,7 @@ dependencies = [ "bytes", "chrono", "cookie", - "datadog-fips 0.1.0 (git+https://github.com/DataDog/serverless-components?rev=fa1d2f4ea2c4c2596144a1f362935e56cf0cb3c7)", + "datadog-fips", "datadog-protos", "datadog-trace-normalization", "datadog-trace-obfuscation", @@ -762,18 +762,7 @@ dependencies = [ [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=b0b0cb9310d8d8f2038c00a46e3267e21dc3e287#b0b0cb9310d8d8f2038c00a46e3267e21dc3e287" -dependencies = [ - "reqwest", - "rustls", - "rustls-native-certs", - "tracing", -] - -[[package]] -name = "datadog-fips" -version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=fa1d2f4ea2c4c2596144a1f362935e56cf0cb3c7#fa1d2f4ea2c4c2596144a1f362935e56cf0cb3c7" +source = "git+https://github.com/DataDog/serverless-components?rev=910668996066b270756b0d700f58da7003ee77bd#910668996066b270756b0d700f58da7003ee77bd" dependencies = [ "reqwest", "rustls", @@ -978,9 +967,9 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=b0b0cb9310d8d8f2038c00a46e3267e21dc3e287#b0b0cb9310d8d8f2038c00a46e3267e21dc3e287" +source = "git+https://github.com/DataDog/serverless-components?rev=910668996066b270756b0d700f58da7003ee77bd#910668996066b270756b0d700f58da7003ee77bd" dependencies = [ - "datadog-fips 0.1.0 (git+https://github.com/DataDog/serverless-components?rev=b0b0cb9310d8d8f2038c00a46e3267e21dc3e287)", + "datadog-fips", "datadog-protos", "ddsketch-agent", "derive_more", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index aef406d32..dbe830dd8 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -61,8 +61,8 @@ datadog-trace-protobuf = { git = "https://github.com/DataDog/libdatadog", rev = datadog-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" , features = ["mini_agent"] } datadog-trace-normalization = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } datadog-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "b0b0cb9310d8d8f2038c00a46e3267e21dc3e287", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "fa1d2f4ea2c4c2596144a1f362935e56cf0cb3c7", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "910668996066b270756b0d700f58da7003ee77bd", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "910668996066b270756b0d700f58da7003ee77bd", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index 36471088b..32f8bd9f5 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -342,13 +342,17 @@ fn enable_logging_subsystem() { fn create_api_key_factory(config: &Arc, aws_config: &Arc) -> Arc { let config = Arc::clone(config); let aws_config = Arc::clone(aws_config); + let api_key_reload_interval = config.api_key_reload_interval; - Arc::new(ApiKeyFactory::new_from_resolver(Arc::new(move || { - let config = Arc::clone(&config); - let aws_config = Arc::clone(&aws_config); + Arc::new(ApiKeyFactory::new_from_resolver( + Arc::new(move || { + let config = Arc::clone(&config); + let aws_config = Arc::clone(&aws_config); - Box::pin(async move { resolve_secrets(config, aws_config).await }) - }))) + Box::pin(async move { resolve_secrets(config, aws_config).await }) + }), + api_key_reload_interval, + )) } async fn extension_loop_idle( diff --git a/bottlecap/src/config/env.rs b/bottlecap/src/config/env.rs index 6b50178d0..c047c3e12 100644 --- a/bottlecap/src/config/env.rs +++ b/bottlecap/src/config/env.rs @@ -395,6 +395,13 @@ pub struct EnvConfig { /// Default is `false`. #[serde(deserialize_with = "deserialize_optional_bool_from_anything")] pub compute_trace_stats_on_extension: Option, + /// @env `DD_API_KEY_RELOAD_INTERVAL` + /// + /// The interval at which the Datadog API key is reloaded, in seconds. + /// If None, the API key will not be reloaded. + /// Default is `None`. + #[serde(deserialize_with = "deserialize_optional_duration_from_seconds")] + pub api_key_reload_interval: Option, /// @env `DD_SERVERLESS_APPSEC_ENABLED` /// /// Enable Application and API Protection (AAP), previously known as AppSec/ASM, for AWS Lambda. diff --git a/bottlecap/src/config/mod.rs b/bottlecap/src/config/mod.rs index e8a1a6f9d..fa65ff0c9 100644 --- a/bottlecap/src/config/mod.rs +++ b/bottlecap/src/config/mod.rs @@ -343,6 +343,7 @@ pub struct Config { pub capture_lambda_payload: bool, pub capture_lambda_payload_max_depth: u32, pub compute_trace_stats_on_extension: bool, + pub api_key_reload_interval: Option, pub serverless_appsec_enabled: bool, pub appsec_rules: Option, @@ -444,6 +445,7 @@ impl Default for Config { capture_lambda_payload: false, capture_lambda_payload_max_depth: 10, compute_trace_stats_on_extension: false, + api_key_reload_interval: None, serverless_appsec_enabled: false, appsec_rules: None, @@ -745,6 +747,17 @@ pub fn deserialize_optional_duration_from_seconds<'de, D: Deserializer<'de>>( deserializer.deserialize_any(DurationVisitor) } +// Like deserialize_optional_duration_from_seconds(), but return None if the duration is 0 seconds +pub fn deserialize_optional_duration_from_seconds_ignore_zero<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result, D::Error> { + let duration: Option = deserialize_optional_duration_from_seconds(deserializer)?; + if duration.is_some_and(|d| d.as_secs() == 0) { + return Ok(None); + } + Ok(duration) +} + #[cfg_attr(coverage_nightly, coverage(off))] // Test modules skew coverage metrics #[cfg(test)] pub mod tests { @@ -1353,4 +1366,26 @@ pub mod tests { } ); } + + #[test] + fn test_parse_duration_from_seconds_ignore_zero() { + #[derive(Deserialize, Debug, PartialEq, Eq)] + struct Value { + #[serde(default)] + #[serde(deserialize_with = "deserialize_optional_duration_from_seconds_ignore_zero")] + duration: Option, + } + + assert_eq!( + serde_json::from_str::(r#"{"duration":1}"#).expect("failed to parse JSON"), + Value { + duration: Some(Duration::from_secs(1)) + } + ); + + assert_eq!( + serde_json::from_str::(r#"{"duration":0}"#).expect("failed to parse JSON"), + Value { duration: None } + ); + } } diff --git a/bottlecap/src/config/yaml.rs b/bottlecap/src/config/yaml.rs index bf814d685..a8fc326ca 100644 --- a/bottlecap/src/config/yaml.rs +++ b/bottlecap/src/config/yaml.rs @@ -111,6 +111,8 @@ pub struct YamlConfig { pub capture_lambda_payload_max_depth: Option, #[serde(deserialize_with = "deserialize_optional_bool_from_anything")] pub compute_trace_stats_on_extension: Option, + #[serde(deserialize_with = "deserialize_optional_duration_from_seconds")] + pub api_key_reload_interval: Option, #[serde(deserialize_with = "deserialize_optional_bool_from_anything")] pub serverless_appsec_enabled: Option, #[serde(deserialize_with = "deserialize_optional_string")] @@ -675,6 +677,7 @@ fn merge_config(config: &mut Config, yaml_config: &YamlConfig) { merge_option_to_value!(config, yaml_config, capture_lambda_payload); merge_option_to_value!(config, yaml_config, capture_lambda_payload_max_depth); merge_option_to_value!(config, yaml_config, compute_trace_stats_on_extension); + merge_option!(config, yaml_config, api_key_reload_interval); merge_option_to_value!(config, yaml_config, serverless_appsec_enabled); merge_option!(config, yaml_config, appsec_rules); merge_option_to_value!(config, yaml_config, appsec_waf_timeout); @@ -844,6 +847,7 @@ lambda_proc_enhanced_metrics: false capture_lambda_payload: true capture_lambda_payload_max_depth: 5 compute_trace_stats_on_extension: true +api_key_reload_interval: None serverless_appsec_enabled: true appsec_rules: "/path/to/rules.json" appsec_waf_timeout: 1000000 # Microseconds @@ -976,6 +980,7 @@ api_security_sample_delay: 60 # Seconds capture_lambda_payload: true, capture_lambda_payload_max_depth: 5, compute_trace_stats_on_extension: true, + api_key_reload_interval: None, serverless_appsec_enabled: true, appsec_rules: Some("/path/to/rules.json".to_string()), diff --git a/bottlecap/src/logs/flusher.rs b/bottlecap/src/logs/flusher.rs index 17332a7dd..36b78623b 100644 --- a/bottlecap/src/logs/flusher.rs +++ b/bottlecap/src/logs/flusher.rs @@ -60,7 +60,7 @@ impl Flusher { if batch.is_empty() { continue; } - let req = self.create_request(batch.clone(), api_key).await; + let req = self.create_request(batch.clone(), api_key.as_str()).await; set.spawn(async move { Self::send(req).await }); } } diff --git a/bottlecap/src/traces/proxy_flusher.rs b/bottlecap/src/traces/proxy_flusher.rs index 462faf483..8d3828faf 100644 --- a/bottlecap/src/traces/proxy_flusher.rs +++ b/bottlecap/src/traces/proxy_flusher.rs @@ -103,7 +103,7 @@ impl Flusher { } else { let mut aggregator = self.aggregator.lock().await; for pr in aggregator.get_batch() { - requests.push(self.create_request(pr, api_key).await); + requests.push(self.create_request(pr, api_key.as_str()).await); } } diff --git a/bottlecap/src/traces/stats_flusher.rs b/bottlecap/src/traces/stats_flusher.rs index e8b9e8f97..1c10979f2 100644 --- a/bottlecap/src/traces/stats_flusher.rs +++ b/bottlecap/src/traces/stats_flusher.rs @@ -102,7 +102,8 @@ impl StatsFlusher for ServerlessStatsFlusher { let start = std::time::Instant::now(); let resp = - stats_utils::send_stats_payload(serialized_stats_payload, endpoint, api_key).await; + stats_utils::send_stats_payload(serialized_stats_payload, endpoint, api_key.as_str()) + .await; let elapsed = start.elapsed(); debug!( "Stats request to {} took {} ms", diff --git a/bottlecap/src/traces/trace_flusher.rs b/bottlecap/src/traces/trace_flusher.rs index dfa45a165..454010e36 100644 --- a/bottlecap/src/traces/trace_flusher.rs +++ b/bottlecap/src/traces/trace_flusher.rs @@ -129,7 +129,8 @@ impl TraceFlusher for ServerlessTraceFlusher { for trace_builders in all_batches { let traces: Vec<_> = trace_builders .into_iter() - .map(|builder| builder.with_api_key(api_key)) + // Lazily set the API key + .map(|builder| builder.with_api_key(api_key.as_str())) .map(SendDataBuilder::build) .collect(); From 78bf9f1832bd4ca37b1f36687dff03786ecf1561 Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Tue, 14 Oct 2025 09:55:49 -0400 Subject: [PATCH 2/8] Update dogstatsd --- bottlecap/Cargo.lock | 4 ++-- bottlecap/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 6b7f98131..87ab654b4 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -762,7 +762,7 @@ dependencies = [ [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=910668996066b270756b0d700f58da7003ee77bd#910668996066b270756b0d700f58da7003ee77bd" +source = "git+https://github.com/DataDog/serverless-components?rev=a7eabe8fa6d2b15f334a6c0b58b28b63609977c2#a7eabe8fa6d2b15f334a6c0b58b28b63609977c2" dependencies = [ "reqwest", "rustls", @@ -967,7 +967,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=910668996066b270756b0d700f58da7003ee77bd#910668996066b270756b0d700f58da7003ee77bd" +source = "git+https://github.com/DataDog/serverless-components?rev=a7eabe8fa6d2b15f334a6c0b58b28b63609977c2#a7eabe8fa6d2b15f334a6c0b58b28b63609977c2" dependencies = [ "datadog-fips", "datadog-protos", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index dbe830dd8..e24c05a51 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -61,8 +61,8 @@ datadog-trace-protobuf = { git = "https://github.com/DataDog/libdatadog", rev = datadog-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" , features = ["mini_agent"] } datadog-trace-normalization = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } datadog-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "910668996066b270756b0d700f58da7003ee77bd", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "910668996066b270756b0d700f58da7003ee77bd", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "a7eabe8fa6d2b15f334a6c0b58b28b63609977c2", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "a7eabe8fa6d2b15f334a6c0b58b28b63609977c2", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] From 600d6e90c2eafe56da8ec3d20dbb04450df99b2f Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Tue, 14 Oct 2025 11:26:50 -0400 Subject: [PATCH 3/8] Fix config load --- bottlecap/Cargo.lock | 4 ++-- bottlecap/Cargo.toml | 4 ++-- bottlecap/src/config/env.rs | 8 ++++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 87ab654b4..6fea36093 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -762,7 +762,7 @@ dependencies = [ [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=a7eabe8fa6d2b15f334a6c0b58b28b63609977c2#a7eabe8fa6d2b15f334a6c0b58b28b63609977c2" +source = "git+https://github.com/DataDog/serverless-components?rev=ebeeedf5451f29ea13229eed3814880bc731f12f#ebeeedf5451f29ea13229eed3814880bc731f12f" dependencies = [ "reqwest", "rustls", @@ -967,7 +967,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=a7eabe8fa6d2b15f334a6c0b58b28b63609977c2#a7eabe8fa6d2b15f334a6c0b58b28b63609977c2" +source = "git+https://github.com/DataDog/serverless-components?rev=ebeeedf5451f29ea13229eed3814880bc731f12f#ebeeedf5451f29ea13229eed3814880bc731f12f" dependencies = [ "datadog-fips", "datadog-protos", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index e24c05a51..03565fd65 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -61,8 +61,8 @@ datadog-trace-protobuf = { git = "https://github.com/DataDog/libdatadog", rev = datadog-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" , features = ["mini_agent"] } datadog-trace-normalization = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } datadog-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "a7eabe8fa6d2b15f334a6c0b58b28b63609977c2", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "a7eabe8fa6d2b15f334a6c0b58b28b63609977c2", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "ebeeedf5451f29ea13229eed3814880bc731f12f", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "ebeeedf5451f29ea13229eed3814880bc731f12f", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] diff --git a/bottlecap/src/config/env.rs b/bottlecap/src/config/env.rs index c047c3e12..0da1e1dc2 100644 --- a/bottlecap/src/config/env.rs +++ b/bottlecap/src/config/env.rs @@ -13,7 +13,8 @@ use crate::{ deserialize_apm_filter_tags, deserialize_array_from_comma_separated_string, deserialize_key_value_pairs, deserialize_option_lossless, deserialize_optional_bool_from_anything, deserialize_optional_duration_from_microseconds, - deserialize_optional_duration_from_seconds, deserialize_optional_string, + deserialize_optional_duration_from_seconds, + deserialize_optional_duration_from_seconds_ignore_zero, deserialize_optional_string, deserialize_string_or_int, flush_strategy::FlushStrategy, log_level::LogLevel, @@ -400,7 +401,7 @@ pub struct EnvConfig { /// The interval at which the Datadog API key is reloaded, in seconds. /// If None, the API key will not be reloaded. /// Default is `None`. - #[serde(deserialize_with = "deserialize_optional_duration_from_seconds")] + #[serde(deserialize_with = "deserialize_optional_duration_from_seconds_ignore_zero")] pub api_key_reload_interval: Option, /// @env `DD_SERVERLESS_APPSEC_ENABLED` /// @@ -605,6 +606,7 @@ fn merge_config(config: &mut Config, env_config: &EnvConfig) { merge_option_to_value!(config, env_config, capture_lambda_payload); merge_option_to_value!(config, env_config, capture_lambda_payload_max_depth); merge_option_to_value!(config, env_config, compute_trace_stats_on_extension); + merge_option!(config, env_config, api_key_reload_interval); merge_option_to_value!(config, env_config, serverless_appsec_enabled); merge_option!(config, env_config, appsec_rules); merge_option_to_value!(config, env_config, appsec_waf_timeout); @@ -798,6 +800,7 @@ mod tests { jail.set_env("DD_CAPTURE_LAMBDA_PAYLOAD", "true"); jail.set_env("DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH", "5"); jail.set_env("DD_COMPUTE_TRACE_STATS_ON_EXTENSION", "true"); + jail.set_env("DD_API_KEY_RELOAD_INTERVAL", "10"); jail.set_env("DD_SERVERLESS_APPSEC_ENABLED", "true"); jail.set_env("DD_APPSEC_RULES", "/path/to/rules.json"); jail.set_env("DD_APPSEC_WAF_TIMEOUT", "1000000"); // Microseconds @@ -947,6 +950,7 @@ mod tests { capture_lambda_payload: true, capture_lambda_payload_max_depth: 5, compute_trace_stats_on_extension: true, + api_key_reload_interval: Some(Duration::from_secs(10)), serverless_appsec_enabled: true, appsec_rules: Some("/path/to/rules.json".to_string()), appsec_waf_timeout: Duration::from_secs(1), From 5a2f1d9a17d8d3215ffbe7b41c3aa256c269c553 Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Tue, 14 Oct 2025 11:34:20 -0400 Subject: [PATCH 4/8] Upgrade dogstatsd --- bottlecap/Cargo.lock | 4 ++-- bottlecap/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 6fea36093..d3a4bb879 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -762,7 +762,7 @@ dependencies = [ [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=ebeeedf5451f29ea13229eed3814880bc731f12f#ebeeedf5451f29ea13229eed3814880bc731f12f" +source = "git+https://github.com/DataDog/serverless-components?rev=bb7aa47ca80f27e06ae48f5867918dd9e300b8fc#bb7aa47ca80f27e06ae48f5867918dd9e300b8fc" dependencies = [ "reqwest", "rustls", @@ -967,7 +967,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=ebeeedf5451f29ea13229eed3814880bc731f12f#ebeeedf5451f29ea13229eed3814880bc731f12f" +source = "git+https://github.com/DataDog/serverless-components?rev=bb7aa47ca80f27e06ae48f5867918dd9e300b8fc#bb7aa47ca80f27e06ae48f5867918dd9e300b8fc" dependencies = [ "datadog-fips", "datadog-protos", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index 03565fd65..3fc2a5cc8 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -61,8 +61,8 @@ datadog-trace-protobuf = { git = "https://github.com/DataDog/libdatadog", rev = datadog-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" , features = ["mini_agent"] } datadog-trace-normalization = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } datadog-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "ebeeedf5451f29ea13229eed3814880bc731f12f", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "ebeeedf5451f29ea13229eed3814880bc731f12f", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "bb7aa47ca80f27e06ae48f5867918dd9e300b8fc", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "bb7aa47ca80f27e06ae48f5867918dd9e300b8fc", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] From a6461fd30deaaa79a486e2f2d00ff5abc761be6f Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Tue, 14 Oct 2025 11:50:42 -0400 Subject: [PATCH 5/8] Fix yaml test --- bottlecap/Cargo.lock | 4 ++-- bottlecap/Cargo.toml | 4 ++-- bottlecap/src/config/yaml.rs | 8 +++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index d3a4bb879..9bdf4a496 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -762,7 +762,7 @@ dependencies = [ [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=bb7aa47ca80f27e06ae48f5867918dd9e300b8fc#bb7aa47ca80f27e06ae48f5867918dd9e300b8fc" +source = "git+https://github.com/DataDog/serverless-components?rev=936b3440a1ffc3dd68d040354b721a3042aad47d#936b3440a1ffc3dd68d040354b721a3042aad47d" dependencies = [ "reqwest", "rustls", @@ -967,7 +967,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=bb7aa47ca80f27e06ae48f5867918dd9e300b8fc#bb7aa47ca80f27e06ae48f5867918dd9e300b8fc" +source = "git+https://github.com/DataDog/serverless-components?rev=936b3440a1ffc3dd68d040354b721a3042aad47d#936b3440a1ffc3dd68d040354b721a3042aad47d" dependencies = [ "datadog-fips", "datadog-protos", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index 3fc2a5cc8..68d65feee 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -61,8 +61,8 @@ datadog-trace-protobuf = { git = "https://github.com/DataDog/libdatadog", rev = datadog-trace-utils = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" , features = ["mini_agent"] } datadog-trace-normalization = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } datadog-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "9405db9cb4ef733f3954c3ee77ce71a502e98e50" } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "bb7aa47ca80f27e06ae48f5867918dd9e300b8fc", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "bb7aa47ca80f27e06ae48f5867918dd9e300b8fc", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "936b3440a1ffc3dd68d040354b721a3042aad47d", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "936b3440a1ffc3dd68d040354b721a3042aad47d", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] diff --git a/bottlecap/src/config/yaml.rs b/bottlecap/src/config/yaml.rs index a8fc326ca..a0e23d039 100644 --- a/bottlecap/src/config/yaml.rs +++ b/bottlecap/src/config/yaml.rs @@ -8,7 +8,9 @@ use crate::{ deserialize_apm_replace_rules, deserialize_key_value_pair_array_to_hashmap, deserialize_option_lossless, deserialize_optional_bool_from_anything, deserialize_optional_duration_from_microseconds, - deserialize_optional_duration_from_seconds, deserialize_optional_string, + deserialize_optional_duration_from_seconds, + deserialize_optional_duration_from_seconds_ignore_zero, + deserialize_optional_string, deserialize_processing_rules, deserialize_string_or_int, flush_strategy::FlushStrategy, log_level::LogLevel, @@ -111,7 +113,7 @@ pub struct YamlConfig { pub capture_lambda_payload_max_depth: Option, #[serde(deserialize_with = "deserialize_optional_bool_from_anything")] pub compute_trace_stats_on_extension: Option, - #[serde(deserialize_with = "deserialize_optional_duration_from_seconds")] + #[serde(deserialize_with = "deserialize_optional_duration_from_seconds_ignore_zero")] pub api_key_reload_interval: Option, #[serde(deserialize_with = "deserialize_optional_bool_from_anything")] pub serverless_appsec_enabled: Option, @@ -847,7 +849,7 @@ lambda_proc_enhanced_metrics: false capture_lambda_payload: true capture_lambda_payload_max_depth: 5 compute_trace_stats_on_extension: true -api_key_reload_interval: None +api_key_reload_interval: 0 serverless_appsec_enabled: true appsec_rules: "/path/to/rules.json" appsec_waf_timeout: 1000000 # Microseconds From 3669cd77db5633fd3cda0d263796820c3c0c919c Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Tue, 14 Oct 2025 11:57:33 -0400 Subject: [PATCH 6/8] fmt --- bottlecap/src/config/yaml.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bottlecap/src/config/yaml.rs b/bottlecap/src/config/yaml.rs index a0e23d039..848378735 100644 --- a/bottlecap/src/config/yaml.rs +++ b/bottlecap/src/config/yaml.rs @@ -9,8 +9,7 @@ use crate::{ deserialize_option_lossless, deserialize_optional_bool_from_anything, deserialize_optional_duration_from_microseconds, deserialize_optional_duration_from_seconds, - deserialize_optional_duration_from_seconds_ignore_zero, - deserialize_optional_string, + deserialize_optional_duration_from_seconds_ignore_zero, deserialize_optional_string, deserialize_processing_rules, deserialize_string_or_int, flush_strategy::FlushStrategy, log_level::LogLevel, From 924bd0f518fdf201b239b166cdf3490cc800104a Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Tue, 14 Oct 2025 11:59:04 -0400 Subject: [PATCH 7/8] Update comments --- bottlecap/src/config/mod.rs | 2 +- bottlecap/src/traces/trace_flusher.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/bottlecap/src/config/mod.rs b/bottlecap/src/config/mod.rs index fa65ff0c9..9721f3526 100644 --- a/bottlecap/src/config/mod.rs +++ b/bottlecap/src/config/mod.rs @@ -747,7 +747,7 @@ pub fn deserialize_optional_duration_from_seconds<'de, D: Deserializer<'de>>( deserializer.deserialize_any(DurationVisitor) } -// Like deserialize_optional_duration_from_seconds(), but return None if the duration is 0 seconds +// Like deserialize_optional_duration_from_seconds(), but return None if the value is 0 pub fn deserialize_optional_duration_from_seconds_ignore_zero<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result, D::Error> { diff --git a/bottlecap/src/traces/trace_flusher.rs b/bottlecap/src/traces/trace_flusher.rs index 454010e36..890cd6abe 100644 --- a/bottlecap/src/traces/trace_flusher.rs +++ b/bottlecap/src/traces/trace_flusher.rs @@ -129,7 +129,6 @@ impl TraceFlusher for ServerlessTraceFlusher { for trace_builders in all_batches { let traces: Vec<_> = trace_builders .into_iter() - // Lazily set the API key .map(|builder| builder.with_api_key(api_key.as_str())) .map(SendDataBuilder::build) .collect(); From ec638a5beec5b14169df5adf78a866fa78e9bf28 Mon Sep 17 00:00:00 2001 From: Yiming Luo Date: Wed, 15 Oct 2025 08:24:26 -0400 Subject: [PATCH 8/8] Rename: api_key_reload_interval -> api_key_secret_reload_interval --- bottlecap/src/bin/bottlecap/main.rs | 4 ++-- bottlecap/src/config/env.rs | 10 +++++----- bottlecap/src/config/mod.rs | 4 ++-- bottlecap/src/config/yaml.rs | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index 32f8bd9f5..b5e17a9bb 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -342,7 +342,7 @@ fn enable_logging_subsystem() { fn create_api_key_factory(config: &Arc, aws_config: &Arc) -> Arc { let config = Arc::clone(config); let aws_config = Arc::clone(aws_config); - let api_key_reload_interval = config.api_key_reload_interval; + let api_key_secret_reload_interval = config.api_key_secret_reload_interval; Arc::new(ApiKeyFactory::new_from_resolver( Arc::new(move || { @@ -351,7 +351,7 @@ fn create_api_key_factory(config: &Arc, aws_config: &Arc) -> Box::pin(async move { resolve_secrets(config, aws_config).await }) }), - api_key_reload_interval, + api_key_secret_reload_interval, )) } diff --git a/bottlecap/src/config/env.rs b/bottlecap/src/config/env.rs index 0da1e1dc2..1ba53dffa 100644 --- a/bottlecap/src/config/env.rs +++ b/bottlecap/src/config/env.rs @@ -396,13 +396,13 @@ pub struct EnvConfig { /// Default is `false`. #[serde(deserialize_with = "deserialize_optional_bool_from_anything")] pub compute_trace_stats_on_extension: Option, - /// @env `DD_API_KEY_RELOAD_INTERVAL` + /// @env `DD_API_KEY_SECRET_RELOAD_INTERVAL` /// /// The interval at which the Datadog API key is reloaded, in seconds. /// If None, the API key will not be reloaded. /// Default is `None`. #[serde(deserialize_with = "deserialize_optional_duration_from_seconds_ignore_zero")] - pub api_key_reload_interval: Option, + pub api_key_secret_reload_interval: Option, /// @env `DD_SERVERLESS_APPSEC_ENABLED` /// /// Enable Application and API Protection (AAP), previously known as AppSec/ASM, for AWS Lambda. @@ -606,7 +606,7 @@ fn merge_config(config: &mut Config, env_config: &EnvConfig) { merge_option_to_value!(config, env_config, capture_lambda_payload); merge_option_to_value!(config, env_config, capture_lambda_payload_max_depth); merge_option_to_value!(config, env_config, compute_trace_stats_on_extension); - merge_option!(config, env_config, api_key_reload_interval); + merge_option!(config, env_config, api_key_secret_reload_interval); merge_option_to_value!(config, env_config, serverless_appsec_enabled); merge_option!(config, env_config, appsec_rules); merge_option_to_value!(config, env_config, appsec_waf_timeout); @@ -800,7 +800,7 @@ mod tests { jail.set_env("DD_CAPTURE_LAMBDA_PAYLOAD", "true"); jail.set_env("DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH", "5"); jail.set_env("DD_COMPUTE_TRACE_STATS_ON_EXTENSION", "true"); - jail.set_env("DD_API_KEY_RELOAD_INTERVAL", "10"); + jail.set_env("DD_API_KEY_SECRET_RELOAD_INTERVAL", "10"); jail.set_env("DD_SERVERLESS_APPSEC_ENABLED", "true"); jail.set_env("DD_APPSEC_RULES", "/path/to/rules.json"); jail.set_env("DD_APPSEC_WAF_TIMEOUT", "1000000"); // Microseconds @@ -950,7 +950,7 @@ mod tests { capture_lambda_payload: true, capture_lambda_payload_max_depth: 5, compute_trace_stats_on_extension: true, - api_key_reload_interval: Some(Duration::from_secs(10)), + api_key_secret_reload_interval: Some(Duration::from_secs(10)), serverless_appsec_enabled: true, appsec_rules: Some("/path/to/rules.json".to_string()), appsec_waf_timeout: Duration::from_secs(1), diff --git a/bottlecap/src/config/mod.rs b/bottlecap/src/config/mod.rs index 9721f3526..3d5e4fc60 100644 --- a/bottlecap/src/config/mod.rs +++ b/bottlecap/src/config/mod.rs @@ -343,7 +343,7 @@ pub struct Config { pub capture_lambda_payload: bool, pub capture_lambda_payload_max_depth: u32, pub compute_trace_stats_on_extension: bool, - pub api_key_reload_interval: Option, + pub api_key_secret_reload_interval: Option, pub serverless_appsec_enabled: bool, pub appsec_rules: Option, @@ -445,7 +445,7 @@ impl Default for Config { capture_lambda_payload: false, capture_lambda_payload_max_depth: 10, compute_trace_stats_on_extension: false, - api_key_reload_interval: None, + api_key_secret_reload_interval: None, serverless_appsec_enabled: false, appsec_rules: None, diff --git a/bottlecap/src/config/yaml.rs b/bottlecap/src/config/yaml.rs index 848378735..4df1f85b2 100644 --- a/bottlecap/src/config/yaml.rs +++ b/bottlecap/src/config/yaml.rs @@ -113,7 +113,7 @@ pub struct YamlConfig { #[serde(deserialize_with = "deserialize_optional_bool_from_anything")] pub compute_trace_stats_on_extension: Option, #[serde(deserialize_with = "deserialize_optional_duration_from_seconds_ignore_zero")] - pub api_key_reload_interval: Option, + pub api_key_secret_reload_interval: Option, #[serde(deserialize_with = "deserialize_optional_bool_from_anything")] pub serverless_appsec_enabled: Option, #[serde(deserialize_with = "deserialize_optional_string")] @@ -678,7 +678,7 @@ fn merge_config(config: &mut Config, yaml_config: &YamlConfig) { merge_option_to_value!(config, yaml_config, capture_lambda_payload); merge_option_to_value!(config, yaml_config, capture_lambda_payload_max_depth); merge_option_to_value!(config, yaml_config, compute_trace_stats_on_extension); - merge_option!(config, yaml_config, api_key_reload_interval); + merge_option!(config, yaml_config, api_key_secret_reload_interval); merge_option_to_value!(config, yaml_config, serverless_appsec_enabled); merge_option!(config, yaml_config, appsec_rules); merge_option_to_value!(config, yaml_config, appsec_waf_timeout); @@ -848,7 +848,7 @@ lambda_proc_enhanced_metrics: false capture_lambda_payload: true capture_lambda_payload_max_depth: 5 compute_trace_stats_on_extension: true -api_key_reload_interval: 0 +api_key_secret_reload_interval: 0 serverless_appsec_enabled: true appsec_rules: "/path/to/rules.json" appsec_waf_timeout: 1000000 # Microseconds @@ -981,7 +981,7 @@ api_security_sample_delay: 60 # Seconds capture_lambda_payload: true, capture_lambda_payload_max_depth: 5, compute_trace_stats_on_extension: true, - api_key_reload_interval: None, + api_key_secret_reload_interval: None, serverless_appsec_enabled: true, appsec_rules: Some("/path/to/rules.json".to_string()),