Developer account
A Wikimedia developer account is an account used for authentication and authorization in Wikimedia's technical spaces such as source code management systems, bug trackers, compute environments, and operational support tooling. Developer accounts are distinct from Wikimedia SUL accounts which are used for authentication and authorization in Wikimedia project wikis, but in the modern era are often linked to a SUL account that is operated by the same human being or for related automation purposes.
Developer account information is stored in an LDAP directory maintained in the Wikimedia production network. More details on the LDAP service itself can be found in SRE/LDAP. The LDAP directory is used in Cloud VPS and Toolforge to provide Unix account information and ssh public keys to virtual machines. This is the same LDAP directory that backs the IDM (Bitu) and CAS-SSO (IDP) services.
Within the LDAP directory, developer accounts are objectClass=posixAccount entities stored in the ou=people,dc=wikimedia,dc=org subtree.
Cloud VPS project membership is recorded with groups named cn=project-$CLOUD_VPS_NAME,ou=groups,dc=wikimedia,dc=org where $CLOUD_VPS_NAME is the user-friendly OpenStack project name, not the project ID which was previously the same as the name but is now an UUID for new projects.
Toolforge tool maintainership is recorded with groups named tools.$TOOLNAME,ou=servicegroups,dc=wikimedia,dc=org where $TOOLNAME is the tool's public name (for example "versions" or "trainbow").
Working with LDAP cli
For simplification of the documentation, cli examples of working with the LDAP directory on this page will generally use the shell aliases that User:BryanDavis has developed and documented at User:BryanDavis/LDAP.
$ alias ldap='ldapsearch -xLLL -P 3 -E pr=5000/noprompt -o ldif-wrap=no -b"dc=wikimedia,dc=org"'
$ alias un64='awk '\''BEGIN{FS=":: ";c="base64 -d"}{if(/\w+:: /) {print $2 |& c; close(c,"to"); c |& getline $2; close(c); printf("%s:: \"%s\"\n", $1, $2); next} print $0 }'\'''
Blocked Developer accounts
Developer accounts can be blocked similar to a full MediaWiki account block. Blocks cascade to disable the account's access rights in Toolforge, Cloud VPS, Gerrit, GitLab, and Phabricator. Blocks are non-destructive and fully reversible.
Blocks are typically applied and removed using https://idm.wikimedia.org/wikimedia/block/ which is available to members of the Bitu account managers group. Other tooling may be used in specific workflows such as WMF staff offboarding.
Blocked developer accounts can be detected in the LDAP directory by looking for the presence of pwdPolicySubentry=cn=disabled,ou=ppolicies,dc=wikimedia,dc=org. More typically you may want to exclude all blocked accounts from a lookup by using the negated form (!(pwdPolicySubentry=cn=disabled,ou=ppolicies,dc=wikimedia,dc=org)).
If you wanted the count of all unblocked Developer accounts:
$ ldap '(&(objectClass=posixAccount)(!(pwdPolicySubentry=cn=disabled,ou=ppolicies,dc=wikimedia,dc=org)))' dn -b ou=people,dc=wikimedia,dc=org | grep dn: | wc -l
36723 # as of 2026-08-20
Developer account details
If you wanted to get the shell account name, legacy Wikitech username, account creation date, SUL account information, and email address of every Toolforge maintainer you could do something like this using my LDAP shell aliases:
$ ldap '(&(objectClass=posixAccount)(memberOf=cn=project-tools,ou=groups,dc=wikimedia,dc=org))' uid cn createTimestamp wikimediaGlobalAccountId wikimediaGlobalAccountName mail | un64
(...snip...)
dn: uid=bd808,ou=people,dc=wikimedia,dc=org
uid: bd808
cn: BryanDavis
createTimestamp: 20130729163514Z
wikimediaGlobalAccountId: 12874
wikimediaGlobalAccountName: BryanDavis
mail: bdavis@wikimedia.org
(...snip...)
The un64 helper can be needed to decode non-ASCII cn values which are stored by LDAP as base-64 encoded strings.
The example above shows some of the core data for BryanDavis's Developer account:
dn: uid=bd808,ou=people,dc=wikimedia,dc=org-- the "dn" is the primary key for an LDAP record.uid: bd808-- "uid" in our environment is the account's shell name.cn: BryanDavis-- "cn" in our environment is the account's "common name" which was also historically the user's Wikitech account name prior to October 2024.createTimestamp: 20130729163514Z-- this Developer account was created 2013-07-29 16:35:51 UTC.wikimediaGlobalAccountId: 12874-- OAuth verified associated SUL account id.wikimediaGlobalAccountName: BryanDavis-- OAuth verified associated SUL account username. Note that the username may have changed via a global account rename since being stored in LDAP. The SUL account id is invariant and can be used to find the current account name in the centralauth.globaluser database table.mail: bdavis@wikimedia.org-- The Developer account's email address.
Command line tools can be nice for making quick lookups. The output format can be challenging to work with if you really want to create a CSV or TSV data file or to drive other automation. In that case some folks tend to write small Python scripts that use the ldap3 library to access the LDAP directory. Here is an example:
import ldap3
import yaml
cfg = yaml.safe_load(open("/etc/ldap.yaml")) # Toolforge bastions and Kubernetes containers have this file at runtime
conn = ldap3.Connection(cfg["servers"], auto_bind=True, read_only=True)
base = "ou=people,{basedn}".format(basedn=cfg["basedn"])
selector = "(&{})".format(
"".join(
[
"(objectClass=posixAccount)",
"(memberOf=cn=project-tools,ou=groups,dc=wikimedia,dc=org)",
]
)
)
r = conn.extend.standard.paged_search(
base,
selector,
attributes=[
"uid",
"cn",
"createTimestamp",
"wikimediaGlobalAccountId",
"wikimediaGlobalAccountName",
"mail",
],
paged_size=256,
time_limit=5,
generator=True,
)
for user in r:
# Do interesting stuff with the Developer account here
print(user)
To run this script on Toolforge one would typically use some tool account they have access to (like https://toolsadmin.wikimedia.org/tools/id/bd808-test) and run things from inside a webservice python3.13 shell session:
$ ssh login.toolforge.org
$ become $MY_TOOL_NAME
$ webservice python3.13 shell
tools.MY_TOOL_NAME@shell-1234567890:~$ python3 -m venv venv
tools.MY_TOOL_NAME@shell-1234567890:~$ ./venv/bin/pip3 install ldap3 pyyaml
tools.MY_TOOL_NAME@shell-1234567890:~$ vim example.py
# Paste in the script
# :wq
tools.MY_TOOL_NAME@shell-1234567890:~$ ./venv/bin/python3 example.py