Fossil includes a powerful role-based access control system which affects which users have which capabilities within a given served Fossil repository. We call this the capability system, or “caps” for short.
Fossil stores a user’s capabilities as an unordered string of ASCII characters, one capability per, limited to alphanumerics. Caps are case-sensitive: “A” and “a” are different capabilities. We explain how we came to assign each character below.
User Categories
Before we explain individual user capabilities and their proper administration, we want to talk about an oft-overlooked and misunderstood feature of Fossil: user categories.
Fossil defines four user categories. Two of these apply based on the user’s login status: nobody and anonymous. The other two act like Unix or LDAP user groups: reader and developer. Because we use the word “group” for another purpose in Fossil, we will avoid using it that way again in this document. The correct term in Fossil is “category.”
Fossil’s user category set is currently fixed. There is no way to define custom categories.
These categories form a strict hierarchy. Mathematically speaking:
developer ≥ reader ≥ anonymous ≥ nobody
When a user visits a served Fossil repository via its web UI, they initially get the capabilities of the “nobody” user category. This category would be better named “everybody” because it applies whether you’re logged in or not.
When a user logs in as “anonymous” via /login
they
get all of the “nobody” category’s caps plus those assigned to the
“anonymous” user category. It would be better named “user” because it
affects all logged-in users, not just those logged in via Fossil’s
anonymous user feature.
When a user with capability letter u signs in, they get their own user’s explicit capabilities plus those assigned to the “reader” category. They also get those assigned to the “anonymous” and “nobody” categories.
That then extends to those in the “developer” category, being those with capability letter v: they get their own explicit caps, plus the “developer” caps, plus the “reader” caps, plus the “anonymous” caps, plus the “nobody” caps. Thus the hierarchy mathematically defined above.
Fossil shows how these capabilities apply hierarchically in the user
editing screen (Admin → Users → name) with the [N]
[A]
[D]
[R]
tags next to each capability check box. If a user gets a capability from
one of the user categories already assigned to it, there is no value in
redundantly assigning that same cap to the user explicitly. For example,
with the default dei cap set for the “developer” category, the cap
set ve is redundant because v grants dei, which includes
e.
We suggest that you lean heavily on these fixed user categories when setting up new users. Ideally, your users will group neatly into one of the predefined categories, but if not, you might be able to shoehorn them into our fixed scheme. For example, the administrator of a repo that’s mainly used as a wiki or forum for non-developers could treat the “developer” user category as if it were called “contributor” or “author.”
Individual User Capabilities
When one or more users need to be different from the basic capabilities defined in user categories, you can assign caps to individual users. For the most part, you want to simply read the reference material below when doing such work.
However, it is useful at this time to expand on the mathematical expression above, which covered only the four user categories. If we bring the individual user capabilities into it, the full hierarchy of user power in Fossil is:
setup ≥ admin ≥ moderator ≥ developer ≥ reader ≥ subscriber ≥ anonymous ≥ nobody
New Repository Defaults
When you create a new repository, Fossil creates only one user account named after your OS user name by default.
Fossil gives the initial repository user the all-powerful Setup capability.
Users who visit a served repository without logging in get the “nobody” user category’s caps which default to gjorz: clone the repo, read the wiki, check-out files via the web UI, view tickets, and pull version archives. The defaults are suited to random passers-by on a typical FOSS project’s public web site and its code repository.
Users who prove they are not a bot by logging in — even if only as “anonymous” — get the “nobody” capability set plus hmnc: see internal hyperlinks, append to existing wiki articles, file new tickets, and comment on existing tickets. We chose these additional capabilities as those we don’t want bots to have, but which a typical small FOSS project would be happy to give anonymous humans visiting the project site.
The “reader” user category is typically assigned to users who want to be identified within the repository but who primarily have a passive role in the project. The default capability set on a Fossil repo adds kptw caps to those granted by “nobody” and “anonymous”. This category is not well-named, because the default caps are all about modifying repository content: edit existing wiki pages, change one’s own password, create new ticket report formats, and modify existing tickets. This category would be better named “contributor,” or “participant.”
Those in the “developer” category get all of the above plus the dei caps: delete wiki articles and tickets, view sensitive user material, and check in changes.
The default setup does not explicitly define anything between “developer” and “setup,” but there is the intermediary Admin capability, a.
Consequences of Taking a Repository Private
When you click Admin → Security-Audit → “Take it private,” one of the things it does is set the user capabilities for the “nobody” and “anonymous” user categories to blank, so that users who haven’t logged in can’t even see your project’s home page, and the option to log in as “anonymous” isn’t even offered. Until you log in with a user name, all you see is the repository’s skin and those few UI elements that work without any user capability checks at all, such as the “Login” link.
Beware: Fossil does not reassign the capabilities these users had to other users or to the “reader” or “developer” user category! All users except those with Setup capability will lose all capabilities they inherited from “nobody” and “anonymous” categories. Setup is the lone exception.
If you will have non-Setup users in your private repo, you should parcel out some subset of the capability set the “nobody” and “anonymous” categories had to other categories or to individual users first.
Default User Name
By default, Fossil assumes your OS user account name is the same as the
one you use in any Fossil repository. It is the default for a new
repository, though you can override this with the --admin-user
option. Fossil has other ways of overriding this in other contexts
such as the name@
syntax in clone URLs.
It’s simplest to stick with the default; a mismatch can cause problems. For example, if you clone someone else’s repo anonymously, turn off autosync, and make check-ins to that repository, they will be assigned to your OS user name by default. If you later get a login on the remote repository under a different name and sync your repo with it, your earlier “private” check-ins will get synced to the remote under your OS user name!
This is unavoidable because those check-ins are already written durably to the local Fossil block chain. Changing a check-in’s user name during sync would require rewriting parts of that block chain, which then means it isn’t actually a “sync” protocol. Either the local and remote clones would be different or the check-in IDs would change as the artifacts get rewritten. That in turn means all references to the old IDs in check-in comments, wiki articles, forum posts, tickets, and more would break.
When such problems occur, you can amend the check-in to hide the incorrect name from Fossil reports, but the original values remain in the repository forever.
This does mean that anyone with check-in rights on your repository can impersonate any Fossil user in those check-ins. They check in their work under any name they like locally, then upon sync, those names are transferred as-is to the remote repository. Be careful who you give check-in rights to!
Login Groups
The Admin → Login-Groups UI feature and its corresponding login-group
command solve a common problem with Fossil: you’ve created multiple
repositories that some set of users all need access to, those users all
have the same access level on all of these shared repositories, and you
don’t want to redundantly configure the user set for each repository.
This feature ties changes to the “user
” table in one repo to that in
one or more other repos. With this configured, you get a new choice on
the user edit screen, offering to make changes specific to the one
repository only or to apply it to all others in the login group as well.
A user can log into one repo in a login group only if that user has an entry in that repo’s user table. That is, setting up a login group doesn’t automatically transfer all user accounts from the joined repo to the joining repo. Only when a user exists by name in both repos will that user be able to share credentials across the repos.
Login groups can have names, allowing one “master” repo to host multiple subsets of its users to other repos.
Trust in login groups is transitive within a single server. If repo C joined repo B and repo B joined A, changes in C’s user table affect both A and B, if you tell Fossil that the change applies to all repos in the login group.
Cloning the User Table
When cloning over HTTP, the initial user table in the local clone is set to its “new state:” only one user with Setup capability, named after either your OS user account or after the user given in the clone URL.
There is one exception: if you clone as a named Setup user, you get a complete copy of the user information. This restriction keeps the user table private except for the only user allowed to make absolutely complete clones of a remote repo, such as for failover or backup purposes. Every other user’s clone is missing this and a few other items, either for information security or PII privacy reasons.
When cloning with file system paths, file://
URLs, or over SSH, you
get a complete clone, including the parent repo’s complete user table.
All of the above applies to login groups as well.
Caps Affect Web Interfaces Only
User caps only affect Fossil’s UI pages and clones done over
http[s]://
URLs. If you use any other URL type, Fossil will not check
user caps.
This is sensible when working only on a local repository: only local
file permissions matter when operating on a local SQLite DB file. The
same sense extends to clones done via a file system path
(/path/to/repo.fossil
) or through a file://
URL. The only difference
is that there are two sets of file system permission checks: once to
modify the working check-out’s repo clone DB file, then again on
sync with the parent DB file.
However, Fossil also ignores caps when working on a repo cloned over SSH! When you make a change to such a repository, the change first goes to the local clone, where file system permissions are all that matter, but then upon sync, the situation is effectively the same as when the parent repo is on the local file system. If you can log into the remote system over SSH and that user has the necessary file system permissions on that remote repo DB file, your user is effectively the all-powerful Setup user on both sides of the SSH connection.
Fossil reuses the HTTP-based sync protocol in both cases above, tunnelling HTTP through an OS pipe or through SSH (FIXME?), but all of the user cap checks in Fossil are on the web UI route handlers only.
TODO: Why then can I not /xfer
my local repo contents to a remote repo
without logging in?
The All-Powerful Setup User
A user with Setup capability, s needs no other user capabliities, because its scope of its power is hard-coded in the Fossil C source. You can take all capabilities away from all of the user categories so that the Setup user inherits no capabilities from them, yet the Setup user will still be able to use every feature of the Fossil web user interface.
Another way to look at it is that the setup user is a superset of all other capabilities, even Admin capability, a. This is literally how it’s implemented in the code: enabling setup capability on a user turns on all of the flags controlled by all of the other capability characters.
When you run fossil ui
, you are effectively given setup
capability on that repo through that UI instance, regardless of the
capability set defined in the repo’s user table. This is why ui
always
binds to localhost
without needing the --localhost
flag: in this
mode, anyone who can connect to that repo’s web UI has full power over
that repo.
See the Admin vs Setup article for a deeper treatment on the differences between these two related capability sets.
Capability Reference
This section documents each currently-defined user capability character in more detail than the brief summary on the user capability “key” page.
a — Admin users have all of the capabilities below except for setup: they can create new users, change user capability assignments, and use about half of the functions on the Admin screen in Fossil UI. (And that is why that screen is now called “Admin,” not “Setup,” as it was in old versions of Fossil!)
There are a couple of ways to view the role of Fossil administrators:
- Administrators occupy a place between “developer” category users and the setup user; a super-developer capability, if you will. Administrators have full control over the repository’s managed content: versioned artifacts in the block chain, unversioned content, forum posts, wiki articles, tickets, etc.
- Administrators are subordinate to the repository’s superuser, being the one with setup capability. Granting users admin capability is useful in repositories with enough users generating enough activity that the all-powerful setup user could use helpers to take care of routine administrivia, user management, content management, site cosmetics, etc. without giving over complete control of the repository.
For a much deeper dive into this topic, see the Admin vs. Setup article.
Mnemonic: administrate.
b — Add attachments to wiki articles or tickets. Mnemonics: bind, button, bond, or bolt.
e — View personal identifying information (PII) about other users such as email addresses. Mnemonics: show email addresses; or Europe, home of GDPR.
f — Create new wiki articles. Mnemonic: fast, English translation of the Hawaiian word wiki.
g — Clone the repository. Note that this is distinct from check-out capability, o. Mnemonic: get.
h — Get hyperlinks in generated HTML which link you to other parts of the repository. This capability exists and is disabled by default for the “nobody” category to prevent bots from wandering around aimlessly in the site’s hyperlink web, chewing up server resources to little good purpose. Mnemonic: hyperlink.
i — Check changes into the repository. Note that a lack of this capability does not prevent you from checking changes into your local clone, only from syncing those changes up to the parent repo, and then only over HTTP. Mnemonic: check in changes.
j — View wiki articles. Mnemonic: injest page content. (All right, you critics, you do better, then.)
l — Moderate wiki article appends. Appends do not get saved permamently to the receiving repo’s block chain until some user (one with this cap or Setup cap) approves it. Mnemonic: allow.
m — Append content to existing wiki articles. Mmnemonics: amend or modify.
o — Check data out from Fossil. This capability has nothing to do with the ability to “open” a local repo clone or switch branches in that clone. It only controls whether similar operations over HTTP to a remote repo are allowed. You must have this capability to view embedded documentation, for example, since that basically amounts to opening a file in the remote repo. This capability also controls the
/artifact
,/file
, and/raw
URLs. Mnemonic: check out file.q — Moderate tickets: comments appended to tickets can be deleted by users with this capability. Mnemonic: quash noise commentary.
s — The all-powerful Setup user. Mnemonics: setup or superuser.
t — Create new ticket report formats. Note that although this allows the user to provide SQL code to be run in the server’s context, and this capability is given to the untrusted “anonymous” user category by default, this is a safe capability to give to users because it is internally restricted to read-only queries on the tickets table only. (This restriction is done with a SQLite authorization hook, not by any method so weak as SQL text filtering.) Mnemonic: new ticket report.
u — Inherit all capabilities of the “reader” user category. Mnemonic: user, per naming suggestion above.
v — Inheheit all capabilities of the “developer” user category. Mnemonic: developer.
x — Push or pull private branches. Mnemonic: exclusivity; “x” connotes unknown material in many Western languages due to its traditional use in mathematics
y — Push unversioned content. Mnemonic: yield, sense 4: “hand over.”
z — Pull archives of particular repository versions via
/zip
,/tarball
, and/sqlar
URLs. This is an expensive capability to assign, because creating such archives can put a large load on a Fossil server, which you may then need to manage. Mnemonic: zip file download.2 — Read forum posts by other users. Mnemonic: from thee 2 me.
3 — Create new forum threads, reply to threads created by others, and edit one’s own posts. New posts are held for moderation, and they are marked to prevent them from being included in clone and sync operations. Mnemonic: post for 3 audiences: me, the mods, and the Man.
4 — Same as 3 except that forum updates bypass the moderation and private artifact restrictions. Mnemonic: post 4 immediate release.
5 — Moderate forum posts. Note that this capabilitty does not automatically grant 4, so it is possible to have a user that can create a new post via capability 3 and then approve that post immediately themselves with this capability! Mnemonic: “May I have 5 seconds of your time, honored Gatekeeper?”
6 — Users with this capability see a checkbox on un-moderated forum posts labeled “Trust user X so that future posts by user X do not require moderation.” Checking that box and then clicking the moderator-only “Approve” button on that post grants capability 4 to that post’s author. There is currently no UI for a user with capability 6 to remove trust from a user once it is granted. Mnemonic: “I’m six of hitting Approve on your posts!”
7 — Sign up for email alerts. Mnemonic: Seven can wait, I’ve got email to read now.
A — Send email announcements to users signed up to receive them. Mnemonic: announce.
Implementation Details
We assigned user capability characters using only lowercase ASCII letters at first, so those are the most important within Fossil: they control the functions most core to Fossil’s operation. Once we used up most of the lowercase letters, we started using uppercase, and then during the development of the forum feature we assigned most of the decimal numerals. Eventually, we might have to start using punctuation. We expect to run out of reasons to define new caps before we’re forced to switch to Unicode, though the possibilities for mnemonic assignments with emoji are intriguing.
The existing caps are usually mnemonic, especially among the earliest and therefore most central assignments, made when we still had lots of letters to choose from. There is still hope for good future mnemonic assignments among the uppercase letters, which are mostly still unused.
When Fossil is deciding whether a user has a given capability, it simply
searches the cap string for a given character. This is slower than
checking bits in a bitfield, but it’s fast enough in the context where
it runs: at the front end of an HTTP request handler, where the
nanosecond differences in such implementation details are completely
swamped by the millisecond scale ping time of that repo’s network
connection, followed by the requires I/O to satisfy the request. A
strchr()
call is
plenty fast in that context.