Skip to content

Commit 9135c18

Browse files
authored
chore(deps): bump datadog-agent-config to 8ce37eb (dd_org_uuid + logs_enabled) (#1267)
## Summary Bumps the \`datadog-agent-config\` / \`dogstatsd\` / \`datadog-fips\` pin to \`8ce37eb\`, which contains two recently-merged upstream features: - [serverless-components#137](DataDog/serverless-components#137) — adds \`Config::dd_org_uuid: String\` (\`DD_ORG_UUID\` / yaml \`org_uuid\`) - [serverless-components#138](DataDog/serverless-components#138) — adds \`Config::logs_enabled: bool\` (\`DD_LOGS_ENABLED\` / yaml \`logs_enabled\`) ## What changes in bottlecap ### dd_org_uuid Drops the now-redundant local copy from \`LambdaConfig\`: - \`LambdaConfig\`: removed \`dd_org_uuid: String\`. - \`LambdaConfigSource\`: removed \`org_uuid: Option<String>\` and the \`merge_string!(self, dd_org_uuid, source, org_uuid)\` source-to-config renaming call in \`merge_from\`. - Consumers (\`secrets/decrypt.rs\`, \`secrets/delegated_auth/client.rs\`) switch from \`config.ext.dd_org_uuid\` → \`config.dd_org_uuid\`. - Tests assert on the upstream field. ### logs_enabled The lambda extension's existing OR-merge contract for log shipping is preserved **exactly**. The legacy semantics are: | \`DD_SERVERLESS_LOGS_ENABLED\` | \`DD_LOGS_ENABLED\` | resolved \`serverless_logs_enabled\` | |---|---|---| | unset | unset | **true** (default kept) | | any | true | true | | true | any | true | | false | false | false | | **unset** | **false** | **false** (alias alone can override default) | | false | unset | false | To preserve "was \`DD_LOGS_ENABLED\` explicitly set?" the alias source field is **retained** on \`LambdaConfigSource\` and the OR-merge in \`merge_from\` is kept. The upstream parsing of the same env var into \`config.logs_enabled\` runs in parallel — that field exists for any non-lambda consumer of the crate, but the lambda extension continues to gate log shipping on \`config.ext.serverless_logs_enabled\`. A regression test was added for the alias-only-false case (the trickiest invariant), so a future refactor that breaks it fails loudly. ## Why two PRs in one Both upstream PRs are merged and \`8ce37eb\` contains them as a single SHA. Bundling lets us bump once and avoid a transitional state where main is pinned to a SHA that has \`logs_enabled\` upstream but the lambda extension's source field still aliases it. ## Test plan - [x] \`cargo test --workspace --features default\` — all pass (lambda_config_tests now at 40, +2 for the new logs_enabled coverage) - [x] \`cargo clippy --workspace --all-targets --features default\` — clean - [x] \`cargo fmt -- --check\` — clean - [x] Regression test \`logs_enabled_alias_only_false_overrides_default\` exercises the invariant that \`DD_LOGS_ENABLED=false\` alone disables logs (overriding the default-true) - [x] No behavior change for customers — same env vars, same resolved field at lambda call sites
1 parent a61ba77 commit 9135c18

5 files changed

Lines changed: 67 additions & 56 deletions

File tree

bottlecap/Cargo.lock

Lines changed: 6 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bottlecap/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ libdd-trace-normalization = { git = "https://github.com/DataDog/libdatadog", rev
8282
libdd-trace-obfuscation = { git = "https://github.com/DataDog/libdatadog", rev = "48da0d82cb32b43d4cdece35b794c9bcbc275a03", default-features = false }
8383
libdd-trace-stats = { git = "https://github.com/DataDog/libdatadog", rev = "48da0d82cb32b43d4cdece35b794c9bcbc275a03", default-features = false }
8484
datadog-opentelemetry = { git = "https://github.com/DataDog/dd-trace-rs", rev = "f51cefc4ad24bec81b38fb2f36b1ed93f21ae913", default-features = false }
85-
dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "bb4dedeee20b949db3143c05e5a779b843a8a484", default-features = false }
86-
datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "bb4dedeee20b949db3143c05e5a779b843a8a484", default-features = false }
87-
datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "bb4dedeee20b949db3143c05e5a779b843a8a484", default-features = false }
85+
dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "8ce37eb029410b7cf30847376772e3af6baa5f5c", default-features = false }
86+
datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "8ce37eb029410b7cf30847376772e3af6baa5f5c", default-features = false }
87+
datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "8ce37eb029410b7cf30847376772e3af6baa5f5c", default-features = false }
8888
libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] }
8989

9090
[dev-dependencies]

bottlecap/src/config/mod.rs

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use datadog_agent_config::{
4545
deserialize_optional_duration_from_microseconds as deser_dur_micros,
4646
deserialize_optional_duration_from_seconds as deser_dur_secs,
4747
deserialize_optional_duration_from_seconds_ignore_zero as deser_dur_secs_ignore_zero,
48-
deserialize_optional_string as deser_opt_str, deserialize_string_or_int as deser_str_or_int,
48+
deserialize_optional_string as deser_opt_str,
4949
flush_strategy::FlushStrategy as UpstreamFlushStrategy,
5050
};
5151

@@ -68,7 +68,6 @@ pub struct LambdaConfig {
6868
pub lambda_extension_compute_stats: bool,
6969
pub span_dedup_timeout: Option<Duration>,
7070
pub api_key_secret_reload_interval: Option<Duration>,
71-
pub dd_org_uuid: String,
7271
pub serverless_appsec_enabled: bool,
7372
pub appsec_rules: Option<String>,
7473
pub appsec_waf_timeout: Duration,
@@ -98,7 +97,6 @@ impl Default for LambdaConfig {
9897
lambda_extension_compute_stats: false,
9998
span_dedup_timeout: None,
10099
api_key_secret_reload_interval: None,
101-
dd_org_uuid: String::new(),
102100
serverless_appsec_enabled: false,
103101
appsec_rules: None,
104102
appsec_waf_timeout: Duration::from_millis(5),
@@ -126,11 +124,17 @@ pub struct LambdaConfigSource {
126124
#[serde(deserialize_with = "deser_opt_str")]
127125
pub api_key_ssm_arn: Option<String>,
128126

129-
/// `DD_SERVERLESS_LOGS_ENABLED` — primary toggle for Lambda log shipping.
127+
/// `DD_SERVERLESS_LOGS_ENABLED` — Lambda-specific log toggle, kept for
128+
/// backwards compatibility. Defaults to `true` (the Lambda extension's
129+
/// historical behavior).
130130
#[serde(deserialize_with = "deser_opt_bool")]
131131
pub serverless_logs_enabled: Option<bool>,
132-
/// `DD_LOGS_ENABLED` — alias for `serverless_logs_enabled`; OR-merged so
133-
/// either being `true` turns logs on. See `merge_from` below.
132+
/// `DD_LOGS_ENABLED` — deserialized here a second time (the canonical
133+
/// `Config::logs_enabled` upstream field is also populated by the upstream
134+
/// env/yaml parsing) because lambda's default for logs is `true` while
135+
/// upstream's is `false`. Keeping the alias as `Option<bool>` lets
136+
/// `merge_from` detect "was it explicitly set?" and OR-merge it into
137+
/// `serverless_logs_enabled` — that is the field lambda call sites read.
134138
#[serde(deserialize_with = "deser_opt_bool")]
135139
pub logs_enabled: Option<bool>,
136140

@@ -154,12 +158,6 @@ pub struct LambdaConfigSource {
154158
#[serde(deserialize_with = "deser_dur_secs_ignore_zero")]
155159
pub api_key_secret_reload_interval: Option<Duration>,
156160

157-
/// `DD_ORG_UUID` — when set, delegated auth is auto-enabled. The source
158-
/// field is `org_uuid` (matching the env var) and merges into the
159-
/// `dd_org_uuid` config field.
160-
#[serde(deserialize_with = "deser_str_or_int")]
161-
pub org_uuid: Option<String>,
162-
163161
#[serde(deserialize_with = "deser_opt_bool")]
164162
pub serverless_appsec_enabled: Option<bool>,
165163
#[serde(deserialize_with = "deser_opt_str")]
@@ -210,17 +208,20 @@ impl DatadogConfigExtension for LambdaConfig {
210208
option: [span_dedup_timeout, api_key_secret_reload_interval, appsec_rules],
211209
);
212210

213-
// OR-merge serverless_logs_enabled with the logs_enabled alias. Either
214-
// env var set to `true` enables logs; if both are absent the default
215-
// (true) is preserved.
211+
// Preserve legacy OR-merge semantics: when either env var is
212+
// explicitly set, the resolved value is the OR of the two (unset
213+
// counts as false for the OR). When neither is set, the default
214+
// (true) is preserved. This invariant — in particular that setting
215+
// only DD_LOGS_ENABLED=false disables logs — predates upstream
216+
// owning `logs_enabled` and must be kept. The duplicate parse of
217+
// DD_LOGS_ENABLED (once upstream, once here via the alias) is
218+
// intentional: upstream populates `config.logs_enabled` for any
219+
// non-lambda consumer, while this branch keeps the lambda contract.
216220
if source.serverless_logs_enabled.is_some() || source.logs_enabled.is_some() {
217221
self.serverless_logs_enabled = source.serverless_logs_enabled.unwrap_or(false)
218222
|| source.logs_enabled.unwrap_or(false);
219223
}
220224

221-
// org_uuid (source) → dd_org_uuid (config)
222-
datadog_agent_config::merge_string!(self, dd_org_uuid, source, org_uuid);
223-
224225
// lambda_customer_metrics_exclude_tags (source) → custom_metrics_exclude_tags (config)
225226
if !source.lambda_customer_metrics_exclude_tags.is_empty() {
226227
self.custom_metrics_exclude_tags
@@ -316,6 +317,14 @@ mod lambda_config_tests {
316317
}
317318

318319
// ---- serverless_logs_enabled with OR-merge alias ----
320+
//
321+
// The legacy contract: DD_SERVERLESS_LOGS_ENABLED and DD_LOGS_ENABLED are
322+
// OR-merged into config.ext.serverless_logs_enabled. The default (true)
323+
// is preserved iff neither env var was explicitly set; otherwise the
324+
// resolved value is the OR of the two (unset counts as false). The
325+
// upstream `Config::logs_enabled` field is also populated independently
326+
// (sourced by the upstream env/yaml parsing), but lambda call sites that
327+
// gate on log shipping continue to use serverless_logs_enabled.
319328

320329
#[test]
321330
fn serverless_logs_enabled_defaults_true() {
@@ -343,14 +352,26 @@ mod lambda_config_tests {
343352
}
344353

345354
#[test]
346-
fn logs_enabled_alias_only() {
355+
fn logs_enabled_alias_only_true() {
347356
let config = load(|jail| {
348357
jail.set_env("DD_LOGS_ENABLED", "true");
349358
Ok(())
350359
});
351360
assert!(config.ext.serverless_logs_enabled);
352361
}
353362

363+
#[test]
364+
fn logs_enabled_alias_only_false_overrides_default() {
365+
// Setting only DD_LOGS_ENABLED=false must disable logs, overriding
366+
// the default-true. This is the legacy behavior that the alias-only
367+
// entry into the OR-merge guards.
368+
let config = load(|jail| {
369+
jail.set_env("DD_LOGS_ENABLED", "false");
370+
Ok(())
371+
});
372+
assert!(!config.ext.serverless_logs_enabled);
373+
}
374+
354375
#[test]
355376
fn serverless_logs_disabled_when_both_false() {
356377
let config = load(|jail| {
@@ -370,6 +391,18 @@ mod lambda_config_tests {
370391
assert!(!config.ext.serverless_logs_enabled);
371392
}
372393

394+
#[test]
395+
fn dd_logs_enabled_also_populates_upstream_field() {
396+
// The upstream Config::logs_enabled field is wired through the
397+
// upstream env parsing independently of the lambda alias. Lambda
398+
// doesn't read this field, but other consumers of the same crate do.
399+
let config = load(|jail| {
400+
jail.set_env("DD_LOGS_ENABLED", "true");
401+
Ok(())
402+
});
403+
assert!(config.logs_enabled);
404+
}
405+
373406
// ---- FlushStrategy ----
374407

375408
#[test]
@@ -598,10 +631,7 @@ mod lambda_config_tests {
598631
jail.set_env("DD_ORG_UUID", "00000000-1111-2222-3333-444444444444");
599632
Ok(())
600633
});
601-
assert_eq!(
602-
config.ext.dd_org_uuid,
603-
"00000000-1111-2222-3333-444444444444"
604-
);
634+
assert_eq!(config.dd_org_uuid, "00000000-1111-2222-3333-444444444444");
605635
}
606636

607637
#[test]
@@ -615,10 +645,7 @@ mod lambda_config_tests {
615645
)?;
616646
Ok(())
617647
});
618-
assert_eq!(
619-
config.ext.dd_org_uuid,
620-
"00000000-1111-2222-3333-444444444444"
621-
);
648+
assert_eq!(config.dd_org_uuid, "00000000-1111-2222-3333-444444444444");
622649
}
623650

624651
#[test]

bottlecap/src/secrets/decrypt.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub async fn resolve_secrets(
2626
let api_key_candidate = if !config.ext.api_key_secret_arn.is_empty()
2727
|| !config.ext.kms_api_key.is_empty()
2828
|| !config.ext.api_key_ssm_arn.is_empty()
29-
|| !config.ext.dd_org_uuid.is_empty()
29+
|| !config.dd_org_uuid.is_empty()
3030
{
3131
let before_decrypt = Instant::now();
3232

@@ -48,7 +48,7 @@ pub async fn resolve_secrets(
4848

4949
let aws_credentials = get_aws_credentials(&client).await?;
5050

51-
let decrypted_key = if !config.ext.dd_org_uuid.is_empty() {
51+
let decrypted_key = if !config.dd_org_uuid.is_empty() {
5252
delegated_auth::get_delegated_api_key(
5353
&config,
5454
&aws_config,

bottlecap/src/secrets/delegated_auth/client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const INTAKE_KEY_ENDPOINT: &str = "/api/v2/intake-key";
1616
/// 3. Returns the managed API key
1717
///
1818
/// # Arguments
19-
/// * `config` - The extension configuration containing site and `org_uuid`
19+
/// * `config` - The agent configuration containing `site` and `dd_org_uuid`
2020
/// * `aws_config` - The AWS configuration containing region
2121
/// * `client` - A pre-built `reqwest::Client` to use for the request. The client is built
2222
/// with `create_reqwest_client_builder()` which respects proxy configuration via
@@ -35,7 +35,7 @@ pub async fn get_delegated_api_key(
3535
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
3636
debug!("Attempting to get API key via delegated auth");
3737

38-
let proof = generate_auth_proof(aws_credentials, &aws_config.region, &config.ext.dd_org_uuid)?;
38+
let proof = generate_auth_proof(aws_credentials, &aws_config.region, &config.dd_org_uuid)?;
3939

4040
let url = get_api_endpoint(&config.site);
4141
debug!("Requesting delegated API key from: {}", url);

0 commit comments

Comments
 (0)