mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-09 04:06:42 +00:00
On a multisite network WP-CLI's `user create` runs wpmu_validate_user_signup(), which only accepts lowercase letters and digits. The MCP subscriber was declared as `mcp-wordpress`, so every variant with `multisite.enabled: true` (variant 1) stopped at "Create the subscriber the MCP adapter authenticates as" with "Usernames can only contain lowercase letters (a-z) and numbers." (WordPress#1 in runs 40625679270 and 40243434327). meta/users.yml now declares `mcpwordpress`. The users dict is the one place the login lives: the role tasks, the MCP basic-auth login (mcp_client_login) and the MCP client configs (mcp_servers) all read users[owner].username, and the owner key, hence the token-store key, stays mcp-web-app-wordpress. The email follows the login. On an existing single-site install the next deploy creates mcpwordpress, mints its application password and replaces the stored token; the old mcp-wordpress subscriber is left in place with its now untracked "mcp" application password. Remove it with `wp user delete mcp-wordpress`. test_multisite_usernames mirrors the multisite signup checks (charset, reserved names, 4-60 characters, not all digits): every account the role declares passes, and mcp-wordpress, `_`, `.`, uppercase, too short, all digits, admin and too long are refused. With the old login the test fails with WordPress's own message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
"""Every account the WordPress role declares passes the multisite signup rule."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
import unittest
|
|
|
|
from utils.cache.users import get_user_defaults
|
|
from utils.cache.yaml import load_yaml
|
|
|
|
from . import PROJECT_ROOT
|
|
|
|
ROLE_USERS = PROJECT_ROOT / "roles/web-app-wordpress/meta/users.yml"
|
|
SIGNUP_CHARSET = re.compile(r"[a-z0-9]+")
|
|
DIGITS_ONLY = re.compile(r"[0-9]+")
|
|
ILLEGAL_NAMES = frozenset(
|
|
{"www", "web", "root", "admin", "main", "invite", "administrator", "files", "blog"}
|
|
)
|
|
|
|
|
|
def multisite_refusals(username: str) -> list[str]:
|
|
"""The errors ``wpmu_validate_user_signup`` raises for a username.
|
|
|
|
Args:
|
|
username: the login ``wp user create`` receives on a multisite network.
|
|
|
|
Returns:
|
|
One WordPress error message per failed check; empty when the name is accepted.
|
|
"""
|
|
refusals = []
|
|
if not SIGNUP_CHARSET.fullmatch(username):
|
|
refusals.append(
|
|
"Usernames can only contain lowercase letters (a-z) and numbers."
|
|
)
|
|
if username in ILLEGAL_NAMES:
|
|
refusals.append("Sorry, that username is not allowed.")
|
|
if len(username) < 4:
|
|
refusals.append("Username must be at least 4 characters.")
|
|
if len(username) > 60:
|
|
refusals.append("Username may not be longer than 60 characters.")
|
|
if DIGITS_ONLY.fullmatch(username):
|
|
refusals.append("Sorry, usernames must have letters too!")
|
|
return refusals
|
|
|
|
|
|
class TestMultisiteUsernames(unittest.TestCase):
|
|
def test_every_declared_account_passes_the_multisite_signup_rule(self):
|
|
users = get_user_defaults(roles_dir=str(PROJECT_ROOT / "roles"))
|
|
offenders = {
|
|
key: refusals
|
|
for key in load_yaml(str(ROLE_USERS))
|
|
if (refusals := multisite_refusals(str(users[key]["username"])))
|
|
}
|
|
self.assertEqual({}, offenders)
|
|
|
|
def test_the_rule_refuses_what_a_multisite_network_refuses(self):
|
|
for username in (
|
|
"mcp-wordpress",
|
|
"mcp_wordpress",
|
|
"mcp.wordpress",
|
|
"McpWordpress",
|
|
"mcp",
|
|
"1234",
|
|
"admin",
|
|
"a" * 61,
|
|
):
|
|
with self.subTest(username=username):
|
|
self.assertNotEqual([], multisite_refusals(username))
|
|
|
|
def test_the_rule_admits_what_a_multisite_network_admits(self):
|
|
for username in ("mcpwordpress", "platformadmin", "biber", "a" * 60):
|
|
with self.subTest(username=username):
|
|
self.assertEqual([], multisite_refusals(username))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|