Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Add browser auth, contributor access, and gated CI

6c84d387e5f608360e30484a1a5b1cff41076850 · Keenan Nemetz · 16d ago · parent c36d5073

Add browser auth, contributor access, and gated CI

Browser sign-in now uses passkeys. Enrollment links are one-time, sessions are hashed in users.db, and issue/comment/approval writes use the session account. HTTPS public_url is required for WebAuthn.

Add the contributor role between read and maintain. Contributors can discuss and open change requests, and may push only refs/heads/contrib/<account-id>/. Contributor CI is held per commit until a maintainer allows the exact tip from the repository page.

Rename the write role to maintain. write remains accepted as the historical spelling, and access.Write remains as a Go alias so existing callers and ACL rows keep working.

Update the web, CLI, queue schema, and guides for the new flows, and cover the role, namespace, auth, and CI-gating paths in tests.

docs/architecture.md +29−15

@@ -9,21 +9,35 @@ hardware you control, and keeps the important parts in Git.
9 9 Vole is built for one team on one server. It does not try to be a hosted service,
10 10 and it does not connect to other Vole instances. That keeps the design small.
11 11
12 ## Trust: your key is your identity
12 ## Trust: a credential resolves to an account
13 13
14 14 Vole uses one rule everywhere:
15 15
16 > Your SSH key proves who you are. Vole checks every change before accepting it,
17 > and records the decision in `data/audit.log`.
16 > A credential proves which account you are. Vole checks every change before
17 > accepting it, and records the decision in `data/audit.log`.
18 18
19 There is no second login system for writes. The web interface is read-only.
20 Approvals, comments, and CI results all belong to the account whose key pushed
21 them.
19 There are two credentials, and they resolve to the same stable account id:
20
21 - an **SSH key** for Git over SSH, administration, and CI;
22 - a **passkey** for browser sessions.
23
24 There is no password database. The browser performs a WebAuthn ceremony, Vole
25 stores only the credential's public half, and the resulting session is an opaque
26 token whose hash alone is in `users.db`.
27
28 Browser writes are deliberately narrow: file or comment on an issue, open a
29 change request from a branch the account may push, and approve a change request.
30 An untrusted contributor's Git writes are confined to
31 `refs/heads/contrib/<account-id>/`; the pre-receive gate enforces the namespace,
32 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 the file format and its validation do not fork. Everything else still changes by
34 pushing over SSH. Approvals, comments, and CI results belong to the account the
35 credential resolved to, never to a name typed into a form.
22 36
23 37 Vole does not require or check Git commit signatures. A signature would only
24 repeat what the SSH connection already established, and it cannot reliably prove
25 who authored a commit. Vole would rather keep one clear path than add a second
26 one that can disagree with the first.
38 repeat what the credential already established, and it cannot reliably prove who
39 authored a commit. Vole would rather keep one clear path than add a second one
40 that can disagree with the first.
27 41
28 42 ## What that means
29 43
@@ -41,9 +55,9 @@ auditable.
41 55 |---|---|---|
42 56 | Repositories | `data/repos/<name>.git` | It is the source |
43 57 | Issues, requests, approvals, release pointers, CI records | The `vole` branch in each repository | It is the source |
44 | Accounts, SSH keys, instance admins, access rules, locks | `data/users.db` | No; back it up |
58 | Accounts, SSH keys, passkeys, invites, sessions, instance admins, access rules, locks | `data/users.db` | No; back it up |
45 59 | Web/search index | `data/index.db` | Yes, with `vole admin index rebuild` |
46 | CI queue and run index | `data/runs.db` | Partly; in-progress work is lost |
60 | CI queue, run index, contributor CI approvals | `data/runs.db` | Partly; in-progress work and approvals are lost |
47 61 | LFS files, CI logs, build artifacts | `data/lfs/` | No; stored by content |
48 62 | Privileged-action history | `data/audit.log` | It is the record |
49 63 | SSH host key | `data/ssh_host_ed25519_key` | No; it is the secret |
@@ -72,10 +86,10 @@ is checked when it is pushed.
72 86 | Choice | Reason |
73 87 |---|---|
74 88 | Use the Git command-line tool | Full push behavior and hooks without reimplementing Git |
75 | SSH for writes, HTTP for anonymous reads | One authenticated way to change data; reads stay simple |
76 | Check everything before accepting a push | One place for policy; the web has no writes to protect |
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 |
90 | Check everything before accepting a change | The push boundary and the narrow web writers share the same metadata validation |
77 91 | Store metadata in Git, rules in SQLite | Project content travels with clones; local settings stay local |
78 | No web login | The web is read-only, so there is no password store or session to build |
92 | Passkeys, not passwords | No shared secret to phish, reset, or store; recovery is an administrator-issued enrollment link |
79 93 | One program with separate serve and runner modes | Easy to deploy anywhere |
80 94 | Keep the host key as the only secret | No signing key to manage or leak |
81 95
@@ -89,7 +103,7 @@ parts of Vole without running the `vole` command.
89 103 | `client` | Talks to an instance: metadata writes, identity lookups, file transfer, reviews, and site deploys |
90 104 | `core/id`, `core/git`, `core/lfs` | Shared primitives and storage |
91 105 | `forge` | Instance setup and administration |
92 | `forge/config`, `forge/identity`, `forge/access`, `forge/repo`, `forge/index` | Settings, accounts, permissions, repositories, and search |
106 | `forge/config`, `forge/identity`, `forge/access`, `forge/repo`, `forge/index`, `forge/session` | Settings, accounts, permissions, repositories, search, and browser sessions |
93 107 | `metadata` | Issues, requests, releases, comments, approvals, and validation |
94 108 | `ci` | Workflow validation and the job queue; `ci/agent` is the embeddable runner |
95 109 | `server` | Network listeners and web pages, with adapters for SSH, Git HTTP, sites, and hooks |