diff --git a/roles/user-administrator/meta/users.yml b/roles/user-administrator/meta/users.yml index 5a280cd3cb..5c04da06f2 100644 --- a/roles/user-administrator/meta/users.yml +++ b/roles/user-administrator/meta/users.yml @@ -3,7 +3,7 @@ platform_administrator: description: Application administrator for {{ ORGANIZATION }} on {{ DOMAIN_PRIMARY }} firstname: Platform lastname: Administrator - username: platform-administrator + username: platformadministrator authorized_keys: [] accounts: [mailbox, identity] diff --git a/roles/web-app-keycloak/meta/users.yml b/roles/web-app-keycloak/meta/users.yml index d8aa494e97..abf2e8c78f 100644 --- a/roles/web-app-keycloak/meta/users.yml +++ b/roles/web-app-keycloak/meta/users.yml @@ -1,6 +1,6 @@ --- keycloak_bootstrap: - username: keycloak-bootstrap + username: keycloakbootstrap roles: - bot platform_administrator: {} diff --git a/tests/lint/ansible/roles/meta/test_identity_username_charset.py b/tests/lint/ansible/roles/meta/test_identity_username_charset.py new file mode 100644 index 0000000000..968acb2cd1 --- /dev/null +++ b/tests/lint/ansible/roles/meta/test_identity_username_charset.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +import re +import unittest + +from utils.cache.users import get_user_defaults + +from . import PROJECT_ROOT + +IDENTITY_USERNAME = re.compile(r"^[a-z0-9]+$") + + +class TestIdentityUsernameCharset(unittest.TestCase): + def test_every_identity_username_is_lowercase_alphanumeric(self): + """ + A user whose ``accounts`` contain ``identity`` MUST have a username of + lowercase letters and digits only. + + Two consumers reject anything else, and both reject it at deploy time + rather than at render time. Keycloak's own user profile pins the + pattern ``^(?!reserved)[a-z0-9]+$`` + (``roles/web-app-keycloak/templates/import/components/ + org.keycloak.userprofile.UserProfileProvider.json.j2``) and answers a + violation with "Username is reserved or contains invalid characters". + Mastodon's ``bin/tootctl accounts create`` answers with + ``Failure/Error: account.username invalid``. + + A hyphen is the way this breaks, because it is the natural separator + for a compound account name and every other hyphenated user in the + repository is exempt by having no ``identity`` account, so nothing + catches it until a realm import or a tootctl call runs. + """ + users = get_user_defaults(roles_dir=str(PROJECT_ROOT / "roles")) + offenders = sorted( + f"{key}: {entry['username']}" + for key, entry in users.items() + if "identity" in (entry.get("accounts") or []) + and not IDENTITY_USERNAME.match(str(entry.get("username", ""))) + ) + + if offenders: + self.fail( + "These users are registered as an identity but carry a " + "username Keycloak and Mastodon both refuse (lowercase " + "letters and digits only):\n - " + "\n - ".join(offenders) + ) + + +if __name__ == "__main__": + unittest.main()