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 the instance access editor and repository danger zone
2973f7274b3c569de6018239ac8c90df98c38a1b · Keenan Nemetz · 15d ago · parent 1948358f
Add the instance access editor and repository danger zone Instance admins get /admin: a repository list and a per-repository ACL editor for default role, per-account roles, protected branches, approvals, checks, and runners. The editor reads repositories directly instead of through the read rule, because an instance admin may not have a role in the repository they are administering. Everything else still hides behind a 404. Repository admins get rename and delete on the settings page behind typed confirmation. Both go through the instance operations that also move the index, queue, LFS namespace, and locks, carry CSRF, and are audited.
server/web/templates/admin.html +100
| @@ -0,0 +1,100 @@ | |||
| 1 | {{define "admin"}} | ||
| 2 | {{template "header" .}} | ||
| 3 | <div class="page-head"> | ||
| 4 | <div class="page-head-main"> | ||
| 5 | <h1>Admin</h1> | ||
| 6 | <p class="page-sub">Instance-wide administration. Repository admins manage their own description, default branch, and visibility.</p> | ||
| 7 | </div> | ||
| 8 | </div> | ||
| 9 | |||
| 10 | {{if .Repos}} | ||
| 11 | <div class="panel"> | ||
| 12 | <table> | ||
| 13 | <thead><tr><th>Repository</th><th>Visibility</th><th>Default role</th><th>Accounts</th><th>Runners</th><th></th></tr></thead> | ||
| 14 | <tbody> | ||
| 15 | {{range .Repos}} | ||
| 16 | <tr> | ||
| 17 | <td> | ||
| 18 | <a href="/r/{{.Name}}">{{.Name}}</a> | ||
| 19 | {{if .Description}}<div class="muted">{{.Description}}</div>{{end}} | ||
| 20 | </td> | ||
| 21 | <td>{{if .Public}}Public{{else}}Private{{end}}</td> | ||
| 22 | <td><code>{{.Default}}</code></td> | ||
| 23 | <td>{{.Principals}}</td> | ||
| 24 | <td>{{.Runners}}</td> | ||
| 25 | <td><a href="/admin/repos/{{.Name}}/access">Access</a></td> | ||
| 26 | </tr> | ||
| 27 | {{end}} | ||
| 28 | </tbody> | ||
| 29 | </table> | ||
| 30 | </div> | ||
| 31 | {{else}} | ||
| 32 | <p class="muted">No repositories.</p> | ||
| 33 | {{end}} | ||
| 34 | {{template "footer" .}} | ||
| 35 | {{end}} | ||
| 36 | |||
| 37 | {{define "admin_access"}} | ||
| 38 | {{template "header" .}} | ||
| 39 | <div class="page-head"> | ||
| 40 | <div class="page-head-main"> | ||
| 41 | <h1>{{.Name}} access</h1> | ||
| 42 | <p class="page-sub">{{if .Description}}{{.Description}} · {{end}}{{if .Public}}public{{else}}private{{end}} · instance-admin rules</p> | ||
| 43 | </div> | ||
| 44 | <div class="page-head-actions"> | ||
| 45 | <a class="button secondary" href="/admin">{{icon "sliders-horizontal"}}All repositories</a> | ||
| 46 | </div> | ||
| 47 | </div> | ||
| 48 | |||
| 49 | {{if .Error}}<div class="flash bad">{{.Error}}</div>{{end}} | ||
| 50 | {{if .Saved}}<div class="flash good">Access rules saved.</div>{{end}} | ||
| 51 | |||
| 52 | <form method="post" action="/admin/repos/{{.Name}}/access" class="form-block"> | ||
| 53 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | ||
| 54 | <div class="card form-card"> | ||
| 55 | <label>Default role | ||
| 56 | <select name="default"> | ||
| 57 | {{range .Roles}}<option value="{{.}}"{{if eq . $.Default}} selected{{end}}>{{.}}</option>{{end}} | ||
| 58 | </select> | ||
| 59 | </label> | ||
| 60 | <label>Approvals required | ||
| 61 | <input type="number" name="approvals" min="0" value="{{.Approvals}}"> | ||
| 62 | </label> | ||
| 63 | <label class="acl-check"><input type="checkbox" name="checks"{{if .Checks}} checked{{end}}> Require CI checks before landing a protected branch</label> | ||
| 64 | <label>Protected branches | ||
| 65 | <textarea name="protected" placeholder="refs/heads/main refs/heads/release/*">{{.Protected}}</textarea> | ||
| 66 | </label> | ||
| 67 | </div> | ||
| 68 | |||
| 69 | <h2>Accounts</h2> | ||
| 70 | <p class="muted">Admins can report CI even when they are not listed. A runner's result counts as a check, and naming one also lets them lease jobs for this repository.</p> | ||
| 71 | <div class="panel"> | ||
| 72 | <table class="acl"> | ||
| 73 | <thead><tr><th>Account</th><th>Role</th><th>Runner</th></tr></thead> | ||
| 74 | <tbody> | ||
| 75 | {{range .Rows}}{{$row := .}} | ||
| 76 | <tr> | ||
| 77 | <td> | ||
| 78 | <span>{{.Label}}</span> | ||
| 79 | {{if and .Name (ne .Name .Label)}}<span class="muted">@{{.Name}}</span>{{end}} | ||
| 80 | {{if ne .Status "active"}}<span class="label">{{.Status}}</span>{{end}} | ||
| 81 | </td> | ||
| 82 | <td> | ||
| 83 | <select name="role:{{.ID}}" aria-label="Role for {{.Label}}"> | ||
| 84 | {{range $.Roles}}<option value="{{.}}"{{if eq . $row.Role}} selected{{end}}>{{.}}</option>{{end}} | ||
| 85 | </select> | ||
| 86 | </td> | ||
| 87 | <td><input type="checkbox" name="runner:{{.ID}}" aria-label="Runner for {{.Label}}"{{if .Runner}} checked{{end}}></td> | ||
| 88 | </tr> | ||
| 89 | {{end}} | ||
| 90 | </tbody> | ||
| 91 | </table> | ||
| 92 | </div> | ||
| 93 | |||
| 94 | <div class="form-actions"> | ||
| 95 | <a class="button secondary" href="/admin">Cancel</a> | ||
| 96 | <button type="submit">{{icon "check"}}Save access</button> | ||
| 97 | </div> | ||
| 98 | </form> | ||
| 99 | {{template "footer" .}} | ||
| 100 | {{end}} | ||