block / block/buzz

NIP-09 event deletion never writes an audit log entry (EventDeleted is defined but has no production call site)

Open
#4,034 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.