<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-hub/tests/test_revoke_is_one_path.py, branch main</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=main</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-25T15:24:16Z</updated>
<entry>
<title>fix(hub): make group revoke admin-only and route it through the broadcasting path</title>
<updated>2026-09-25T15:24:16Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-25T11:58:40Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=43c72cf9e8853cd5b2f59d4a4acd87729b0ddae0'/>
<id>urn:sha1:43c72cf9e8853cd5b2f59d4a4acd87729b0ddae0</id>
<content type='text'>
Two coupled gaps in the moderation surface (docs/MESHBAY_DESIGN.md §7.5):
admin_patch_group let a moderator set a group to "revoked", while the user
handler makes revoke admin-only; and a "revoked" set through either PATCH was
never broadcast to nodes — unlike POST /v1/admin/revoke and account deletion —
so it behaved like "suspended" on nodes while claiming to be the signed,
node-enforced state H4 promises.

PATCH now refuses "revoked" on both users and groups (400, pointing at
POST /v1/admin/revoke, which signs and broadcasts), a moderator setting a group
to revoked is refused with 403 as on the user handler, and moving an entity out
of "revoked" requires admin — a moderator flipping the hub row back to active
would only disagree with the nodes still enforcing the broadcast. Revoke has one
door and it broadcasts.

The admin SPA already revokes through POST /v1/admin/revoke, so this is not a
UI-visible change.

test_revoke_is_one_path.py holds the refusals and the working path; verified red
against the pre-fix admin.py and green after.

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
