<feed xmlns='http://www.w3.org/2005/Atom'>
<title>luke/mattertimectl/src/controller.rs, branch main</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<id>https://src.nth.io/luke/mattertimectl/atom?h=main</id>
<link rel='self' href='https://src.nth.io/luke/mattertimectl/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/mattertimectl/'/>
<updated>2026-07-28T22:42:46+00:00</updated>
<entry>
<title>Split the controller operations into a submodule</title>
<updated>2026-07-28T22:42:46+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-07-28T22:42:46+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/mattertimectl/commit/?id=4129dcaeceab060d9f1cac599e9e29cab0f44fd7'/>
<id>urn:sha1:4129dcaeceab060d9f1cac599e9e29cab0f44fd7</id>
<content type='text'>
controller.rs had grown to ~1400 lines gluing the one-shot stack harness
and persistent-identity lifecycle to the four on-wire operations. Move the
operations (commission, sync, inspect, decommission, plus connect and the
timeout helper) into controller/ops.rs; the harness, identity/fabric
bootstrap, KV store, and locking stay in controller/mod.rs. ops.rs sees the
parent module private items via use super::*, so no visibility changes were
needed, and pub use ops::* keeps the existing controller::* paths.

No behavior change. 36 unit tests, clippy clean.
</content>
</entry>
<entry>
<title>Address remaining audit findings: input hardening and cleanup</title>
<updated>2026-07-28T22:38:06+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-07-28T22:38:06+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/mattertimectl/commit/?id=29943e536f2be420a9d4042cd26d7b7eddf71438'/>
<id>urn:sha1:29943e536f2be420a9d4042cd26d7b7eddf71438</id>
<content type='text'>
Security:
- SNTP replies must echo a random nonce in their originate timestamp, and
  unsynchronized (LI=3) or invalid-stratum servers are rejected, so an
  off-path spoofer cannot defeat the clock-trust gate
- The storage directory is created 0700 but an existing one is tightened
  only when it is provably ours (holds our artifacts or is empty); a
  misconfigured path like /tmp under root is left alone with a warning
- Device-supplied vendor/product names are stripped of control characters
  at ingestion so a device cannot inject terminal escapes

Cleanup:
- ensure_fabric splits into decision logic plus bootstrap_fabric
- read_device_names merges the two name readers; a From impl replaces the
  hand-mapped IdentityReport; run_sync uses map/transpose with an extracted
  manual_instant; pick_interface runs once; print_json escapes its fallback;
  device_name dedups the vendor/product join; identity_status ignores
  leftover .tmp blobs; dead parameters and repeated random-id code removed

36 unit tests, clippy clean.
</content>
</entry>
<entry>
<title>Harden against untrusted input and reduce controller boilerplate</title>
<updated>2026-07-28T22:18:43+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-07-28T22:18:43+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/mattertimectl/commit/?id=28a660e8bacac84523601f67547b2671058d9b20'/>
<id>urn:sha1:28a660e8bacac84523601f67547b2671058d9b20</id>
<content type='text'>
Security:
- Epoch conversions no longer panic on out-of-range values: a device may
  report any u64 as its clock, so to_timestamp is fallible (rendered
  labeled-raw), from_timestamp clamps a pre-epoch host clock to zero (a
  Pi with no RTC reads 1970 early after boot), and delta arithmetic
  saturates. Fixes crashes in inspect and status
- Identity Debug redacts the root CA private key so no stray {:?} leaks it
- fsync the temp file before rename, so a power loss cannot surface an
  empty identity.json
- Document in the README that device attestation is not verified, the NTP
  servers contacted, and the at-rest key

Cleanup:
- A MatterCtx extension trait replaces the repeated map_err/anyhow closure
  at every rs-matter call site with .ctx("what")
- SyncOutcome::failed/skipped constructors collapse two large literals
- read_our_fabric_entry shares the fabric-filtered read across the label,
  decommission, and inspect paths

36 unit tests, clippy clean.
</content>
</entry>
<entry>
<title>Implement mattertimesync: one-shot Matter time synchronization CLI</title>
<updated>2026-07-28T21:58:20+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-07-28T21:58:20+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/mattertimectl/commit/?id=07d4713f554b2ae2ccf4871f6be0590c129342b0'/>
<id>urn:sha1:07d4713f554b2ae2ccf4871f6be0590c129342b0</id>
<content type='text'>
A standalone CLI Matter controller that joins Matter devices as a
secondary administrator (multi-admin) and sets their clocks via the
standard Time Synchronization cluster. Built on rs-matter 0.2.0, the
official CSA Rust Matter stack: its PASE/CASE initiators, Commissioner
flow, builtin mDNS, and generated cluster clients. One-shot runs from a
systemd timer; there is no daemon.

Hardware-validated end to end (commission, inspect, sync, decommission)
against an IKEA ALPSTUGA air quality monitor over Thread, commissioned
alongside Apple Home. Design and operation are documented in the
README. 34 unit tests, clippy clean.
</content>
</entry>
</feed>
