Skip to content

Pending approvals are in-memory only — daemon restart drops them with no audit trail #3611

Description

@houko

Severity: Critical
Location: crates/librefang-kernel/src/approval.rs:36, 80, 277, 352

Problem

The pending: DashMap<Uuid, PendingRequest> is never persisted. Only the audit log and TOTP lockout state are written to SQLite. The waiting tool call's oneshot receiver was dropped when the daemon died, so on restart the agent loop receives no decision.

Failure scenario

Operator submits a high-stakes approval (deploy, transfer, send message); daemon is restarted (deploy, OOM, crash); on restart the pending entry is gone. A second operator approval attempt returns "not found or expired", with no audit trail of what was lost. The agent loop either hangs forever (paths without a per-call timeout) or treats it as denied, and there is no UI surface telling the user "we lost N pending approvals on the last restart".

Suggested fix

Persist PendingRequest to a pending_approvals table; replay on boot, re-broadcast NeedsApproval to whichever path is waiting (or treat replayed entries as failed and require resubmission, but at minimum surface them in the dashboard with a banner so operators are not silently misled).


Filed from cross-cutting bug/design audit (2026-04-28). Line numbers may drift across commits — verify before fixing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/apiREST/WS endpoints and dashboardarea/kernelCore kernel (scheduling, RBAC, workflows)area/memorySQLite memory substratearea/securitySecurity systems and auditingbugSomething isn't workinghas-prA pull request has been linked to this issueseverity/criticalRemote-exploitable, data loss, or production-blocking

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions