Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8937e2b
fix(libdd-trace-obfuscation): cargo clippy fix with all lints
Eldolfin May 5, 2026
efd9e87
fix(libdd-trace-obfuscation): cargo clippy llm pass 1
Eldolfin May 5, 2026
bb56e9b
fix(libdd-trace-obfuscation): cargo clippy llm pass 2
Eldolfin May 5, 2026
b78d263
feat(clippy): use warn instead of deny, temp allow some lints
Eldolfin May 6, 2026
14213c2
fix(libdd-trace-obfuscation): cargo clippy llm pass 3
Eldolfin May 6, 2026
38d5837
fix(libdd-trace-obfuscation): remove now redundant lints in lib.rs
Eldolfin May 6, 2026
88d11fe
fix(clippy): allow some lints which make the code harder to understand
Eldolfin May 6, 2026
6a27b69
fix(clippy): add codeowners to clippy config
Eldolfin May 6, 2026
293605d
fix: revert map_or_else lint fix
Eldolfin May 6, 2026
564eca3
fix(libdd-trace-obfuscation): remove all easy unwraps
Eldolfin May 6, 2026
cb549cf
Merge branch 'main' into oscarld/restrictive-clippy-on-trace-obfuscation
Eldolfin May 7, 2026
3d6dc3d
Merge branch 'main' into oscarld/restrictive-clippy-on-trace-obfuscation
Eldolfin May 7, 2026
bbc5099
fix: llm pass 4 on tests/bench
Eldolfin May 7, 2026
162391b
fix(libdd-trace-obfuscation): fix CI failures (rustfmt, clippy 1.84.1…
Eldolfin May 7, 2026
fad877f
fix(libdd-trace-obfuscation): fix clippy compat across 1.84.1, stable…
Eldolfin May 7, 2026
158bb5d
fix(libdd-trace-obfuscation): update Cargo.lock for version bump to 2…
Eldolfin May 7, 2026
e085bb0
fix(libdd-trace-obfuscation): revert random version bump
Eldolfin May 7, 2026
b4c7349
Revert "fix(libdd-trace-obfuscation): revert random version bump"
Eldolfin May 11, 2026
c352714
Merge branch 'main' into oscarld/restrictive-clippy-on-trace-obfuscation
Eldolfin May 11, 2026
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ build-common/ @DataDog/apm-common-components-core
builder @DataDog/apm-common-components-core
Cargo.* @DataDog/libdatadog
cliff.toml @DataDog/libdatadog-core
clippy.toml @DataDog/libdatadog
cmake/ @DataDog/apm-common-components-core
CONTRIBUTING.md @DataDog/libdatadog-core
Cross.toml @DataDog/apm-common-components-core
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,36 @@ codegen-units = 1
# so benchmarks are not measuring the same thing as the release build. This patch removes
# the default dependency on libm. A PR will be opened to proptest to make this optional.
proptest = { git = 'https://github.com/bantonsson/proptest.git', branch = "ban/avoid-libm-in-std" }


# Using `warn` instead of `deny` for iterating in local without blocking the build. Warnings fail CI anyway
[workspace.lints.clippy]
blanket_clippy_restriction_lints = "allow" # Required when enabling restriction as a group. Clippy itself warns about this
# Groups of lints
all = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 }
cargo = { level = "warn", priority = -1 }
# No panics
panic = "warn"
unwrap_used = "warn"
expect_used = "warn"
todo = "warn"
unimplemented = "warn"
unreachable = "warn"
panic_in_result_fn = "warn"
# TODO: Re-enable once every crate defines package keywords and categories.
cargo_common_metadata = "allow"
# TODO: Re-enable once the workspace dependency graph is deduplicated.
multiple_crate_versions = "allow"
# FIXME: rename libdd-crashtracker-ffi/use_webpki_roots feature to webpki_roots ?
redundant_feature_names = "allow"
# --- Whitelist ---
redundant_else = "allow" # less clear
option_if_let_else = "allow" # less clear

[workspace.lints.rust]
future_incompatible = { level = "warn", priority = -1 }
nonstandard_style = { level = "warn", priority = -1 }
rust_2018_idioms = { level = "warn", priority = -1 }
unused = { level = "warn", priority = -1 }
5 changes: 5 additions & 0 deletions clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Allow configuration structs to expose a few independent feature flags.
max-struct-bools = 5
allow-unwrap-in-tests = true
allow-expect-in-tests = true
allow-panic-in-tests = true
7 changes: 6 additions & 1 deletion libdd-trace-obfuscation/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
[package]
name = "libdd-trace-obfuscation"
version = "2.0.0"
version = "2.1.0"
description = "A duplicate of trace obfuscator implemented in the agent and documented in https://docs.datadoghq.com/tracing/configure_data_security/?tab=net#trace-obfuscation"
homepage = "https://github.com/DataDog/libdatadog/tree/main/libdd-trace-obfuscation"
repository = "https://github.com/DataDog/libdatadog/tree/main/libdd-trace-obfuscation"
keywords = ["datadog", "trace", "obfuscation"]
categories = ["development-tools"]
edition.workspace = true
rust-version.workspace = true
license.workspace = true
Expand Down Expand Up @@ -38,3 +40,6 @@ bench = false
name = "trace_obfuscation"
harness = false
path = "benches/trace_obfuscation.rs"

[lints]
workspace = true
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ fn is_card_number_no_luhn_bench(c: &mut Criterion) {
bench_is_card_number(c, "is_card_number_no_luhn", false);
}

#[inline(always)]
fn bench_is_card_number(c: &mut Criterion, function_name: &str, validate_luhn: bool) {
let mut group = c.benchmark_group("credit_card");
// Measure over a number of calls to minimize impact of OS noise
Expand All @@ -36,17 +35,17 @@ fn bench_is_card_number(c: &mut Criterion, function_name: &str, validate_luhn: b
"x371413321323331", // invalid characters
"",
];
for c in ccs.iter() {
for c in &ccs {
group.bench_with_input(BenchmarkId::new(function_name, c), c, |b, i| {
b.iter_batched(
|| {},
|_| {
|()| {
for _ in 0..elements {
black_box(is_card_number_uninlined(i, validate_luhn));
}
},
BatchSize::SmallInput,
)
);
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn quantize_peer_ip_address_benchmark(c: &mut Criterion) {
}
},
criterion::BatchSize::LargeInput,
)
);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ fn obfuscate_redis_string_benchmark(c: &mut Criterion) {
"ZADD key XX INCR score member score member",
"ZADD key XX INCR score member",
"ZADD key XX INCR score",
r#"
r"
CONFIG command
SET k v
"#,
",
"",
"SET key value",
"GET k",
Expand Down Expand Up @@ -105,7 +105,7 @@ SET k v
}
},
criterion::BatchSize::LargeInput,
)
);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use criterion::{black_box, criterion_group, Criterion};
use libdd_trace_obfuscation::replacer;
use libdd_trace_protobuf::pb;

#[allow(clippy::unwrap_used)]
fn criterion_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("tags");
let rules: &[replacer::ReplaceRule] = &replacer::parse_rules_from_string(
Expand All @@ -21,14 +22,14 @@ fn criterion_benchmark(c: &mut Criterion) {
.unwrap();

let span_1 = pb::Span {
duration: 10000000,
duration: 10_000_000,
error: 0,
resource: "GET /some/raclette".to_string(),
service: "django".to_string(),
name: "django.controller".to_string(),
span_id: 123,
start: 1448466874000000000,
trace_id: 424242,
start: 1_448_466_874_000_000_000,
trace_id: 424_242,
meta: HashMap::from([
Comment on lines -30 to 32
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this lint is good, IDs are not meant to be read 3 by 3

("resource.name".to_string(), "this is prod".to_string()),
(
Expand All @@ -41,7 +42,7 @@ fn criterion_benchmark(c: &mut Criterion) {
),
("custom.tag".to_string(), "/foo/bar/foo".to_string()),
]),
metrics: HashMap::from([("cheese_weight".to_string(), 100000.0)]),
metrics: HashMap::from([("cheese_weight".to_string(), 100_000.0)]),
parent_id: 1111,
r#type: "http".to_string(),
meta_struct: HashMap::new(),
Expand All @@ -55,7 +56,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|| trace.to_owned(),
|t| replacer::replace_trace_tags(black_box(t), black_box(rules)),
criterion::BatchSize::LargeInput,
)
);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn sql_obfuscation(c: &mut Criterion) {
}
},
criterion::BatchSize::LargeInput,
)
);
});
}

Expand Down
65 changes: 36 additions & 29 deletions libdd-trace-obfuscation/src/credit_cards.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
// SPDX-License-Identifier: Apache-2.0

/// is_card_number checks if b could be a credit card number by checking the digit count and IIN
/// prefix. If validate_luhn is true, the Luhn checksum is also applied to potential candidates.
/// `is_card_number` checks if b could be a credit card number by checking the digit count and IIN
/// prefix.
///
/// If `validate_luhn` is true, the Luhn checksum is also applied to potential candidates.
/// Note: This code is based on the code from datadog-agent/pkg/obfuscate/credit_cards.go
pub fn is_card_number<T: AsRef<str>>(s: T, validate_luhn: bool) -> bool {
let s = s.as_ref();
Expand All @@ -15,15 +17,14 @@ pub fn is_card_number<T: AsRef<str>>(s: T, validate_luhn: bool) -> bool {
let mut len = 0;
for c in s.chars() {
// Only valid characters are 0-9, space (" ") and dash("-")
#[allow(clippy::unwrap_used)]
match c {
' ' | '-' => continue,
'0'..='9' => {
num_s[len] = c.to_digit(10).unwrap();
num_s[len] = u32::from(c) - u32::from('0');
len += 1;
}
_ => return false,
};
}
if len > 16 {
// too long for any known card number; stop looking
return false;
Expand All @@ -38,13 +39,17 @@ pub fn is_card_number<T: AsRef<str>>(s: T, validate_luhn: bool) -> bool {
let mut is_valid_iin = FuzzyBool::Maybe;
let mut cs = num_s.iter();

#[allow(clippy::unwrap_used)]
let mut prefix: u32 = *cs.next().unwrap();
#[allow(clippy::unwrap_used)]
let Some(&first_digit) = cs.next() else {
return false;
};
let mut prefix = first_digit;
while is_valid_iin == FuzzyBool::Maybe {
is_valid_iin = valid_card_prefix(prefix);

prefix = 10 * prefix + cs.next().unwrap();
let Some(next_digit) = cs.next() else {
return false;
};
prefix = 10 * prefix + *next_digit;
}

if is_valid_iin == FuzzyBool::True && validate_luhn {
Expand All @@ -57,10 +62,11 @@ pub fn is_card_number<T: AsRef<str>>(s: T, validate_luhn: bool) -> bool {
/// algorithm. nums must be non-empty
///
/// See:
/// https://en.wikipedia.org/wiki/Luhn_algorithm
/// <https://en.wikipedia.org/wiki/Luhn_algorithm>
fn luhn_valid(nums: &[u32]) -> bool {
#[allow(clippy::unwrap_used)]
let (given_digit, payload) = nums.split_last().unwrap();
let Some((given_digit, payload)) = nums.split_last() else {
return false;
};
calculate_luhn(payload) == *given_digit
}

Expand Down Expand Up @@ -102,10 +108,10 @@ enum FuzzyBool {
/// TODO(x): this whole code could be code generated from a prettier data structure.
/// Ultimately, it could even be user-configurable.
/// Note: This code is ported from datadog-agent/pkg/obfuscate/credit_cards.go
fn valid_card_prefix(n: u32) -> FuzzyBool {
const fn valid_card_prefix(n: u32) -> FuzzyBool {
// Validates IIN prefix possibilities
// Source: https://www.regular-expressions.info/creditcard.html
if n > 699999 {
if n > 699_999 {
// too long for any known prefix; stop looking
return FuzzyBool::False;
}
Expand Down Expand Up @@ -139,15 +145,15 @@ fn valid_card_prefix(n: u32) -> FuzzyBool {
_ => FuzzyBool::False,
};
}
if n < 100000 {
if n < 100_000 {
return match n {
22210..=27209 | 50000..=50999 | 56000..=58999 | 60000..=69999 => FuzzyBool::Maybe,
_ => FuzzyBool::False,
};
}
if n < 1000000 {
if n < 1_000_000 {
return match n {
222100..=272099 | 500000..=509999 | 560000..=589999 | 600000..=699999 => {
222_100..=272_099 | 500_000..=509_999 | 560_000..=589_999 | 600_000..=699_999 => {
FuzzyBool::True
}
_ => FuzzyBool::False,
Expand Down Expand Up @@ -242,26 +248,26 @@ mod tests {
(21000, FuzzyBool::False),
(55555, FuzzyBool::False),
// yes
(222100, FuzzyBool::True),
(272099, FuzzyBool::True),
(500000, FuzzyBool::True),
(509999, FuzzyBool::True),
(560000, FuzzyBool::True),
(589999, FuzzyBool::True),
(600000, FuzzyBool::True),
(699999, FuzzyBool::True),
(222_100, FuzzyBool::True),
(272_099, FuzzyBool::True),
(500_000, FuzzyBool::True),
(509_999, FuzzyBool::True),
(560_000, FuzzyBool::True),
(589_999, FuzzyBool::True),
(600_000, FuzzyBool::True),
(699_999, FuzzyBool::True),
// no
(551234, FuzzyBool::False),
(594388, FuzzyBool::False),
(219899, FuzzyBool::False),
(551_234, FuzzyBool::False),
(594_388, FuzzyBool::False),
(219_899, FuzzyBool::False),
];

for (num, expected) in test_cases {
let actual = valid_card_prefix(num);
assert_eq!(
actual, expected,
"card prefix '{num}' was expected to be {expected:?} but got {actual:?}"
)
);
}
}

Expand All @@ -287,6 +293,7 @@ mod tests {
}

#[test]
#[allow(clippy::too_many_lines)]
fn test_valid_cards() {
let valid_cards = vec![
"378282246310005",
Expand Down
Loading
Loading