Skip to content

Commit d90907c

Browse files
[DSEC-223] Update sds-result and emit total matches (#54293)
### What does this PR do? - Update `sds_result` proto schema to the last version - Populates `count_matches` in the datasecurity check: total matches per `(column, rule)`, distinct from `count_matched_rows` which counts rows. - Adds a CODEOWNERS entry for `/pkg/proto/datadog/sds`. ### Motivation Emit the total number of matches, not just the number of matched rows (a single row can contain several matches). Co-authored-by: aimene.belfodil <aimene.belfodil@datadoghq.com>
1 parent 2eebbaf commit d90907c

5 files changed

Lines changed: 32 additions & 9 deletions

File tree

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@
667667
/pkg/proto/datadog/languagedetection @DataDog/container-experiences
668668
/pkg/proto/datadog/privateactionrunner @DataDog/action-platform
669669
/pkg/proto/datadog/process @DataDog/container-experiences
670+
/pkg/proto/datadog/sds @DataDog/sensitive-data-scanner
670671
/pkg/proto/datadog/trace @DataDog/agent-apm
671672
/pkg/proto/datadog/workloadmeta @DataDog/container-platform
672673
/pkg/remoteconfig/ @DataDog/remote-config

pkg/collector/sharedlibrary/rustchecks/checks/datasecurity/src/scanning/mod.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,24 @@ impl Scanner {
5353
}
5454
}
5555

56-
/// Groups hits into `(column, rule)` pairs and counts matched rows.
56+
/// Groups hits into `(column, rule)` pairs and counts matched rows and total
57+
/// matches.
5758
fn aggregate_matches(rule_ids: &[String], hits: &[RuleMatch]) -> Result<Vec<Match>> {
58-
let mut rows: HashMap<(&str, usize), HashSet<&Path>> = HashMap::new();
59-
// Bucket each hit by (column, rule), collecting its distinct row paths.
59+
// For each (column, rule): the distinct matched row paths and the total
60+
// number of matches (a single row may contain several matches).
61+
let mut buckets: HashMap<(&str, usize), (HashSet<&Path>, i64)> = HashMap::new();
6062
for hit in hits {
61-
rows.entry((column_name_from_path(&hit.path), hit.rule_index))
62-
.or_default()
63-
.insert(&hit.path);
63+
let (paths, count_matches) = buckets
64+
.entry((column_name_from_path(&hit.path), hit.rule_index))
65+
.or_default();
66+
paths.insert(&hit.path);
67+
*count_matches += 1;
6468
}
6569

6670
// Convert to matches.
67-
rows.into_iter()
68-
.map(|((column, rule_index), paths)| {
71+
buckets
72+
.into_iter()
73+
.map(|((column, rule_index), (paths, count_matches))| {
6974
// return an error if the rule index is unknown.
7075
let rule_id = rule_ids
7176
.get(rule_index)
@@ -75,6 +80,7 @@ fn aggregate_matches(rule_ids: &[String], hits: &[RuleMatch]) -> Result<Vec<Matc
7580
rule_id,
7681
column_name: column.to_string(),
7782
count_matched_rows: paths.len() as i64,
83+
count_matches,
7884
..Default::default()
7985
})
8086
})

pkg/collector/sharedlibrary/rustchecks/checks/datasecurity/src/scanning/tests.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ scan_data: []
169169
rule_id: "email".to_string(),
170170
column_name: "email".to_string(),
171171
count_matched_rows: 2,
172+
count_matches: 2,
172173
..Default::default()
173174
}]
174175
);
@@ -205,6 +206,7 @@ scan_data: []
205206
rule_id: "token".to_string(),
206207
column_name: "note".to_string(),
207208
count_matched_rows: 1,
209+
count_matches: 1,
208210
..Default::default()
209211
}]
210212
);
@@ -241,6 +243,7 @@ scan_data: []
241243
rule_id: "code".to_string(),
242244
column_name: "code".to_string(),
243245
count_matched_rows: 1,
246+
count_matches: 1,
244247
..Default::default()
245248
}]
246249
);
@@ -259,7 +262,7 @@ scan_data: []
259262
);
260263

261264
// A single row holds two emails: both match the rule, but they share the
262-
// same row path, so the row is counted once.
265+
// same row path, so the row is counted once while both matches are counted.
263266
let data = json!({ "email": ["alice@corp.io and bob@corp.io"] });
264267

265268
let matches = scanner.scan(data).expect("failed to scan data");
@@ -270,6 +273,7 @@ scan_data: []
270273
rule_id: "email".to_string(),
271274
column_name: "email".to_string(),
272275
count_matched_rows: 1,
276+
count_matches: 2,
273277
..Default::default()
274278
}]
275279
);
@@ -305,6 +309,7 @@ scan_data: []
305309
rule_id: "credit-card".to_string(),
306310
column_name: "card".to_string(),
307311
count_matched_rows: 1,
312+
count_matches: 1,
308313
..Default::default()
309314
}]
310315
);
@@ -353,6 +358,7 @@ scan_data: []
353358
rule_id: "email".to_string(),
354359
column_name: "foo[bar]".to_string(),
355360
count_matched_rows: 1,
361+
count_matches: 1,
356362
..Default::default()
357363
}]
358364
);
@@ -382,6 +388,7 @@ scan_data: []
382388
rule_id: "email".to_string(),
383389
column_name: "first.last".to_string(),
384390
count_matched_rows: 2,
391+
count_matches: 2,
385392
..Default::default()
386393
}]
387394
);

pkg/proto/datadog/sds/sds_result.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ message SdsResultPayload {
9494
int64 table_row_count = 6;
9595
int64 scanned_row_count = 7;
9696
repeated ScannedColumn scanned_columns = 8;
97+
string entity_id = 9;
9798

9899
message ScannedColumn {
99100
string name = 1;
@@ -154,6 +155,7 @@ message SdsResultPayload {
154155
string column_name = 2;
155156
int64 count_matched_rows = 3;
156157
int64 count_total_rows = 4 [deprecated = true]; // rely on ScanLocation.RdsTable.table_row_count
158+
int64 count_matches = 5;
157159
}
158160

159161
message ScanMetadata {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
enhancements:
3+
- |
4+
Data Security scan results now report the total number of sensitive-data
5+
matches found in each column (``count_matches``), in addition to the number
6+
of distinct rows that contain a match. This gives more accurate visibility
7+
when a single row contains several matches.

0 commit comments

Comments
 (0)