Skip to content

ci: publish to Play open testing when a PR is merged to main - #7

Merged
mohitsoni48 merged 3 commits into
mainfrom
ci/beta-on-merge
Oct 31, 2026
Merged

mohitsoni48 merged 3 commits into
mainfrom
ci/beta-on-merge

Conversation

@mohitsoni48

Copy link
Copy Markdown
Owner

What

Merging to main now uploads a signed release bundle to the Play beta (open testing) track, in addition to the existing PR → alpha builds.

Security

  • New play-beta environment with its own copy of the secrets, restricted to the main branch. PR branches cannot select it, so a modified workflow on a branch cannot read these secrets.
  • main itself is owner-only: PR + code-owner review, no direct pushes.
  • PR builds still go through the play-alpha environment and need owner approval.

Notes

  • One workflow for both triggers so the run number (the versionCode attempt) is a single sequence and PR/main codes can't collide. The file keeps its name pr-alpha.yml for the same reason (a new file would restart the run number at 1).
  • Open testing may be subject to Play review before it reaches testers.
  • This PR edits the workflow, so its alpha run will wait for your approval.

🤖 Generated with Claude Code

The existing workflow now also runs on pushes to main and uploads to the beta track through a
new play-beta environment. That environment holds its own copy of the secrets, needs no approval
(main is owner-only via PR + code-owner review) and is restricted to the main branch, so PR
branches cannot read it. PR and main builds share one workflow, so their run numbers (the
versionCode attempt) never collide.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

Copy link
Copy Markdown
Owner Author

Review of head 0df4327

No blocking defects in the diff. It extends pr-alpha.yml with a push trigger on main, using the play-beta environment and the beta track (Play's open testing). The workflow is otherwise unchanged. Keeping one file means PR and main runs share one run_number sequence, so alpha and beta version codes can't collide.

Before merging

Merging this PR is itself a push to main, so it starts a beta upload immediately. Please set these up first:

  • Create the play-beta environment with all five secrets and a deployment rule limiting it to main. If the environment doesn't exist, GitHub creates it empty and the job fails safely at "Check required secrets". But if secrets are added later without the branch rule, any push-triggered workflow on any branch can use them without approval. I couldn't check this, since the environments API wasn't reachable from my side.
  • Make sure Play's open testing track is set up in the Console (countries, open availability).

Findings

Medium

  1. Nothing ties open-testing builds to what was tested.
    • The beta build checks out the TurboLLM daemon repo's main at merge time with no pin (pr-alpha.yml:70-74), so testers can get a daemon and web UI that no alpha build contained.
    • The push run doesn't depend on the alpha run succeeding (:35), and direct or admin-bypass pushes to main publish too.
    • A PR can also be merged while its alpha run is still waiting for approval.
    • Fix: make publish-alpha a required status check, pin the daemon ref to a SHA or tag, or promote the tested alpha artifact with promoteReleaseArtifact instead of rebuilding. build.gradle.kts:104-107 already recommends that.
  2. Alpha and beta uploads can run at the same time (:21-23). The concurrency groups are play-<PR#> and play-main. In the Play Developer API, committing one edit invalidates other open edits on the app, so a beta publish can fail because a PR's alpha finished first, or the reverse. Give the Gradle publish step one shared group for the whole app (for example play-publish, no cancel), or split the upload into its own job. Per-PR cancelling can stay for the build.

Low
3. Re-running a failed main build doesn't work (:139-141, no workflow_dispatch). A re-run reuses run_number, so if the bundle upload succeeded before the failure, Play rejects the duplicate version code. Add workflow_dispatch (it gets a new run number) and route it to beta / play-beta.
4. The docs overstate how well the beta secrets are isolated. play-beta holds its own copy of the same keystore and Play service-account JSON as play-alpha. If a malicious PR's alpha run is approved, those credentials can still publish to beta, or to production if the service account allows it. The alpha approval is the real gate. Say so in RELEASING.md, or use a separate service account limited to testing tracks.
5. Actions are pinned to tags, not SHAs (:66, :70, :76, :81, :85). The main path now runs with the signing secrets and no human approval, so a moved tag would run with them unattended. Pin to commit SHAs.
6. If an alpha approval is granted after a merge, alpha gets a lower version code than beta, and Play shows that alpha release as shadowed. Harmless but confusing.
7. RELEASING.md:233-235 still says no publish* task has ever run end to end. That no longer matches run #1 from PR #6.

Done well

  • It uses push on main, not pull_request_target, and the checkout is the trusted merge commit.
  • Nothing a PR author controls reaches a run: step, and permissions are contents: read.
  • Fork PRs are still excluded.
  • Credentials are written with umask 077 and removed under if: always().
  • cancel-in-progress: false on main means an upload is never killed partway.
  • The build prerequisites match pr-alpha exactly, since it is the same file.

The publish-alpha check on this head is waiting on play-alpha approval, and the PR is blocked, most likely on the CODEOWNERS review.


Generated by Claude Code

…try only on a Play edit conflict

The pin was the annotated tag object, which Actions cannot resolve as a commit. The retry check matched the bare
word "concurrent", present in java.util.concurrent frames of almost any Gradle stack trace, so a real build failure
was retried three times with 45 s waits.
@mohitsoni48
mohitsoni48 merged commit f45bc46 into main Oct 31, 2026
1 check failed

This branch was successfully deployed

No deployments
play-alpha — c5ae6565 Deployed Oct 31, 2026 by mohitsoni48 via publish-alpha #36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant