SvnBd Open the console

Self-hosted Subversion server

Set it in the browser.
Enforce it on every client.

SvnBd manages repositories, accounts and path permissions from a web console, then compiles them into the authz and htpasswd files Apache reads on every request. One set of rules, honoured by the browser and by svn alike.

Console Permissions · docs
mahi can read & write in /trunk

Console writes data/conf/authz

[docs:/trunk]
mahi = rw
Someone's laptop svn 1.14
$ svn commit -m "fix the install steps"
Sending        trunk/README.md
Transmitting file data .done
Committed revision 42.
HEAD · r42

No second place to keep permissions in sync. The console is the only writer; Apache is the only enforcer.

How it works

A control plane and a data plane, kept apart on purpose

The console never speaks the Subversion wire protocol. It owns everything around the repositories — creating them, hashing credentials, compiling access rules — and leaves the serving to Apache and mod_dav_svn, exactly as VisualSVN does on Windows.

Administrator Browser
Control plane SvnBd console ASP.NET Core 8 · SQLite
compiles, on every change
Generated authz · htpasswd written 0640, never by hand
read on every request
Your team svn · TortoiseSVN
Data plane Apache + mod_dav_svn the only thing that serves commits
On disk data/repos/

Because both sides read the same generated files, a permission you set in the console is the permission a checkout gets. There is no sync step to forget, and nothing to reconcile after a change.

What it manages

Everything you would otherwise do over SSH

Each row is a real mechanism, not a wrapper around a config file you still have to edit. The right column is what actually runs.

In the consoleUnderneath
RepositoriesCreate, delete, standard trunk/branches/tagssvnadmin create
Repository browserTree, files, history, changesets, diffs — at any revisionsvn --xml, peg revisions
AccountsSVN users, self-service password portalhtpasswd -bnB (bcrypt)
GroupsGrant to a team instead of a person[groups] in authz
PermissionsPer repository, per path: read, read-write, noneauthz, default deny
HooksNine standard hooks, edited in the browserrepos/<name>/hooks/
BackupsHot copy a live repository, then verify itsvnadmin hotcopy · verify
ActivityWho did what, from where, and whether it workedappend-only audit log
Guarantees

The parts worth being strict about

Passwords are never stored

Console sign-ins use PBKDF2-SHA256 at 210,000 iterations. Subversion accounts are bcrypt-hashed straight into the htpasswd file. Neither is recoverable, including by the server.

No shell, ever

Every external tool is invoked with an argv array, so a repository named with a semicolon is just an invalid name — not a command. Names containing .. or a path separator are rejected before that.

Deny is the default

The generated authz file opens with [/] * =. Nobody reaches a repository until a rule says so, and a rule can only be added by someone signed in to the console.

The web view can't over-share

Browsing a repository replays your credentials against Apache first. If a checkout would be refused, so is the page — the browser is never a second, looser door.

Brute force runs out

Five failed sign-ins lock the account for fifteen minutes. Failures are logged with the address they came from, whether or not the username exists.

Nothing happens unwitnessed

Creating, deleting, resetting and signing in all land in an append-only audit log with the actor, the address and the result. The console cannot edit it.

Set up

Running in about five minutes

One Debian or Ubuntu host. Subversion and Apache from the distribution, the console published next to them.

# 1 — the Subversion side
sudo apt-get install subversion libapache2-mod-svn
sudo a2enmod dav dav_svn authz_svn

# 2 — the console
dotnet publish -c Release -o published
ASPNETCORE_URLS=http://0.0.0.0:3122 dotnet published/SvnBd.dll

# 3 — point Apache at the files the console generates
#     Settings → Download svnbd-apache.conf, then a2ensite

Sign in, add a repository, grant yourself access. Then anyone on the team checks out the same way they always have:

svn checkout https://svn.void.bd/svn/<repo>