feat(releases): map recovery artifact filename per SKU#59
Merged
adamshiervani merged 1 commit intodevfrom Apr 28, 2026
Merged
Conversation
The system recovery endpoint hard-coded `update.img`, which is the eMMC/RKDevTool image. The SDMMC variant ships as `update_sd.img.zip` (a balenaEtcher-flashable archive), so requesting recovery for the `jetkvm-v2-sdmmc` SKU returned the wrong artifact (or 404'd once SKU folders were enforced). Drive the filename from a small per-SKU map and reject unmapped SKUs with 400 so a typo can't silently fall back to the wrong image.
adamshiervani
added a commit
that referenced
this pull request
Apr 29, 2026
* feat(sync-releases): show artifact details, verify GPG, allow custom rollout (#58) * feat(sync-releases): show artifact details, verify GPG, allow custom rollout The previous production prompt was a single y/N with no artifact context, no way to override the hardcoded 10% rollout, and no signature verification. An operator confirming a release this way had to trust that the right files were in S3 and that the .sig was issued by the OTA root key — neither was visible. Changes: * Print full artifact summary before the prompt: URL, sha256, compatibleSkus, and signature status for each artifact. * Verify each .sig file with gpg --status-fd=1 and check the primary key fingerprint against OTA_ROOT_KEY_FPR (mirrored from rv1106-system's release_r2.sh). Reports valid / wrong-root / invalid / missing-pubkey / gpg-unavailable / absent, with a loud WARNING line for wrong-root and invalid signatures so the operator cannot miss them. * Print the latest already-synced release of the same type before the prompt so the operator can confirm this is the next expected version. * Add an interactive rollout-percentage prompt with 10% default, validated to 0-100, replacing the hardcoded 10. * Add an `a`/`abort` answer alongside y/N so operators can stop a multi- release sync mid-run when they spot something wrong, instead of having to N through every remaining version. * Print the DB target and bucket as the first line of main() so a wrong .env.production selection is obvious before any prompts fire. * Print a final run summary with counters: created / skipped-by-user / already-synced / no-artifacts, plus an "aborted at <type> <version>" line when the run was cut short. * Add `npm run sync-releases:production` script and ignore .env.production. Verification path runs only when NODE_ENV=production, so non-prod runs and the test suite never spawn gpg or download artifacts. All 52 existing tests still pass; tsc build is clean. * refactor: hoist objectKeyFromArtifactUrl into helpers Both src/releases.ts and scripts/sync-releases.ts had their own copy of the same URL-to-S3-key conversion. Moved into src/helpers.ts and imported from both call sites so a future change (e.g. CDN path prefix handling) only needs to land once. * fix(sync-releases): only treat ERRSIG rc=9 as missing pubkey GnuPG's ERRSIG line carries an `rc` reason code. rc=9 is the only one that means "we don't have the signer's key" — rc=4 (unsupported algorithm) and other codes are real verification failures. The previous implementation collapsed every ERRSIG into noPubkey, which would have falsely told the operator the OTA root key was missing when the actual problem was e.g. an unsupported pubkey algorithm. Now parses the rc field and surfaces non-9 ERRSIG codes as `invalid` with a human reason (rc=4 → "unsupported algorithm", others → "gpg error code N"). * feat(releases): map recovery artifact filename per SKU (#59) The system recovery endpoint hard-coded `update.img`, which is the eMMC/RKDevTool image. The SDMMC variant ships as `update_sd.img.zip` (a balenaEtcher-flashable archive), so requesting recovery for the `jetkvm-v2-sdmmc` SKU returned the wrong artifact (or 404'd once SKU folders were enforced). Drive the filename from a small per-SKU map and reject unmapped SKUs with 400 so a typo can't silently fall back to the wrong image.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The system recovery endpoint always served
update.img, which is the eMMC image, so requests for the SDMMC SKU got the wrong artifact. Pick the filename from a small per-SKU map (update_sd.img.zipforjetkvm-v2-sdmmc) and reject unmapped SKUs with a 400 so a typo can't silently flash the wrong image.