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.

server/web/runners.go +3−3

@@ -76,7 +76,7 @@ func (w *Web) RunnersPage(rw http.ResponseWriter, r *http.Request) {
76 76 }
77 77 if s.Repo != "" {
78 78 m, err := w.Repos.Open(s.Repo)
79 if err != nil || !w.public(m) {
79 if err != nil || !w.canRead(r, m) {
80 80 continue // a private repository's build is not an anonymous reader's business
81 81 }
82 82 if run, err := w.Runs.Get(s.RunID); err == nil && run != nil {
@@ -96,7 +96,7 @@ func (w *Web) RunnersPage(rw http.ResponseWriter, r *http.Request) {
96 96 }
97 97 for name, d := range depths {
98 98 m, err := w.Repos.Open(name)
99 if err != nil || !w.public(m) {
99 if err != nil || !w.canRead(r, m) {
100 100 continue
101 101 }
102 102 queue = append(queue, queueView{Name: name, Queued: d.Queued, Running: d.Running, Cap: perRepoCap})
@@ -110,7 +110,7 @@ func (w *Web) RunnersPage(rw http.ResponseWriter, r *http.Request) {
110 110 Queue []queueView
111 111 Window string
112 112 }{
113 Page: w.base("Runners"),
113 Page: w.page(r, "Runners"),
114 114 Sessions: sessions,
115 115 Queue: queue,
116 116 Window: presenceWindow.String(),