Skip to content

Serve the OTAFIX bootloader factory-erase image - #136

Merged
jamesarich merged 2 commits into
masterfrom
feat/bootloader-factory-erase
Sep 6, 2026
Merged

jamesarich merged 2 commits into
masterfrom
feat/bootloader-factory-erase

Conversation

@jamesarich

@jamesarich jamesarich commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Consumer side of meshtastic/Adafruit_nRF52_Bootloader_OTAFIX#41 (merged, not yet released). Draft until an OTAFIX release ships the file.

What

  • Vendor static/maintenanceUf2/meshtastic_factory_erase.uf2 (512 bytes, one UF2 block, family ID 0x4D455348, MIT, from OTAFIX c8ccd1d7 tools/) with an ATTRIBUTION.md entry.
  • Manifest: new erase.nrf52Bootloader {fileName, sha256, expectedFamilyId: 1296388936} beside the SoftDevice-keyed erase.nrf52 and erase.rp2040, which are unchanged. manifestVersion stays 1 - additive, and Android decodes with ignoreUnknownKeys.
  • Types: EraseImageEntry.expectedFamilyId?, erase.nrf52Bootloader?.
  • scripts/validate-maintenance-uf2.ts: for an entry carrying expectedFamilyId, parse the file the way the bootloader does - exactly 512 bytes, both start magics, family-present flag, family ID at offset 28, end magic. The script previously never read UF2 bytes.

Why

A bootloader that prints Factory-Erase: UF2 family 0x4D455348 in INFO_UF2.TXT erases its own App Data region (LittleFS plus the WarmNodeStore ring) when this block lands on its drive, keeps the installed firmware, and comes back as a UF2 drive. One file for every nRF52 board, no SoftDevice choice, no serial terminal. Older bootloaders ignore the file silently, so clients gate on that line and fall back to erase.nrf52. Android consumer: meshtastic/Meshtastic-Android#7058. Also: meshtastic/Meshtastic-Apple#2433, meshtastic/meshtastic#2650, meshtastic/web-flasher#431.

Merge order

Deploy this before the Android PR merges. Android's scheduled seed refresh pulls this manifest from production; its guard now requires erase.nrf52Bootloader, so until this is live that job skips with a warning rather than overwriting the bundled seed.

Verified

  • validate:maintenance-uf2 passes (4 erase images); negative-tested by corrupting family, flags, end magic and length in a scratch copy.
  • biome ci clean on tracked files, pnpm build passes, route filename regex accepts the new name.
  • Ran with npx pnpm@9: the workspace shell's pnpm 11 rejects this lockfile (ERR_PNPM_MISSING_TARBALL_INTEGRITY on the @buf/* entries); CI pins pnpm 9.

Swap the vendored bytes for the OTAFIX release asset once one exists (same digest expected).

Summary by CodeRabbit

  • New Features

    • Added support for recognizing and using the nRF52 bootloader factory-erase UF2 image.
    • Added compatibility handling for newer bootloaders that identify supported factory-erase images.
  • Bug Fixes

    • Improved validation of UF2 family identifiers and image integrity before use.
  • Documentation

    • Documented the source, licensing, and verification details of the new factory-erase image.

Vendor meshtastic_factory_erase.uf2 and publish it as erase.nrf52Bootloader
in resource/maintenanceUf2, next to the existing per-SoftDevice nrf52 images
and rp2040, which are unchanged. manifestVersion stays 1: the key is additive
and the clients parse with unknown keys ignored.

The file is one 512-byte UF2 block, board-agnostic, with targetAddr 0 and UF2
family 0x4D455348 ("MESH", 1296388936). The OTAFIX bootloader consumes it
itself and erases its whole App Data reservation (LittleFS config, keys, BLE
bonds, plus the node-DB ring) while leaving MBR, SoftDevice, bootloader,
bootloader settings and the application intact. A device advertises support
with a "Factory-Erase: UF2 family 0x4D455348" line in INFO_UF2.TXT; every
bootloader shipped before that line silently ignores the file, so clients
must fall back to erase.nrf52 when the line is absent.

Because targetAddr is 0, the first-target-address check the other nrf52
images carry does not apply. The entry instead carries expectedFamilyId, and
validate-maintenance-uf2.ts now parses the vendored block for any entry that
has one: exact 512 bytes, UF2 start and end magics, the family-ID-present
flag, and the family ID at offset 28 - the same header the bootloader keys
on, so a wrong file cannot ship unnoticed.

Source: meshtastic/Adafruit_nRF52_Bootloader_OTAFIX PR #41, merged as
c8ccd1d7419fda4c01c30c8a9bf144d30a424c46 (tools/meshtastic_factory_erase.uf2,
MIT, generated by tools/make_factory_erase_uf2.py). No OTAFIX release ships
it yet; swap the vendored copy for the release asset once one exists.

Merge order: Meshtastic-Android's scheduled seed refresh pulls this manifest
from production and only checks that .erase is an object, so its consuming
change must not merge before this is deployed - otherwise the next scheduled
run overwrites its bundled seed with a manifest lacking nrf52Bootloader.
Order is api merge, deploy, then android merge.

biome ci over the tracked files is unchanged at 0 errors and the same 2
pre-existing warnings in src/services/gateway.ts; validate:maintenance-uf2
and build pass.
@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 0b199249-05da-4806-98c9-3f4f4d89d414

📥 Commits

Reviewing files that changed from the base of the PR and between fae27f2 and ff3cf2c.

📒 Files selected for processing (5)
  • data/maintenanceUf2.json
  • scripts/validate-maintenance-uf2.ts
  • src/lib/maintenanceUf2.ts
  • static/maintenanceUf2/ATTRIBUTION.md
  • static/maintenanceUf2/meshtastic_factory_erase.uf2

📝 Walkthrough

Walkthrough

The maintenance UF2 manifest now includes an NRF52 bootloader erase image. Public types describe its expected UF2 family ID. The validator checks the image structure and family ID, and attribution documents the asset source.

Changes

NRF52 bootloader erase image

Layer / File(s) Summary
Manifest contract and asset metadata
src/lib/maintenanceUf2.ts, data/maintenanceUf2.json, static/maintenanceUf2/ATTRIBUTION.md
The manifest and public types add the optional nrf52Bootloader entry and expectedFamilyId. The manifest records the image name, SHA-256 digest, and family ID. The attribution file records the image source and release.
UF2 family validation
scripts/validate-maintenance-uf2.ts
The validator checks UF2 block size, magic values, family-ID presence, and family ID. It applies the check to the bootloader erase entry and includes the entry in the erase image count.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Manifest
  participant Validator
  participant UF2Image
  Manifest->>Validator: provide nrf52Bootloader entry and expectedFamilyId
  Validator->>UF2Image: read vendored erase image
  Validator->>Validator: validate UF2 family block
  Validator-->>Manifest: report validated erase image count
Loading

Poem

A rabbit checks the UF2 byte,
With family ID tucked in tight.
The manifest names the bootloader bright,
Hashes guard the file just right.
“Hop!” says the validator, “all blocks unite!”


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jamesarich
jamesarich marked this pull request as ready for review September 6, 2026 14:44
@jamesarich
jamesarich merged commit ad5dddd into master Sep 6, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant