Repository navigation
fix(streams): guard and audit stream deletion - #1798
EmperorNexus wants to merge 9 commits into
Conversation
|
@EmperorNexus Our automated scan matched code from the PolinRider malware campaign, which steals developer credentials (GitHub, npm, wallets) and spreads through infected repositories:
What to do:
The PR will be re-scanned automatically and can be merged once it is clean. |
|
@EmperorNexus Our automated scan matched code from the PolinRider malware campaign, which steals developer credentials (GitHub, npm, wallets) and spreads through infected repositories:
What to do:
The PR will be re-scanned automatically and can be merged once it is clean. |
31fcf13 to
98e89ca
Compare
Strips the payload this branch picked up (deleted api.js, truncated tailwind.config.js, unhooked package.json). No functional change to the branch's own work.
78130a7 to
22e7578
Compare
Strips the payload this branch picked up (deleted api.js, truncated tailwind.config.js, unhooked package.json). No functional change to the branch's own work.
|
@EmperorNexus Our automated scan matched code from the PolinRider malware campaign, which steals developer credentials (GitHub, npm, wallets) and spreads through infected repositories:
What to do:
The PR will be re-scanned automatically and can be merged once it is clean. |
|
This PR came from a machine infected with the PolinRider malware. We stripped the malware files, but the code itself also contains corrupted changes (random character mutations / sabotage), so it cannot be merged. Found: an unrelated rewrite of |
|
@EmperorNexus Our automated scan matched code from the PolinRider malware campaign, which steals developer credentials (GitHub, npm, wallets) and spreads through infected repositories:
What to do:
The PR will be re-scanned automatically and can be merged once it is clean. |
Overview
This PR prevents deletion of streams that still hold unwithdrawn or pending-withdrawal funds, restricts deletion to the sender (or an org owner), converts deletion to a soft delete, and records a
stream.deleteaudit event. Both v1 and v2 delete handlers now share one helper,deleteStream(id, actor, tenant), so the deletability rules and audit trail stay in sync.Related Issue
Changes
🗑️ Shared delete helper
app/lib/stream-delete.tsdeleteStream(id, actor, tenant)helper used by both v1 and v2 routes.draft→ allowedcancelled→ allowedwithdrawnwithwithdrawal.state === "succeeded"→ allowedended→409 FUNDS_PENDING_WITHDRAWAL(never deletable)active/paused→ existing409senderAddressor an org owner, otherwise403.404.deletedAtinstead of physically removing the row.204; unknown id returns404.streamCacheon soft delete so a staleIf-None-Matchcannot return304.🔌 Route wiring
[MODIFY]
app/api/streams/[id]/route.tsdeleteStreaminstead of the previousactive/paused-only guard and directdb.streams.delete(id).404for soft-deleted rows.[MODIFY]
app/api/v2/streams/[id]/route.tsdeleteStreamhelper, adding the missing ownership check and audit call.404for soft-deleted rows.[MODIFY]
app/api/streams/route.tsdeletedAtrows before pagination.[MODIFY]
app/api/v2/streams/route.tsdeletedAtrows before pagination.📝 Audit
app/lib/audit-log.tsstream.deleteto the privileged stream audit events, recorded with a before snapshot of the stream row.📄 Docs
__tests__/openapi-webhooks.test.tsVerification Results
deleteStreaminapp/lib/stream-delete.tsnpm test,npm run lint,npm run buildandnpm run openapi:checkpassCloses #1733