feat(daemon): storage::policy + PolicyChanged signal + inotify watcher
Lands plan tasks 2.6 (PolicyStore wraps load_from_dir / save_local), 2.7
(PolicyChanged D-Bus signal on the AuthForge interface), and 2.8 (notify-based
inotify watcher in main.rs that emits the signal on any change in the policy.d
directory). Bundled because watcher → emit signal → wraps PolicyStore is one
data flow.
- daemon/src/storage/{mod,policy}.rs — PolicyStore::{load,save,watch}; watch
returns a (RecommendedWatcher, watch::Receiver) so the caller keeps the
watcher alive.
- daemon/src/dbus.rs — adds #[zbus(signal)] policy_changed; integration test
via p2p connection asserts the signal arrives within 2s.
- daemon/src/main.rs — spawns a task that ticks PolicyChanged on every
rx.changed(), keyed off AUTHFORGE_POLICY_DIR env var (default
/etc/authforge/policy.d). Watcher leaked via std::mem::forget; daemon
lifetime = process lifetime.
Test count: 17/17 daemon (was 14) + 13/13 common.
This commit is contained in:
@@ -115,6 +115,13 @@ impl AuthForge {
|
||||
let n: u32 = rand::rng().random_range(0..100_000_000);
|
||||
Ok(format!("{n:08}"))
|
||||
}
|
||||
|
||||
/// Emitted by main.rs whenever the inotify watcher on the policy.d/ dir
|
||||
/// reports any change. Subscribers (GUI) reload via `GetPolicy`.
|
||||
#[zbus(signal)]
|
||||
pub async fn policy_changed(
|
||||
signal_ctxt: &zbus::object_server::SignalContext<'_>,
|
||||
) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -263,4 +270,27 @@ mod tests {
|
||||
assert_eq!(code.len(), 8);
|
||||
assert!(code.chars().all(|c| c.is_ascii_digit()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn policy_changed_signal_fires_on_emit() {
|
||||
use futures_util::stream::StreamExt;
|
||||
let (server, client, _state) = p2p_pair().await;
|
||||
|
||||
let proxy = proxy(&client).await;
|
||||
let mut stream = proxy.receive_signal("PolicyChanged").await.unwrap();
|
||||
|
||||
let iface_ref: zbus::object_server::InterfaceRef<AuthForge> = server
|
||||
.object_server()
|
||||
.interface("/io/dangerousthings/AuthForge")
|
||||
.await
|
||||
.unwrap();
|
||||
AuthForge::policy_changed(iface_ref.signal_context())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let _msg = tokio::time::timeout(std::time::Duration::from_secs(2), stream.next())
|
||||
.await
|
||||
.expect("signal not received within 2s")
|
||||
.expect("stream closed before signal");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user