This is a complex topic, so some sub-topics have their own documents:
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 user categories give you a way to define capability sets for four hard-coded situations within the Fossil C source code. Logically 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
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 either the “reader” (u) or “developer” (v) capability letter logs in, they get their individual user caps plus those assigned to this special user category. They also get those assigned to the “anonymous” and “nobody” categories.
Because “developer” users do not automatically inherit “reader” caps, it is standard practice to give both letters to your “developer” users: uv. You could instead just assign cap u to the “developer” category.
Fossil shows how these capabilities apply hierarchically in the user
editing screen (Admin → Users → name) with the
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 ei cap set for the “developer” category, the cap
set ve is redundant because v grants ei, which includes
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 wiki-only Fossil repo for non-developers could treat the “developer” user category as if it were called “author,” and a forum-only repo could treat the same category as if it were called “member.”
There is currently no way to define custom user categories.
When one or more users need to be different from the basic capabilities defined in user categories, you can assign caps to individual users. You may want to have the cap reference open when doing such work.
It is useful at this time to expand on the logical expression above, which covered only the four fixed user categories. When we bring the individual user capabilities into it, the complete expression of the way Fossil implements user power becomes:
setup ≥ admin ≥ moderator ≥ (developer ∨ reader) ≥ [subscriber] ≥ anonymous ≥ nobody
The moderator insertion could go anywhere from where it’s shown now down to above the “anonymous” level, depending on what other caps you give to your moderators. Also, there is not just one type of moderator: Fossil has wiki, ticket, and forum moderators, each independent of the others. Usually your moderators are fairly high-status users, with developer capabilities or higher, but Fossil does allow the creation of low-status moderators.
The placement of “subscriber” in that hierarchy is for the sort of subscriber who has registered an account on the repository purely to receive email alerts and announcements. Users with additional caps can also be subscribers, but not all users are in fact subscribers, which is why we show it in square brackets. (See Users vs Subscribers.)
Fossil creates one user account in new repos, which is 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. This default is 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 “participant”.
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.
The Read capability has nothing to do with reading data from a local repository, because caps affect Fossil’s web interfaces only. Once you’ve cloned a remote repository to your local machine, you can do any reading you want on that repository irrespective of whether your local user within that repo has Read capability. The repo clone is completely under your user’s power at that point, affected only by OS file permissions and such. If you need to prevent that, you want to deny Clone capability instead.
Withholding the Read capability has a different effect: it
prevents a web client from viewing embedded documentation,
using the file browser,
exploring the history of check-ins,
and pulling file content via the
It is common to withhold Read capability from low-status visitors
on private or semi-private repos to prevent them from pulling individual
elements of the repo over the web one at a time, as someone may do when
denied the bulk Clone capability.
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
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!
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. It is difficult enough to fix such problems automatically during sync that we are unlikely to ever do so.
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, per the default above, 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.
Fossil’s user capability system only affects accesses over
URLs. This includes clone, sync/push/pull, the UI pages, and the
JSON API. For everything else, the user caps aren’t consulted at
The only checks made when working directly with a local repository are the operating system’s file system permissions. This should strike you as sensible, since if you have read access to the repository file, you can do anything you want to that repo DB including giving your user’s record the Setup capability, after which Fossil’s user capability system is effectively bypassed. (Or, create another Setup user, with the same end effect.) If you’re objecting that you need write access to the DB file to achieve this, realize that you can copy a read-only file to another location, giving yourself write access to it.
This is why the
fossil ui command
gives you Setup permissions within Fossil UI: it can’t usefully prevent
you from doing anything through the UI since only the local file system
permissions actually matter, and you can’t start
fossil ui without
having at least read access to that file.
What may be more surprising to you is that this is also true when working on a clone done over a local file path, except that there are then 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. The Fossil capability checks are effectively defeated because your user has Setup capability on both sides of the sync. Be aware that those file checks do still matter, however: Fossil requires write access to a repo DB while cloning from it, so you can’t clone from a read-only repo DB file over a local file path.
Even more surprising to you may be the fact that user caps do not affect cloning and syncing over SSH! (Not unless you go out of your way patch around it, at any rate.) When you make a change to such a repository, the stock Fossil behavior is that the change first goes to the local repo 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. The reason behind this is that 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 to allow clone and sync operations, then we’re back in the same situation as with local files: there’s no point trying to enforce the Fossil user capabilities when you can just modify the remote DB directly, so the operation proceeds unimpeded by any user capability settings on the remote repo.
Where this gets confusing is that all Fossil syncs are done over the
HTTP protocol, including those done over
not just those done over
ssh://URLs, Fossil pipes the HTTP conversation through a local SSH client to a remote instance of Fossil running the
test-httpcommand to receive the tunneled HTTP connection. This interface is intentionally permissionless.
file://URLs — as opposed to plain local file paths — the “sending” Fossil instance writes its side of the HTTP conversation out to a temporary file in the same directory as the local repo clone and then calls itself on the “receiving” repository to read that same HTTP transcript file back in to apply those changes to that repository. Presumably Fossil does this instead of using a pipe to ease portability to Windows.
Despite use of HTTP for these URL types, the fact remains that
checks for capabilities like Read and Write within the
HTTP conversation between two Fossil instances only have a useful effect
when done over an
In Admin → Access, there is an option for giving a list of globs to name URLs which get treated as if the visitor had the default cap set. For example, you could take the Read capability away from the “nobody” user category, who has it by default, to prevent users without logins from pulling down your repository contents one artifact at a time, yet give those users the ability to read the project documentation by setting the glob to match your embedded documentation’s URL root.
In Admin → Access, you can define a default user capability set, which is used as:
- the default caps for users newly created by an Admin or Setup user
- the default caps for self-registered users, an option in that same UI
- the effective caps for URIs considered public pages
This defaults to Reader.