vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Name branches after the account, and labels after the display
474a812d199a109ba894124cd6f26be12c73285d · Keenan Nemetz · 15d ago · parent ade6107e
Name branches after the account, and labels after the display
A contributor's folder was `refs/heads/contrib/<account-id>/`, which told a
reader nothing without decoding a ULID. It is now the account name,
refs/heads/contrib/<name>/<branch>
and the name is therefore fixed at creation: renaming an account would strand
every ref under its old folder, so `vole admin user rename` is gone and the
users row itself — kept after retirement — is what stops a name being reissued.
What people see is now a separate, mutable display name, validated by the same
rules wherever it is set (CLI, remote admin, registration, `/account`) and shown
on pages, approvals, listings and refusals. Nothing is authorized by it and
nothing on disk is keyed by it: metadata authors stay account names because the
push boundary resolves them for ownership, and approvals stay account ids.
`user_names`, `Snapshot.Reserved` and `Account.Former` are dropped: with a fixed
name there are no former names to remember, and the UNIQUE column already does
the reserving. Opening an older roster adds the `display` column and drops the
alias table in place; contributor refs written under the old id namespace are
left where they are, readable, and landable by a maintainer.
docs/architecture.md +6−3
| @@ -16,7 +16,10 @@ Vole uses one rule everywhere: | |||
| 16 | 16 | > A credential proves which account you are. Vole checks every change before | |
| 17 | 17 | > accepting it, and records the decision in `data/audit.log`. | |
| 18 | 18 | ||
| 19 | There are two credentials, and they resolve to the same stable account id: | ||
| 19 | There are two credentials, and they resolve to the same account: a **name** fixed | ||
| 20 | at creation, which contributor branches and metadata authors are written with, and | ||
| 21 | an internal **id**, which access rules and approval files are keyed by. A | ||
| 22 | **display name** is a third, purely presentational label that anyone may change. | ||
| 20 | 23 | ||
| 21 | 24 | - an **SSH key** for Git over SSH, administration, and CI; | |
| 22 | 25 | - a **passkey** for browser sessions. | |
| @@ -28,7 +31,7 @@ token whose hash alone is in `users.db`. | |||
| 28 | 31 | Browser writes are deliberately narrow: file or comment on an issue, open a | |
| 29 | 32 | change request from a branch the account may push, and approve a change request. | |
| 30 | 33 | An untrusted contributor's Git writes are confined to | |
| 31 | `refs/heads/contrib/<account-id>/`; the pre-receive gate enforces the namespace, | ||
| 34 | `refs/heads/contrib/<name>/`; the pre-receive gate enforces the namespace, | ||
| 32 | 35 | and CI for that branch does not run until a maintainer allows the exact tip. They are built by the same metadata writers the CLI uses, so | |
| 33 | 36 | the file format and its validation do not fork. Everything else still changes by | |
| 34 | 37 | pushing over SSH. Approvals, comments, and CI results belong to the account the | |
| @@ -86,7 +89,7 @@ is checked when it is pushed. | |||
| 86 | 89 | | Choice | Reason | | |
| 87 | 90 | |---|---| | |
| 88 | 91 | | Use the Git command-line tool | Full push behavior and hooks without reimplementing Git | | |
| 89 | | SSH for Git writes, passkeys for the browser | Each transport gets the credential it can actually use, and both resolve to one account id | | ||
| 92 | | SSH for Git writes, passkeys for the browser | Each transport gets the credential it can actually use, and both resolve to one account | | ||
| 90 | 93 | | Check everything before accepting a change | The push boundary and the narrow web writers share the same metadata validation | | |
| 91 | 94 | | Store metadata in Git, rules in SQLite | Project content travels with clones; local settings stay local | | |
| 92 | 95 | | Passkeys, not passwords | No shared secret to phish, reset, or store; recovery is an administrator-issued enrollment link | | |