From 53bfa262eb668a687053034d0de4748c168104f2 Mon Sep 17 00:00:00 2001 From: Trevor Elkins Date: Thu, 20 Nov 2025 12:07:02 -0500 Subject: [PATCH 1/4] fix --- .../project_preprod_artifact_update.py | 24 +------------------ .../project_preprod_build_details_models.py | 8 ++++--- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/src/sentry/preprod/api/endpoints/project_preprod_artifact_update.py b/src/sentry/preprod/api/endpoints/project_preprod_artifact_update.py index 5139d880e06513..268a75fbd36421 100644 --- a/src/sentry/preprod/api/endpoints/project_preprod_artifact_update.py +++ b/src/sentry/preprod/api/endpoints/project_preprod_artifact_update.py @@ -288,31 +288,10 @@ def put( head_artifact.main_binary_identifier = apple_info["main_binary_uuid"] updated_fields.append("main_binary_identifier") - # Truncate missing_dsym_binaries if total character count exceeds 1024 if "missing_dsym_binaries" in apple_info: binaries = apple_info["missing_dsym_binaries"] if isinstance(binaries, list): - total_chars = sum(len(str(b)) for b in binaries) - if total_chars > 1024: - truncated = [] - char_count = 0 - for binary in binaries: - binary_str = str(binary) - if char_count + len(binary_str) <= 1024: - truncated.append(binary_str) - char_count += len(binary_str) - else: - break - apple_info["missing_dsym_binaries"] = truncated - logger.warning( - "Truncated missing_dsym_binaries list to not exceed 1024 characters limit", - extra={ - "artifact_id": artifact_id_int, - "original_count": len(binaries), - "truncated_count": len(truncated), - "total_chars": total_chars, - }, - ) + extras_updates["has_missing_dsym_binaries"] = len(binaries) > 0 for field in [ "is_simulator", @@ -322,7 +301,6 @@ def put( "certificate_expiration_date", "is_code_signature_valid", "code_signature_errors", - "missing_dsym_binaries", ]: if field in apple_info: extras_updates[field] = apple_info[field] diff --git a/src/sentry/preprod/api/models/project_preprod_build_details_models.py b/src/sentry/preprod/api/models/project_preprod_build_details_models.py index ee105943dab4b9..6c2026499406f3 100644 --- a/src/sentry/preprod/api/models/project_preprod_build_details_models.py +++ b/src/sentry/preprod/api/models/project_preprod_build_details_models.py @@ -19,7 +19,7 @@ class Platform(StrEnum): class AppleAppInfo(BaseModel): - missing_dsym_binaries: list[str] = [] + has_missing_dsym_binaries: bool = False class AndroidAppInfo(BaseModel): @@ -183,8 +183,10 @@ def transform_preprod_artifact_to_build_details( apple_app_info = None if platform == Platform.IOS or platform == Platform.MACOS: apple_app_info = AppleAppInfo( - missing_dsym_binaries=( - artifact.extras.get("missing_dsym_binaries", []) if artifact.extras else [] + has_missing_dsym_binaries=( + artifact.extras.get("has_missing_dsym_binaries", False) + if artifact.extras + else False ) ) From 444ca256ed2c9a29324c36bf4c205ac711fa735b Mon Sep 17 00:00:00 2001 From: Trevor Elkins Date: Thu, 20 Nov 2025 12:39:01 -0500 Subject: [PATCH 2/4] tests --- .../test_project_preprod_artifact_update.py | 47 +++++++++++++------ .../test_project_preprod_build_details.py | 28 +++++++---- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/tests/sentry/preprod/api/endpoints/test_project_preprod_artifact_update.py b/tests/sentry/preprod/api/endpoints/test_project_preprod_artifact_update.py index 678c8019fc1f96..3d12e478f5aac2 100644 --- a/tests/sentry/preprod/api/endpoints/test_project_preprod_artifact_update.py +++ b/tests/sentry/preprod/api/endpoints/test_project_preprod_artifact_update.py @@ -177,7 +177,16 @@ def test_update_preprod_artifact_with_apple_app_info(self) -> None: self.preprod_artifact.refresh_from_db() stored_apple_info = self.preprod_artifact.extras or {} - assert stored_apple_info == apple_info + # Verify that missing_dsym_binaries array is converted to has_missing_dsym_binaries boolean + expected_extras = { + "is_simulator": True, + "codesigning_type": "development", + "profile_name": "Test Profile", + "is_code_signature_valid": False, + "code_signature_errors": ["Certificate expired", "Missing entitlements"], + "has_missing_dsym_binaries": True, # Converted from non-empty array + } + assert stored_apple_info == expected_extras @override_settings(LAUNCHPAD_RPC_SHARED_SECRET=["test-secret-key"]) def test_update_preprod_artifact_with_android_app_info(self) -> None: @@ -204,14 +213,28 @@ def test_update_preprod_artifact_with_android_app_info(self) -> None: assert stored_android_info["has_proguard_mapping"] is True @override_settings(LAUNCHPAD_RPC_SHARED_SECRET=["test-secret-key"]) - def test_update_preprod_artifact_with_missing_dsym_binaries_truncation(self) -> None: - """Test that missing_dsym_binaries list is truncated if it exceeds 1024 chars.""" - # Create a list that exceeds 1024 chars total - # Each item is 30 chars, so 40 items = 1200 chars - large_list = [f"VeryLongLibraryName{i:04d}.dylib" for i in range(40)] - total_chars = sum(len(s) for s in large_list) - assert total_chars > 1024, "Test data should exceed 1024 chars" + def test_update_preprod_artifact_with_missing_dsym_binaries_empty_array(self) -> None: + """Test that empty missing_dsym_binaries array converts to has_missing_dsym_binaries=False.""" + apple_info = {"missing_dsym_binaries": []} + data = { + "artifact_type": 1, + "apple_app_info": apple_info, + } + response = self._make_request(data) + + assert response.status_code == 200 + resp_data = response.json() + assert resp_data["success"] is True + self.preprod_artifact.refresh_from_db() + stored_apple_info = self.preprod_artifact.extras or {} + assert stored_apple_info.get("has_missing_dsym_binaries") is False + + @override_settings(LAUNCHPAD_RPC_SHARED_SECRET=["test-secret-key"]) + def test_update_preprod_artifact_with_missing_dsym_binaries_non_empty_array(self) -> None: + """Test that non-empty missing_dsym_binaries array converts to has_missing_dsym_binaries=True.""" + # Even a large list should just convert to True + large_list = [f"VeryLongLibraryName{i:04d}.dylib" for i in range(40)] apple_info = {"missing_dsym_binaries": large_list} data = { "artifact_type": 1, @@ -225,13 +248,7 @@ def test_update_preprod_artifact_with_missing_dsym_binaries_truncation(self) -> self.preprod_artifact.refresh_from_db() stored_apple_info = self.preprod_artifact.extras or {} - stored_binaries = stored_apple_info.get("missing_dsym_binaries", []) - - # Verify the list was truncated - assert len(stored_binaries) < len(large_list) - # Verify total chars is within limit - stored_total_chars = sum(len(s) for s in stored_binaries) - assert stored_total_chars <= 1024 + assert stored_apple_info.get("has_missing_dsym_binaries") is True @override_settings(LAUNCHPAD_RPC_SHARED_SECRET=["test-secret-key"]) def test_update_preprod_artifact_with_partial_apple_app_info(self) -> None: diff --git a/tests/sentry/preprod/api/endpoints/test_project_preprod_build_details.py b/tests/sentry/preprod/api/endpoints/test_project_preprod_build_details.py index 60700f9fd8948a..799d34c8ab4296 100644 --- a/tests/sentry/preprod/api/endpoints/test_project_preprod_build_details.py +++ b/tests/sentry/preprod/api/endpoints/test_project_preprod_build_details.py @@ -228,11 +228,9 @@ def test_size_info_none_when_no_metrics(self) -> None: assert resp_data["size_info"] is None def test_get_build_details_with_missing_dsym_binaries(self) -> None: - """Test that missing_dsym_binaries is returned in apple_app_info.""" + """Test that has_missing_dsym_binaries is returned in apple_app_info.""" self.preprod_artifact.artifact_type = PreprodArtifact.ArtifactType.XCARCHIVE - self.preprod_artifact.extras = { - "missing_dsym_binaries": ["libTest.dylib", "TestFramework.framework"] - } + self.preprod_artifact.extras = {"has_missing_dsym_binaries": True} self.preprod_artifact.save() url = self._get_url() @@ -243,10 +241,24 @@ def test_get_build_details_with_missing_dsym_binaries(self) -> None: assert response.status_code == 200 resp_data = response.json() - assert resp_data["app_info"]["apple_app_info"]["missing_dsym_binaries"] == [ - "libTest.dylib", - "TestFramework.framework", - ] + assert resp_data["app_info"]["apple_app_info"]["has_missing_dsym_binaries"] is True + assert resp_data["app_info"]["android_app_info"] is None + + def test_get_build_details_without_missing_dsym_binaries(self) -> None: + """Test that has_missing_dsym_binaries defaults to False when not set.""" + self.preprod_artifact.artifact_type = PreprodArtifact.ArtifactType.XCARCHIVE + self.preprod_artifact.extras = {"has_missing_dsym_binaries": False} + self.preprod_artifact.save() + + url = self._get_url() + response = self.client.get( + url, format="json", HTTP_AUTHORIZATION=f"Bearer {self.api_token.token}" + ) + + assert response.status_code == 200 + resp_data = response.json() + + assert resp_data["app_info"]["apple_app_info"]["has_missing_dsym_binaries"] is False assert resp_data["app_info"]["android_app_info"] is None def test_get_build_details_with_missing_proguard_mapping(self) -> None: From 032253226c5508019df57e860323b46993ba3174 Mon Sep 17 00:00:00 2001 From: Trevor Elkins Date: Thu, 20 Nov 2025 12:45:08 -0500 Subject: [PATCH 3/4] fix --- .../project_preprod_build_details_models.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sentry/preprod/api/models/project_preprod_build_details_models.py b/src/sentry/preprod/api/models/project_preprod_build_details_models.py index 6c2026499406f3..88415f45c378ef 100644 --- a/src/sentry/preprod/api/models/project_preprod_build_details_models.py +++ b/src/sentry/preprod/api/models/project_preprod_build_details_models.py @@ -182,13 +182,16 @@ def transform_preprod_artifact_to_build_details( apple_app_info = None if platform == Platform.IOS or platform == Platform.MACOS: - apple_app_info = AppleAppInfo( - has_missing_dsym_binaries=( - artifact.extras.get("has_missing_dsym_binaries", False) - if artifact.extras - else False - ) + legacy_missing_dsym_binaries = ( + artifact.extras.get("missing_dsym_binaries", []) if artifact.extras else [] + ) + has_missing_dsym_binaries = ( + artifact.extras.get("has_missing_dsym_binaries", False) + or len(legacy_missing_dsym_binaries) > 0 + if artifact.extras + else False ) + apple_app_info = AppleAppInfo(has_missing_dsym_binaries=has_missing_dsym_binaries) android_app_info = None if platform == Platform.ANDROID: From 66730234d95d70f96ddfaa5655b5f187ba7ca0b0 Mon Sep 17 00:00:00 2001 From: Trevor Elkins Date: Thu, 20 Nov 2025 13:29:14 -0500 Subject: [PATCH 4/4] fix --- .../api/endpoints/test_project_preprod_artifact_update.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/sentry/preprod/api/endpoints/test_project_preprod_artifact_update.py b/tests/sentry/preprod/api/endpoints/test_project_preprod_artifact_update.py index 3d12e478f5aac2..85715b1cb85e8a 100644 --- a/tests/sentry/preprod/api/endpoints/test_project_preprod_artifact_update.py +++ b/tests/sentry/preprod/api/endpoints/test_project_preprod_artifact_update.py @@ -215,7 +215,7 @@ def test_update_preprod_artifact_with_android_app_info(self) -> None: @override_settings(LAUNCHPAD_RPC_SHARED_SECRET=["test-secret-key"]) def test_update_preprod_artifact_with_missing_dsym_binaries_empty_array(self) -> None: """Test that empty missing_dsym_binaries array converts to has_missing_dsym_binaries=False.""" - apple_info = {"missing_dsym_binaries": []} + apple_info: dict[str, Any] = {"missing_dsym_binaries": []} data = { "artifact_type": 1, "apple_app_info": apple_info, @@ -235,7 +235,7 @@ def test_update_preprod_artifact_with_missing_dsym_binaries_non_empty_array(self """Test that non-empty missing_dsym_binaries array converts to has_missing_dsym_binaries=True.""" # Even a large list should just convert to True large_list = [f"VeryLongLibraryName{i:04d}.dylib" for i in range(40)] - apple_info = {"missing_dsym_binaries": large_list} + apple_info: dict[str, Any] = {"missing_dsym_binaries": large_list} data = { "artifact_type": 1, "apple_app_info": apple_info,