Skip to content

ci: fail closed if a pre-release tag would publish to Play production - #245

Open
TimeToBuildBob wants to merge 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:ci/assert-play-track
Open

ci: fail closed if a pre-release tag would publish to Play production#245
TimeToBuildBob wants to merge 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:ci/assert-play-track

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Why

#243 reported a GitHub pre-release (v0.14.0b2) reaching production Play devices. Erik confirmed that was an intentional Play Console promotion from the internal track, not a CI mapping bug (comment).

The CI mapping itself is already correct after #182: X.Y.Zproduction, anything else → internal. What was missing is a fail-closed assert at publish time, so a later regression (or copying the leftover test-job SUPPLY_TRACK: production env onto the publish job) cannot silently ship a pre-release tag to production.

This does not close #243. Play Console can still promote a track by hand; that is how b2 reached production. The remaining user-facing work on that issue is the bucket-migration path (aw-android-test-bucket-migration-merge / #244), not CI.

What changed

  • scripts/assert-play-track.sh — resolve + assert + --self-test (stable v0.14.0 → production; v0.14.0b2 / dev / rc → internal; production + pre-release tag → hard fail).
  • release-fastlane uses the script to set SUPPLY_TRACK, writes tag+track to the job summary, asserts after resolve, and asserts again immediately before fastlane supply run.
  • Test job runs --self-test on every PR and drops the unused job-level SUPPLY_TRACK: production (it never reached fastlane).

Overlap

#212 also edits build.yml (signing hardening). Different hunks; rebase this if #212 lands first.

Test plan

  • bash scripts/assert-play-track.sh --self-test
  • resolve v0.14.0b2internal
  • assert v0.14.0b2 production → exit 1
  • CI: Test job Assert Play-track resolver green on this PR

The tag→track mapping already sends X.Y.Z to production and everything
else to internal (ActivityWatch#182). This makes that contract executable: resolve
via scripts/assert-play-track.sh, write the track into the job summary,
and refuse to run supply when a pre-release tag would hit production.

Also drop the leftover test-job `SUPPLY_TRACK: production` env (it never
reached fastlane) so it cannot be copied onto the publish job.

Git-Session-Id: 5802
@greptile-apps

greptile-apps Bot commented Aug 29, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a tested Play-track resolver and assertions intended to prevent pre-release tags from reaching production. It also removes the unused test-job track variable, records the selected track in the job summary, and rechecks it before Fastlane runs, but the selected value is not forwarded to the upload command.

Confidence Score: 4/5

The PR should not merge until the asserted Play track is explicitly passed to Fastlane, because a pre-release upload can still use the production default.

The resolver correctly derives and validates an internal track for pre-releases, but the actual supply invocation omits that value, leaving the publication behavior disconnected from the new guard.

Files Needing Attention: .github/workflows/build.yml

Important Files Changed

Filename Overview
.github/workflows/build.yml Adds resolver checks around Play publication, but the Fastlane command does not consume the asserted track.
scripts/assert-play-track.sh Implements consistent stable-versus-prerelease resolution, strict assertions, and representative self-tests.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Tag[Release tag] --> Resolve[Resolve SUPPLY_TRACK]
  Resolve --> Assert[Assert tag and track agree]
  Assert --> Supply[Fastlane supply]
  Supply --> Default[Fastlane track selection]
  Resolve -. SUPPLY_TRACK not forwarded .-> Supply
  Default --> Play[Google Play]
Loading

Reviews (1): Last reviewed commit: "ci: fail closed if a pre-release tag wou..." | Re-trigger Greptile

# This is idempotent (exits 0 if already present).
gem sources --add https://rubygems.org
# Re-check at the publish boundary: the env that actually reaches supply.
bash scripts/assert-play-track.sh assert "${{ github.ref_name }}" "${SUPPLY_TRACK}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Asserted track never reaches Fastlane

When a pre-release tag reaches this job, the resolver and assertions accept SUPPLY_TRACK=internal, but fastlane supply run is invoked without that track, causing Fastlane to use its production default and publish the pre-release AAB to production.

Knowledge Base Used:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 5e935bf: fastlane supply run now takes --track "$SUPPLY_TRACK" so the asserted value is on the argv that uploads.

Historical path was SUPPLY_TRACK via GITHUB_ENV (fastlane maps that onto supply's track; default is production). Env still gets set; --track is the fail-closed copy so a missing env cannot silently fall back to production.

supply defaults to production. The historical path was SUPPLY_TRACK
via GITHUB_ENV; pass --track explicitly so the asserted value is the
one that actually uploads.

Git-Session-Id: 5802
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.

Releases marked "pre-release" on github seem to be getting automatically pushed to the Play Store & auto-installed on devices

1 participant