Security model
Shipping code around the app store review queue only works if the pipe is trustworthy. This is what Birdify signs, what your users' devices check before running anything, and what happens when a patch turns out to be bad.
What we're defending against
Over-the-air updates move executable behaviour to devices you don't control, over a network you don't own. Three things have to hold:
- Nobody else can ship to your users. A bundle that Birdify didn't sign with your project key is never applied.
- Nothing changes in transit. A truncated or modified bundle fails its checksum and is discarded.
- A bad patch can't strand anyone. An update that fails to boot reverts on the device itself, without waiting for you to notice.
What Birdify explicitly does not do is download native machine code — that's both the store-policy line and the reason the blast radius of a bad patch is bounded. See How Birdify works for what a bundle actually contains.
What gets signed
Every release and every patch is signed at publish time with your project's Ed25519 private key, and a SHA-256 checksum is recorded alongside it. Bundles move over TLS 1.3.
$ birdify release
✓ release 1.4.0 registered · signed ed25519:shop_appKey handling, rotation, and who holds the private half: Signing & verification.
What the device checks
Before a bundle is applied, the SDK re-computes the checksum and verifies the signature against the public key compiled into your binary. Either check failing means the update is dropped and the app keeps running the last good version. You can run the identical check from your machine:
$ birdify verify patch#3
checksum 9f2c…a71b
signer birdify:shop_app
signature valid ✓ · native code: noneWhen something goes wrong
Two independent paths pull a bad update, and neither depends on the other:
- You pull it.
birdify rollbackwithholds the patch fleet-wide; devices return to the last good bundle on next launch. - The device pulls it. A patch that fails to boot is reverted locally and reported back, so a release that only breaks on one OS version doesn't need you awake to catch it.
$ birdify rollback
✓ patch #3 withheld · reverting fleet
# fail-open: unhealthy patches auto-revert tooThe full state machine, including staged rollouts: Rollback & health checks.
Where the trust boundary sits
On Birdify cloud we store your signed bundles and the metadata needed to deliver them — deployment config, target framework, and patch versions. We never receive your source, and we never see data from inside your app.
If that boundary is in the wrong place for you, run the update server yourself: point the CLI at your own host and bundles never leave your infrastructure.
$ birdify config set server https://ota.internal.example.com
✓ server updated (self-hosted)Setup and operational notes: Self-hosting.
Why this stays store-safe
Apple's Guideline 2.5.2 and Google's equivalent permit updating interpreted code and data; they prohibit downloading new native binaries. Birdify only ever moves the managed layer — the Dart bundle, the JS bundle, or a UI description — so a patch changes what your shipped binary does with data, never what native code it contains.
The consequence worth internalising: anything that needs new native code — a new SDK, a new permission, a new platform dependency — is a store release, not a patch.