Merge pull request 'Discord: Connect a Discord server — OAuth UI (#225 S7) — merge after S6' (#259) from feat/225-s7-oauth-ui into main
Build & Deploy / Build & push images (push) Successful in 4m11s
Build & Deploy / Deploy Firestore rules & indexes (push) Successful in 30s
Build & Deploy / Deploy to VM (push) Successful in 1m34s
Build & Deploy / Report a failed deploy (push) Skipped

This commit was merged in pull request #259.
This commit is contained in:
2026-10-05 03:11:23 -04:00
17 changed files with 846 additions and 65 deletions
+52
View File
@@ -187,6 +187,58 @@ async def test_preferred_bot_for_the_nodes_system_wins(fs):
assert e.value.status_code == 404
async def test_system_id_invites_that_systems_preferred_bot(fs):
"""The S7 picker's "bot for a system" choice: a platform-pinned pool bot
is invited by system_id, never quietly swapped for Automatic."""
fs.put("systems", "s1", {"system_id": "s1", "org_id": "org-a", "preferred_token_id": "pool-1"})
out = await router.oauth_options(node_id=None, token_id=None, org_id=None, decoded=OWNER_A, system_id="s1")
assert out["bot"] == {"name": "DRB Radio 1", "reason": "preferred", "own_bot": False}
out, q = await _start(system_id="s1", return_to="/settings")
assert q["client_id"] == "201" and out["bot"]["reason"] == "preferred"
assert _audit(fs, "discord.oauth.start")[-1]["details"]["system_id"] == "s1"
# a shared system (no org_id) serves every org, as on the node path
fs.put("systems", "shared", {"system_id": "shared", "org_id": None, "preferred_token_id": "pool-1"})
out = await router.oauth_options(node_id=None, token_id=None, org_id=None, decoded=OWNER_B,
system_id="shared")
assert out["bot"]["name"] == "DRB Radio 1"
# system_id outranks node_id
fs.put("nodes", "n1", {"node_id": "n1", "org_id": "org-a", "assigned_system_id": "s2"})
fs.put("systems", "s2", {"system_id": "s2", "org_id": "org-a", "preferred_token_id": "own-a"})
out = await router.oauth_options(node_id="n1", token_id=None, org_id=None, decoded=OWNER_A, system_id="s1")
assert out["bot"]["name"] == "DRB Radio 1"
async def test_system_id_of_another_org_or_unknown_is_404(fs):
fs.put("systems", "sb", {"system_id": "sb", "org_id": "org-b", "preferred_token_id": "pool-1"})
for sid in ("sb", "nope"):
with pytest.raises(HTTPException) as e:
await router.oauth_options(node_id=None, token_id=None, org_id=None, decoded=OWNER_A, system_id=sid)
assert e.value.status_code == 404 and e.value.detail == "System not found."
with pytest.raises(HTTPException) as e:
await _start(system_id=sid)
assert e.value.status_code == 404
assert not _audit(fs, "discord.oauth.start")
# a platform admin acting for org-b may use it
out = await router.oauth_options(node_id=None, token_id=None, org_id="org-b", decoded=ADMIN, system_id="sb")
assert out["bot"]["name"] == "DRB Radio 1"
async def test_system_id_whose_bot_cannot_connect_is_404_not_a_swap(fs):
# pool-2 is at the cap; another org's bot pinned (bad data); no secret
fs.put("systems", "s1", {"system_id": "s1", "org_id": "org-a", "preferred_token_id": "pool-2"})
fs.put("systems", "s2", {"system_id": "s2", "org_id": "org-a", "preferred_token_id": "own-b"})
fs.put("systems", "s3", {"system_id": "s3", "org_id": "org-a", "preferred_token_id": "pool-1"})
fs.data[oauth.OAUTH].pop("pool-1")
for sid in ("s1", "s2", "s3"):
with pytest.raises(HTTPException) as e:
await router.oauth_options(node_id=None, token_id=None, org_id=None, decoded=OWNER_A, system_id=sid)
assert e.value.status_code == 404 and "Harbor" not in str(e.value.detail)
# no preferred bot at all: the usual order (org's own bot first)
fs.put("systems", "s4", {"system_id": "s4", "org_id": "org-a"})
out = await router.oauth_options(node_id=None, token_id=None, org_id=None, decoded=OWNER_A, system_id="s4")
assert out["bot"]["reason"] == "org_bot"
async def test_explicit_bot_must_be_usable_by_the_org(fs):
out = await router.oauth_options(node_id=None, token_id="pool-1", org_id=None, decoded=OWNER_A)
assert out["bot"]["reason"] == "chosen"
+20 -1
View File
@@ -84,7 +84,7 @@ def fs(monkeypatch):
monkeypatch.setattr(settings, "discord_unlinked_guild_org_id", "")
monkeypatch.setattr(settings, "discord_perm_check_enabled", True)
# Per-token snapshot behaviour: "ok" | "muted" | "unknown" | "slow" | "not_member"
# Per-token snapshot behaviour: "ok" | "muted" | "unknown" | "slow" | "not_member" | "invalid"
fake.snap_mode = {}
fake.snap_calls = []
@@ -99,6 +99,8 @@ def fs(monkeypatch):
return _snap(tid, status=discord_rest.UNKNOWN)
if mode == "not_member":
return _snap(tid, status=discord_rest.NOT_MEMBER)
if mode == "invalid":
return _snap(tid, status=discord_rest.INVALID)
return _snap(tid, muted=(mode == "muted"))
monkeypatch.setattr(discord_rest, "guild_snapshot", _snapshot)
@@ -413,6 +415,23 @@ def test_voice_check_needs_fix_when_every_free_bot_is_denied(fs):
assert out["channels"][0]["state"] == "unknown" # can't tell -> start still allowed
def test_voice_check_invalid_token_is_not_no_bot(fs):
# server-26#257: the bot is in the server but Discord rejected its token.
# "No radio bot" (and an invite to a bot already there) would be wrong.
_token(fs, "t1")
fs.snap_mode["t1"] = "invalid"
out = run(checks.node_voice_check("n1", GUILD, refresh=0, channel_id="1001", decoded=OWNER))
assert out["channels"][0]["state"] == "invalid"
assert out["channels"][0]["bots"][0]["status"] == "invalid"
# a working bot elsewhere in the list still wins
_token(fs, "t2")
discord_rest.invalidate()
out = run(checks.node_voice_check("n1", GUILD, refresh=0, channel_id="1001", decoded=OWNER))
assert out["channels"][0]["state"] == "ready"
# no bot at all is still no_bot
assert checks._channel_state([], True) == "no_bot"
def test_voice_check_is_org_scoped(fs):
_token(fs, "t1")
for node, guild, who in (("n1", "200", OWNER), ("nx", GUILD, OWNER), ("n1", GUILD, STRANGER)):