Files
zpan/server
Jasper VanandCopilot 1b734c0ff9 feat: expand audit event coverage across all state-changing operations (#357)
* feat: expand audit event coverage across all state-changing operations

Add audit events for share lifecycle, object operations, team management,
admin/system mutations, storage, quotas, invite codes, site invitations,
users, licensing, and branding.

New events recorded:
- Share: share_create, share_revoke
- Object: upload_confirm, upload_cancel, object_copy, object_purge,
  batch_trash, batch_purge, trash_empty
- Team/org: team_invite_link_create, team_member_join, team_logo_update,
  team_logo_delete
- System: system_option_set, system_option_delete
- Storage: storage_create, storage_update, storage_delete
- Quota: quota_update
- Invite codes: invite_code_generate, invite_code_delete
- Site invitations: site_invitation_create, site_invitation_revoke
- Users: user_disable, user_enable, user_delete
- Licensing: license_pair, license_disconnect
- Branding: branding_update, branding_reset

Auth sign-up/sign-in events: not logged. The Better Auth hook lifecycle
does not provide reliable org context at sign-up (personal org is created
after the user.create.after hook), and sign-in cannot be distinguished
from normal session refresh without brittle internal request parsing.

No schema migration required; existing activityEvents table fields
support all new event types.

Add i18n translations (en + zh) for all new action names and target types.
Add 26 integration tests verifying every new event category and asserting
no secrets are stored in metadata.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Agent-Profile: https://agent-kanban.dev/agents/f68cfbce6456edb5

* feat: add missing audit event coverage for share_download, org lifecycle, license_refresh

Fill gaps identified in code review:

1. share_download: record after successful file download via public share
   endpoint (publicShares GET /:token/objects/:ref). Authenticated viewer
   is used as actor; share creator is proxy for anonymous downloads with
   anonymous:true in metadata. Presigned URL never stored.

2. team lifecycle via Better Auth organizationHooks (server/auth.ts):
   - team_member_remove (afterRemoveMember): member.userId used as actor
     since BA hook does not expose the initiator
   - team_member_role_update (afterUpdateMemberRole): same limitation,
     member.userId used; previousRole/newRole recorded in metadata
   - team_settings_update (afterUpdateOrganization): actor user available
   - team_delete (afterDeleteOrganization): actor user available
   - team_member_join via email invite (afterAcceptInvitation): joins
     existing link-based join coverage in teams.ts

3. license_refresh: record after POST /api/licensing/refresh succeeds
   (licensing-admin.ts)

Unhookable events (documented with code references):
- invite_code_redeem: called at server/auth.ts:269 in user.create.after;
  personal org (required for activityEvents.orgId NOT NULL) is created in
  session.create.before which runs after this hook. Better Auth provides
  no shared state between these hooks.
- site_invitation_accept: called at server/auth.ts:275 in user.create.after;
  same orgId unavailability issue.

Add 7 new integration tests for: share_download (×2, authed + anonymous),
team_settings_update, team_member_remove, team_member_role_update,
team_delete, license_refresh.

Add i18n translations (en + zh) for new actions:
share_download, team_member_remove, team_member_role_update,
team_settings_update, team_delete, license_refresh.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Agent-Profile: https://agent-kanban.dev/agents/f68cfbce6456edb5

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-04 15:25:47 -04:00
..
2026-05-04 07:50:02 -04:00