#![allow(clippy::too_many_lines, clippy::doc_markdown)]
use std::path::PathBuf;
use std::sync::Arc;
use anyhow::{bail, Context, Result};
use clap::Parser;
use matter_controller::{
AclAuthMode, AclEntry, AclPrivilege, Error as ControllerError, FileStore, MatterController,
};
const OUR_FABRIC_ID: u64 = 1;
#[derive(Parser)]
#[command(about = "M9-D real-device validation (fabric mgmt + ACL)")]
struct Args {
#[arg(long)]
store: PathBuf,
#[arg(long)]
node: u64,
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Args::parse();
if !args.store.exists() {
bail!(
"store {} does not exist — commission first",
args.store.display()
);
}
let store = Arc::new(FileStore::new(&args.store));
let controller = MatterController::builder(store)
.build()
.await
.context("opening controller")?;
let node = controller.node(args.node);
println!("== M9-D validation against node 0x{:016X} ==\n", args.node);
let status = node
.commissioning_window_status()
.await
.context("commissioning_window_status")?;
println!("[1] WindowStatus: {:?}", status.status);
println!(
" admin_fabric_index={:?} admin_vendor_id={:?}\n",
status.admin_fabric_index, status.admin_vendor_id
);
let fabrics = node.list_fabrics().await.context("list_fabrics")?;
println!(
"[2] list_fabrics: {} fabric(s) on the device",
fabrics.len()
);
for f in &fabrics {
println!(
" idx={} fabric_id=0x{:016X} vendor=0x{:04X} node=0x{:016X} label={:?}",
f.fabric_index, f.fabric_id, f.vendor_id, f.node_id, f.label
);
}
let our = fabrics
.iter()
.find(|f| f.fabric_id == OUR_FABRIC_ID)
.context("could not find our own fabric (fabric_id=1) in the device's fabric list")?;
let our_index = our.fabric_index;
let original_label = our.label.clone();
println!(" -> our fabric index = {our_index} (label {original_label:?})\n");
let acl = node.read_acl().await.context("read_acl")?;
println!("[3] read_acl: {} entry(ies)", acl.len());
for e in &acl {
println!(
" privilege={:?} auth_mode={:?} subjects={:?} targets={:?} fabric_index={:?}",
e.privilege, e.auth_mode, e.subjects, e.targets, e.fabric_index
);
}
println!();
println!("[4] update_fabric_label round-trip");
node.update_fabric_label("matter-rust-d3")
.await
.context("update_fabric_label set")?;
let relabeled = node
.list_fabrics()
.await
.context("list_fabrics after relabel")?;
let new_label = relabeled
.iter()
.find(|f| f.fabric_index == our_index)
.map(|f| f.label.clone());
println!(" set 'matter-rust-d3' -> readback {new_label:?}");
node.update_fabric_label(&original_label)
.await
.context("update_fabric_label restore")?;
println!(" restored original label {original_label:?}\n");
println!("[5] write_acl round-trip");
let base: Vec<AclEntry> = acl
.iter()
.cloned()
.map(|mut e| {
e.fabric_index = None;
e
})
.collect();
let extra = AclEntry::new(
AclPrivilege::Operate,
AclAuthMode::Case,
Some(vec![0x0000_0000_0000_ACED]),
None,
);
let mut augmented = base.clone();
augmented.push(extra);
let statuses = node
.write_acl(&augmented)
.await
.context("write_acl append")?;
println!(
" wrote {} entries -> statuses {:?}",
augmented.len(),
statuses
);
let after = node.read_acl().await.context("read_acl after append")?;
println!(" read_acl now: {} entry(ies)", after.len());
let restored = node.write_acl(&base).await.context("write_acl restore")?;
println!(" restored original ACL -> statuses {restored:?}");
let final_acl = node.read_acl().await.context("read_acl after restore")?;
println!(
" read_acl after restore: {} entry(ies)\n",
final_acl.len()
);
println!("[6] remove_fabric self-protection");
match node.remove_fabric(our_index).await {
Err(ControllerError::WouldRemoveSelf) => {
println!(" remove_fabric({our_index}) -> WouldRemoveSelf ✓ (guard fired, no fabric removed)\n");
}
Err(e) => bail!("expected WouldRemoveSelf removing our own fabric, got: {e}"),
Ok(()) => bail!("DANGER: remove_fabric removed our own fabric — guard FAILED"),
}
println!("== M9-D validation complete — device left as found (still on our fabric) ==");
Ok(())
}