Il corpo completo di un post in coda rimane nella coda di revisione anche dopo che l'autore lo ha eliminato, senza modo di rimuoverlo

Riepilogo

Quando un post passa attraverso la coda di approvazione, ReviewableQueuedPost.payload["raw"] contiene una copia completa del corpo inviato. Dopo che il post viene approvato e successivamente cancellato dall’autore, il post pubblico viene sostituito dallo stub “(post cancellato dall’autore)”, ma l’elemento in revisione (reviewable) conserva il corpo originale per tutto il tempo in cui esiste la riga del post — che, dopo una cancellazione da parte dell’autore, è indefinito — e continua a fornirlo al personale in /review.

Non esiste un percorso di pulizia (scrub) per questo: Reviewable.scrubbable_types è [ReviewableUser], quindi l’azione di amministrazione per la pulizia aggiunta in #36556 (“i moderatori possono ora utilizzare un’azione ‘Scrub’ per rimuovere i dati personali dell’utente”) non copre i post in coda. Il payload viene rimosso solo se qualcuno distrugge permanentemente il record del post, cosa che la cancellazione dell’autore non fa e che l’interfaccia utente non consente per il primo post di un topic.

Riprodotto su v2026.7.1. Il codice pertinente è invariato su main al 25-09-2026.

Versione

Discourse v2026.7.1 (self-hosted, istanza di test locale autorizzata). Solo Core — nessun plugin coinvolto.

Passi per riprodurre

  1. Come amministratore, imposta che i post di un utente normale richiedano approvazione, ad esempio impostando approve post count su 5 e rimuovendo trust_level_0 da approve unless allowed groups.

  2. Come quell’utente normale, crea un topic con un marker univoco nel corpo. La risposta torna come {"action": "enqueued"}.

  3. Come personale, approvalo: PUT /review/<reviewable_id>/perform/approve_post?version=0. Il post viene creato.

  4. Come autore, cancellalo tramite l’azione normale rivolta all’utente — DELETE /t/<topic_id>.json per il topic di cui questo è il primo post.

  5. Come personale, richiedi GET /review.json?status=all.

Atteso

Una volta che l’autore cancella il contenuto, la copia di moderazione dello stesso testo dovrebbe seguire il ciclo di vita del contenuto: dovrebbe essere eliminata, pulita o almeno essere pulibile da un amministratore allo stesso modo di un ReviewableUser rifiutato.

Reale

Il passo 5 restituisce ancora l’intero corpo originale. Misurato nell’esecuzione riprodotta:

Osservazione Risultato
riga posts dopo la cancellazione dell’autore user_deleted = t, raw = '(topic cancellato dall'autore)'
reviewables.payload dopo la cancellazione dell’autore {"raw":"Corpo in coda DRLGQUEUEDfb08ab5b648f. padding …"} — invariato
Personale GET /review.json?status=all contiene il corpo originale
Reviewable.scrubbable_types ["ReviewableUser"]
Amministratore PUT /review/<id>/scrub.json HTTP 404 (non è un tipo pulibile)
Dopo che il record del post viene distrutto permanentemente la riga reviewable è scomparsa (dependent: :destroy)

L’ultima riga è l’unico percorso che la elimina, e non è raggiungibile dalla cancellazione dell’autore: la cancellazione dell’autore marca il post come user_deleted e, dopo delete_removed_posts_after ore, lo sposta nel cestino. Una riga di post nel cestino continua a esistere, quindi il payload continua a esistere.

Da dove deriva

  • app/models/reviewable_queued_post.rb costruisce e legge payload['raw']; nulla specifica uno scopo o una durata di conservazione per questo.

  • lib/post_destroyer.rb:562 resolve_reviewables_for_author_deletion tocca solo Reviewable.where(target: @post, status: pending). Un reviewable di post in coda approvato non viene mai fatto passare a uno stato successivo o pulito.

  • app/models/post.rb:71 has_many :reviewables, as: :target, dependent: :destroy — si attiva alla distruzione del record, non alla cancellazione soft prodotta dalla cancellazione dell’autore.

  • app/models/reviewable.rb:81 scrubbable_types restituisce [ReviewableUser]; app/controllers/reviewables_controller.rb:191 richiede inoltre status: rejected.

  • Non esiste una pulizia programmata per i reviewables. app/jobs/scheduled/ contiene job clean_up_* / purge_* per bozze, token email, esportazioni, upload, chiavi API e altro, ma nulla per i reviewables.

Impatto

Questo non è una divulgazione pubblica — la coda di revisione è riservata al personale, e non affermo il contrario. È un gap di conservazione dei dati: il testo che un utente ha rimosso dal forum rimane indefinitamente nello store di moderazione, viene mostrato nell’interfaccia della coda di revisione e nessuna azione amministrativa può rimuoverlo se non distruggendo permanentemente il record del post.

Questo è importante per lo stesso motivo per cui #36556 ha aggiunto la pulizia per gli utenti rifiutati: i payload dei reviewables possono contenere dati personali, e un sito che riceve una richiesta di cancellazione non ha un modo supportato per eliminare un payload di post in coda.

Correzione suggerita

Uno di questi la risolve; farne entrambi è meglio:

  1. Estendere resolve_reviewables_for_author_deletion (e il percorso del cestino) per pulire payload['raw'] sui reviewables il cui post di destinazione è stato cancellato dall’autore o spostato nel cestino.

  2. Aggiungere ReviewableQueuedPost a Reviewable.scrubbable_types e consentire che l’azione di pulizia amministrativa esistente si applichi quando il post di destinazione non contiene più il contenuto, in modo che gli operatori abbiano un rimedio supportato per i payload creati prima della correzione.

Una specifica di regressione dovrebbe asserire che dopo che un autore cancella un post in coda approvato, il payload del reviewable non contiene più il corpo inviato.

2 Mi Piace