NIP-09 event deletion never writes an audit log entry (EventDeleted is defined but has no production call site)
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
**Summary**
`AuditAction::EventDeleted` is defined but has no production call site anywhere in the codebase. Neither of the two paths that delete/tombstone an event (the standard NIP-09 soft-delete, or the hard-delete-on-supersede path for parameterized-replaceable events) ever writes an audit log entry. This relay currently cannot produce an audit trail for any event deletion.
**Where**
- `crates/buzz-audit/src/action.rs` (~lines 8-31) defines `AuditAction` with 11 variants including `EventDeleted` (`event_deleted` in storage). Searching the whole tree, it appears in exactly two places: the enum definition itself, and one `#[cfg(test)]` unit test (`crates/buzz-audit/src/service.rs`, `verify_detects_tampering_within_a_community`) that uses it only as a generic sample action to exercise hash-chain tamper detection — not a real deletion code path.
- NIP-09 deletion dispatch is in `crates/buzz-relay/src/handlers/side_effects.rs`:
- `handle_delete_event_side_effect` (standard `e`-tag deletion) calls `soft_delete_event_and_update_thread`.
- The `a`-tag (addressable/parameterized-replaceable) NIP-09 deletion path also calls `soft_delete_event_and_update_thread`.
Neither call path touches `buzz_audit` — there's no `audit_tx.send(...)` anywhere near either handler. Contrast with the two paths that *do* audit correctly on the same pattern:
- `crates/buzz-relay/src/handlers/event.rs` (`enqueue_event_created_audit`) sends `AuditAction::EventCreated` after every successful event write.
- `crates/buzz-relay/src/api/media.rs` sends `AuditAction::MediaUploaded` after a successful Blossom upload (explicitly commented as following "the same pattern as event audit").
No equivalent `enqueue_event_deleted_audit` exists.
- Both deletion mechanisms confirmed:
- **Soft delete / tombstone** (the normal user-facing NIP-09 delete, both `e`-tag and `a`-tag): `soft_delete_event_and_update_thread` and the lower-level `delete_event`/`delete_by_kind_pubkey_dtag` in `crates/buzz-db/src/event.rs` do `UPDATE events SET deleted_at = NOW() WHERE ... AND deleted_at IS NULL`. There is no `DELETE FROM events` anywhere in that file.
- **Hard delete** for parameterized-replaceable event supersession, gated behind a `hard_delete_superseded` flag: `replace_parameterized_event` in `crates/buzz-db/src/lib.rs` issues `DELETE FROM events WHERE community_id = $1 AND kind = $2 AND pubkey = $3 AND d_tag = $4 AND deleted_at IS NULL` plus a companion `DELETE FROM event_mentions`.
Neither path calls into `buzz_audit` anywhere in `crates/buzz-db` or in the `crates/buzz-relay/src/handlers/side_effects.rs` caller.
**Reproduction**
A regression test reproducing this against real Postgres (`standard_deletion_writes_no_audit_entry`, `crates/buzz-relay`) is here, passing in CI: https://github.com/frodoHost/buzz/pull/1
**Related doc gap**
`ARCHITECTURE.md` (~line 503) lists only 10 audit actions and omits `MediaUploaded` (which does exist and is wired up correctly) — worth fixing alongside this, and worth noting there that `EventDeleted` is defined-but-dead.
Contributor guide
Assessment
This issue has not been assessed yet.