From 437a7ee332086b7248d1627fc5345d96c6f4c7a8 Mon Sep 17 00:00:00 2001 From: agessaman Date: Fri, 21 Aug 2026 11:57:24 -0700 Subject: [PATCH] fix(api): declare read_write in the ACL client permissions enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ACL client list now reports the real role, so a room server's read-write clients emit "read_write" — a value the OpenAPI schema did not allow, which generated clients and validators reject. Add it to the enum, document all four roles, and add a test asserting every role_name() we can emit is declared in the schema. --- repeater/web/openapi.yaml | 10 ++++++---- tests/test_acl_role_numbering.py | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/repeater/web/openapi.yaml b/repeater/web/openapi.yaml index ca8912d..03eb921 100644 --- a/repeater/web/openapi.yaml +++ b/repeater/web/openapi.yaml @@ -5243,12 +5243,14 @@ components: example: "e1" permissions: type: string - enum: [admin, guest, read_only] + enum: [admin, read_write, read_only, guest] description: | - Client permission level: - - admin: Full access - - guest: Limited access + Client ACL role (low two bits of the permissions byte, matching + MeshCore ClientACL.h): + - admin: Full access, including settings and CLI + - read_write: May send and receive messages (room server guests) - read_only: Read-only access + - guest: Base telemetry only (repeater guests, read-only logins) example: "admin" last_activity: type: integer diff --git a/tests/test_acl_role_numbering.py b/tests/test_acl_role_numbering.py index 4647fdb..bf75216 100644 --- a/tests/test_acl_role_numbering.py +++ b/tests/test_acl_role_numbering.py @@ -8,7 +8,10 @@ admin being rendered read-write/guest in third-party apps (openhop_repeater issue #388). """ +from pathlib import Path + import pytest +import yaml from repeater.handler_helpers.acl import ( ACL, @@ -191,3 +194,23 @@ def test_role_change_replaces_the_role_without_touching_reserved_bits(): assert role_of(perms) == PERM_ACL_GUEST assert perms & 0x40 # reserved flag preserved assert client.is_admin() is False + + +def test_every_role_name_is_allowed_by_the_openapi_schema(): + """The ACL client list advertises an enum; every role we emit must be in it. + + The role split added "read_write", which the schema did not previously + allow — generated clients and validators reject undeclared values. + """ + spec = yaml.safe_load( + (Path(__file__).resolve().parents[1] / "repeater/web/openapi.yaml").read_text() + ) + enum = spec["components"]["schemas"]["ACLClient"]["properties"]["permissions"]["enum"] + + emitted = { + role_name(PERM_ACL_GUEST), + role_name(PERM_ACL_READ_ONLY), + role_name(PERM_ACL_READ_WRITE), + role_name(PERM_ACL_ADMIN), + } + assert emitted <= set(enum), f"roles missing from the OpenAPI enum: {emitted - set(enum)}"