ROLE
The ROLE command family manages roles and users at runtime. It requires
role-based access control to be enabled (--rbac-config) and the caller to
hold the ROLE permission (granted by the admin category) — otherwise the
server replies -NOPERM.
Mutations are atomic: each one clones the active policy, applies the change, and republishes the snapshot in a single swap. Readers never observe a half-applied policy.
Enable
Section titled “Enable”./bin/tellstone --rbac-config policy.yamlROLE CREATE
Section titled “ROLE CREATE”ROLE CREATE <name> <rule>...Defines a new role. Rules use the Redis-style tokens +cmd, -cmd, +@cat,
-@cat, and ~prefix (see Rule syntax).
Fails if the role already exists — updating a role is DELETE then CREATE.
Reply: +OK
> ROLE CREATE operator +get '~users:*'+OKROLE SETUSER
Section titled “ROLE SETUSER”ROLE SETUSER <username> <role> [>password] [nopass]Creates or updates a user, binding it to a role. At least one password option
is required: >password bcrypt-hashes the plaintext server-side,
nopass marks a passwordless user. When both are given, the last option wins.
Reply: +OK
> ROLE SETUSER bob operator '>bobpw'+OK> ROLE SETUSER carol readonly nopass+OKROLE DELUSER
Section titled “ROLE DELUSER”ROLE DELUSER <username>Removes a user.
Reply: +OK
ROLE DELETE
Section titled “ROLE DELETE”ROLE DELETE <role>Removes a role. Users referencing the deleted role fall back to the default role on their next policy lookup (fail-safe).
Reply: +OK, or -ERR when the role does not exist.
ROLE LIST
Section titled “ROLE LIST”ROLE LISTEnumerates every role with its name, granted commands, and namespace whitelist. Names and commands are sorted for deterministic output. Password hashes are never rendered.
Reply: an array with the role’s name, command array, and namespace array.
ROLE GETUSER
Section titled “ROLE GETUSER”ROLE GETUSER <username>Returns the username, its assigned role (or null when the default role
applies), and 1/0 for whether a password is set. The hash is never
exposed.
Reply:
> ROLE GETUSER bobbob / operator / 1Native binary protocol
Section titled “Native binary protocol”The client package exposes the same operations as typed Go calls:
| Call | Equivalent |
|---|---|
c.AuthUser(username, password, scratch) | AUTH <username> <password> |
c.RoleCreate(role, rules, scratch) | ROLE CREATE <name> <rule>... |
c.RoleSetUser(username, role, passOptions, scratch) | ROLE SETUSER <user> <role> [>pw] [nopass] — passOptions are []byte(">pw") / []byte("nopass") |
c.RoleDelUser(username, scratch) | ROLE DELUSER <user> |
c.RoleDelete(role, scratch) | ROLE DELETE <role> |
c.RoleList(scratch) | ROLE LIST — returns []RoleListEntry |
c.RoleGetUser(username, scratch) | ROLE GETUSER <user> — returns RoleUser{Role, HasPass} |
c, _ := client.Dial("127.0.0.1:9988", 2*time.Second)defer c.Close()
scratch := make([]byte, 4096)if err := c.AuthUser("admin", "adminsecret", scratch); err != nil { log.Fatal(err)}if err := c.RoleCreate("user-reader", []string{"+get", "~users:*"}, scratch); err != nil { log.Fatal(err)}if err := c.RoleSetUser("alice", "user-reader", [][]byte{[]byte(">alicepw")}, scratch); err != nil { log.Fatal(err)}The binary protocol carries its own wire encoding for each subcommand, separate from the RESP2 reply format.
Example
Section titled “Example”A full walkthrough ships in the main repository at cmd/example/role: it
authenticates as an admin, creates a role and a user, lists the roles, then
connects as the new user to prove the role’s limits — GET on a matching key
passes, SET and keys outside the whitelist are denied as NOT_AUTHORIZED.