* fix: gate chat_completion channel: branch on channel access + message scoping
When chat_id starts with 'channel:' the chat-completion handler skips
the chat ownership / storage block below it. Nothing replaced that
gate. The downstream channel emitter in socket/main.py:_make_channel_
emitter writes to Messages.update_message_by_id using a caller-supplied
message_id pulled from form_data['id'], with no membership check, no
write-access check, and no validation that the message_id belongs to
the channel.
Net effect: any authenticated user could submit
chat_id='channel:<any-channel-uuid>' + id='<any-message-uuid>' and
overwrite that message with attacker-controlled LLM output. Cross-
channel writes worked too — private channels, DMs, channels the
caller has no access to. Original author attribution stayed intact on
the overwritten row.
Add the missing checks at the channel: branch:
1. Channel must exist (404 otherwise).
2. Non-admin caller must have write access to the channel — membership
for group/dm channels, AccessGrants permission='write' for others.
3. The message_id (if supplied) must belong to the same channel — a
caller with write access to channel A cannot use this path to
overwrite a message in channel B.
Behaviour change is limited to callers who were exploiting the gap:
legitimate flows that supply a message_id under their own channel
membership continue to work unchanged.
Co-authored-by: sfwani <sfwani@users.noreply.github.com>
* chore: trim verbose comment on channel: branch gate
---------
Co-authored-by: sfwani <sfwani@users.noreply.github.com>