mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Add a tenant-scoped 'moderator' role to relay_members that holds
ViewQueue, ResolveReport, DeleteMessage, Kick, Timeout, Untimeout
capabilities community-wide. Ban/Unban remain admin+ only. Guard
rails prevent a moderator from Kicking or Timing-out the community
owner or a fellow admin.
Relay/DB changes:
- migrations/0028_relay_moderator_role.sql: additive migration that
drops and recreates the relay_members.role CHECK to include
'moderator'; schema/schema.sql snapshot updated; migration count
assertion advanced to 28
- moderation_authz.rs: ModerationAuthority::CommunityModerator; full
decide_authority arm for 'moderator' with exhaustive unit tests
- side_effects.rs: kind 9005 validator gains additive relay-role path
through authorize_moderation_action(DeleteMessage); kind 9001 gains
additive Kick path + routes to remove_member_as_community_moderator
(new preauthorized DB mutation) when actor has no channel role
- moderation_commands.rs: 9044 resolve builds one resolved report-action
value (required_capability, target_author, channel_id) from stored
report + get_event_by_id_including_deleted; normalization matrix
enforced before authorization; capability map delete→DeleteMessage,
kick→Kick, ban→Ban, timeout→Timeout, dismiss/escalate→ResolveReport
- relay_admin.rs: 9030/9032 accept 'moderator'; 9031 admin removal uses
atomic role = ANY('member','moderator') predicate (no TOCTOU race)
- buzz-db channel.rs: remove_member_as_community_moderator acquires same
per-channel membership lock as remove_member, re-checks last-owner
protection in-transaction, performs soft removal without channel role
- relay main.rs metrics role set extended; buzz-admin CLI role validation
extended; deploy/compose/run.sh docs updated
Desktop changes:
- capabilities.ts: moderationCapabilities(role) helper returning
typed capability struct; single source of truth consumed by both
MessageModerationMenuItems and ModerationQueueCard
- ModerationQueueCard: uses moderationCapabilities; passes canBan into
resolvableActions; uses moderatorDeleteMessage (kind 9005) for delete
- MessageModerationMenuItems: capability-aware per action; Ban/Unban
hidden for moderators
- TimelineMessageRow: moderator delete affordance via 9005 path when
canDelete && !isOwnMessage
- CommunityMembersSettingsCard: moderator role shown with ShieldHalf
icon; role management extended to moderator tier
- relayMembers.ts/types.ts/e2eBridge.ts: 'moderator' added to all role
unions; downgrade-to-member normalization updated
- events.rs: VALID_RELAY_ROLES includes 'moderator'
- commands/moderator.rs: new Tauri command moderator_delete_message
builds kind 9005 inline (avoids file-size ratchet growth on messages.rs)
- shared/api/moderator.ts: moderatorDeleteMessage TS wrapper
Tests added:
- 13 unit tests for decide_authority (moderator grid exhaustive)
- 9 unit tests for moderationCapabilities exhaustive cases
- 5 unit tests for resolvableActions(canBan=false)
- 3 DB integration tests for remove_member_as_community_moderator
(ordinary kick, last-owner guard, non-member not-found) [ignored]
- 1 DB integration test for admin remove member/moderator matrix [ignored]
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>