feat(daemon): GetPendingStatus D-Bus method + 2 integration tests

Drops the #[allow(dead_code)] on AppState::get_pending_status — it's now
called from the D-Bus dispatch. Two new p2p tests cover the absent and
the round-trip cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
michael
2026-04-27 10:51:25 -07:00
parent 86e3ffe8d5
commit 1976971bb5
2 changed files with 39 additions and 2 deletions

View File

@@ -1,7 +1,9 @@
use crate::polkit::Polkit;
use crate::state::AppState;
use authforge_common::policy::Policy;
use authforge_common::types::{Credential, PendingFlag, PolicyApplyResult, RecoveryCodeSummary};
use authforge_common::types::{
Credential, PendingFlag, PendingStatus, PolicyApplyResult, RecoveryCodeSummary,
};
use std::sync::Arc;
pub struct AuthForge {
@@ -129,6 +131,14 @@ impl AuthForge {
Ok(())
}
async fn get_pending_status(&self, user: String) -> zbus::fdo::Result<PendingStatus> {
// No polkit gate — pure read; daemon's pattern is gates on writes only.
self.state
.get_pending_status(&user)
.await
.map_err(|e| zbus::fdo::Error::Failed(e.to_string()))
}
async fn generate_recovery_code(&self, user: String) -> zbus::fdo::Result<String> {
self.authz("io.dangerousthings.AuthForge.generate-recovery")
.await?;
@@ -387,6 +397,34 @@ central_path = "{}"
assert!(!state.has_pending("alice").await.unwrap());
}
#[tokio::test]
async fn pending_status_is_absent_for_fresh_user() {
let (_srv, client, _state, _tmp) = p2p_pair().await;
let p = proxy(&client).await;
let s: PendingStatus = p.call("GetPendingStatus", &("alice",)).await.unwrap();
assert!(!s.present);
assert!(s.flag.required_methods.is_empty());
}
#[tokio::test]
async fn pending_status_round_trips_set_flag() {
let (_srv, client, _state, _tmp) = p2p_pair().await;
let p = proxy(&client).await;
let flag = PendingFlag {
required_methods: vec![Method::Fido2],
created_unix: 100,
deadline_unix: 200,
re_enroll: true,
};
let _: () = p
.call("SetPendingFlag", &("alice", flag.clone()))
.await
.unwrap();
let s: PendingStatus = p.call("GetPendingStatus", &("alice",)).await.unwrap();
assert!(s.present);
assert_eq!(s.flag, flag);
}
#[tokio::test]
async fn generate_recovery_code_returns_8_digits() {
let (_srv, client, _state, _tmp) = p2p_pair().await;

View File

@@ -259,7 +259,6 @@ impl AppState {
Ok(self.pending.get(user)?.is_some())
}
#[allow(dead_code)] // wired through D-Bus in Task 5.
pub async fn get_pending_status(&self, user: &str) -> Result<PendingStatus, StateError> {
match self.pending.get(user)? {
Some(flag) => Ok(PendingStatus { present: true, flag }),