Skip to content

Fix pairing recovery and harden device, runtime, and backup reliability - #2

Open
bcbetterninja wants to merge 3 commits into
masterfrom
fix/pairing-recovery-and-fleet-reliability
Open

Fix pairing recovery and harden device, runtime, and backup reliability#2
bcbetterninja wants to merge 3 commits into
masterfrom
fix/pairing-recovery-and-fleet-reliability

Conversation

@bcbetterninja

@bcbetterninja bcbetterninja commented Sep 13, 2026

Copy link
Copy Markdown

Pairing could stop permanently after a network/JSON error, lose a confirmed device's identity on its first bundle failure, or strand ioBOX credentials when the one-time claim response was lost. This change makes enrollment retryable across disconnects and restarts and fixes the related server, runtime and deployment defects found in the repository review.

Changes

  • Commit kiosk confirmation/replacement atomically with row locking, idempotent confirmation, a 15-minute delivery window, secret-protected retries and authenticated acknowledgment. Serialize tenant migrations and make tenant provisioning transactional, including legacy broken hyphenated registrations.
  • Persist complete encrypted Linux/Windows device identities before acknowledgment; retain pending secure sessions during outages, show recoverable error states, supervise the Linux worker, and preserve identity when bundles or authentication temporarily fail.
  • Add durable ioBOX enrollment secrets/acknowledgments, verified HTTPS on Wi-Fi and W5500, and embedded-key Ed25519 OTA verification compatible with existing server signatures. Pin firmware dependencies and test signature tampering.
  • Protect internal Node-RED events and keep runtime credentials out of public flows; dispatch events to all matching trigger nodes. Fix stale WebSocket ownership, liveness deadlines and offline request queuing. Own GStreamer bus watches and reuse software converters.
  • Replace unsafe SQLite backup/restore endpoints with a coordinated encrypted PostgreSQL/key/Node-RED backup script; correct PostgreSQL 18 volume mounting. Install managed-image detection and a narrow timezone polkit rule compatible with NoNewPrivileges.
  • Add PR validation for PostgreSQL/server, native Linux/Windows clients and both ioBOX variants; make the server test command run individual cases.

Validation

  • 57 server tests passed, including real PostgreSQL 18 concurrent migration/claim/rollback/replacement tests and backup failure cleanup tests. Legacy long schema migration preserves existing data and refuses ambiguous truncated ownership.
  • Server production build and source/test TypeScript checks passed.
  • 10 shared Rust core tests and 6 actual Linux pairing/storage tests passed (Linux modules compiled in an isolated harness with hardware-only stubs).
  • Both ioBOX variants compiled with embedded disposable test trust; four trust-provisioning tests and native server-format signature/tampering tests passed.
  • Node-RED manager regression self-tests, deployment shell syntax, workflow YAML parsing and diff checks passed.
  • GitHub CI passed native Linux (15 platform + 10 core tests), Windows (5 platform + 10 core tests), server and ioBOX jobs on the final PR head 4d943ae (Actions run 34753594964). Physical device/media/TPM and power-loss qualification remains necessary.

Rollout requirements

Read docs/pairing-recovery.md, docs/backup-recovery.md and iobox-firmware/README.md before deployment. Deploy server and Node-RED components together, then clients. Configure verified public BF_IOBOX_TLS_CA_PEM and BF_IOBOX_OTA_PUBLIC_KEY_PEM repository variables before release builds; absent trust anchors intentionally fail the release build. PR test trust is not deployable.

Back up and inspect the actual existing PostgreSQL cluster before changing its volume mount. Legacy stranded ioBOX credentials require operator reset/re-enrollment; serial-only retrieval is unsafe. New enrollment secrets authenticate retries but do not prove factory identity. Managed-image/polkit changes require the updated image or installation steps, not only a binary update.

@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 8f0272b4-b0ca-4454-9bf8-bc7960e97ac3


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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6cc6b2403b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

});

const wss = new WebSocketServer({ noServer: true });
const wss = new WebSocketServer({ noServer: true, maxPayload: 1024 * 1024 });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve the supported camera proxy payload size

Raising an incoming camera-proxy-response with a moderately large snapshot now closes the kiosk socket before the response handler can run: the client explicitly accepts camera bodies up to 10 MiB in client/src/platform/linux/ws_client.rs:805-822 and base64-encodes them into the WebSocket message, while this limit rejects messages above 1 MiB (roughly 768 KiB of raw image data). High-resolution camera snapshots therefore cause the pending admin request to fail and /api/admin/cameras/:id/proxy to return 502; either align maxPayload with the existing 10 MiB contract plus base64 overhead or introduce a smaller/streamed camera response contract.

Useful? React with 👍 / 👎.

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