Hive Hive
Sign in

fix(server): remote xcresult processing follow-ups (grants + test-run UX)

GitHub issue · Closed

Metadata
Source
tuist/tuist #11604
Updated
Jul 5, 2026
Domains
Atlas Testing
Details

Follow-up fixes surfaced while investigating remote xcresult processing, after #11602 landed the migrate-time processor grants + the webhook_endpoints fix. Four fixes across three commits.

1. Grant tuist_processor read on automation_alerts

#11602 granted webhook_endpoints, which let ingestion run past the test_case.created dispatch and hit the next ungranted table. The flaky-alert enqueue (Tuist.Automations.enqueue_flaky_alert_evaluations -> Repo.all(Alert)) reads automation_alerts, which the least-privilege processor role also can’t read, raising 42501. It’s non-fatal (runs inside Tuist.Tasks.run_async), so the run still ingests fully but flaky-alert scheduling is silently skipped. Enumerated the full Postgres surface of the ingestion path (accounts, projects, webhook_endpoints, automation_alerts, oban_jobs, oban_peers); automation_alerts was the last gap. Added to both do_grant_processor_role and the runbook SQL.

While here, folded in the refactor from the closed #11607 so both land together: the grant set is now driven off a single audited table list (@processor_write_tables / @processor_read_tables) exposed as a DB-free Release.processor_role_grant_statements/3, and do_grant_processor_role/2 applies the REVOKE + re-GRANT sequence inside one repo.transaction/1 so a mid-sequence failure can’t leave the role with a torn privilege set. The runbook SQL was restructured to the same shape (REVOKE-first, ON TABLE on every grant, one combined read grant).

2. Download result for remote tuist inspect test runs

The “Download result” button only rendered when a command_events row was linked to the run, keyed under the command_event id. Remote inspect-test runs create no command_event and store the bundle under the test run id, so the button never appeared even though the bundle is in S3. Resolve the download source run-scoped: prefer the command_event key, else the run-scoped key (get_result_bundle_key/2, exactly what the upload wrote). The route/controller tries the command_event first, then the test run, and 404s cleanly if neither has a bundle.

3. De-duplicate devices on the test-run detail

A run processed across multiple retries could list the same device several times, because create_run_destinations inserts a fresh row per attempt. Collapse run_destinations to distinct (name, platform, os_version) for display.

4. No-test parse shows failed_processing, not “Skipped”

When the parser extracts zero test modules (aborted/empty xcresult), the Swift parser reports “skipped” vacuously from an empty test-case list, which reads on the dashboard as a real skip. Surface a zero-module parse as failed_processing.

Validation

  • mix format clean on all touched Elixir files; mix compile clean with no new warnings on the changed files.
  • New Tuist.ReleaseTest (DB-free) pins the exact processor_role_grant_statements/3 output and asserts the runbook SQL keeps the same read/write/REVOKE lines in sync, so the two grant paths can’t silently drift again.
  • Fixes 2-4 are dashboard/parse behavior with no existing unit tests; verified by compile + review. The download path reuses the existing get_result_bundle_key/2 the upload path already writes to, so keys match.

Notes

  • automation_alerts is non-urgent (non-fatal). It applies automatically on the next deploy via the migrate-time grant, or can be applied ahead of the deploy with the runbook SQL.
  • The write-side of duplicate destinations (non-idempotent create_run_destinations) is intentionally left as display-time dedup, since the grant fix stops the retries that produced duplicates.
  • The xctest (N) encountered an error normalization that was briefly here has been pulled into a dedicated PR that models these as run/target-level errors (matching Xcode’s Errors section) rather than as test cases.

🤖 Generated with Claude Code

Flights

Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.

New Flights are paused Configure model inference, GitHub, and a sandbox provider to start another Flight. Existing results remain available below.
No Flights yet

Start a Flight and preserve its objective, outcome, and session here.

Comments

No GitHub comments yet.