aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_username_floor.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-15 02:16:39 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-15 02:21:01 +0200
commitbdefcd025604f2c3009fe5e0cc01213c2ba62a6a (patch)
treeeebd34aa234a9148045ca25b00bf7c8039e00ccf /packages/meshbay-hub/tests/test_username_floor.py
parent027e7d55f3bb57ba5150fd77e8f0114a0baf8d5c (diff)
downloadmeshbay-bdefcd025604f2c3009fe5e0cc01213c2ba62a6a.tar.gz
feat(hub): usernames are at least 8 characters at registration
Existing shorter accounts keep signing in. Test usernames padded to match. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
Diffstat (limited to 'packages/meshbay-hub/tests/test_username_floor.py')
-rw-r--r--packages/meshbay-hub/tests/test_username_floor.py58
1 files changed, 58 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_username_floor.py b/packages/meshbay-hub/tests/test_username_floor.py
new file mode 100644
index 0000000..607aacc
--- /dev/null
+++ b/packages/meshbay-hub/tests/test_username_floor.py
@@ -0,0 +1,58 @@
+"""
+A username is at least 8 characters — at registration, and nowhere else.
+
+Accounts created under the older 3-character floor must keep signing in, so
+the check lives on `RegisterRequest` alone. The client checks the same number
+before deriving anything; the two constants are held equal here.
+"""
+
+import re
+from pathlib import Path
+
+import pytest
+from meshbay_hub.api import users
+
+AUTH_PAGE = (Path(__file__).resolve().parents[1]
+ / "src" / "meshbay_hub" / "static" / "auth-page.js")
+AUTH_KEY = "k" * 44
+
+
+async def _register(client, username):
+ return await client.post("/v1/users/register", json={
+ "username": username, "email": "floor@example.com", "auth_key": AUTH_KEY})
+
+
+@pytest.mark.asyncio
+async def test_seven_characters_is_refused(client):
+ r = await _register(client, "sevenc7")
+ assert r.status_code == 422, r.text
+
+
+@pytest.mark.asyncio
+async def test_surrounding_spaces_do_not_count(client):
+ r = await _register(client, " sevenc7 ")
+ assert r.status_code == 422, r.text
+
+
+@pytest.mark.asyncio
+async def test_eight_characters_is_accepted(client):
+ r = await _register(client, "eightch8")
+ assert r.status_code == 201, r.text
+
+
+@pytest.mark.asyncio
+async def test_an_existing_short_account_still_signs_in(client, monkeypatch):
+ """An account made under the old floor is not locked out by the new one."""
+ monkeypatch.setattr(users, "USERNAME_MIN_LEN", 3)
+ assert (await _register(client, "bob")).status_code == 201
+ monkeypatch.setattr(users, "USERNAME_MIN_LEN", 8)
+
+ r = await client.post("/v1/users/login", json={"username": "bob", "auth_key": AUTH_KEY})
+ assert r.status_code == 200, r.text
+
+
+def test_the_client_checks_the_same_floor():
+ m = re.search(r"^const USERNAME_MIN_LEN = (\d+);", AUTH_PAGE.read_text(encoding="utf-8"),
+ re.M)
+ assert m, "auth-page.js no longer declares USERNAME_MIN_LEN"
+ assert int(m.group(1)) == users.USERNAME_MIN_LEN