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/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.

Identify accounts by their registered name

62576fa8157d431dcf2d360f3ebe481de77bda03 · Keenan Nemetz · 14d ago · parent 642e5994

Identify accounts by their registered name

Drop the internal account id and display name. Users, keys, passkeys,
invites, sessions, ACL entries, approvals, locks and CI records now all
use the registered name as the single identity.

The roster migrates in place: old id-keyed tables are rebuilt around the
name, and access-rule/lock references are rewritten through the same
mapping. Display-name editing and whoami --id are removed.

server/web/writes.go +27−27

@@ -38,7 +38,7 @@ func (w *Web) CreateIssue(rw http.ResponseWriter, r *http.Request) {
38 38 return
39 39 }
40 40 acl, err := m.ACL()
41 if err != nil || !acl.CanDiscuss(pr.account.ID) {
41 if err != nil || !acl.CanDiscuss(pr.account.Name) {
42 42 http.Error(rw, "you do not have permission to file issues here", http.StatusForbidden)
43 43 return
44 44 }
@@ -68,7 +68,7 @@ func (w *Web) CreateIssue(rw http.ResponseWriter, r *http.Request) {
68 68 w.serverError(rw, r, "cannot create the issue: "+err.Error())
69 69 return
70 70 }
71 w.audit("web.issue.create", pr.account.ID, m.Name+" "+iss.ID)
71 w.audit("web.issue.create", pr.account.Name, m.Name+" "+iss.ID)
72 72 if problems := metadata.ValidateIssues(m.Git(), metadata.Ref); len(problems) > 0 {
73 73 w.Logger("web: issue %s left the metadata tree invalid: %v", iss.ID, problems)
74 74 }
@@ -99,7 +99,7 @@ func (w *Web) SetIssueLabels(rw http.ResponseWriter, r *http.Request) {
99 99 return
100 100 }
101 101 acl, err := m.ACL()
102 if err != nil || (!acl.CanTriage(pr.account.ID) && iss.Author != pr.account.Name) {
102 if err != nil || (!acl.CanTriage(pr.account.Name) && iss.Author != pr.account.Name) {
103 103 http.Error(rw, "you do not have permission to edit these labels", http.StatusForbidden)
104 104 return
105 105 }
@@ -123,7 +123,7 @@ func (w *Web) SetIssueLabels(rw http.ResponseWriter, r *http.Request) {
123 123 http.Error(rw, "cannot update the labels: "+err.Error(), http.StatusBadRequest)
124 124 return
125 125 }
126 w.audit("web.issue.labels", pr.account.ID, m.Name+" "+id+" "+strings.Join(labels, ","))
126 w.audit("web.issue.labels", pr.account.Name, m.Name+" "+id+" "+strings.Join(labels, ","))
127 127 if problems := metadata.ValidateIssues(m.Git(), metadata.Ref); len(problems) > 0 {
128 128 w.Logger("web: issue labels %s left the metadata tree invalid: %v", id, problems)
129 129 }
@@ -160,7 +160,7 @@ func (w *Web) SetIssueAssignees(rw http.ResponseWriter, r *http.Request) {
160 160 return
161 161 }
162 162 acl, err := m.ACL()
163 if err != nil || (!acl.CanTriage(pr.account.ID) && iss.Author != pr.account.Name) {
163 if err != nil || (!acl.CanTriage(pr.account.Name) && iss.Author != pr.account.Name) {
164 164 http.Error(rw, "you do not have permission to edit these assignees", http.StatusForbidden)
165 165 return
166 166 }
@@ -195,7 +195,7 @@ func (w *Web) SetIssueAssignees(rw http.ResponseWriter, r *http.Request) {
195 195 http.Error(rw, "cannot update the assignees: "+err.Error(), http.StatusBadRequest)
196 196 return
197 197 }
198 w.audit("web.issue.assignees", pr.account.ID, m.Name+" "+id+" "+strings.Join(assignees, ","))
198 w.audit("web.issue.assignees", pr.account.Name, m.Name+" "+id+" "+strings.Join(assignees, ","))
199 199 if problems := metadata.ValidateIssues(m.Git(), metadata.Ref); len(problems) > 0 {
200 200 w.Logger("web: issue assignees %s left the metadata tree invalid: %v", id, problems)
201 201 }
@@ -224,7 +224,7 @@ func (w *Web) AddIssueComment(rw http.ResponseWriter, r *http.Request) {
224 224 return
225 225 }
226 226 acl, err := m.ACL()
227 if err != nil || !acl.CanDiscuss(pr.account.ID) {
227 if err != nil || !acl.CanDiscuss(pr.account.Name) {
228 228 http.Error(rw, "you do not have permission to comment here", http.StatusForbidden)
229 229 return
230 230 }
@@ -267,7 +267,7 @@ func (w *Web) AddIssueComment(rw http.ResponseWriter, r *http.Request) {
267 267 http.Error(rw, "cannot add the comment: "+err.Error(), http.StatusBadRequest)
268 268 return
269 269 }
270 w.audit("web.issue.comment", pr.account.ID, m.Name+" "+id+" "+c.ID)
270 w.audit("web.issue.comment", pr.account.Name, m.Name+" "+id+" "+c.ID)
271 271 if problems := metadata.ValidateIssues(m.Git(), metadata.Ref); len(problems) > 0 {
272 272 w.Logger("web: comment %s left the metadata tree invalid: %v", c.ID, problems)
273 273 }
@@ -290,7 +290,7 @@ func canManageComment(pr *principal, acl *access.ACL, author string) bool {
290 290 if pr.account.Name == author {
291 291 return true
292 292 }
293 return acl != nil && acl.RoleFor(pr.account.ID).AtLeast(access.Admin)
293 return acl != nil && acl.RoleFor(pr.account.Name).AtLeast(access.Admin)
294 294 }
295 295
296 296 func issueCommentByID(iss *metadata.Issue, id string) *metadata.Comment {
@@ -368,7 +368,7 @@ func (w *Web) EditIssueComment(rw http.ResponseWriter, r *http.Request) {
368 368 if pr.account.Name != c.Author {
369 369 detail += " (author " + c.Author + ", admin override)"
370 370 }
371 w.audit("web.issue.comment.edit", pr.account.ID, detail)
371 w.audit("web.issue.comment.edit", pr.account.Name, detail)
372 372 if problems := metadata.ValidateIssues(m.Git(), metadata.Ref); len(problems) > 0 {
373 373 w.Logger("web: edit comment %s left the metadata tree invalid: %v", commentID, problems)
374 374 }
@@ -426,7 +426,7 @@ func (w *Web) DeleteIssueComment(rw http.ResponseWriter, r *http.Request) {
426 426 if pr.account.Name != c.Author {
427 427 detail += " (author " + c.Author + ", admin override)"
428 428 }
429 w.audit("web.issue.comment.delete", pr.account.ID, detail)
429 w.audit("web.issue.comment.delete", pr.account.Name, detail)
430 430 if problems := metadata.ValidateIssues(m.Git(), metadata.Ref); len(problems) > 0 {
431 431 w.Logger("web: delete comment %s left the metadata tree invalid: %v", commentID, problems)
432 432 }
@@ -457,7 +457,7 @@ func (w *Web) ApproveRequest(rw http.ResponseWriter, r *http.Request) {
457 457 return
458 458 }
459 459 acl, err := m.ACL()
460 if err != nil || !acl.CanApprove(pr.account.ID) {
460 if err != nil || !acl.CanApprove(pr.account.Name) {
461 461 http.Error(rw, "you do not have permission to approve here", http.StatusForbidden)
462 462 return
463 463 }
@@ -471,11 +471,11 @@ func (w *Web) ApproveRequest(rw http.ResponseWriter, r *http.Request) {
471 471 http.Error(rw, "this change request is not open", http.StatusBadRequest)
472 472 return
473 473 }
474 if req.AuthorID == pr.account.ID {
474 if req.Author == pr.account.Name {
475 475 http.Error(rw, "you cannot approve your own change request", http.StatusForbidden)
476 476 return
477 477 }
478 if _, err := metadata.ApproveRequest(m.Git(), id, pr.account.ID, time.Now().UTC(), pr.account.Name); err != nil {
478 if _, err := metadata.ApproveRequest(m.Git(), id, pr.account.Name, time.Now().UTC(), pr.account.Name); err != nil {
479 479 if htmxRequest(r) {
480 480 w.render(rw, "request_sidebar", w.requestSidebar(r, m, req, "", err.Error()), 0)
481 481 return
@@ -483,7 +483,7 @@ func (w *Web) ApproveRequest(rw http.ResponseWriter, r *http.Request) {
483 483 http.Error(rw, "cannot approve: "+err.Error(), http.StatusBadRequest)
484 484 return
485 485 }
486 w.audit("web.request.approve", pr.account.ID, m.Name+" "+id+" "+req.Head)
486 w.audit("web.request.approve", pr.account.Name, m.Name+" "+id+" "+req.Head)
487 487 if problems := metadata.ValidateRequests(m.Git(), metadata.Ref); len(problems) > 0 {
488 488 w.Logger("web: approval left the request tree invalid: %v", problems)
489 489 }
@@ -532,7 +532,7 @@ func (w *Web) CreateChangeRequest(rw http.ResponseWriter, r *http.Request) {
532 532 return
533 533 }
534 534 acl, err := m.ACL()
535 if err != nil || !acl.CanOpenRequest(pr.account.ID) {
535 if err != nil || !acl.CanOpenRequest(pr.account.Name) {
536 536 http.Error(rw, "you do not have permission to open change requests here", http.StatusForbidden)
537 537 return
538 538 }
@@ -554,7 +554,7 @@ func (w *Web) CreateChangeRequest(rw http.ResponseWriter, r *http.Request) {
554 554 return
555 555 }
556 556 headRef := "refs/heads/" + head
557 if acl.RoleFor(pr.account.ID) == access.Contributor {
557 if acl.RoleFor(pr.account.Name) == access.Contributor {
558 558 // A contributor's head must be a branch the hook would let them push. The
559 559 // namespace is the account name, which cannot change, so this agrees with
560 560 // the gate without a roster lookup.
@@ -572,7 +572,7 @@ func (w *Web) CreateChangeRequest(rw http.ResponseWriter, r *http.Request) {
572 572 http.Error(rw, "that base branch does not exist", http.StatusBadRequest)
573 573 return
574 574 }
575 req, err := metadata.NewRequest(title, body, pr.account.Name, pr.account.ID, base, headCommit, time.Now().UTC())
575 req, err := metadata.NewRequest(title, body, pr.account.Name, base, headCommit, time.Now().UTC())
576 576 if err != nil {
577 577 http.Error(rw, err.Error(), http.StatusBadRequest)
578 578 return
@@ -581,7 +581,7 @@ func (w *Web) CreateChangeRequest(rw http.ResponseWriter, r *http.Request) {
581 581 w.serverError(rw, r, "cannot open the change request: "+err.Error())
582 582 return
583 583 }
584 w.audit("web.request.create", pr.account.ID, m.Name+" "+req.ID+" "+headCommit)
584 w.audit("web.request.create", pr.account.Name, m.Name+" "+req.ID+" "+headCommit)
585 585 if problems := metadata.ValidateRequests(m.Git(), metadata.Ref); len(problems) > 0 {
586 586 w.Logger("web: request %s left the request tree invalid: %v", req.ID, problems)
587 587 }
@@ -621,7 +621,7 @@ func (w *Web) ChangeIssueState(rw http.ResponseWriter, r *http.Request) {
621 621 return
622 622 }
623 623 acl, err := m.ACL()
624 if err != nil || (!acl.CanTriage(pr.account.ID) && iss.Author != pr.account.Name) {
624 if err != nil || (!acl.CanTriage(pr.account.Name) && iss.Author != pr.account.Name) {
625 625 http.Error(rw, "you do not have permission to change this issue", http.StatusForbidden)
626 626 return
627 627 }
@@ -630,7 +630,7 @@ func (w *Web) ChangeIssueState(rw http.ResponseWriter, r *http.Request) {
630 630 w.serverError(rw, r, "cannot change the issue: "+err.Error())
631 631 return
632 632 }
633 w.audit("web.issue.state", pr.account.ID, m.Name+" "+id+" "+state)
633 w.audit("web.issue.state", pr.account.Name, m.Name+" "+id+" "+state)
634 634 if problems := metadata.ValidateIssues(m.Git(), metadata.Ref); len(problems) > 0 {
635 635 w.Logger("web: issue state %s left the metadata tree invalid: %v", id, problems)
636 636 }
@@ -655,7 +655,7 @@ func (w *Web) AddRequestComment(rw http.ResponseWriter, r *http.Request) {
655 655 return
656 656 }
657 657 acl, err := m.ACL()
658 if err != nil || !acl.CanDiscuss(pr.account.ID) {
658 if err != nil || !acl.CanDiscuss(pr.account.Name) {
659 659 http.Error(rw, "you do not have permission to comment here", http.StatusForbidden)
660 660 return
661 661 }
@@ -727,7 +727,7 @@ func (w *Web) AddRequestComment(rw http.ResponseWriter, r *http.Request) {
727 727 http.Error(rw, "cannot add the comment: "+err.Error(), http.StatusBadRequest)
728 728 return
729 729 }
730 w.audit("web.request.comment", pr.account.ID, m.Name+" "+id+" "+c.ID)
730 w.audit("web.request.comment", pr.account.Name, m.Name+" "+id+" "+c.ID)
731 731 if problems := metadata.ValidateRequests(m.Git(), metadata.Ref); len(problems) > 0 {
732 732 w.Logger("web: request comment %s left the request tree invalid: %v", c.ID, problems)
733 733 }
@@ -807,7 +807,7 @@ func (w *Web) EditRequestComment(rw http.ResponseWriter, r *http.Request) {
807 807 if pr.account.Name != c.Author {
808 808 detail += " (author " + c.Author + ", admin override)"
809 809 }
810 w.audit("web.request.comment.edit", pr.account.ID, detail)
810 w.audit("web.request.comment.edit", pr.account.Name, detail)
811 811 if problems := metadata.ValidateRequests(m.Git(), metadata.Ref); len(problems) > 0 {
812 812 w.Logger("web: edit comment %s left the metadata tree invalid: %v", commentID, problems)
813 813 }
@@ -865,7 +865,7 @@ func (w *Web) DeleteRequestComment(rw http.ResponseWriter, r *http.Request) {
865 865 if pr.account.Name != c.Author {
866 866 detail += " (author " + c.Author + ", admin override)"
867 867 }
868 w.audit("web.request.comment.delete", pr.account.ID, detail)
868 w.audit("web.request.comment.delete", pr.account.Name, detail)
869 869 if problems := metadata.ValidateRequests(m.Git(), metadata.Ref); len(problems) > 0 {
870 870 w.Logger("web: delete comment %s left the metadata tree invalid: %v", commentID, problems)
871 871 }
@@ -905,7 +905,7 @@ func (w *Web) ChangeRequestState(rw http.ResponseWriter, r *http.Request) {
905 905 return
906 906 }
907 907 acl, err := m.ACL()
908 if err != nil || (!acl.CanTriage(pr.account.ID) && req.AuthorID != pr.account.ID) {
908 if err != nil || (!acl.CanTriage(pr.account.Name) && req.Author != pr.account.Name) {
909 909 http.Error(rw, "you do not have permission to change this change request", http.StatusForbidden)
910 910 return
911 911 }
@@ -922,7 +922,7 @@ func (w *Web) ChangeRequestState(rw http.ResponseWriter, r *http.Request) {
922 922 w.serverError(rw, r, "cannot change the change request: "+err.Error())
923 923 return
924 924 }
925 w.audit("web.request.state", pr.account.ID, m.Name+" "+id+" "+state)
925 w.audit("web.request.state", pr.account.Name, m.Name+" "+id+" "+state)
926 926 if problems := metadata.ValidateRequests(m.Git(), metadata.Ref); len(problems) > 0 {
927 927 w.Logger("web: request state %s left the request tree invalid: %v", id, problems)
928 928 }