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.

Let an account be a bot

29a795b9d5b79cf5c8f2b7f3b4f6572f7cdff444 · Keenan Nemetz · 7d ago · parent e7aa0785

Let an account be a bot

An automation needs an identity: something to assign an issue to, mention in a
comment, and name in an approval and the audit log. An account already gives all
of that, so this adds only the invariants a bot needs and the word for it.

A bot is created with `vole admin account create --bot`, with the repository role
the admin decides it should have. It has no browser sign-in — `account invite` and
adding a passkey are refused — and it cannot hold the instance-admin role, because
Admin reaches every repository and every instance surface while a bot is a
repository automation. It is marked as a bot in the user directory and on its
profile.

Everything else is deliberately unchanged. A bot obeys the rules of its role: a
contribute bot pushes only its own contributor branch and its CI waits for a
maintainer to allow the tip; a maintain bot pushes shared branches, runs CI
immediately, and its approval counts. The kind is fixed at creation, like the name,
and a roster that predates it reads every account as a person.

This is the first of three slices of #165. The per-run credential that lets a
workflow act as a bot without a long-lived key in a repository secret is next; this
slice changes no push rule and no permission.

server/web/people.go +2−1

@@ -35,6 +35,7 @@ const peoplePage = 50
35 35 // profile reads, so a row and the page it opens tell the same story.
36 36 type peopleRow struct {
37 37 Name string
38 Bot bool
38 39 Active bool
39 40 Joined time.Time
40 41 Role string // rendered only for an instance admin
@@ -256,7 +257,7 @@ func (w *Web) PeoplePage(rw http.ResponseWriter, r *http.Request) {
256 257 rows := make([]peopleRow, 0, len(matched))
257 258 for _, acct := range matched {
258 259 row := peopleRow{
259 Name: acct.Name, Active: acct.Active(), Joined: acct.Created,
260 Name: acct.Name, Bot: acct.Bot(), Active: acct.Active(), Joined: acct.Created,
260 261 Summary: summaries[acct.Name],
261 262 }
262 263 if page.InstanceAdmin {