From e4d90d5d28ba94bcb1365e6eff697ae33a179f9f Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 3 Nov 2026 14:46:41 +1100 Subject: [PATCH] Show /run to every member: Discord lets only its users change who sees it --- deploy/README.md | 5 ++--- docs/jobs/session-ops-discord.md | 8 ++++---- src/session_ops/ops/discord_commands.py | 11 +++++------ tests/ops/test_discord_relay.py | 4 ++-- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 1900007..53c7216 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -87,9 +87,8 @@ What `/run` and `/versions` do, and who may run them: /opt/session-ops/.venv/bin/session-ops discord-register ``` -6. The commands start hidden from everyone but server administrators. In Server - Settings → Integrations, allow them for the role or channel that runs jobs. Seeing - them is not running them: the relay's allowlist still decides. +6. Every member sees the commands. In Server Settings → Integrations, limit them to the + channels that run jobs. Seeing them is not running them: the relay's allowlist decides. Register again after changing which jobs have `discord = true`. diff --git a/docs/jobs/session-ops-discord.md b/docs/jobs/session-ops-discord.md index 6bb9cbd..68de2de 100644 --- a/docs/jobs/session-ops-discord.md +++ b/docs/jobs/session-ops-discord.md @@ -20,10 +20,10 @@ options chosen. A request is refused unless Discord signed it in the last five minutes, it comes from `DISCORD_GUILD_ID` and, when `ALLOWED_CHANNEL_IDS` is set, one of its channels, and its author is in `ALLOWED_USER_IDS` or holds a role in `ALLOWED_ROLE_IDS`. Both lists empty -refuses everybody. `/run` is registered hidden from everyone but server administrators, -and the server's Integrations settings show it to the right role; that only hides it, and -these checks are what refuse everyone else, administrators included. `/versions` only reads, so it is shown to -everyone and skips the author check. +refuses everybody, administrators included. Both commands are shown to every member, since +Discord lets only someone who can use a command change who sees it; the server's +Integrations settings can narrow the channels. `/versions` only reads, so it skips the +author check. The relay runs as `opsbot`, which can start no unit itself. It can write only to `/run/session-ops/requests`, where `session-ops units` writes a `PathChanged=` watch for diff --git a/src/session_ops/ops/discord_commands.py b/src/session_ops/ops/discord_commands.py index d431b04..5d782ac 100644 --- a/src/session_ops/ops/discord_commands.py +++ b/src/session_ops/ops/discord_commands.py @@ -3,10 +3,10 @@ session-ops discord-register # with discord.env's variables in the environment Registered on one guild rather than globally: a guild's commands update at once, and -nobody outside that server can see or run them. /run starts hidden from every member but -server administrators; the server's Integrations settings grant it to a role or channel. -That only hides it, and the relay's allowlist is what refuses everyone else, -administrators included. /versions only reads, so everyone sees it. +nobody outside that server can see or run them. Both are shown to every member, since +Discord lets only someone who can use a command change who sees it; the relay's +allowlist is what refuses /run to everyone else. The server's Integrations settings can +still narrow where they show. """ import os import sys @@ -28,8 +28,7 @@ def commands(jobs): choices = [{"name": discord.clip(f"{job.name}: {job.description}", MAX_CHOICE_NAME), "value": job.name} for job in jobs if job.discord] - hidden = {"type": CHAT_INPUT, "default_member_permissions": "0"} - found = [{**hidden, "name": RUN, "description": "Start a session-ops job now", + found = [{"type": CHAT_INPUT, "name": RUN, "description": "Start a session-ops job now", "options": [{"type": OPTION_STRING, "name": "job", "required": True, "description": "The job to start", "choices": choices}]}] if any(job.name == STORE_VERSIONS_JOB for job in jobs): diff --git a/tests/ops/test_discord_relay.py b/tests/ops/test_discord_relay.py index f647d2f..51ad6e0 100644 --- a/tests/ops/test_discord_relay.py +++ b/tests/ops/test_discord_relay.py @@ -327,13 +327,13 @@ def test_anyone_in_the_server_can_ask_but_not_from_elsewhere(self): class TestCommands(unittest.TestCase): - def test_run_offers_the_discord_jobs_and_starts_hidden(self): + def test_run_offers_the_discord_jobs_to_every_member(self): jobs = registry.load() run, versions = discord_commands.commands(jobs) offered = [choice["value"] for choice in run["options"][0]["choices"]] self.assertEqual(offered, [job.name for job in jobs if job.discord]) self.assertIn("crowdin-sync", offered) - self.assertEqual(run["default_member_permissions"], "0") + self.assertNotIn("default_member_permissions", run) for choice in run["options"][0]["choices"]: self.assertLessEqual(len(choice["name"]), discord_commands.MAX_CHOICE_NAME) self.assertEqual(versions["name"], discord_commands.VERSIONS)