Skip to content

QuakeGuard v1.2.2 - Zero-Trust Serial Fallback

Choose a tag to compare

@GiZano GiZano released this 31 Aug 13:30
· 19 commits to main since this release
7b2f809

Release Date: 2026-08-31
Type: Minor
Codename: Zero-Trust Serial Fallback


🎯 Highlights

  • Zero-Trust USB Serial Fallback: When MQTT/WiFi is unreachable the ESP32-C3 still delivers ECDSA-signed telemetry over USB CDC ([QG:FB] frames). A pure C++ decidePath + RetentionRing core is shared between the firmware and host SIL tests, so the offline path has the same cryptographic guarantees as the MQTT data plane.
  • Host-Aware Retention & Offline Wall Clock: Serial.isConnected() (HWCDC) prevents writing to a power-only charger; events are retained in a bounded FIFO ring (100 slots) and drained in order when a path returns. Each retained event is re-signed with the current software wall clock (epochAtSync + millis()) at drain time so the backend ±300 s anti-replay window accepts retransmissions. No frame is emitted before time is valid.
  • Host Serial Bridge: firmware/tools/serial_bridge.py tails /dev/ttyACM0, filters [QG:FB] lines and POSTs them to /readings/ with X-API-Key — the same ingestion gate as the MQTT bridge — with SSRF-safe URL validation and a parser smoke test in CI.
  • Automatic First-Boot Provisioning: The compile-time SENSOR_ID shortcut is removed. On first boot the node POSTs /devices/register (public key + MAC + enrollment token + GNSS-ready coordinates) and the backend assigns sensor_id and zone; NULL geometry is accepted when no GNSS fix exists yet. Verified live on hardware.

🔧 Changes by Component

Firmware (ESP32-C3)

Change Description
SerialFallback.h (new) Pure C++ header: [QG:FB] marker, buildSerialFrame() (std::string, no char arrays), DeliveryPath enum, decidePath() and RetentionRing<N> — shared with host test_serial_fallback.cpp.
main.cppnetworkTask Becomes a first-available-path dispatcher: MQTT publish (unchanged), else USB CDC Serial.print(buildSerialFrame(...)), else RetentionRing push. Drains retained FIFO when a path returns, re-signing with the current wall time.
main.cpp — clock & USB Anchors epochAtSync/millisAtSync at first NTP sync (pool.ntp.org); Serial.isConnected() polled each loop to gate SERIAL_CDC. ARDUINO_USB_MODE=1 / ARDUINO_USB_CDC_ON_BOOT=1 via platformio.ini.
main.cpp — provisioning Removes SENSOR_ID define; globalSensorID loaded from NVS (quake-config), performProvisioning() assembles /devices/register payload (host scheme stripping, optional GnssModule coords).
firmware/tools/serial_bridge.py (new) Host-side bridge: reads CDC, parse_frame() filtering, _validate_api_url() SSRF guard, forward() with X-API-Key, --stdin/--dry-run for testing.

Backend (FastAPI + Redis + TimescaleDB)

Area Changes
POST /devices/register Validates ENROLLMENT_TOKEN, idempotent lookup by MAC/public key, re-resolves zone when a relocated node reports new coords, accepts latitude/longitude = None (NULL PostGIS geometry → Unknown Region).
POST /readings/ Unchanged ingestion gate (API key + ECDSA + 300 s anti-replay); serial-bridged payloads traverse the identical validate_iot_payload path as MQTT-bridged ones.
Version artifact FastAPI(version="1.2.2"), idempotent TimescaleDB hypertable remains unified TimescaleDB+PostGIS image.

Mobile (React Native + Expo)

Area Changes
Version footer settings.tsx already shows QuakeGuard v1.2.2; no behavioural change in this release (serial path is host-side).

Documentation & Infrastructure

File/Area Changes
ROADMAP.md / CHANGELOG.md / README.md v1.2.2 promoted from Current to Released; CHANGELOG date bumped to 2026-08-31.
CITATION.cff date-released: 2026-08-31, version: 1.2.2; DOI update deferred to post-release Zenodo mint.
docs/whitepaper main.typ cover updated to Zero-Trust Serial Fallback; new sections in 02-hardware.typ (serial fallback, retention, offline clock), 04-broker.typ (host serial bridge), 03-security.typ (identical signing + re-sign on drain). Rebuilt QuakeGuard_Technical_Report_v1.2.2.pdf and synced to docs/web/assets/quakeguard/quakeguard-whitepaper.pdf.
docs/web quakeguard.html synced: softwareVersion 1.2.2, JSON-LD description mentions USB CDC fallback, hero v1.2.2, roadmap v1.2.1 Released / v1.2.2 Current (matches quakeguard.js i18n).
CITATION.cff / docs/whitepaper/README.md Guidance that Zenodo DOI will be updated after the GitHub Release is published (automatic DOI generation).

🔒 Security

  • Zero-Trust serial plane: Serial frames carry the same value:timestamp ECDSA P-256 signature as MQTT; verification uses the same cryptography path (DER/raw r||s tolerant). The backend cannot distinguish MQTT vs serial origin — equal trust verification.
  • Re-sign on drain prevents replay rejection: Retained events are not replayed with stale timestamps; they are freshly signed at drain with the current wall time, staying inside the 300 s window without weakening the anti-replay check.
  • SSRF hardening in the bridge: _validate_api_url() whitelists http/https, rejects embedded credentials and non-alphanumeric hostnames before any requests.post.
  • Host-presence check: Serial.isConnected() ensures data is never written to a dead USB port when only a charger is attached; events are retained instead.

🧪 Testing Summary

Suite Status
Backend (pytest) Pass (existing unit/integration; ingestion gate exercised by serial_bridge.py POSTs via validate_iot_payload) ✅
Mobile (jest / ESLint) Pass (no behavioural change) ✅
Firmware (PlatformIO / Native) Build SUCCESS — test_serial_fallback.cpp covers buildSerialFrame, decidePath (MQTT vs SERIAL_CDC vs RETAIN) and RetentionRing FIFO/bounded eviction ✅
Static Analysis (CodeQL/Sonar) Clean — prior SonarCloud gate fixes retained (CSP externalized, role="status"<output>, char arrays removed, cognitive complexity reductions); new code uses std::string and validated URL construction ✅

🚀 Deployment & Artifacts

Auto-triggers post-merge:

  • GitHub Container Registry push (backend Docker image)
  • GitHub Pages deploy (docs/web)
  • Zenodo archive (via CITATION.cff — DOI to be updated after release publication)

Versioned Artifacts:

  • CHANGELOG.md
  • CITATION.cff
  • README.md & ROADMAP.md
  • docs/whitepaper/QuakeGuard_Technical_Report_v1.2.2.pdf + docs/web/assets/quakeguard/quakeguard-whitepaper.pdf

🔗 Related

What's Changed

  • refactor(fullstack): clear sonarcloud code smells and cpd false positive by @GiZano in #368
  • fix(fullstack): sonarcloud quality gate + remove ITACA fetcher + dual-track roadmap by @GiZano in #369
  • feat(iot): v1.2.2 zero-trust usb serial fallback by @GiZano in #370
  • fix(fullstack): sonarcloud gate + v1.2.2 release prep by @GiZano in #371
  • chore(fullstack): v1.2.2 release finalization by @GiZano in #372

Full Changelog: v1.2.1...v1.2.2