Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ private boolean isAllowedToAttachRequestBody(final @NotNull IScopes scopes) {
}

private boolean isAllowedToAttachResponseBody(final @NotNull IScopes scopes) {
final @NotNull SentryOptions options = scopes.getOptions();
return options.isSendDefaultPii()
&& !SentryOptions.RequestSize.NONE.equals(options.getMaxRequestBodySize());
return scopes
.getOptions()
.getDataCollectionResolver()
.isOutgoingResponseBodyWithLegacyBodyGate();
}

private void setRequestDetailsOnEvent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import graphql.schema.GraphQLObjectType
import graphql.schema.GraphQLScalarType
import graphql.schema.GraphQLSchema
import io.sentry.Hint
import io.sentry.HttpBodyType
import io.sentry.IScope
import io.sentry.IScopes
import io.sentry.KeyValueCollectionBehavior
Expand Down Expand Up @@ -253,6 +254,124 @@ class ExceptionReporterTest {
)
}

@Test
fun `legacy options can disable outgoing response data`() {
val options = SentryOptions().also { it.maxRequestBodySize = SentryOptions.RequestSize.ALWAYS }
val exceptionReporter = fixture.getSut(options)

exceptionReporter.captureThrowable(
fixture.exception,
ExceptionReporter.ExceptionDetails(
fixture.scopes,
fixture.instrumentationExecutionParameters,
false,
),
fixture.executionResult,
)

verify(fixture.scopes)
.captureEvent(
org.mockito.kotlin.check { assertNull(it.contexts.response) },
any<Hint>(),
)
}

@Test
fun `legacy request body size can disable outgoing response data`() {
val options = SentryOptions().also { it.isSendDefaultPii = true }
val exceptionReporter = fixture.getSut(options)

exceptionReporter.captureThrowable(
fixture.exception,
ExceptionReporter.ExceptionDetails(
fixture.scopes,
fixture.instrumentationExecutionParameters,
false,
),
fixture.executionResult,
)

verify(fixture.scopes)
.captureEvent(
org.mockito.kotlin.check { assertNull(it.contexts.response) },
any<Hint>(),
)
}

@Test
fun `data collection response ignores legacy request body options`() {
val options =
SentryOptions().also {
it.maxRequestBodySize = SentryOptions.RequestSize.NONE
it.dataCollection.httpBodies = setOf(HttpBodyType.OUTGOING_RESPONSE)
}
val exceptionReporter = fixture.getSut(options)

exceptionReporter.captureThrowable(
fixture.exception,
ExceptionReporter.ExceptionDetails(
fixture.scopes,
fixture.instrumentationExecutionParameters,
false,
),
fixture.executionResult,
)

verify(fixture.scopes)
.captureEvent(
org.mockito.kotlin.check { assertNotNull(it.contexts.response?.data) },
any<Hint>(),
)
}

@Test
fun `data collection can disable outgoing response data`() {
val options = fixture.defaultOptions.also { it.dataCollection.httpBodies = emptySet() }
val exceptionReporter = fixture.getSut(options)

exceptionReporter.captureThrowable(
fixture.exception,
ExceptionReporter.ExceptionDetails(
fixture.scopes,
fixture.instrumentationExecutionParameters,
false,
),
fixture.executionResult,
)

verify(fixture.scopes)
.captureEvent(
org.mockito.kotlin.check { assertNull(it.contexts.response) },
any<Hint>(),
)
}

@Test
fun `data collection namespace default enables outgoing response data`() {
val options =
SentryOptions().also {
it.maxRequestBodySize = SentryOptions.RequestSize.NONE
it.dataCollection.cookies = KeyValueCollectionBehavior.off()
}
val exceptionReporter = fixture.getSut(options)

exceptionReporter.captureThrowable(
fixture.exception,
ExceptionReporter.ExceptionDetails(
fixture.scopes,
fixture.instrumentationExecutionParameters,
false,
),
fixture.executionResult,
)

verify(fixture.scopes)
.captureEvent(
org.mockito.kotlin.check { assertNotNull(it.contexts.response?.data) },
any<Hint>(),
)
}

@Test
fun `does not attach query or variables if sendDefaultPii is false`() {
val exceptionReporter =
Expand Down
1 change: 1 addition & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ public final class io/sentry/DataCollectionResolver {
public fun isIncomingResponseBody ()Z
public fun isOutgoingRequestBody ()Z
public fun isOutgoingResponseBody ()Z
public fun isOutgoingResponseBodyWithLegacyBodyGate ()Z
public fun isUserInfo ()Z
}

Expand Down
4 changes: 4 additions & 0 deletions sentry/src/main/java/io/sentry/DataCollectionResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ public boolean isOutgoingResponseBody() {
return isHttpBodyEnabled(HttpBodyType.OUTGOING_RESPONSE, options.isSendDefaultPii());
}

public boolean isOutgoingResponseBodyWithLegacyBodyGate() {
return isHttpBodyEnabled(HttpBodyType.OUTGOING_RESPONSE, isLegacyGraphqlBodyEnabled());
}

private boolean isLegacyGraphqlBodyEnabled() {
return options.isSendDefaultPii()
&& !SentryOptions.RequestSize.NONE.equals(options.getMaxRequestBodySize());
Expand Down
31 changes: 31 additions & 0 deletions sentry/src/test/java/io/sentry/DataCollectionResolverTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,37 @@ class DataCollectionResolverTest {
assertThat(options.dataCollectionResolver.isGraphqlVariablesWithLegacyBodyGate).isTrue()
}

@Test
fun `outgoing response legacy body variant preserves the legacy size gate`() {
val options =
SentryOptions().apply {
isSendDefaultPii = true
maxRequestBodySize = SentryOptions.RequestSize.NONE
}

assertThat(options.dataCollectionResolver.isOutgoingResponseBodyWithLegacyBodyGate).isFalse()

options.maxRequestBodySize = SentryOptions.RequestSize.SMALL

assertThat(options.dataCollectionResolver.isOutgoingResponseBodyWithLegacyBodyGate).isTrue()
}

@Test
fun `outgoing response legacy body variant uses data collection when namespace is explicit`() {
val options =
SentryOptions().apply {
isSendDefaultPii = false
maxRequestBodySize = SentryOptions.RequestSize.NONE
dataCollection.graphql.setDocument(true)
}

assertThat(options.dataCollectionResolver.isOutgoingResponseBodyWithLegacyBodyGate).isTrue()

options.dataCollection.httpBodies = emptySet()

assertThat(options.dataCollectionResolver.isOutgoingResponseBodyWithLegacyBodyGate).isFalse()
}

@Test
fun `GraphQL legacy body variants ignore the size option when namespace is explicit`() {
val options =
Expand Down
Loading