bundle verify — Verify a signed bundle with your public key
native-update bundle verify <bundlePath> --key <public-key> re-verifies the RSA-SHA256 signature on a bundle the same way the device-side SDK does. Use it as a CI safety net before uploading: if the signature is invalid, the device-side SDK will reject the bundle, so catching the failure on the build machine saves you a debugging round-trip.
The command operates entirely on local files and does no network I/O.
Synopsis
npx native-update bundle verify <bundlePath> --key <publicKey>
# Alias:
npx native-update bundle verify-bundle <bundlePath> --key <publicKey>
Arguments
| Argument | Required | Description |
|---|---|---|
<bundlePath> | Yes | Path to the bundle ZIP. The sidecar .sig file is read automatically from the matching path (same basename, .sig extension). |
Flags
| Flag | Required | Default | Description |
|---|---|---|---|
-k, --key <path> | Yes | — | Path to a PEM-encoded public key (SPKI — the format keys generate writes). |
-h, --help | — | — | Print help and exit. |
How the signature is located
The command looks for the signature at <bundlePath> with .zip replaced by .sig. For example:
| Bundle path | Expected signature path |
|---|---|
./bundle.zip | ./bundle.sig |
./releases/bundle-1.2.0.signed.zip | ./releases/bundle-1.2.0.signed.sig |
If the sidecar is missing, the command exits 1 with No signature file found at <path> — there is no flag to override the lookup; rename the sidecar to match the bundle.
Examples
Verify a freshly signed bundle
npx native-update bundle verify \
./update-bundles/bundle-1.2.0-1715450096000.signed.zip \
--key ./keys/public-1715000000000.pem
A valid signature prints:
🔍 Verifying bundle signature...
✅ Bundle signature is VALID
Bundle Details:
Signed at: 2026-05-11T12:35:40.000Z
Algorithm: RSA-SHA256
This bundle can be trusted and deployed safely.
An invalid signature prints:
🔍 Verifying bundle signature...
❌ Bundle signature is INVALID
WARNING: This bundle may have been tampered with!
Do not deploy this bundle.
…and exits 1.
Use in a CI release gate
yarn build
npx native-update bundle create ./dist --version "$RELEASE_VERSION" --channel production
npx native-update bundle sign ./update-bundles/bundle-*-*.zip --key ./keys/private.pem
# Safety net — fail the build if the signature does not verify
npx native-update bundle verify ./update-bundles/bundle-*-*.signed.zip --key ./keys/public.pem || exit 1
# Upload step here…
This catches three real-world failure modes before they reach a device:
- Private/public key drift (signing key does not match the public key shipped in the app).
- Bundle corruption between signing and upload (rare, but happens when a transfer step rewrites the file).
- Signature sidecar missing or pointing at the wrong bundle.
Common errors
| Error | Cause | Fix |
|---|---|---|
No signature file found at <path> | No .sig sidecar next to the bundle. | Run bundle sign to create it, or rename your sidecar to match the bundle's basename. |
Failed to verify bundle: ENOENT, no such file or directory '<bundle>' | Bundle path is wrong. | Use the exact path printed by bundle create / bundle sign. |
Failed to verify bundle: error:0909006C:PEM routines:get_name:no start line | The file at --key is not PEM, or is a private key instead of a public key. | Pass the matching public-*.pem file produced by keys generate. |
Failed to verify bundle: <other> | Filesystem / OpenSSL error. | Read the message; usually a path or permission issue. |
Bundle signature is INVALID (exit 1) | The signature does not match the bundle bytes under the given public key. | Re-sign with the matching private key, or check whether the bundle bytes were modified after signing. |
How verification works
- Read
<bundlePath>into memory as raw bytes. - Read
<bundlePath>.sigand parse the JSON; pull outsignature(base64-encoded RSA-SHA256). - Read
--keyas a PEM-encoded public key. - Run
crypto.createVerify('RSA-SHA256')over the bundle bytes; call.verify(publicKey, signature, 'base64'). - Print the result and exit with
0(valid) or1(invalid).
The device-side SDK performs the same five steps, with the bundle on the device's filesystem and the public key compiled into the app. If bundle verify exits 0 with your public key, the device-side SDK will accept the bundle (assuming the same public key is shipped in the app).
Notes and limitations
- Public key must match the signing private key. Mismatched key pairs are by far the most common cause of
INVALID— verify the timestamps in the filenames match (private-X.pem/public-X.pem). - No partial / streaming verify. Verification reads the full bundle into memory. For a 100+ MB bundle this is fine on a build machine but worth noting.
- No support for detached signatures over chunks. The signature covers the whole ZIP. If you need chunked verification for very large bundles, file an issue.
Authored by
Ahsan Mahmood — author and maintainer of native-update.