Skip to content

Commit 259ce9d

Browse files
committed
feat(core): [Data Collection 25] Apply file path policy
Add the specification-defined filePaths option across programmatic, external, Spring Boot, and Android manifest configuration. Gate automatically captured File I/O paths through the resolved policy while preserving sendDefaultPii when Data Collection is absent.\n\nRefs #5666
1 parent 29e42b8 commit 259ce9d

17 files changed

Lines changed: 129 additions & 6 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
| `graphql.document` | `true` | Collects GraphQL documents. |
2121
| `graphql.variables` | `true` | Collects GraphQL variables. |
2222
| `databaseQueryData` | `true` | Allows collection of associated query data, such as bound parameters, write payloads, and results, where supported. Sanitized query statements and structural database metadata remain available. |
23+
| `filePaths` | `true` | Allows file-system instrumentation to collect file and directory paths. File extensions and byte counts remain available when disabled. |
2324

2425
Cookies, HTTP headers, and URL query parameters support three modes:
2526

@@ -29,7 +30,7 @@
2930

3031
Matching is case-insensitive and partial. The built-in sensitive deny-list contains `auth`, `token`, `secret`, `password`, `passwd`, `pwd`, `key`, `jwt`, `bearer`, `sso`, `saml`, `csrf`, `xsrf`, `credentials`, `session`, `sid`, and `identity`. Filtered values are replaced with `"[Filtered]"`. Custom deny-list terms extend rather than replace this list.
3132

32-
Configure all HTTP body types, a custom cookie deny-list, a request-header allow-list, and disable URL query parameter collection in an options callback:
33+
Configure all HTTP body types, a custom cookie deny-list, a request-header allow-list, and disable URL query parameter and file path collection in an options callback:
3334

3435
```java
3536
Sentry.init(
@@ -55,6 +56,7 @@
5556
options
5657
.getDataCollection()
5758
.setUrlQueryParams(KeyValueCollectionBehavior.off());
59+
options.getDataCollection().setFilePaths(false);
5860
});
5961
```
6062

@@ -67,6 +69,7 @@
6769
data-collection.http-headers.request.mode=allow_list
6870
data-collection.http-headers.request.terms=content-type,x-request-id
6971
data-collection.url-query-params.mode=off
72+
data-collection.file-paths=false
7073
```
7174

7275
Configure them with Spring Boot properties:
@@ -78,6 +81,7 @@
7881
sentry.data-collection.http-headers.request.mode=allow-list
7982
sentry.data-collection.http-headers.request.terms=content-type,x-request-id
8083
sentry.data-collection.url-query-params.mode=off
84+
sentry.data-collection.file-paths=false
8185
```
8286

8387
Configure them in `AndroidManifest.xml`:
@@ -101,6 +105,9 @@
101105
<meta-data
102106
android:name="io.sentry.data-collection.url-query-params.mode"
103107
android:value="off" />
108+
<meta-data
109+
android:name="io.sentry.data-collection.file-paths"
110+
android:value="false" />
104111
```
105112

106113
See the [Data Collection documentation](https://docs.sentry.io/platforms/java/configuration/options/#dataCollection) for all configuration keys, supported integrations, and migration guidance.

‎sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ final class ManifestMetadataReader {
126126
"io.sentry.data-collection.graphql.variables";
127127
static final String DATA_COLLECTION_DATABASE_QUERY_DATA =
128128
"io.sentry.data-collection.database-query-data";
129+
static final String DATA_COLLECTION_FILE_PATHS = "io.sentry.data-collection.file-paths";
129130

130131
static final String PERFORM_FRAMES_TRACKING = "io.sentry.traces.frames-tracking";
131132

@@ -886,6 +887,10 @@ static void applyMetadata(
886887
readBool(metadata, logger, DATA_COLLECTION_DATABASE_QUERY_DATA, false));
887888
}
888889

890+
if (containsKey(metadata, DATA_COLLECTION_FILE_PATHS)) {
891+
dataCollection.setFilePaths(readBool(metadata, logger, DATA_COLLECTION_FILE_PATHS, false));
892+
}
893+
889894
return dataCollection.isExplicitlyConfigured() ? dataCollection : null;
890895
}
891896

@@ -918,6 +923,9 @@ private static void mergeDataCollection(
918923
if (source.getDatabaseQueryData() != null) {
919924
target.setDatabaseQueryData(source.getDatabaseQueryData());
920925
}
926+
if (source.getFilePaths() != null) {
927+
target.setFilePaths(source.getFilePaths());
928+
}
921929
}
922930

923931
private static @NotNull Set<HttpBodyType> readHttpBodyTypes(

‎sentry-android-core/src/test/java/io/sentry/android/core/ManifestMetadataReaderTest.kt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,7 @@ class ManifestMetadataReaderTest {
14851485
ManifestMetadataReader.DATA_COLLECTION_GRAPHQL_DOCUMENT to false,
14861486
ManifestMetadataReader.DATA_COLLECTION_GRAPHQL_VARIABLES to true,
14871487
ManifestMetadataReader.DATA_COLLECTION_DATABASE_QUERY_DATA to false,
1488+
ManifestMetadataReader.DATA_COLLECTION_FILE_PATHS to false,
14881489
)
14891490
val context = fixture.getContext(metaData = bundle)
14901491

@@ -1504,6 +1505,7 @@ class ManifestMetadataReaderTest {
15041505
assertThat(dataCollection.graphql.document).isFalse()
15051506
assertThat(dataCollection.graphql.variables).isTrue()
15061507
assertThat(dataCollection.databaseQueryData).isFalse()
1508+
assertThat(dataCollection.filePaths).isFalse()
15071509
}
15081510

15091511
@Test
@@ -1519,6 +1521,7 @@ class ManifestMetadataReaderTest {
15191521
graphql.setDocument(true)
15201522
graphql.setVariables(false)
15211523
setDatabaseQueryData(true)
1524+
setFilePaths(true)
15221525
}
15231526
val bundle =
15241527
bundleOf(
@@ -1543,6 +1546,7 @@ class ManifestMetadataReaderTest {
15431546
assertThat(dataCollection.graphql.document).isTrue()
15441547
assertThat(dataCollection.graphql.variables).isFalse()
15451548
assertThat(dataCollection.databaseQueryData).isTrue()
1549+
assertThat(dataCollection.filePaths).isTrue()
15461550
}
15471551

15481552
@Test

‎sentry-spring-boot-4/src/test/kotlin/io/sentry/spring/boot4/SentryAutoConfigurationTest.kt‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ class SentryAutoConfigurationTest {
308308
}
309309

310310
@Test
311-
fun `data collection key value properties are applied to SentryOptions`() {
311+
fun `data collection properties are applied to SentryOptions`() {
312312
contextRunner
313313
.withPropertyValues(
314314
"sentry.dsn=http://key@localhost/proj",
@@ -319,6 +319,7 @@ class SentryAutoConfigurationTest {
319319
"sentry.data-collection.http-headers.request.terms=forwarded,-ip",
320320
"sentry.data-collection.http-headers.response.mode=allow-list",
321321
"sentry.data-collection.http-headers.response.terms=content-type,x-request-id",
322+
"sentry.data-collection.file-paths=false",
322323
)
323324
.run {
324325
val dataCollection = it.getBean(SentryProperties::class.java).dataCollection
@@ -333,6 +334,7 @@ class SentryAutoConfigurationTest {
333334
.isEqualTo(KeyValueCollectionBehavior.Mode.ALLOW_LIST)
334335
assertThat(dataCollection.httpHeaders.response!!.terms)
335336
.containsExactly("content-type", "x-request-id")
337+
assertThat(dataCollection.filePaths).isFalse()
336338
}
337339
}
338340

‎sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ class SentryAutoConfigurationTest {
316316
}
317317

318318
@Test
319-
fun `data collection key value properties are applied to SentryOptions`() {
319+
fun `data collection properties are applied to SentryOptions`() {
320320
contextRunner
321321
.withPropertyValues(
322322
"sentry.dsn=http://key@localhost/proj",
@@ -327,6 +327,7 @@ class SentryAutoConfigurationTest {
327327
"sentry.data-collection.http-headers.request.terms=forwarded,-ip",
328328
"sentry.data-collection.http-headers.response.mode=allow-list",
329329
"sentry.data-collection.http-headers.response.terms=content-type,x-request-id",
330+
"sentry.data-collection.file-paths=false",
330331
)
331332
.run {
332333
val dataCollection = it.getBean(SentryProperties::class.java).dataCollection
@@ -341,6 +342,7 @@ class SentryAutoConfigurationTest {
341342
.isEqualTo(KeyValueCollectionBehavior.Mode.ALLOW_LIST)
342343
assertThat(dataCollection.httpHeaders.response!!.terms)
343344
.containsExactly("content-type", "x-request-id")
345+
assertThat(dataCollection.filePaths).isFalse()
344346
}
345347
}
346348

‎sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ class SentryAutoConfigurationTest {
314314
}
315315

316316
@Test
317-
fun `data collection key value properties are applied to SentryOptions`() {
317+
fun `data collection properties are applied to SentryOptions`() {
318318
contextRunner
319319
.withPropertyValues(
320320
"sentry.dsn=http://key@localhost/proj",
@@ -325,6 +325,7 @@ class SentryAutoConfigurationTest {
325325
"sentry.data-collection.http-headers.request.terms=forwarded,-ip",
326326
"sentry.data-collection.http-headers.response.mode=allow-list",
327327
"sentry.data-collection.http-headers.response.terms=content-type,x-request-id",
328+
"sentry.data-collection.file-paths=false",
328329
)
329330
.run {
330331
val dataCollection = it.getBean(SentryProperties::class.java).dataCollection
@@ -339,6 +340,7 @@ class SentryAutoConfigurationTest {
339340
.isEqualTo(KeyValueCollectionBehavior.Mode.ALLOW_LIST)
340341
assertThat(dataCollection.httpHeaders.response!!.terms)
341342
.containsExactly("content-type", "x-request-id")
343+
assertThat(dataCollection.filePaths).isFalse()
342344
}
343345
}
344346

‎sentry/api/sentry.api‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ public final class io/sentry/DataCollection {
390390
public fun <init> (Z)V
391391
public fun getCookies ()Lio/sentry/KeyValueCollectionBehavior;
392392
public fun getDatabaseQueryData ()Ljava/lang/Boolean;
393+
public fun getFilePaths ()Ljava/lang/Boolean;
393394
public fun getGraphql ()Lio/sentry/DataCollection$Graphql;
394395
public fun getHttpBodies ()Ljava/util/Set;
395396
public fun getHttpHeaders ()Lio/sentry/DataCollection$HttpHeaders;
@@ -398,6 +399,7 @@ public final class io/sentry/DataCollection {
398399
public fun isExplicitlyConfigured ()Z
399400
public fun setCookies (Lio/sentry/KeyValueCollectionBehavior;)V
400401
public fun setDatabaseQueryData (Z)V
402+
public fun setFilePaths (Z)V
401403
public fun setHttpBodies (Ljava/util/Set;)V
402404
public fun setUrlQueryParams (Lio/sentry/KeyValueCollectionBehavior;)V
403405
public fun setUserInfo (Z)V
@@ -426,6 +428,7 @@ public final class io/sentry/DataCollectionResolver {
426428
public fun getUrlQueryParams ()Lio/sentry/KeyValueCollectionBehavior;
427429
public fun isDataCollectionConfigured ()Z
428430
public fun isDatabaseQueryData ()Z
431+
public fun isFilePaths ()Z
429432
public fun isGraphqlDocument ()Z
430433
public fun isGraphqlDocumentWithLegacyAlways ()Z
431434
public fun isGraphqlDocumentWithLegacyBodyGate ()Z

‎sentry/src/main/java/io/sentry/DataCollection.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public final class DataCollection {
1717
private @Nullable KeyValueCollectionBehavior urlQueryParams;
1818
private @Nullable Set<HttpBodyType> httpBodies;
1919
private @Nullable Boolean databaseQueryData;
20+
private @Nullable Boolean filePaths;
2021
private final @NotNull HttpHeaders httpHeaders = new HttpHeaders();
2122
private final @NotNull Graphql graphql = new Graphql();
2223

@@ -74,6 +75,14 @@ public void setDatabaseQueryData(final boolean databaseQueryData) {
7475
this.databaseQueryData = databaseQueryData;
7576
}
7677

78+
public @Nullable Boolean getFilePaths() {
79+
return filePaths;
80+
}
81+
82+
public void setFilePaths(final boolean filePaths) {
83+
this.filePaths = filePaths;
84+
}
85+
7786
public @NotNull HttpHeaders getHttpHeaders() {
7887
return httpHeaders;
7988
}
@@ -90,6 +99,7 @@ public boolean isExplicitlyConfigured() {
9099
|| urlQueryParams != null
91100
|| httpBodies != null
92101
|| databaseQueryData != null
102+
|| filePaths != null
93103
|| httpHeaders.hasOverrides()
94104
|| graphql.hasOverrides();
95105
}

‎sentry/src/main/java/io/sentry/DataCollectionResolver.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ public boolean isDatabaseQueryData() {
2727
return explicitOrSendDefaultPii(options.getDataCollection().getDatabaseQueryData(), true);
2828
}
2929

30+
public boolean isFilePaths() {
31+
return explicitOrSendDefaultPii(options.getDataCollection().getFilePaths(), true);
32+
}
33+
3034
public boolean isGraphqlDocument() {
3135
return explicitOrSendDefaultPii(options.getDataCollection().getGraphql().getDocument(), true);
3236
}

‎sentry/src/main/java/io/sentry/ExternalOptions.java‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,11 @@ public final class ExternalOptions {
305305
dataCollection.setDatabaseQueryData(databaseQueryData);
306306
}
307307

308+
final Boolean filePaths = propertiesProvider.getBooleanProperty("data-collection.file-paths");
309+
if (filePaths != null) {
310+
dataCollection.setFilePaths(filePaths);
311+
}
312+
308313
return dataCollection.isExplicitlyConfigured() ? dataCollection : null;
309314
}
310315

0 commit comments

Comments
 (0)