CI should build and ship to testers freely, but a production release is better behind a deliberate trigger, such as a tag or a manual job, plus an approval step and a separate, narrower credential. That keeps a bad commit or a hijacked branch from reaching every user.
What the tool docs suggest
The fastlane CI page makes a practical point first: do not deploy a new App Store update after every commit, because you still wait one to two days for review. It recommends Git tags or custom triggers, and says you can set up a release job triggered only manually. That is a workflow advice, but it has a security side effect: fewer paths lead to production.
Google Play's permission model supports the same split. One permission lets a user release to testing tracks without allowing publishing to production. A separate permission covers production releases and unpublishing. So the platforms already let you give branch builds and release builds different rights.
Two lanes, two credentials
| Lane | Trigger | Credential | Output |
|---|---|---|---|
| Beta | Merge to main | Testing-track role only | Internal or TestFlight build |
| Release | Tag or manual run, approved | Production-capable role, only here | Store submission or rollout |
The point is that the powerful credential is reachable from one job, not every job.
Add a human approval
A hosted CI service lets you define a deployment environment with required reviewers. Up to six people or teams can be listed, one of them must approve before the job proceeds, and you can enable a setting that stops users approving runs they triggered. There is also an optional wait timer. Note the plan limit on that documentation page: environment protections for private repositories need a paid plan tier, so check yours before you design around it.
Put the production credentials in that environment's secrets so they are only released when the approval passes.
What the release job should check
- The commit is on the protected default branch and tagged.
- The dependency inventory matches the reviewed one. A dependency inventory diff catches a surprise addition.
- Known critical advisories were triaged.
- The build was produced by the pipeline, not a laptop.
- A staged rollout is configured where the store supports it, so a bad release can be paused.
Common objections
Some teams say approval slows hot fixes. Keep an emergency path, but make it the same job with the same approval and a shorter timer, not a side door with a personal token. If you cannot name who can approve at 2am, fix that before an incident.
Try it yourself
Open the demo and watch how a pull request gate blocks a change before it reaches a release. Look at which check fails and what the developer sees.
Click through it at your own pace, or open it full screen.
Where Safeguard fits
Safeguard supports policies, gates and guardrails around releases, SBOM and dependency scanning, and reachability analysis. Autonomous remediation with fix PRs is off by default. Try a free scan.
Quick check
Is a manual release job slower for no reason?
It adds a pause, but store review already takes time. The pause buys a chance to check what is shipping.
Can the same credential serve both lanes?
It can, but then every job that reads it can release. Separate credentials reduce that exposure.
Sources
- fastlane docs: continuous integration
- Play Console permissions help
- GitHub Docs: managing environments for deployment
Last reviewed: 19 October 2026.