Skip to content

Commit

Permalink
feat(replays): Add denylist feature handling for replay video (#3803)
Browse files Browse the repository at this point in the history
Adds a pre-processing step to `ReplayGroup` processing. The envelope
items are iterated over and if a replay-video event is found processing
exits early before the items are processed.

This feature should always default to enabled. It should only return the
disabled state if the feature was successfully evaluated and the
organization was found to be explicitly denied access.

I'm not familiar with all the implications these code paths have. If
someone with more knowledge and experience could double-check my work I
would appreciate it.

Related: getsentry/getsentry#14569
Related: getsentry/sentry#73981

---------

Co-authored-by: Joris Bayer <joris.bayer@sentry.io>
  • Loading branch information
cmanallen and jjbayer committed Jul 10, 2024
1 parent 2c68339 commit f9acbbc
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- Add support for `all` and `any` `RuleCondition`(s). ([#3791](https://github.com/getsentry/relay/pull/3791))
- Copy root span data from `contexts.trace.data` when converting transaction events into raw spans. ([#3790](https://github.com/getsentry/relay/pull/3790))
- Remove experimental double-write from spans to transactions. ([#3801](https://github.com/getsentry/relay/pull/3801))
- Add feature flag to disable replay-video events. ([#3803](https://github.com/getsentry/relay/pull/3803))

## 24.6.0

Expand Down
5 changes: 5 additions & 0 deletions relay-dynamic-config/src/feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ pub enum Feature {
/// Serialized as `organizations:session-replay-combined-envelope-items`.
#[serde(rename = "organizations:session-replay-combined-envelope-items")]
SessionReplayCombinedEnvelopeItems,
/// Disables select organizations from processing mobile replay events.
///
/// Serialized as `organizations:session-replay-video-disabled`.
#[serde(rename = "organizations:session-replay-video-disabled")]
SessionReplayVideoDisabled,
/// Enables new User Feedback ingest.
///
/// TODO(jferg): rename to UserFeedbackIngest once old UserReport logic is deprecated.
Expand Down
19 changes: 19 additions & 0 deletions relay-server/src/services/processor/replay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub fn process(
let project_state = &state.project_state;
let replays_enabled = project_state.has_feature(Feature::SessionReplay);
let scrubbing_enabled = project_state.has_feature(Feature::SessionReplayRecordingScrubbing);
let replay_video_disabled = project_state.has_feature(Feature::SessionReplayVideoDisabled);

let meta = state.envelope().meta().clone();
let client_addr = meta.client_addr();
Expand Down Expand Up @@ -60,6 +61,13 @@ pub fn process(
return Ok(());
}

// If the replay video feature is not enabled check the envelope items for a
// replay video event.
if replay_video_disabled && count_replay_video_events(state) > 0 {
state.managed_envelope.drop_items_silently();
return Ok(());
}

for item in state.managed_envelope.envelope_mut().items_mut() {
// Set the combined payload header to the value of the combined feature.
item.set_replay_combined_payload(combined_envelope_items);
Expand Down Expand Up @@ -300,3 +308,14 @@ fn handle_replay_video_item(
)),
}
}

// Pre-processors

fn count_replay_video_events(state: &ProcessEnvelopeState<ReplayGroup>) -> usize {
state
.managed_envelope
.envelope()
.items()
.filter(|item| item.ty() == &ItemType::ReplayVideo)
.count()
}
57 changes: 56 additions & 1 deletion tests/integration/test_replay_videos.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def test_replay_recording_with_video(
replay_id = "515539018c9b4260a6f999572f1661ee"
relay = relay_with_processing()
mini_sentry.add_basic_project_config(
project_id, extra={"config": {"features": ["organizations:session-replay"]}}
project_id,
extra={"config": {"features": ["organizations:session-replay"]}},
)
replay = generate_replay_sdk_event(replay_id)
replay_events_consumer = replay_events_consumer(timeout=10)
Expand Down Expand Up @@ -76,3 +77,57 @@ def test_replay_recording_with_video(
replay_recordings_consumer.assert_empty()
outcomes_consumer.assert_empty()
replay_events_consumer.assert_empty()


def test_replay_recording_with_video_denied(
mini_sentry,
relay_with_processing,
replay_recordings_consumer,
outcomes_consumer,
replay_events_consumer,
):
project_id = 42
replay_id = "515539018c9b4260a6f999572f1661ee"
relay = relay_with_processing()
mini_sentry.add_basic_project_config(
project_id,
extra={
"config": {
"features": [
"organizations:session-replay",
"organizations:session-replay-video-disabled",
]
}
},
)
replay = generate_replay_sdk_event(replay_id)
replay_events_consumer = replay_events_consumer(timeout=10)
replay_recordings_consumer = replay_recordings_consumer()
outcomes_consumer = outcomes_consumer()

_recording_payload = recording_payload(b"[]")
payload = msgpack.packb(
{
"replay_event": json.dumps(replay).encode(),
"replay_recording": _recording_payload,
"replay_video": b"hello, world!",
}
)

envelope = Envelope(
headers=[
[
"event_id",
replay_id,
],
["attachment_type", "replay_video"],
]
)
envelope.add_item(Item(payload=PayloadRef(bytes=payload), type="replay_video"))

relay.send_envelope(project_id, envelope)

# Assert all conumers are empty.
replay_recordings_consumer.assert_empty()
outcomes_consumer.assert_empty()
replay_events_consumer.assert_empty()

0 comments on commit f9acbbc

Please sign in to comment.