Skip to content

Commit 5eaf5cd

Browse files
runningcodeclaude
andcommitted
fix(artifacts): Report error for iOS distribution failures (EME-422)
When a ZippedXCArchive has an invalid code signature or is a simulator build, _do_distribution now reports the specific error via _update_artifact_error instead of silently doing nothing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4c731e6 commit 5eaf5cd

3 files changed

Lines changed: 75 additions & 7 deletions

File tree

src/launchpad/artifact_processor.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -302,13 +302,32 @@ def _do_distribution(
302302
logger.info(f"BUILD_DISTRIBUTION for {artifact_id} (project: {project_id}, org: {organization_id})")
303303
if isinstance(artifact, ZippedXCArchive):
304304
apple_info = cast(AppleAppInfo, info)
305-
if apple_info.is_code_signature_valid and not apple_info.is_simulator:
306-
with tempfile.TemporaryDirectory() as temp_dir_str:
307-
temp_dir = Path(temp_dir_str)
308-
ipa_path = temp_dir / "App.ipa"
309-
artifact.generate_ipa(ipa_path)
310-
with open(ipa_path, "rb") as f:
311-
self._sentry_client.upload_installable_app(organization_id, project_id, artifact_id, f)
305+
if not apple_info.is_code_signature_valid:
306+
logger.warning(f"BUILD_DISTRIBUTION skipped for {artifact_id}: invalid code signature")
307+
self._update_artifact_error(
308+
organization_id,
309+
project_id,
310+
artifact_id,
311+
ProcessingErrorCode.ARTIFACT_PROCESSING_ERROR,
312+
ProcessingErrorMessage.INVALID_CODE_SIGNATURE,
313+
)
314+
return
315+
if apple_info.is_simulator:
316+
logger.warning(f"BUILD_DISTRIBUTION skipped for {artifact_id}: simulator build")
317+
self._update_artifact_error(
318+
organization_id,
319+
project_id,
320+
artifact_id,
321+
ProcessingErrorCode.ARTIFACT_PROCESSING_ERROR,
322+
ProcessingErrorMessage.SIMULATOR_BUILD,
323+
)
324+
return
325+
with tempfile.TemporaryDirectory() as temp_dir_str:
326+
temp_dir = Path(temp_dir_str)
327+
ipa_path = temp_dir / "App.ipa"
328+
artifact.generate_ipa(ipa_path)
329+
with open(ipa_path, "rb") as f:
330+
self._sentry_client.upload_installable_app(organization_id, project_id, artifact_id, f)
312331
elif isinstance(artifact, (AAB, ZippedAAB)):
313332
with tempfile.TemporaryDirectory() as temp_dir_str:
314333
temp_dir = Path(temp_dir_str)

src/launchpad/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class ProcessingErrorMessage(Enum):
4949
SIZE_ANALYSIS_FAILED = "Failed to perform size analysis"
5050
ARTIFACT_PARSING_FAILED = "Failed to parse artifact file"
5151
UNSUPPORTED_ARTIFACT_TYPE = "Unsupported artifact type"
52+
INVALID_CODE_SIGNATURE = "Cannot distribute app with invalid code signature"
53+
SIMULATOR_BUILD = "Cannot distribute simulator builds"
5254

5355
# System-related errors
5456
TEMP_FILE_CREATION_FAILED = "Failed to create temporary file"

tests/unit/artifacts/test_artifact_processor.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
)
77

88
from launchpad.artifact_processor import ArtifactProcessor
9+
from launchpad.artifacts.apple.zipped_xcarchive import ZippedXCArchive
910
from launchpad.artifacts.artifact import Artifact
1011
from launchpad.constants import (
1112
ProcessingErrorCode,
@@ -161,6 +162,52 @@ def test_do_distribution_unknown_artifact_type_reports_error(self):
161162
},
162163
)
163164

165+
def test_do_distribution_invalid_code_signature_reports_error(self):
166+
mock_sentry_client = Mock(spec=SentryClient)
167+
mock_sentry_client.update_artifact.return_value = None
168+
self.processor._sentry_client = mock_sentry_client
169+
170+
artifact = Mock(spec=ZippedXCArchive)
171+
mock_info = Mock()
172+
mock_info.is_code_signature_valid = False
173+
mock_info.is_simulator = False
174+
175+
self.processor._do_distribution("test-org-id", "test-project-id", "test-artifact-id", artifact, mock_info)
176+
177+
mock_sentry_client.update_artifact.assert_called_once_with(
178+
org="test-org-id",
179+
project="test-project-id",
180+
artifact_id="test-artifact-id",
181+
data={
182+
"error_code": ProcessingErrorCode.ARTIFACT_PROCESSING_ERROR.value,
183+
"error_message": ProcessingErrorMessage.INVALID_CODE_SIGNATURE.value,
184+
},
185+
)
186+
mock_sentry_client.upload_installable_app.assert_not_called()
187+
188+
def test_do_distribution_simulator_build_reports_error(self):
189+
mock_sentry_client = Mock(spec=SentryClient)
190+
mock_sentry_client.update_artifact.return_value = None
191+
self.processor._sentry_client = mock_sentry_client
192+
193+
artifact = Mock(spec=ZippedXCArchive)
194+
mock_info = Mock()
195+
mock_info.is_code_signature_valid = True
196+
mock_info.is_simulator = True
197+
198+
self.processor._do_distribution("test-org-id", "test-project-id", "test-artifact-id", artifact, mock_info)
199+
200+
mock_sentry_client.update_artifact.assert_called_once_with(
201+
org="test-org-id",
202+
project="test-project-id",
203+
artifact_id="test-artifact-id",
204+
data={
205+
"error_code": ProcessingErrorCode.ARTIFACT_PROCESSING_ERROR.value,
206+
"error_message": ProcessingErrorMessage.SIMULATOR_BUILD.value,
207+
},
208+
)
209+
mock_sentry_client.upload_installable_app.assert_not_called()
210+
164211

165212
class TestArtifactProcessorMessageHandling:
166213
"""Test message processing functionality in ArtifactProcessor."""

0 commit comments

Comments
 (0)