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/ssh/admin.go +50−85
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | package ssh | |
| 2 | 2 | ||
| 3 | 3 | // Remote administration over SSH. The command grammar is fixed; nothing here | |
| 4 | // goes through a shell. Authorization is the account id from the SSH handshake, | ||
| 4 | // goes through a shell. Authorization is the account name from the SSH handshake, | ||
| 5 | 5 | // and every successful or rejected command is recorded with that identity. | |
| 6 | 6 | ||
| 7 | 7 | import ( | |
| @@ -41,38 +41,38 @@ func (e *adminUsageError) Error() string { return e.msg } | |||
| 41 | 41 | type adminRender func(stdout, stderr io.Writer) | |
| 42 | 42 | ||
| 43 | 43 | // serveAdmin runs one `vole-admin` command and returns the process exit code. | |
| 44 | func (s *Server) serveAdmin(ch xssh.Channel, argv []string, user, accountID, remote string) int { | ||
| 44 | func (s *Server) serveAdmin(ch xssh.Channel, argv []string, user, remote string) int { | ||
| 45 | 45 | jsonOut, args, err := splitAdminJSON(argv) | |
| 46 | 46 | if err != nil { | |
| 47 | return s.adminError(ch, jsonOut, "usage", err, user, accountID, remote) | ||
| 47 | return s.adminError(ch, jsonOut, "usage", err, user, remote) | ||
| 48 | 48 | } | |
| 49 | if !s.cfg.Identity.IsAdmin(accountID) { | ||
| 49 | if !s.cfg.Identity.IsAdmin(user) { | ||
| 50 | 50 | return s.adminError(ch, jsonOut, "permission_denied", | |
| 51 | fmt.Errorf("instance admin required for %s", user), user, accountID, remote) | ||
| 51 | fmt.Errorf("instance admin required for %s", user), user, remote) | ||
| 52 | 52 | } | |
| 53 | 53 | if s.cfg.Instance == nil { | |
| 54 | 54 | return s.adminError(ch, jsonOut, "unavailable", | |
| 55 | errors.New("admin API is not wired into this server"), user, accountID, remote) | ||
| 55 | errors.New("admin API is not wired into this server"), user, remote) | ||
| 56 | 56 | } | |
| 57 | 57 | if len(args) < 2 { | |
| 58 | 58 | return s.adminError(ch, jsonOut, "usage", &adminUsageError{msg: "usage: vole-admin <resource> <action> [args]"}, | |
| 59 | user, accountID, remote) | ||
| 59 | user, remote) | ||
| 60 | 60 | } | |
| 61 | 61 | ||
| 62 | 62 | data, render, err := s.runAdmin(args, user, ch) | |
| 63 | 63 | if err != nil { | |
| 64 | return s.adminError(ch, jsonOut, "failed", err, user, accountID, remote) | ||
| 64 | return s.adminError(ch, jsonOut, "failed", err, user, remote) | ||
| 65 | 65 | } | |
| 66 | 66 | if jsonOut { | |
| 67 | 67 | _ = json.NewEncoder(ch).Encode(adminResponse{OK: true, Data: data}) | |
| 68 | 68 | } else if render != nil { | |
| 69 | 69 | render(ch, ch.Stderr()) | |
| 70 | 70 | } | |
| 71 | s.auditAdmin(user, accountID, remote, strings.Join(args, " ")+" ok") | ||
| 71 | s.auditAdmin(user, remote, strings.Join(args, " ")+" ok") | ||
| 72 | 72 | return 0 | |
| 73 | 73 | } | |
| 74 | 74 | ||
| 75 | func (s *Server) adminError(ch xssh.Channel, jsonOut bool, code string, err error, user, accountID, remote string) int { | ||
| 75 | func (s *Server) adminError(ch xssh.Channel, jsonOut bool, code string, err error, user, remote string) int { | ||
| 76 | 76 | exitCode := 1 | |
| 77 | 77 | if _, ok := err.(*adminUsageError); ok { | |
| 78 | 78 | exitCode = 129 | |
| @@ -82,7 +82,7 @@ func (s *Server) adminError(ch xssh.Channel, jsonOut bool, code string, err erro | |||
| 82 | 82 | } else { | |
| 83 | 83 | fmt.Fprintf(ch.Stderr(), "vole: %v\n", err) | |
| 84 | 84 | } | |
| 85 | s.auditAdmin(user, accountID, remote, "failed: "+err.Error()) | ||
| 85 | s.auditAdmin(user, remote, "failed: "+err.Error()) | ||
| 86 | 86 | return exitCode | |
| 87 | 87 | } | |
| 88 | 88 | ||
| @@ -136,11 +136,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 136 | 136 | if a.Admin { | |
| 137 | 137 | role = " admin" | |
| 138 | 138 | } | |
| 139 | display := a.Display | ||
| 140 | if display == "" { | ||
| 141 | display = "-" | ||
| 142 | } | ||
| 143 | fmt.Fprintf(out, "%-16s %s %-24s %-8s%s keys=%d\n", a.Name, a.ID, display, a.Status, role, len(a.Keys)) | ||
| 139 | fmt.Fprintf(out, "%-32s %-8s%s keys=%d\n", a.Name, a.Status, role, len(a.Keys)) | ||
| 144 | 140 | for _, k := range a.Keys { | |
| 145 | 141 | fmt.Fprintf(out, " %s %s %s\n", k.Fingerprint, k.Type, k.Comment) | |
| 146 | 142 | } | |
| @@ -149,41 +145,36 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 149 | 145 | ||
| 150 | 146 | case "show": | |
| 151 | 147 | if len(args) != 1 { | |
| 152 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user show <name|id>"} | ||
| 148 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user show <name>"} | ||
| 153 | 149 | } | |
| 154 | 150 | a, err := s.cfg.Identity.Find(args[0]) | |
| 155 | 151 | if err != nil { | |
| 156 | 152 | return nil, nil, err | |
| 157 | 153 | } | |
| 158 | 154 | return userData(a), func(out, _ io.Writer) { | |
| 159 | display := a.Display | ||
| 160 | if display == "" { | ||
| 161 | display = "-" | ||
| 162 | } | ||
| 163 | fmt.Fprintf(out, "name: %s\ndisplay: %s\nid: %s\nstatus: %s\nadmin: %t\ncreated: %s\n", | ||
| 164 | a.Name, display, a.ID, a.Status, a.Admin, a.Created.Format(time.RFC3339)) | ||
| 155 | fmt.Fprintf(out, "name: %s\nstatus: %s\nadmin: %t\ncreated: %s\n", | ||
| 156 | a.Name, a.Status, a.Admin, a.Created.Format(time.RFC3339)) | ||
| 165 | 157 | for _, k := range a.Keys { | |
| 166 | 158 | fmt.Fprintf(out, "key: %s %s %s\n", k.Fingerprint, k.Type, k.Comment) | |
| 167 | 159 | } | |
| 168 | 160 | }, nil | |
| 169 | 161 | ||
| 170 | 162 | case "create": | |
| 171 | f, err := parseAdminFlags(args, adminFlagSpec{long: "no-key", boolean: true}, adminFlagSpec{long: "display"}) | ||
| 163 | f, err := parseAdminFlags(args, adminFlagSpec{long: "no-key", boolean: true}) | ||
| 172 | 164 | if err != nil { | |
| 173 | 165 | return nil, nil, err | |
| 174 | 166 | } | |
| 175 | 167 | if len(f.rest) != 1 { | |
| 176 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user create [--no-key] [--display <label>] <name> (public key on stdin unless --no-key)"} | ||
| 168 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user create [--no-key] <name> (public key on stdin unless --no-key)"} | ||
| 177 | 169 | } | |
| 178 | display := f.one("display") | ||
| 179 | 170 | if f.has("no-key") { | |
| 180 | a, inv, err := s.cfg.Identity.CreateWithInvite(f.rest[0], display, actor, 0) | ||
| 171 | a, inv, err := s.cfg.Identity.CreateWithInvite(f.rest[0], actor, 0) | ||
| 181 | 172 | if err != nil { | |
| 182 | 173 | return nil, nil, err | |
| 183 | 174 | } | |
| 184 | 175 | data := map[string]any{"account": userData(a), "invite": s.inviteData(inv)} | |
| 185 | 176 | return data, func(out, errOut io.Writer) { | |
| 186 | fmt.Fprintf(out, "%s\t%s\n", a.Name, a.ID) | ||
| 177 | fmt.Fprintln(out, a.Name) | ||
| 187 | 178 | s.renderInvite(inv, out) | |
| 188 | 179 | }, nil | |
| 189 | 180 | } | |
| @@ -191,12 +182,12 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 191 | 182 | if err != nil { | |
| 192 | 183 | return nil, nil, err | |
| 193 | 184 | } | |
| 194 | a, err := s.cfg.Identity.Create(f.rest[0], display, key, actor) | ||
| 185 | a, err := s.cfg.Identity.Create(f.rest[0], key, actor) | ||
| 195 | 186 | if err != nil { | |
| 196 | 187 | return nil, nil, err | |
| 197 | 188 | } | |
| 198 | 189 | return userData(a), func(out, errOut io.Writer) { | |
| 199 | fmt.Fprintf(out, "%s\t%s\n", a.Name, a.ID) | ||
| 190 | fmt.Fprintln(out, a.Name) | ||
| 200 | 191 | if len(a.Keys) > 0 { | |
| 201 | 192 | fmt.Fprintf(errOut, "key %s\n", a.Keys[0].Fingerprint) | |
| 202 | 193 | } | |
| @@ -204,7 +195,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 204 | 195 | ||
| 205 | 196 | case "invite": | |
| 206 | 197 | if len(args) != 1 { | |
| 207 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user invite <name|id>"} | ||
| 198 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user invite <name>"} | ||
| 208 | 199 | } | |
| 209 | 200 | inv, err := s.cfg.Identity.Invite(args[0], actor, 0) | |
| 210 | 201 | if err != nil { | |
| @@ -216,7 +207,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 216 | 207 | ||
| 217 | 208 | case "credentials": | |
| 218 | 209 | if len(args) != 1 { | |
| 219 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user credentials <name|id>"} | ||
| 210 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user credentials <name>"} | ||
| 220 | 211 | } | |
| 221 | 212 | creds, err := s.cfg.Identity.Credentials(args[0]) | |
| 222 | 213 | if err != nil { | |
| @@ -245,7 +236,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 245 | 236 | ||
| 246 | 237 | case "rm-credential": | |
| 247 | 238 | if len(args) != 2 { | |
| 248 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user rm-credential <name|id> <credential-id>"} | ||
| 239 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user rm-credential <name> <credential-id>"} | ||
| 249 | 240 | } | |
| 250 | 241 | id, err := identity.ParseCredentialID(args[1]) | |
| 251 | 242 | if err != nil { | |
| @@ -260,7 +251,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 260 | 251 | ||
| 261 | 252 | case "sessions": | |
| 262 | 253 | if len(args) != 1 { | |
| 263 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user sessions <name|id>"} | ||
| 254 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user sessions <name>"} | ||
| 264 | 255 | } | |
| 265 | 256 | a, err := s.cfg.Identity.Find(args[0]) | |
| 266 | 257 | if err != nil { | |
| @@ -269,7 +260,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 269 | 260 | if s.cfg.Instance == nil || s.cfg.Instance.Sessions == nil { | |
| 270 | 261 | return nil, nil, errors.New("session store is not wired into this server") | |
| 271 | 262 | } | |
| 272 | list, err := s.cfg.Instance.Sessions.List(a.ID) | ||
| 263 | list, err := s.cfg.Instance.Sessions.List(a.Name) | ||
| 273 | 264 | if err != nil { | |
| 274 | 265 | return nil, nil, err | |
| 275 | 266 | } | |
| @@ -295,7 +286,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 295 | 286 | } | |
| 296 | 287 | if f.has("all") { | |
| 297 | 288 | if len(f.rest) != 0 { | |
| 298 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user revoke-sessions [--all | <name|id>]"} | ||
| 289 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user revoke-sessions [--all | <name>]"} | ||
| 299 | 290 | } | |
| 300 | 291 | n, err := s.cfg.Instance.Sessions.RevokeAll() | |
| 301 | 292 | if err != nil { | |
| @@ -306,13 +297,13 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 306 | 297 | }, nil | |
| 307 | 298 | } | |
| 308 | 299 | if len(f.rest) != 1 { | |
| 309 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user revoke-sessions [--all | <name|id>]"} | ||
| 300 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user revoke-sessions [--all | <name>]"} | ||
| 310 | 301 | } | |
| 311 | 302 | a, err := s.cfg.Identity.Find(f.rest[0]) | |
| 312 | 303 | if err != nil { | |
| 313 | 304 | return nil, nil, err | |
| 314 | 305 | } | |
| 315 | n, err := s.cfg.Instance.Sessions.RevokeAccount(a.ID) | ||
| 306 | n, err := s.cfg.Instance.Sessions.RevokeAccount(a.Name) | ||
| 316 | 307 | if err != nil { | |
| 317 | 308 | return nil, nil, err | |
| 318 | 309 | } | |
| @@ -322,7 +313,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 322 | 313 | ||
| 323 | 314 | case "add-key": | |
| 324 | 315 | if len(args) != 1 { | |
| 325 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user add-key <name|id>"} | ||
| 316 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user add-key <name>"} | ||
| 326 | 317 | } | |
| 327 | 318 | key, err := readAdminKey(in) | |
| 328 | 319 | if err != nil { | |
| @@ -340,7 +331,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 340 | 331 | ||
| 341 | 332 | case "rm-key": | |
| 342 | 333 | if len(args) != 2 { | |
| 343 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user rm-key <name|id> <fingerprint>"} | ||
| 334 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user rm-key <name> <fingerprint>"} | ||
| 344 | 335 | } | |
| 345 | 336 | if err := s.cfg.Identity.RemoveKey(args[0], args[1], actor); err != nil { | |
| 346 | 337 | return nil, nil, err | |
| @@ -349,35 +340,19 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 349 | 340 | fmt.Fprintf(out, "revoked %s\n", args[1]) | |
| 350 | 341 | }, nil | |
| 351 | 342 | ||
| 352 | case "rename": | ||
| 353 | return nil, nil, &adminUsageError{msg: "account names are permanent; use vole-admin user display <name|id> <display-name>"} | ||
| 354 | |||
| 355 | case "display": | ||
| 356 | if len(args) != 2 { | ||
| 357 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user display <name|id> <display-name>"} | ||
| 358 | } | ||
| 359 | a, err := s.cfg.Identity.SetDisplay(args[0], args[1], actor) | ||
| 360 | if err != nil { | ||
| 361 | return nil, nil, err | ||
| 362 | } | ||
| 363 | return userData(a), func(out, _ io.Writer) { | ||
| 364 | if a.Display == "" { | ||
| 365 | fmt.Fprintf(out, "cleared the display name for %s; showing %s\n", a.Name, a.Name) | ||
| 366 | } else { | ||
| 367 | fmt.Fprintf(out, "%s now shows as %s\n", a.Name, a.Display) | ||
| 368 | } | ||
| 369 | }, nil | ||
| 343 | case "rename", "display": | ||
| 344 | return nil, nil, &adminUsageError{msg: "account names are permanent and are the only identifier an account has"} | ||
| 370 | 345 | ||
| 371 | 346 | case "retire", "rm", "delete": | |
| 372 | 347 | if len(args) != 1 { | |
| 373 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user retire <name|id>"} | ||
| 348 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user retire <name>"} | ||
| 374 | 349 | } | |
| 375 | 350 | a, err := s.cfg.Identity.Retire(args[0], actor) | |
| 376 | 351 | if err != nil { | |
| 377 | 352 | return nil, nil, err | |
| 378 | 353 | } | |
| 379 | 354 | return userData(a), func(out, errOut io.Writer) { | |
| 380 | fmt.Fprintf(out, "retired %s\t%s\n", a.Name, a.ID) | ||
| 355 | fmt.Fprintln(out, "retired "+a.Name) | ||
| 381 | 356 | fmt.Fprintln(errOut, "keys stop working within 5s; the name is never reissued") | |
| 382 | 357 | }, nil | |
| 383 | 358 | ||
| @@ -386,7 +361,7 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 386 | 361 | ||
| 387 | 362 | case "grant-admin", "revoke-admin": | |
| 388 | 363 | if len(args) != 1 { | |
| 389 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user " + action + " <name|id>"} | ||
| 364 | return nil, nil, &adminUsageError{msg: "usage: vole-admin user " + action + " <name>"} | ||
| 390 | 365 | } | |
| 391 | 366 | a, err := s.cfg.Identity.SetAdmin(args[0], action == "grant-admin", actor) | |
| 392 | 367 | if err != nil { | |
| @@ -394,9 +369,9 @@ func (s *Server) adminUser(action string, args []string, actor string, in io.Rea | |||
| 394 | 369 | } | |
| 395 | 370 | return userData(a), func(out, _ io.Writer) { | |
| 396 | 371 | if action == "grant-admin" { | |
| 397 | fmt.Fprintf(out, "granted instance admin to %s\t%s\n", a.Name, a.ID) | ||
| 372 | fmt.Fprintln(out, "granted instance admin to "+a.Name) | ||
| 398 | 373 | } else { | |
| 399 | fmt.Fprintf(out, "revoked instance admin from %s\t%s\n", a.Name, a.ID) | ||
| 374 | fmt.Fprintln(out, "revoked instance admin from "+a.Name) | ||
| 400 | 375 | } | |
| 401 | 376 | }, nil | |
| 402 | 377 | } | |
| @@ -471,7 +446,7 @@ func (s *Server) adminRepo(action string, args []string, actor string) (any, adm | |||
| 471 | 446 | if !owner.Active() { | |
| 472 | 447 | return nil, nil, fmt.Errorf("owner %q is retired", owner.Name) | |
| 473 | 448 | } | |
| 474 | m, err := s.cfg.Instance.Repos.Create(f.rest[0], owner.ID, f.one("description")) | ||
| 449 | m, err := s.cfg.Instance.Repos.Create(f.rest[0], owner.Name, f.one("description")) | ||
| 475 | 450 | if err != nil { | |
| 476 | 451 | return nil, nil, err | |
| 477 | 452 | } | |
| @@ -554,7 +529,7 @@ func (s *Server) adminACL(action string, args []string, actor string) (any, admi | |||
| 554 | 529 | if err != nil { | |
| 555 | 530 | return nil, nil, err | |
| 556 | 531 | } | |
| 557 | if err := a.SetEntry(account.ID, role.String()); err != nil { | ||
| 532 | if err := a.SetEntry(account.Name, role.String()); err != nil { | ||
| 558 | 533 | return nil, nil, err | |
| 559 | 534 | } | |
| 560 | 535 | return finish() | |
| @@ -631,7 +606,7 @@ func (s *Server) adminACL(action string, args []string, actor string) (any, admi | |||
| 631 | 606 | if err != nil { | |
| 632 | 607 | return "", err | |
| 633 | 608 | } | |
| 634 | return account.ID, nil | ||
| 609 | return account.Name, nil | ||
| 635 | 610 | } | |
| 636 | 611 | switch { | |
| 637 | 612 | case f.has("clear"): | |
| @@ -700,20 +675,12 @@ func (s *Server) aclResult(m *repo.Meta, a *access.ACL) (any, adminRender, error | |||
| 700 | 675 | entries := make([]map[string]string, 0, len(a.Entries)) | |
| 701 | 676 | for _, principal := range a.Principals() { | |
| 702 | 677 | entries = append(entries, map[string]string{ | |
| 703 | "id": principal, | ||
| 704 | "name": s.cfg.Identity.Name(principal), | ||
| 705 | "display": s.cfg.Identity.Label(principal), | ||
| 706 | "role": a.Entries[principal], | ||
| 707 | }) | ||
| 708 | } | ||
| 709 | runners := make([]map[string]string, 0, len(a.Runners)) | ||
| 710 | for _, runner := range a.Runners { | ||
| 711 | runners = append(runners, map[string]string{ | ||
| 712 | "id": runner, | ||
| 713 | "name": s.cfg.Identity.Name(runner), | ||
| 714 | "display": s.cfg.Identity.Label(runner), | ||
| 678 | "name": principal, | ||
| 679 | "role": a.Entries[principal], | ||
| 715 | 680 | }) | |
| 716 | 681 | } | |
| 682 | runners := make([]string, 0, len(a.Runners)) | ||
| 683 | runners = append(runners, a.Runners...) | ||
| 717 | 684 | data := map[string]any{ | |
| 718 | 685 | "repo": m.Name, | |
| 719 | 686 | "public": a.Can("", access.Read), | |
| @@ -732,7 +699,7 @@ func (s *Server) aclResult(m *repo.Meta, a *access.ACL) (any, adminRender, error | |||
| 732 | 699 | fmt.Fprintf(out, "repo: %s (%s)\n", m.Name, vis) | |
| 733 | 700 | fmt.Fprintf(out, "default: %s\n", a.Default) | |
| 734 | 701 | for _, e := range entries { | |
| 735 | fmt.Fprintf(out, " %-16s %-28s %s\n", e["display"], e["id"], e["role"]) | ||
| 702 | fmt.Fprintf(out, " %-32s %s\n", e["name"], e["role"]) | ||
| 736 | 703 | } | |
| 737 | 704 | if len(a.Protected) > 0 { | |
| 738 | 705 | fmt.Fprintf(out, "protected: %s\n", strings.Join(a.Protected, ", ")) | |
| @@ -748,7 +715,7 @@ func (s *Server) aclResult(m *repo.Meta, a *access.ACL) (any, adminRender, error | |||
| 748 | 715 | return | |
| 749 | 716 | } | |
| 750 | 717 | for _, r := range runners { | |
| 751 | fmt.Fprintf(out, "runner %-28s %s\n", r["id"], r["display"]) | ||
| 718 | fmt.Fprintf(out, "runner %s\n", r) | ||
| 752 | 719 | } | |
| 753 | 720 | fmt.Fprintln(out, "(admins may also report CI results)") | |
| 754 | 721 | }, nil | |
| @@ -790,9 +757,7 @@ func userData(a *identity.Account) map[string]any { | |||
| 790 | 757 | return nil | |
| 791 | 758 | } | |
| 792 | 759 | return map[string]any{ | |
| 793 | "id": a.ID, | ||
| 794 | 760 | "name": a.Name, | |
| 795 | "display": a.Display, | ||
| 796 | 761 | "status": a.Status, | |
| 797 | 762 | "admin": a.Admin, | |
| 798 | 763 | "keys": a.Keys, | |
| @@ -800,7 +765,7 @@ func userData(a *identity.Account) map[string]any { | |||
| 800 | 765 | } | |
| 801 | 766 | } | |
| 802 | 767 | ||
| 803 | func (s *Server) auditAdmin(user, accountID, remote, detail string) { | ||
| 768 | func (s *Server) auditAdmin(user, remote, detail string) { | ||
| 804 | 769 | if s.cfg.AuditPath == "" { | |
| 805 | 770 | return | |
| 806 | 771 | } | |
| @@ -811,8 +776,8 @@ func (s *Server) auditAdmin(user, accountID, remote, detail string) { | |||
| 811 | 776 | return | |
| 812 | 777 | } | |
| 813 | 778 | defer f.Close() | |
| 814 | fmt.Fprintf(f, "%s\tadmin\t%s\t%s\t%s\t%s\n", | ||
| 815 | time.Now().UTC().Format(time.RFC3339), user, accountID, remote, detail) | ||
| 779 | fmt.Fprintf(f, "%s\tadmin\t%s\t%s\t%s\n", | ||
| 780 | time.Now().UTC().Format(time.RFC3339), user, remote, detail) | ||
| 816 | 781 | } | |
| 817 | 782 | ||
| 818 | 783 | // adminFlagSpec and parseAdminFlags are a small local flag parser for the | |