Hive Hive
Sign in

fix(server): route build multipart upload start to the project’s account

GitHub issue · Closed

Metadata
Source
tuist/tuist #11307
Updated
Jun 24, 2026
Domains
Kura
Details

Describe here the purpose of your PR.

What

multipart_start for build artifact uploads now selects the storage backend from selected_project.account instead of Authentication.authenticated_subject_account(conn), making it consistent with multipart_generate_url, multipart_complete, and the runs/analytics controller.

Why (root cause)

A customer’s tuist test run created the build run successfully, but the xcactivitylog (build.zip) never uploaded, so server-side build processing never ran. Every part PUT to S3 failed with:

404 NoSuchUpload — The specified upload does not exist.
UploadId: 592c5bdd-8760-3721-c345-734875f2d0a2

After 3 retries the CLI gave up and never called /builds/upload/complete. The test-run result_bundle in the same session uploaded fine.

The tell was the upload-id shape. Both artifacts targeted the same custom AWS bucket, but the build start returned a UUID (a default/Tigris-issued id) while the test-run start returned a real AWS multipart id. The three build multipart steps disagreed on which account selects the storage backend:

  • multipart_startAuthentication.authenticated_subject_account(conn) (the caller’s account)
  • multipart_generate_urlselected_project.account
  • multipart_completeselected_project.account

Storage routes per-account via s3_config_and_bucket/1: custom bucket if Account.custom_s3_storage_configured?/1, else the default backend. When a project’s account has custom S3 configured but the upload is performed by a subject whose account differs (a user uploading to an org project), start initiated the multipart upload on the default backend (foreign upload id) while the part PUTs and completion targeted the project’s custom bucket — which rejected the foreign id with NoSuchUpload.

This only affects accounts with custom S3 storage configured whose builds are uploaded by a non-matching subject. It has been present since the build-upload feature shipped (7e2168ef8bb).

Why this fix over alternatives

The object key for all three steps is already derived from selected_project.account, so the upload’s lifetime is owned by the project’s account. start was the only step routing to a different account; aligning it with the others is the minimal, internally-consistent fix.

Impact

Builds from projects with custom S3 storage now upload and process correctly regardless of which subject performs the upload. No schema or data-storage change.

How to test locally

Automated coverage added in builds_controller_test.exs: a project owned by an org account distinct from the authenticated user’s account asserts that Storage.multipart_start receives the project’s account, not the caller’s.

mix test test/tuist_web/controllers/api/builds_controller_test.exs

Validation run: 23 tests, 0 failures; mix format clean; mix credo no issues.

Comments
TA
tuist-atlas[bot] Jun 17, 2026

This fix is now available in xcresult-processor-image@0.24.0. Update to this version to ensure build multipart uploads correctly route to the project’s account when custom S3 storage is configured.

TA
tuist-atlas[bot] Jun 17, 2026

The fix for routing build multipart upload start to the project’s account is now available in server@1.212.3. Please update to that version.