Skip to content

auto_approve persists Approved request before identity validation — orphaned non-terminal row on validation failure #395

Description

@forkwright

Finding

In submit_request, the auto_approve branch constructs the MediaRequest with status = RequestStatus::Approved and persists it before identity validation runs. The subsequent identity.validate(...) call can return an error (unknown title, unreachable metadata service). When it does, the function returns early via ?, leaving a row in the database with status Approved and want_id = None. No compensating delete or update_status follows. Approved → Monitoring is the only valid next transition, but want_id is null and the transition is never completed, so the row is permanently stuck in a non-terminal state.

Evidence

crates/aitesis/src/lib.rs:135 constructs the request with status = RequestStatus::Approved. crates/aitesis/src/lib.rs:155 persists it before validation:

repo::insert_request(&self.write, &request).await?;
// ...
if auto_approve {
    self.identity.validate(...).await?; // failure leaves Approved row with no want_id
    let want_id = self.monitor.create_want(&request).await?;

The insert is committed before identity.validate(...) (line 166) and monitor.create_want(...) run; an error from either path returns before any compensating write.

Why this matters

A flaky or adversarially-degraded metadata service silently fills the database with dead Approved rows. Because they are non-terminal they count toward the user's pending-request limit but can never be resolved — re-running approve fails with InvalidTransition since the status is already Approved, and normal cleanup ignores them. On a counter-surveillance device this is both a pending-limit denial-of-service (a degraded upstream exhausts the user's quota with phantom requests) and an uncontrolled accumulation of persistent request records that cannot be purged through the supported path — increasing the on-disk forensic footprint that the system is supposed to keep minimal.

Desired correction

Insert with Submitted status first, then perform identity validation and want creation, and only then update_status to Approved → Monitoring. Alternatively, perform the insert and all post-insert steps inside a single transaction and roll back if any step fails. Done when: an identity-validation failure during auto-approve results in no persisted row (or a Submitted-status row that can be retried), with no Approved row left lacking a want_id.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions