From 038647411867384b4874c27aaf8db9bec990dd50 Mon Sep 17 00:00:00 2001 From: Lotus CI Date: Wed, 28 Oct 2026 21:58:34 -0400 Subject: [PATCH] discord-bridge: bot profile, down alert, login-owner account Add the Discord-logo avatar and a script that uploads it as the bridge bot and sets the display name to "Discord Bridge". Document the new "Discord Bridge Down" Grafana alert, and why the bot login belongs on a dedicated non-chatting account: whoever holds it sends to Discord as the bot instead of through the relay webhook. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5 --- README.md | 10 +++++++++ discord-bridge/bot-avatar.png | Bin 0 -> 10598 bytes discord-bridge/config.yaml | 2 +- discord-bridge/set-bot-profile.sh | 34 ++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 discord-bridge/bot-avatar.png create mode 100755 discord-bridge/set-bot-profile.sh diff --git a/README.md b/README.md index 98de7c5..6bdc62d 100644 --- a/README.md +++ b/README.md @@ -424,6 +424,15 @@ Skip `guilds bridge`: it sets the guild to create a Matrix room for every channe old room). The relay webhook stays with the channel. Keep `@discordbot` at the default power level so it can't overwrite the room's name and icon with the Discord channel's. +**Bot profile:** `@discordbot` shows as "Discord Bridge" with the Discord logo +(`discord-bridge/bot-avatar.png`). To reapply it: `pct exec 151 -- bash /opt/matrix-config/discord-bridge/set-bot-profile.sh`. + +**Who the Discord bot login belongs to:** whichever Matrix account ran `login-token bot` sends its own +messages to Discord *as the bot* ("matrix-bridge APP"), not through the relay webhook. So it lives on a +dedicated account, `@discord-relay:matrix.lotusguild.org`, which never chats. Everyone else, admins +included, stays logged out of the bridge and is relayed under their own name and avatar. Logging the +bot in on one account automatically logs out any other account that had it. + **Rotating the bot token:** reset it in the Developer Portal, then DM the bridge bot `logout` and `login-token bot `. @@ -1006,6 +1015,7 @@ Checklist in this file. | PostgreSQL Down | `pg_up` < 1 for 2m | critical | | LiveKit Down | `up{job="livekit"}` < 1 for 2m | critical | | Hookshot Down | `up{job="hookshot"}` < 1 for 2m | critical | +| Discord Bridge Down | `node_systemd_unit_state{name="mautrix-discord.service",state="active"}` < 1 (or no data) for 3m | critical | | Draupnir Down | `up{job="draupnir-node"}` < 0.5 for 2m | critical | | PG Connection Saturation | connections > 80% of max for 5m | warning | | Federation Queue Backing Up | pending PDUs > 100 for 10m | warning | diff --git a/discord-bridge/bot-avatar.png b/discord-bridge/bot-avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..560252458d4f39647d1c99d206831b7baea03a02 GIT binary patch literal 10598 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 literal 0 HcmV?d00001 diff --git a/discord-bridge/config.yaml b/discord-bridge/config.yaml index 403a4ef..0b23cf5 100644 --- a/discord-bridge/config.yaml +++ b/discord-bridge/config.yaml @@ -61,7 +61,7 @@ appservice: username: discordbot # Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty # to leave display name/avatar as-is. - displayname: Discord bridge bot + displayname: Discord Bridge avatar: mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC # Whether or not to receive ephemeral events via appservice transactions. diff --git a/discord-bridge/set-bot-profile.sh b/discord-bridge/set-bot-profile.sh new file mode 100755 index 0000000..02c0fc8 --- /dev/null +++ b/discord-bridge/set-bot-profile.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Gives @discordbot the Discord logo and the display name "Discord Bridge". +# Run inside LXC 151 (from the Proxmox node): +# pct exec 151 -- bash /opt/matrix-config/discord-bridge/set-bot-profile.sh +# Uploads bot-avatar.png as the bridge bot, points config.yaml at it and +# restarts the bridge, which applies the profile on startup. Safe to re-run. +set -euo pipefail + +DIR=/opt/mautrix-discord +CFG="$DIR/config.yaml" +AVATAR=/opt/matrix-config/discord-bridge/bot-avatar.png +BOT="@discordbot:matrix.lotusguild.org" + +AS_TOKEN=$(awk '/^as_token:/ {gsub(/"/, "", $2); print $2; exit}' "$DIR/registration.yaml") +[ -n "$AS_TOKEN" ] || { echo "no as_token in $DIR/registration.yaml" >&2; exit 1; } + +MXC=$(curl -fsS -X POST \ + -H "Authorization: Bearer $AS_TOKEN" \ + -H "Content-Type: image/png" \ + --data-binary "@$AVATAR" \ + "http://127.0.0.1:8008/_matrix/media/v3/upload?filename=discord.png&user_id=${BOT/@/%40}" | + python3 -c 'import json, sys; print(json.load(sys.stdin)["content_uri"])') +echo "uploaded $MXC" + +# Only the bot block's two lines; the 8-space indent is unique to appservice.bot. +sed -i -E \ + -e 's|^( displayname: ).*$|\1Discord Bridge|' \ + -e "s|^( avatar: )mxc://.*$|\1$MXC|" \ + "$CFG" +grep -A7 '^ bot:' "$CFG" + +systemctl restart mautrix-discord +sleep 3 +systemctl is-active mautrix-discord -- 2.47.3