feat(abuse): send new events and identity metadata to abuse service (#3288)#3289
feat(abuse): send new events and identity metadata to abuse service (#3288)#3289jrf0110 wants to merge 6 commits into
Conversation
…r abuse service - Add CloudEvent union type and reportEvents() helper hitting POST /api/events - Expand AuthEventPayload with new optional user/auth/org metadata fields - Emit user.blocked/unblocked from admin-router updateBlockStatus and bulkBlock helpers - Emit user.deleted from softDeleteUser - Emit org.created/org.member_added from createOrganization and addUserToOrganization - Emit org.member_added from acceptOrganizationInvite - Emit org.member_removed from removeUserFromOrganization - Emit org.deleted from organization-admin-router delete mutation - Emit billing.credit_purchased from processTopUp - Emit billing.kilo_pass_changed from handleKiloPassSubscriptionEvent - Emit stripe.payment_method.attached/detached from handlePaymentMethodEvent - Emit stripe.charge.dispute.created alongside existing KiloClaw logic - Add new cases for stripe.charge.dispute.funds_withdrawn, stripe.radar.early_fraud_warning.created, stripe.charge.failed, stripe.payment_intent.succeeded - Update fireAuthEvent to send richer user metadata fields Closes #3288
- Add user.blocked event to Stytch autoban path (stytch.ts) - Add user.blocked event to admin cancel-and-refund flow (cancel-and-refund.ts) - Add billing.credit_purchased event for org admin credit grants (organization-admin-router.ts) - Expand fireAuthEvent to include auth_providers and org_memberships fields by querying DB at auth time; makes fireAuthEvent async (user.ts) The abuse-service.ts types and reportEvents helper, plus the bulk of the CloudEvent emit sites, were already implemented. This completes coverage for the remaining production call sites per issue #3288.
|
@kilocode-bot review please? |
|
To use Kilo from GitHub you first need to link your GitHub account to Kilo. Link your Kilo account to continue. After linking, mention me again in this issue or pull request. |
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryAll previously-flagged issues remain resolved. The single incremental change (removing Resolved Issues (from previous rounds)
Files Reviewed (12 files)
Reviewed by claude-4.6-sonnet-20260217 · 352,618 tokens Review guidance: REVIEW.md from base branch |
…ll in cancel-and-refund - user.ts: reportEvents for user.deleted was firing before the db.transaction, meaning phantom events could be sent if precondition checks (active subscription, live KiloClaw instance) threw SoftDeletePreconditionError. Move it to after the transaction completes. - cancel-and-refund.ts: actor_email was mistakenly set to adminKiloUserId (a UUID), not an email address. Set it to null as a safe stopgap.
jeanduplessis
left a comment
There was a problem hiding this comment.
Found six concrete event-contract issues in this PR:
- bulk block reports admin UUIDs as
actor_email - async auth enrichment can reject outside existing fail-open handling
- duplicate invite acceptance emits false
org.member_added - Kilo Pass changes use subscription creation time as event time
- admin block/unblock emits events without confirming a real mutation
- dispute-created Stripe payload stores charge identity under
customer
These affect event correctness, retry behavior, and downstream abuse-service attribution/state ordering.
- bulkBlock: set actor_email to null instead of UUID - user.ts fireAuthEvent: catch DB enrichment errors to preserve fail-open behavior - organizations: only emit org.member_added when membership was actually inserted - stripe-handlers-subscription-events: remove incorrect occurred_at backdated to subscription.created - admin-router updateBlockStatus: gate event emission on .returning() confirming a real mutation - stripe.ts dispute.created: use dispute.customer instead of dispute.charge for customer field
…te.created event data Stripe's Dispute type does not have a customer field. The previous fix incorrectly used dispute.customer (which doesn't exist on the type) instead of dispute.charge. Since we cannot get the customer ID without an extra API call, omit the customer field entirely, consistent with how the charge.dispute.funds_withdrawn event is handled.
Summary
reportEventscalls for three previously missing production call sites: Stytch autoban (user.blocked), admin cancel-and-refund (user.blocked), and org admin credit grant (billing.credit_purchased).fireAuthEventinuser.tsto populate the newAuthEventPayloadfields (auth_providers,org_memberships) via parallel DB queries at auth time, keeping the call fire-and-forget.reportEventshelper, all CloudEvent types, the expandedAuthEventPayloadtype, and the majority of the 17 event emit sites were already implemented on this branch prior to this commit. This completes coverage for the remaining gaps identified during codebase audit.Closes #3288
Verification
ABUSE_SERVICE_URLis unset in CI so all newreportEvents/reportAuthEventcalls no-op safely..returning()to confirm the row was actually updated before firing the event, matching the conditional guard that was already present.Visual Changes
N/A
Reviewer Notes
fireAuthEventis now async; all three call sites already usedvoidso the change is non-blocking.billing.credit_purchasedonly for positive grant amounts and only whencreated_by_kilo_user_idis set (orgs created before that column existed have it null).user.email_changedhas no call site because the email field is immutable in normal flows (tied to OAuth provider); no change needed.blocked_atwere intentionally skipped per the bead guidance (low priority for one-off migration scripts).