at main
3 folders
2 files
Harden BLE bond lifecycle and land full on-device QA coverage
Defensive BLE audit of src/ble/ (audit dossier: docs/security/audit-ble.md).
The stack was sound; this closes the one actionable finding plus the QA gaps.
BLE-L1 (the finding): BLE bonds survived a vault wipe / factory reset — the
NimBLE keystore (nimble_bond NVS), the kleidos_blnames name blob, and its RTC
mirror all live in NVS, which wipeAll() never touched, so a previous owner's
bonded hosts and the device IRK persisted across a factory reset. Add
BondStore::factoryReset() (erases all three backing stores, radio OFF) exposed
via Facade::factoryResetBonds() and wired into every wipe path (pin_state
brute-force wipe, settings wipe, boot recovery, debug WIPEVAULT/lockout). Clearing
the RTC mirror is essential — reconcile() would otherwise resurrect the bonds
after the post-wipe reboot. Validated on-device. Native regression in
test_bond_store / test_name_store.
QA coverage: implement and validate the eight proposed BLE QA tests —
nc-reject (QA-1), conn-param (QA-2), disconnect (QA-4), factory-reset regression
(QA-5), adv-minimization (QA-7) on the mastodon Linux/BlueZ central; redaction
(QA-6) + UTF-8 robustness (QA-8) in CI; and N4 eviction (QA-3) end-to-end on the
DUT via the ESP32 Plus1 central. New mastodon scenarios (adv-scan,
disconnect-mid-type, conn-param, evict, restore) in ble_attack.sh + ble_probe.py.
Plus1 harness: unify the separate _blehost/_wifihost binaries into one
command-switchable BLE+WiFi binary (m5stickc_plus1_host, MODE BLE|WIFI|NONE).
Add an OWNADDR command that rotates the central's LE random-static identity
(fills the DUT bond table for N4 eviction, no BlueZ). Fix two firmware bugs: the
harness was mute without KLEIDOS_USB_SERIAL_CONSOLE (serial facade compiled to
no-op stubs), and identity rotation broke discovery until OWNADDR/FORGET also
clear the resolving list (ble_hs_resolv_list_clear_all).
CVE maintenance: register CVE-2025-53470/53477 (NimBLE HCI, low-reachability)
and record the advertising-report/Mesh/BlueDroid/BluFi CVEs as not-applicable;
2026 re-check found no new NimBLE CVEs. Plus readability + file:line doc-drift
fixes across ble.md / cve-register.md.
Gates: native 233/233, sticks3 + m5stickc_plus2 + m5stickc_plus1_host build
clean, pio check no defects, clang-format/check_layout/check_variants/typos/
gitleaks/ruff/editorconfig all pass.
Claude-Session: https://claude.ai/code/session_01MyjYtwfLCwUUfGVYuTQqSv
ci: build a representative variant set + share one PlatformIO home cache
Two CI-infra fixes (backlog item 4):
Representative build matrix. The device-build matrix compiled 6 near-overlapping
variants (12 jobs) yet MISSED the e-paper HAL and AXP2101 compile paths entirely.
Replace it with the 5 variants that cover every compile-time feature branch —
sticks3 (S3/M5PM1/ST7789-DMA/buttons/full debug console), tdeck (S3/keyboard/
touch/trackball/SD/GPS), cores3_se (S3/AXP2101/PSRAM), m5core_ink (classic-ESP32
xtensa + e-paper, 4 MB no-OTA), m5stack_gray (classic-ESP32 + ST7789 full-frame
polling). Repoint the design-token guard from m5stickc_plus2 to sticks3, and add
the missing install_idf602.sh step to the tag-only release job (same latent
UnknownPackageError the other jobs had).
Shared PlatformIO home cache. ~/.platformio (the espressif32 platform, the ~1.9 GB
ESP-IDF 6.0.2 framework, the toolchains) is identical for every variant, but each
matrix job cached its own ~2 GB copy under a per-env key — ~10 duplicates that
overflowed GitHub's 10 GB repo cache limit and caused intermittent cache-save
failures (e.g. the cardputer_debug Post-Cache flake). Cache it once under a shared
repo-scoped key used by every device-building job across ci/codeql/quality, with a
small per-variant .pio for build output. The host native job keeps its own key
(no device framework).
Claude-Session: https://claude.ai/code/session_01SV58JXhfxhhc9DC6vdjBo4
ci: build a representative variant set + share one PlatformIO home cache
Two CI-infra fixes (backlog item 4):
Representative build matrix. The device-build matrix compiled 6 near-overlapping
variants (12 jobs) yet MISSED the e-paper HAL and AXP2101 compile paths entirely.
Replace it with the 5 variants that cover every compile-time feature branch —
sticks3 (S3/M5PM1/ST7789-DMA/buttons/full debug console), tdeck (S3/keyboard/
touch/trackball/SD/GPS), cores3_se (S3/AXP2101/PSRAM), m5core_ink (classic-ESP32
xtensa + e-paper, 4 MB no-OTA), m5stack_gray (classic-ESP32 + ST7789 full-frame
polling). Repoint the design-token guard from m5stickc_plus2 to sticks3, and add
the missing install_idf602.sh step to the tag-only release job (same latent
UnknownPackageError the other jobs had).
Shared PlatformIO home cache. ~/.platformio (the espressif32 platform, the ~1.9 GB
ESP-IDF 6.0.2 framework, the toolchains) is identical for every variant, but each
matrix job cached its own ~2 GB copy under a per-env key — ~10 duplicates that
overflowed GitHub's 10 GB repo cache limit and caused intermittent cache-save
failures (e.g. the cardputer_debug Post-Cache flake). Cache it once under a shared
repo-scoped key used by every device-building job across ci/codeql/quality, with a
small per-variant .pio for build output. The host native job keeps its own key
(no device framework).
Claude-Session: https://claude.ai/code/session_01SV58JXhfxhhc9DC6vdjBo4