Files
ruvnet--RuView/v2/crates/homecore-migrate
ruv c88b7a12d8 fix(homecore): review findings from PR #1451 — HAP secret redaction, REST history/logbook cap, event_type validation, migration --force
Post-release deep review of the merged HOMECORE platform PR (#1451)
turned up several real issues, fixed here:

- homecore-hap: StoredAccessory's permanent Ed25519 signing seed and
  StoredSetup's SRP salt/verifier were reachable via derived Debug.
  Not actively triggered by any current code path, but a future
  logging/panic-message change (an ordinary thing to add) would have
  printed the accessory's compromise-forever identity key in
  plaintext -- there's no rotation mechanism. Added manual, redacted
  Debug impls matching the existing SetupCode pattern; StoreState/
  PairingStore's derived Debug inherits the redaction automatically.
  New test pins the exact rendered output.

- homecore-api: /api/history/period and /api/logbook rejected the
  default (no filter_entity_id/entity) call shape once a room had
  more than 32 known entities -- exactly how the real HA frontend
  calls these endpoints. The MAX_HISTORY_ENTITIES cap now only
  applies to an explicit, unusually-large filter list; the existing
  MAX_API_HISTORY_ROWS total-row budget already bounds the actual
  work regardless of entity count. Two new tests: unfiltered succeeds
  with 40 known entities, explicit oversized filter is still rejected.

- homecore-api: fire_event (both REST and WS) restricted event_type
  to [a-z0-9_]+, but real HA integrations commonly fire mixed-case,
  dotted, or hyphenated types (mobile_app.notification_action,
  ios.action_fired). Factored the check into a single
  is_valid_event_type() shared by both transports, relaxed to what
  actually matters for server safety: non-empty, length-bounded, no
  control characters.

- homecore-migrate: write_config_entries/write_device_registry/
  write_entity_registry's atomic no-clobber write had no escape
  hatch -- an operator who fixed a bad source row (or wanted a fresh
  re-import) had to manually delete prior output first. Added a
  --force CLI flag (default off, preserving the existing no-clobber
  default and its explicit malformed_entry_is_an_error_not_a_partial_write
  test) that atomically replaces an existing destination. First
  attempt used bare fs::rename, which hit real ERROR_ACCESS_DENIED
  sharing-violation flakiness on Windows; switched to pre-clearing
  the destination then publishing through the same hard_link step
  the default path already uses reliably.

All touched crates re-verified: homecore-hap 46 tests (was 45),
homecore-api 20+6+6+7=39 tests (was 18+6+6+7=37), homecore-migrate 25
tests (was 24), all 0 failed, clippy clean under -D warnings.

Also corrected the public v2051 GitHub release notes: "Wasmtime
36.0.12 component loading" was inaccurate (the crate uses the
core-module API with a hand-rolled host ABI, not the Component
Model/WIT) -- doc-only, not a code change.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-07-27 16:15:56 -04:00
..

homecore-migrate

Migration tooling for importing Home Assistant filesystem storage into HOMECORE. The implementation follows ADR-165.

Implemented

  • Reads versioned HA .storage JSON and rejects unknown schema versions.
  • Converts entity registry metadata to homecore::EntityEntry.
  • Converts the supported HA v13 device-registry fields to homecore::DeviceEntry, including identifiers, connections, versions, serial number, labels, topology, and config-entry links.
  • Converts core.config_entries to a versioned homecore.config_entries file. Each original row is retained verbatim. Unsupported domains and non-portable fields produce typed warnings.
  • Publishes destination JSON through a synced same-directory temporary file and an atomic no-clobber link. Existing destination files are never replaced.
  • Emits one-line JSON summaries from every import command.
  • Parses secrets with redacted errors and inspects automations.

CLI

The import commands take the HA .storage directory and the HOMECORE storage destination:

homecore-migrate import-entities \
  --storage ~/.homeassistant/.storage \
  --to ~/.homecore/storage

homecore-migrate import-devices \
  --storage ~/.homeassistant/.storage \
  --to ~/.homecore/storage

homecore-migrate import-config-entries \
  --storage ~/.homeassistant/.storage \
  --to ~/.homecore/storage

Successful imports print a machine-readable JSON object:

{"kind":"device_registry","imported":8,"warning_count":0,"warnings":[],"destination":"/home/user/.homecore/storage/core.device_registry"}

inspect, inspect-config-entries, inspect-secrets, and inspect-automations are read-only.

Destination files

Source Destination Format
core.entity_registry core.entity_registry HA-compatible v1/minor 13 envelope
core.device_registry core.device_registry HA-compatible v1/minor 13 envelope
core.config_entries homecore.config_entries HOMECORE v1/minor 0 envelope

Config entries are storage-compatible, not runtime-compatible: importing an entry does not install or execute its HA integration. A HOMECORE plugin must explicitly claim the domain and consume the preserved source payload.

Remaining limitations

  • Automation conversion is not implemented; the tool only inspects automations.yaml.
  • !secret reference resolution in other YAML files is not implemented.
  • Deleted entity/device tombstones are not imported.
  • Device fields newer than HA registry minor version 13 require an explicit parser update; unknown versions fail closed.
  • No side-by-side HA recorder database exporter is provided.

Validation

cargo test -p homecore-migrate
cargo clippy -p homecore-migrate --all-targets -- -D warnings