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>
## Summary
- add one strict `BUZZ_S3_ADDRESSING_STYLE=path|virtual` setting shared
by media and Git/CAS storage
- preserve path-style defaults for bundled Compose/Helm MinIO while
supporting Railway's virtual-hosted bucket contract
- fail startup on invalid or non-Unicode values before dependency
connection, and validate the Helm value with the same two choices
- document operator mappings and why endpoint and bucket remain separate
for routing and SigV4 signing
## Best-practice rationale
AWS documents both URL forms and favors virtual-hosted addressing for
S3, while compatibility endpoints such as the bundled MinIO deployment
can require path style. `rust-s3` defaults to virtual/subdomain
addressing and provides `with_path_style()` for the explicit
compatibility case.
Some providers buckets only support as virtual-hosted bucket styles.
This PR therefore uses one explicit, provider-neutral switch rather than
endpoint heuristics or fallback behavior, while retaining `path` as
Buzz's backward-compatible default.
Sources:
-
https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html
- https://docs.rs/rust-s3/0.37.0/s3/bucket/struct.Bucket.html
- https://docs.railway.com/storage-buckets#url-style
-
https://github.com/minio/minio/blob/master/docs/config/README.md#domain
## Validation
- `cargo fmt --all`
- `cargo check --workspace --all-targets`
- targeted `buzz-media` and `buzz-relay` parsing/client-construction
tests for defaults, strict errors, and both URL styles
- Helm unittest: 45/45 passed
- Compose config/render validation passed
- local MinIO path-mode relay startup passed the Git A3 conformance
probe and became ready
- unreachable object storage failed startup and readiness never opened
- push hooks completed the broader Rust and desktop suites successfully
---------
Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz>
Signed-off-by: Kalvin Chau <kalvin@block.xyz>
Co-authored-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz>
Search migrated to Postgres FTS (commit f8bbe6efc).
The Typesense container was removed from compose.yml and the Helm chart,
but the cleanup missed two template/config files:
- `deploy/compose/.env.example`: `TYPESENSE_API_KEY` and
`TYPESENSE_PORT` are dead — no typesense service exists in compose.yml
and the relay binary no longer reads `TYPESENSE_API_KEY`. The
`CHANGE_ME_RANDOM_API_KEY` placeholder was never consumed, so removing
it also unbreaks the sed loop in the blog draft (one fewer no-op secret
to generate).
- `benchmarks/harbor-buzz-orchestra/scripts/benchmark.py`: generates a
typesense_api_key in state and writes `TYPESENSE_API_KEY` to the .env
file it creates.
- *Editing this file caused the
https://github.com/block/buzz/blob/main/.github/workflows/benchmark-harbor.yml
linter ci checks to run, which seemingly haven't run before, so I needed
fix the lint issues to pass this.*
---------
Signed-off-by: Kalvin Chau <kalvin@block.xyz>
Co-authored-by: npub1c4alndp82zyt9veaklm5d965quss79vlhk9awv7qu5erwhmf42qqlvc25c <c57bf9b4275088b2b33db7f746975407210f159fbd8bd733c0e532375f69aa80@buzz.block.builderlab.xyz>