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.
Let instance admins create bot accounts from the web UI
8c72543b9ef4ac728740a6f0b3a649f9c3102e7a · Keenan Nemetz · 5d ago · parent f422c24f
Let instance admins create bot accounts from the web UI The Accounts page could only invite a person with an enrollment link. A bot has no browser sign-in, so it needs an SSH key at creation instead. Add a bot form that reuses identity.CreateBot, keep admin out of its role picker, and hide the enrollment action on a bot's account page.
server/web/templates/admin_users.html +25−5
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | <div class="page-head"> | |
| 4 | 4 | <div class="page-head-main"> | |
| 5 | 5 | <h1>Accounts</h1> | |
| 6 | <p class="page-sub">Enrollment links, keys, sessions, and instance roles. New accounts start with an enrollment link, never a pasted SSH key.</p> | ||
| 6 | <p class="page-sub">Invite people, set their role, and set up automation accounts.</p> | ||
| 7 | 7 | </div> | |
| 8 | 8 | </div> | |
| 9 | 9 | ||
| @@ -16,7 +16,7 @@ | |||
| 16 | 16 | {{range .Users}} | |
| 17 | 17 | <tr> | |
| 18 | 18 | <td> | |
| 19 | <a href="/users/{{.Account.Name}}">{{.Account.Name}}</a> | ||
| 19 | <a href="/users/{{.Account.Name}}">{{.Account.Name}}</a>{{if .Account.Bot}} <span class="state">bot</span>{{end}} | ||
| 20 | 20 | </td> | |
| 21 | 21 | <td><span class="state {{.Account.Status}}">{{.Account.Status}}</span></td> | |
| 22 | 22 | <td>{{if .Account.Admin}}<span class="label">instance admin</span>{{else}}<span class="muted">{{.Account.Role}}</span>{{end}}</td> | |
| @@ -29,7 +29,8 @@ | |||
| 29 | 29 | </table> | |
| 30 | 30 | </div> | |
| 31 | 31 | ||
| 32 | <h2>Create an account</h2> | ||
| 32 | <h2>Invite a person</h2> | ||
| 33 | <p class="muted">Send them a one-time link: they choose a passkey, then can add an SSH key.</p> | ||
| 33 | 34 | <form method="post" action="/users" class="form-block"> | |
| 34 | 35 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 35 | 36 | <div class="card form-card"> | |
| @@ -40,6 +41,21 @@ | |||
| 40 | 41 | </div> | |
| 41 | 42 | <div class="form-actions"><button type="submit">{{icon "user"}}Create account</button></div> | |
| 42 | 43 | </form> | |
| 44 | |||
| 45 | <h2>Create a bot account</h2> | ||
| 46 | <p class="muted">For a runner or another automation. It acts with the SSH key you paste here and cannot sign in to the browser or become an instance admin.</p> | ||
| 47 | <form method="post" action="/users/bots" class="form-block"> | ||
| 48 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | ||
| 49 | <div class="card form-card"> | ||
| 50 | <label>Account name | ||
| 51 | <input type="text" name="name" required maxlength="63" autocomplete="off" placeholder="lowercase-name"> | ||
| 52 | </label> | ||
| 53 | <label for="bot-public-key">SSH public key</label> | ||
| 54 | <textarea id="bot-public-key" name="key" rows="3" placeholder="ssh-ed25519 AAAA... you@example.com" required></textarea> | ||
| 55 | {{template "role-picker" (rolePicker "role" "none" "Instance role" "Instance roles apply to public repositories. A bot cannot be an instance admin." "bot" false)}} | ||
| 56 | </div> | ||
| 57 | <div class="form-actions"><button type="submit">{{icon "terminal"}}Create bot</button></div> | ||
| 58 | </form> | ||
| 43 | 59 | {{template "footer" .}} | |
| 44 | 60 | {{end}} | |
| 45 | 61 | ||
| @@ -47,19 +63,21 @@ | |||
| 47 | 63 | {{template "header" .}} | |
| 48 | 64 | <div class="page-head"> | |
| 49 | 65 | <div class="page-head-main"> | |
| 50 | <h1>{{.Account.Name}}</h1> | ||
| 66 | <h1>{{.Account.Name}}{{if .Account.Bot}} <span class="state">bot</span>{{end}}</h1> | ||
| 51 | 67 | <p class="page-sub"> | |
| 52 | 68 | <span class="state {{.Account.Status}}">{{.Account.Status}}</span> | |
| 53 | 69 | · instance role {{.Account.Role}} | |
| 54 | 70 | · created {{since .Account.Created.Unix}} | |
| 55 | 71 | </p> | |
| 56 | 72 | </div> | |
| 73 | {{if not .Account.Bot}} | ||
| 57 | 74 | <div class="page-head-actions"> | |
| 58 | 75 | <form class="inline" method="post" action="/users/{{.Account.Name}}/invite"> | |
| 59 | 76 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 60 | 77 | <button type="submit" class="secondary">{{icon "external-link"}}New enrollment link</button> | |
| 61 | 78 | </form> | |
| 62 | 79 | </div> | |
| 80 | {{end}} | ||
| 63 | 81 | </div> | |
| 64 | 82 | ||
| 65 | 83 | {{if .Error}}<div class="flash bad">{{.Error}}</div>{{end}} | |
| @@ -69,7 +87,7 @@ | |||
| 69 | 87 | <form method="post" action="/users/{{.Account.Name}}/role" class="form-block"> | |
| 70 | 88 | <input type="hidden" name="csrf" value="{{.CSRF}}"> | |
| 71 | 89 | <div class="card form-card"> | |
| 72 | {{template "role-picker" (rolePicker "role" $role (printf "Role for %s" .Account.Name) "Instance roles apply to public repositories. A repository-specific role can grant more on one repository. admin is the exception: it applies to every repository, private ones included." "instance" false)}} | ||
| 90 | {{template "role-picker" (rolePicker "role" $role (printf "Role for %s" .Account.Name) .RoleHelp .RoleScope false)}} | ||
| 73 | 91 | </div> | |
| 74 | 92 | <div class="form-actions"> | |
| 75 | 93 | <button type="submit">{{icon "check"}}Save role</button> | |
| @@ -99,6 +117,8 @@ | |||
| 99 | 117 | </tbody> | |
| 100 | 118 | </table> | |
| 101 | 119 | </div> | |
| 120 | {{else if .Account.Bot}} | ||
| 121 | <p class="muted">No SSH keys. This bot cannot act until a key is added.</p> | ||
| 102 | 122 | {{else}} | |
| 103 | 123 | <p class="muted">No SSH keys. This account can sign in with a passkey only.</p> | |
| 104 | 124 | {{end}} | |