Skip to content

ci: restrict production OTA pushes to release branch PRs#30286

Open
weitingsun wants to merge 2 commits into
mainfrom
wsun/gate-ota-production-push
Open

ci: restrict production OTA pushes to release branch PRs#30286
weitingsun wants to merge 2 commits into
mainfrom
wsun/gate-ota-production-push

Conversation

@weitingsun
Copy link
Copy Markdown
Contributor

@weitingsun weitingsun commented May 15, 2026

Description

Adds a hard guardrail to the OTA push workflow so that production channel updates can only be dispatched from a PR whose head branch matches release/*. Previously, anyone with workflow dispatch permissions could push an OTA update to the production channel from any PR — the only safeguards downstream were the release-team approval step and the fingerprint comparison, neither of which protects against pushing the wrong branch's code to production users.

This change introduces a new dedicated job, verify-release-branch, that runs early in push-eas-update.yml:

  • For exp / rc channels — the job logs an info message and exits 0 (no behavior change for non-production flows).
  • For production channel — the job fetches the target PR via the GitHub API, reads head.ref, and fails the run with a clear annotation and step-summary block if the head branch does not match release/*.

The gate is added to the needs: of the expensive downstream jobs (setup-dependencies, setup-dependencies-base, prepare, push-update) so a doomed production run fails fast — saving ~5–10 minutes of CI per misfire — and surfaces as its own red box in the Actions UI labelled "Verify release branch (production only)", rather than being buried inside the existing validate-pr step.

Because the check lives inside push-eas-update.yml itself, it is automatically inherited by every caller that invokes the workflow via workflow_call:

  • runway-ota-production.yml (hardcoded channel: production) — gate enforced
  • runway-ota-rc.yml (hardcoded channel: rc) — gate skipped
  • auto-rc-ota-build-core.yml (dynamic channel) — gate enforced only when the dynamic channel resolves to production
    No changes are required in any caller workflow.

workflow tests:
from non release branch to production (fail): https://github.com/MetaMask/metamask-mobile/actions/runs/25946843695

from release branch to production (pass):
https://github.com/MetaMask/metamask-mobile/actions/runs/25946935860

from non release branch to non production (pass):
https://github.com/MetaMask/metamask-mobile/actions/runs/25946974294

Changelog

CHANGELOG entry:null

Related issues

Fixes:

Manual testing steps

Feature: Production OTA channel restricted to release branch PRs
  
Scenario: Production OTA push from a non-release branch PR is rejected
    Given a PR exists whose head branch is "fix/some-non-release-change"
    When a maintainer dispatches "Push OTA Update" with channel="production" and that PR number
    Then the workflow run shows a failed job named "Verify release branch (production only)"
    And the run summary contains "Production OTA push rejected" with the PR number and offending head branch
    And no downstream jobs (setup-dependencies, fingerprint-comparison, push-update) execute
  
Scenario: Production OTA push from a release branch PR is allowed
    Given a PR exists whose head branch is "release/7.78.0"
    When a maintainer dispatches "Push OTA Update" with channel="production" and that PR number
    Then the "Verify release branch (production only)" job succeeds
    And the run summary contains "Release branch verified"
    And the workflow proceeds through fingerprint comparison, approval, and the push-update job
  
Scenario: Non-production OTA push is unaffected
    Given any PR exists
    When a maintainer dispatches "Push OTA Update" with channel="exp" or channel="rc"
    Then the "Verify release branch (production only)" job succeeds with "Release branch check skipped"
    And the workflow proceeds normally
  
Scenario: Runway production OTA flow still works
    Given the user dispatches "Runway OTA Production" with source_branch="release/7.78.0"
    And an open PR exists whose head branch is "release/7.78.0"
    When Runway resolves the PR via runway-ota-resolve-context
    And calls push-eas-update.yml with channel="production"
    Then the new gate verifies the PR head branch matches "release/*"
    And the OTA update proceeds end-to-end

Screenshots/Recordings

Before

After

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Changes the production OTA release workflow gating; a misconfiguration or GitHub API/JQ failure could incorrectly block legitimate production updates.

Overview
Adds a new verify-release-branch job to push-eas-update.yml that blocks production OTA updates unless the target PR’s head branch matches release/*, using the GitHub API to read head.ref and emitting clear run summaries/errors.

Wires this guard into the needs: chain for the expensive downstream jobs (setup-dependencies, setup-dependencies-base, prepare, push-update) so invalid production runs fail fast, while non-production channels (exp/rc) explicitly skip the check.

Reviewed by Cursor Bugbot for commit f89dc9e. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbotv2 metamaskbotv2 Bot added the team-mobile-platform Mobile Platform team label May 15, 2026
@weitingsun weitingsun marked this pull request as ready for review May 15, 2026 23:55
@weitingsun weitingsun requested a review from a team as a code owner May 15, 2026 23:55
Copy link
Copy Markdown
Contributor

@Cal-L Cal-L left a comment

Choose a reason for hiding this comment

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

Lgtm

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size-S team-mobile-platform Mobile Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants