Skip to content
Open
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
3 changes: 0 additions & 3 deletions relay-dynamic-config/src/feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,6 @@ pub enum Feature {
/// Enable the experimental Trace Attachment pipeline in Relay.
#[serde(rename = "projects:trace-attachment-processing")]
TraceAttachmentProcessing,
/// Enable the upload endpoint for attachments.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing graduated upload flag

Medium Severity

Removing UploadEndpoint without following the usual graduation pattern leaves downstream relays without projects:relay-upload-endpoint. Upgraded relays drop that string as an unknown feature during deserialization, and ProjectConfig::sanitize no longer injects it, so older hops that still call require_feature can reject uploads even when Sentry still sends the flag.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c9b94d1. Configure here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nobody cares

#[serde(rename = "projects:relay-upload-endpoint")]
UploadEndpoint,
/// Upload non-prosperodmp playstation attachments via the upload endpoint.
#[serde(rename = "projects:relay-playstation-uploads")]
PlaystationUploads,
Expand Down
4 changes: 1 addition & 3 deletions relay-server/src/endpoints/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,6 @@ async fn validate_and_limit(
project: Project<'_>,
) -> Result<ProjectContext, BadStoreRequest> {
let mut envelope = Envelope::from_request(None, meta);
envelope.require_feature(Feature::UploadEndpoint);
let mut item = Item::new(ItemType::Attachment);
item.set_payload(ContentType::AttachmentRef, vec![]);
item.set_attachment_length(headers.upload_length.unwrap_or(1));
Expand Down Expand Up @@ -386,8 +385,7 @@ async fn validate(
meta: RequestMeta,
project: Project<'_>,
) -> Result<ProjectContext, BadStoreRequest> {
let mut envelope = Envelope::from_request(None, meta);
envelope.require_feature(Feature::UploadEndpoint);
let envelope = Envelope::from_request(None, meta);
let mut envelope = Managed::from_envelope(envelope, state.outcome_aggregator().clone());

let _ = project
Expand Down
10 changes: 2 additions & 8 deletions tests/integration/test_attachment_ref.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from sentry_relay.consts import DataCategory
from sentry_sdk.envelope import Envelope, Item, PayloadRef


from .asserts import matches_any
from .test_store import make_transaction

Expand Down Expand Up @@ -112,9 +113,6 @@ def test_attachment_ref_ratelimit(
project_id = 42

project_config = mini_sentry.add_full_project_config(project_id)
project_config["config"].setdefault("features", []).append(
"projects:relay-upload-endpoint"
)
project_config["config"]["quotas"] = [
{
"id": f"test_rate_limiting_{uuid.uuid4().hex}",
Expand Down Expand Up @@ -170,10 +168,7 @@ def test_attachment_ref(
):
event_id = "515539018c9b4260a6f999572f1661ee"
project_id = 42
project_config = mini_sentry.add_full_project_config(project_id)
project_config["config"].setdefault("features", []).append(
"projects:relay-upload-endpoint"
)
mini_sentry.add_full_project_config(project_id)
mini_sentry.global_config["options"][
"relay.objectstore-attachments.sample-rate"
] = 1.0
Expand Down Expand Up @@ -257,7 +252,6 @@ def test_attachment_ref_validation(
project_config = mini_sentry.add_full_project_config(project_id)
project_config["config"].setdefault("features", []).extend(
[
"projects:relay-upload-endpoint",
"organizations:relay-generate-billing-outcome",
]
)
Expand Down
7 changes: 1 addition & 6 deletions tests/integration/test_minidump.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,10 +929,7 @@ def test_minidump_placeholder(
"""
event_id = "515539018c9b4260a6f999572f1661ee"
project_id = 42
project_config = mini_sentry.add_full_project_config(project_id)
project_config["config"].setdefault("features", []).append(
"projects:relay-upload-endpoint"
)
mini_sentry.add_full_project_config(project_id)
mini_sentry.global_config["options"][
"relay.objectstore-attachments.sample-rate"
] = 1.0
Expand Down Expand Up @@ -1184,7 +1181,6 @@ def test_minidump_objectstore_uploads_external_chain(
project_config["config"].setdefault("features", []).extend(
[
"projects:relay-minidump-attachment-uploads",
"projects:relay-upload-endpoint",
]
)

Expand Down Expand Up @@ -1224,7 +1220,6 @@ def test_minidump_objectstore_uploads_external_chain_attachment_limited(
project_config["config"].setdefault("features", []).extend(
[
"projects:relay-minidump-attachment-uploads",
"projects:relay-upload-endpoint",
"projects:relay-minidump-uploads",
]
)
Expand Down
1 change: 0 additions & 1 deletion tests/integration/test_playstation.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ def playstation_project_config():
"features": [
"organizations:relay-playstation-ingestion",
"organizations:relay-new-error-processing",
"projects:relay-upload-endpoint",
"projects:relay-playstation-uploads",
],
}
Expand Down
48 changes: 12 additions & 36 deletions tests/integration/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,35 @@
from concurrent.futures import ThreadPoolExecutor, as_completed

from flask import Response
from enum import Enum
import pytest

from .consts import DUMMY_UPLOAD_PATH, DUMMY_UPLOAD_LOCATION


class FeatureState(Enum):
ENABLED = "enabled"
DISABLED = "disabled"
KILLSWITCHED = "killswitched"


@pytest.fixture
def project_config(mini_sentry):
project_id = 42
config = mini_sentry.add_full_project_config(project_id)["config"]
config.setdefault("features", []).append("projects:relay-upload-endpoint")
config.setdefault("features", []).append("projects:relay-minidump-uploads")
return config


@pytest.mark.parametrize(
"feature_state,expected_status_code",
"killswitched,expected_status_code",
[
pytest.param(FeatureState.ENABLED, 201, id="feature enabled"),
pytest.param(FeatureState.DISABLED, 403, id="feature disabled"),
pytest.param(FeatureState.KILLSWITCHED, 503, id="killswitch active"),
pytest.param(False, 201, id="killswitch off"),
pytest.param(True, 503, id="killswitch on"),
],
)
def test_forward_create(
mini_sentry, relay, dummy_upload, feature_state, expected_status_code
mini_sentry, relay, dummy_upload, killswitched, expected_status_code
):
project_id = 42
config = mini_sentry.add_full_project_config(project_id)
if feature_state is FeatureState.KILLSWITCHED:
mini_sentry.add_full_project_config(project_id)
if killswitched:
mini_sentry.global_config["options"][
"relay.endpoint-fetch-config.enabled"
] = False
if feature_state is FeatureState.ENABLED:
config["config"].setdefault("features", []).append(
"projects:relay-upload-endpoint"
)
relay = relay(mini_sentry)

response = relay.post(
Expand All @@ -64,26 +51,21 @@ def test_forward_create(


@pytest.mark.parametrize(
"feature_state,expected_status_code",
"killswitched,expected_status_code",
[
pytest.param(FeatureState.ENABLED, 204, id="feature enabled"),
pytest.param(FeatureState.DISABLED, 403, id="feature disabled"),
pytest.param(FeatureState.KILLSWITCHED, 503, id="killswitch active"),
pytest.param(False, 204, id="killswitch off"),
pytest.param(True, 503, id="killswitch on"),
],
)
def test_forward_patch(
mini_sentry, relay, dummy_upload, feature_state, expected_status_code
mini_sentry, relay, dummy_upload, killswitched, expected_status_code
):
project_id = 42
config = mini_sentry.add_full_project_config(project_id)
if feature_state is FeatureState.KILLSWITCHED:
mini_sentry.add_full_project_config(project_id)
if killswitched:
mini_sentry.global_config["options"][
"relay.endpoint-fetch-config.enabled"
] = False
if feature_state is FeatureState.ENABLED:
config["config"].setdefault("features", []).append(
"projects:relay-upload-endpoint"
)
relay = relay(mini_sentry)

data = b"hello world"
Expand All @@ -99,11 +81,6 @@ def test_forward_patch(
)

assert response.status_code == expected_status_code, response.text
if feature_state is FeatureState.DISABLED:
assert (
response.json()["detail"]
== "event submission rejected with_reason: FeatureDisabled(UploadEndpoint)"
)


def test_post_retries(mini_sentry, relay, project_config):
Expand Down Expand Up @@ -677,7 +654,6 @@ def test_upload_minidump_opt_in(
project_id = 42
config = mini_sentry.add_full_project_config(project_id)["config"]
features = config.setdefault("features", [])
features.append("projects:relay-upload-endpoint")
if opted_in:
features.append("projects:relay-minidump-uploads")

Expand Down
Loading