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/integration_test.go +61−82

@@ -169,7 +169,7 @@ func newFixtureWith(t *testing.T, tweak func(*config.Config)) *fixture {
169 169 if err != nil {
170 170 t.Fatal(err)
171 171 }
172 owner, err := ident.Create("keenan", "", pub, "test")
172 owner, err := ident.Create("keenan", pub, "test")
173 173 if err != nil {
174 174 t.Fatal(err)
175 175 }
@@ -188,7 +188,7 @@ func newFixtureWith(t *testing.T, tweak func(*config.Config)) *fixture {
188 188
189 189 f := &fixture{
190 190 t: t, cfg: cfg, srv: srv, http: ts, sshAddr: ln.Addr().String(),
191 keyPath: priv, keyPub: pub, repo: "demo", ownerID: owner.ID,
191 keyPath: priv, keyPub: pub, repo: "demo", ownerID: owner.Name,
192 192 }
193 193 t.Cleanup(func() {
194 194 ts.Close()
@@ -196,7 +196,7 @@ func newFixtureWith(t *testing.T, tweak func(*config.Config)) *fixture {
196 196 srv.Close()
197 197 })
198 198
199 m, err := srv.Repos.Create(f.repo, owner.ID, "demo repo")
199 m, err := srv.Repos.Create(f.repo, owner.Name, "demo repo")
200 200 if err != nil {
201 201 t.Fatal(err)
202 202 }
@@ -230,7 +230,7 @@ func keypair(t *testing.T, path string) (pubLine, privPath string) {
230 230 func (f *fixture) addWriter(t *testing.T) string {
231 231 t.Helper()
232 232 pub, priv := keypair(t, filepath.Join(f.cfg.DataDir, "id_writer"))
233 writer, err := f.srv.Identity.Create("wilbur", "", pub, "test")
233 writer, err := f.srv.Identity.Create("wilbur", pub, "test")
234 234 if err != nil {
235 235 t.Fatal(err)
236 236 }
@@ -240,24 +240,25 @@ func (f *fixture) addWriter(t *testing.T) string {
240 240 t.Fatal(err)
241 241 }
242 242 // ACL entries are keyed by account id, not by name.
243 if err := a.SetEntry(writer.ID, "maintain"); err != nil {
243 if err := a.SetEntry(writer.Name, "maintain"); err != nil {
244 244 t.Fatal(err)
245 245 }
246 246 if err := m.SetACL(a, "test"); err != nil {
247 247 t.Fatal(err)
248 248 }
249 f.writerID = writer.ID
249 f.writerID = writer.Name
250 250 return priv
251 251 }
252 252
253 // accountID resolves a name to the account id that approvals and ACLs store.
254 func (f *fixture) accountID(name string) string {
253 // accountName checks that a fixture account is active and returns its name, the
254 // identifier ACLs and approvals store.
255 func (f *fixture) accountName(name string) string {
255 256 f.t.Helper()
256 accountID, ok := f.srv.Identity.ResolveID(name)
257 if !ok {
258 f.t.Fatalf("no account %q", name)
257 a, err := f.srv.Identity.Find(name)
258 if err != nil || !a.Active() {
259 f.t.Fatalf("no active account %q", name)
259 260 }
260 return accountID
261 return a.Name
261 262 }
262 263
263 264 // gitWithKey is f.git with a specific identity.
@@ -999,14 +1000,6 @@ func TestWhoAmIAnswersFromTheInstance(t *testing.T) {
999 1000 if got := strings.TrimSpace(out); got != "keenan" {
1000 1001 t.Fatalf("whoami = %q, want the account name keenan", got)
1001 1002 }
1002 out, _, err = f.cli(clone, "whoami", "--id")
1003 if err != nil {
1004 t.Fatalf("whoami --id: %v", err)
1005 }
1006 if got := strings.TrimSpace(out); got != f.ownerID {
1007 t.Fatalf("whoami --id = %q, want %q", got, f.ownerID)
1008 }
1009
1010 1003 // A filed issue is authored by the account, not by the guess, and the command
1011 1004 // says where to read it.
1012 1005 out, errs, err = f.cli(clone, "issue", "new", "--title", "who am I")
@@ -1114,8 +1107,8 @@ func TestRequestAuthorComesFromTheKey(t *testing.T) {
1114 1107 if !strings.Contains(raw, "author: keenan\n") {
1115 1108 t.Fatalf("request author is not the account:\n%s", raw)
1116 1109 }
1117 if !strings.Contains(raw, "author_id: "+f.ownerID) {
1118 t.Fatalf("request author_id is not the account id %s:\n%s", f.ownerID, raw)
1110 if strings.Contains(raw, "author_id:") {
1111 t.Fatalf("request still carries a second identifier:\n%s", raw)
1119 1112 }
1120 1113 if strings.Contains(raw, "keenan-nemetz") {
1121 1114 t.Fatalf("the git-config guess reached the request:\n%s", raw)
@@ -1212,7 +1205,7 @@ func TestRequestPageSaysWhenItWouldConflict(t *testing.T) {
1212 1205
1213 1206 meta := f.newMetaRepo(t)
1214 1207 if err := meta.apply(map[string]string{
1215 "requests/" + reqID + "/request.md": requestFile("main", head, "keenan", f.ownerID, "why this change\n"),
1208 "requests/" + reqID + "/request.md": requestFile("main", head, "keenan", "why this change\n"),
1216 1209 }, "request"); err != nil {
1217 1210 t.Fatalf("request push: %v", err)
1218 1211 }
@@ -1236,7 +1229,7 @@ func TestRequestPageSaysWhenItWouldConflict(t *testing.T) {
1236 1229 }
1237 1230 const cleanID = "01M5JR2JK29KKMAA1T9MDNTR02"
1238 1231 if err := meta.apply(map[string]string{
1239 "requests/" + cleanID + "/request.md": requestFile("main", cleanHead, "keenan", f.ownerID, "clean change\n"),
1232 "requests/" + cleanID + "/request.md": requestFile("main", cleanHead, "keenan", "clean change\n"),
1240 1233 }, "clean request"); err != nil {
1241 1234 t.Fatalf("clean request push: %v", err)
1242 1235 }
@@ -1280,7 +1273,7 @@ func TestRequestPageSaysWhenItWouldConflict(t *testing.T) {
1280 1273 const ghostID = "01M5JR2JK29KKMAA1T9MDNTR03"
1281 1274 if err := meta.apply(map[string]string{
1282 1275 "requests/" + ghostID + "/request.md": requestFile("main",
1283 "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "keenan", f.ownerID, "ghost head\n"),
1276 "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "keenan", "ghost head\n"),
1284 1277 }, "ghost request"); err != nil {
1285 1278 t.Fatalf("ghost request push: %v", err)
1286 1279 }
@@ -1310,7 +1303,7 @@ func TestRequestDiscussionIsPushedAndOwned(t *testing.T) {
1310 1303 }
1311 1304 meta := f.newMetaRepo(t)
1312 1305 if err := meta.apply(map[string]string{
1313 "requests/" + reqID + "/request.md": requestFile("main", head, "keenan", f.ownerID, "rationale\n"),
1306 "requests/" + reqID + "/request.md": requestFile("main", head, "keenan", "rationale\n"),
1314 1307 }, "request"); err != nil {
1315 1308 t.Fatalf("request push: %v", err)
1316 1309 }
@@ -1431,7 +1424,7 @@ func TestReviewCommentAnchorsALine(t *testing.T) {
1431 1424 }
1432 1425 meta := f.newMetaRepo(t)
1433 1426 if err := meta.apply(map[string]string{
1434 "requests/" + reqID + "/request.md": requestFile("main", head, "keenan", f.ownerID, "rationale\n"),
1427 "requests/" + reqID + "/request.md": requestFile("main", head, "keenan", "rationale\n"),
1435 1428 }, "request"); err != nil {
1436 1429 t.Fatalf("request push: %v", err)
1437 1430 }
@@ -2132,12 +2125,11 @@ const reqID = "01M5JR2JK29KKMAA1T9MDNTR01"
2132 2125
2133 2126 // requestFile renders requests/<id>/request.md. The body is the request's
2134 2127 // description, so a fixture cannot drift from the format the reader expects.
2135 func requestFile(base, head, author, authorID, body string) string {
2128 func requestFile(base, head, author, body string) string {
2136 2129 d := metadata.NewDoc()
2137 2130 d.Text("title", "Land the feature")
2138 2131 d.Word("state", "open")
2139 2132 d.Word("author", author)
2140 d.Word("author_id", authorID)
2141 2133 d.Word("base", base)
2142 2134 d.Word("head", head)
2143 2135 d.Word("created", "2026-10-22T22:00:00Z")
@@ -2149,8 +2141,8 @@ func requestFile(base, head, author, authorID, body string) string {
2149 2141 }
2150 2142
2151 2143 // requestMeta is requestFile with no description: the common fixture shape.
2152 func requestMeta(base, head, author, authorID string) string {
2153 return requestFile(base, head, author, authorID, "")
2144 func requestMeta(base, head, author string) string {
2145 return requestFile(base, head, author, "")
2154 2146 }
2155 2147
2156 2148 func approvalFile(base, head string) string {
@@ -2222,7 +2214,7 @@ func TestProtectedBranchRequiresApprovedRequest(t *testing.T) {
2222 2214 // 2. Request open, no approvals: still refused.
2223 2215 meta := f.newMetaRepo(t)
2224 2216 if err := meta.apply(map[string]string{
2225 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur", f.accountID("wilbur")),
2217 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur"),
2226 2218 }, "request"); err != nil {
2227 2219 t.Fatalf("request push: %v", err)
2228 2220 }
@@ -2235,7 +2227,7 @@ func TestProtectedBranchRequiresApprovedRequest(t *testing.T) {
2235 2227 // 3. Approval by another principal: allowed.
2236 2228 approver := f.newMetaRepo(t)
2237 2229 if err := approver.apply(map[string]string{
2238 "requests/" + reqID + "/approvals/" + f.accountID("keenan") + ".md": approvalFile("main", head),
2230 "requests/" + reqID + "/approvals/" + f.accountName("keenan") + ".md": approvalFile("main", head),
2239 2231 }, "approve"); err != nil {
2240 2232 t.Fatalf("approval push: %v", err)
2241 2233 }
@@ -2274,13 +2266,13 @@ func TestApprovalIsBoundToTheCommit(t *testing.T) {
2274 2266
2275 2267 meta := f.newMetaRepo(t)
2276 2268 if err := meta.apply(map[string]string{
2277 "requests/" + reqID + "/request.md": requestMeta("main", approved, "wilbur", f.accountID("wilbur")),
2269 "requests/" + reqID + "/request.md": requestMeta("main", approved, "wilbur"),
2278 2270 }, "request"); err != nil {
2279 2271 t.Fatalf("request: %v", err)
2280 2272 }
2281 2273 approver := f.newMetaRepo(t)
2282 2274 if err := approver.apply(map[string]string{
2283 "requests/" + reqID + "/approvals/" + f.accountID("keenan") + ".md": approvalFile("main", approved),
2275 "requests/" + reqID + "/approvals/" + f.accountName("keenan") + ".md": approvalFile("main", approved),
2284 2276 }, "approve"); err != nil {
2285 2277 t.Fatalf("approve: %v", err)
2286 2278 }
@@ -2309,8 +2301,8 @@ func TestSelfApprovalRejected(t *testing.T) {
2309 2301
2310 2302 meta := f.newMetaRepo(t)
2311 2303 err := meta.apply(map[string]string{
2312 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur", f.accountID("wilbur")),
2313 "requests/" + reqID + "/approvals/" + f.accountID("wilbur") + ".md": approvalFile("main", head),
2304 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur"),
2305 "requests/" + reqID + "/approvals/" + f.accountName("wilbur") + ".md": approvalFile("main", head),
2314 2306 }, "self approve")
2315 2307 if err == nil {
2316 2308 t.Fatal("a self-approval was accepted")
@@ -2346,13 +2338,13 @@ func TestMergeCommitShapeAllowed(t *testing.T) {
2346 2338 }
2347 2339 meta := f.newMetaRepo(t)
2348 2340 if err := meta.apply(map[string]string{
2349 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur", f.accountID("wilbur")),
2341 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur"),
2350 2342 }, "request"); err != nil {
2351 2343 t.Fatalf("request: %v", err)
2352 2344 }
2353 2345 approver := f.newMetaRepo(t)
2354 2346 if err := approver.apply(map[string]string{
2355 "requests/" + reqID + "/approvals/" + f.accountID("keenan") + ".md": approvalFile("main", head),
2347 "requests/" + reqID + "/approvals/" + f.accountName("keenan") + ".md": approvalFile("main", head),
2356 2348 }, "approve"); err != nil {
2357 2349 t.Fatalf("approve: %v", err)
2358 2350 }
@@ -2391,7 +2383,7 @@ func TestImpersonatedApprovalRejected(t *testing.T) {
2391 2383
2392 2384 meta := f.newMetaRepo(t)
2393 2385 if err := meta.apply(map[string]string{
2394 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur", f.accountID("wilbur")),
2386 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur"),
2395 2387 }, "request"); err != nil {
2396 2388 t.Fatalf("request: %v", err)
2397 2389 }
@@ -2399,7 +2391,7 @@ func TestImpersonatedApprovalRejected(t *testing.T) {
2399 2391 impostor := f.newMetaRepo(t)
2400 2392 impostor.key = writerKey
2401 2393 err := impostor.apply(map[string]string{
2402 "requests/" + reqID + "/approvals/" + f.accountID("keenan") + ".md": approvalFile("main", head),
2394 "requests/" + reqID + "/approvals/" + f.accountName("keenan") + ".md": approvalFile("main", head),
2403 2395 }, "approve as someone else")
2404 2396 if err == nil {
2405 2397 t.Fatal("a writer approved in another principal's name")
@@ -2434,13 +2426,13 @@ func TestApprovalIsBoundToTheBase(t *testing.T) {
2434 2426 feature, head := f.cloneWithChange(t, map[string]string{"a.md": "v2\n"}, "feature")
2435 2427 meta := f.newMetaRepo(t)
2436 2428 if err := meta.apply(map[string]string{
2437 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur", f.accountID("wilbur")),
2429 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur"),
2438 2430 }, "request"); err != nil {
2439 2431 t.Fatalf("request: %v", err)
2440 2432 }
2441 2433 approver := f.newMetaRepo(t)
2442 2434 if err := approver.apply(map[string]string{
2443 "requests/" + reqID + "/approvals/" + f.accountID("keenan") + ".md": approvalFile("main", head),
2435 "requests/" + reqID + "/approvals/" + f.accountName("keenan") + ".md": approvalFile("main", head),
2444 2436 }, "approve"); err != nil {
2445 2437 t.Fatalf("approve: %v", err)
2446 2438 }
@@ -2448,7 +2440,7 @@ func TestApprovalIsBoundToTheBase(t *testing.T) {
2448 2440 // Repoint the request at release. The approval named main.
2449 2441 repoint := f.newMetaRepo(t)
2450 2442 if err := repoint.apply(map[string]string{
2451 "requests/" + reqID + "/request.md": requestMeta("release", head, "wilbur", f.accountID("wilbur")),
2443 "requests/" + reqID + "/request.md": requestMeta("release", head, "wilbur"),
2452 2444 }, "repoint"); err != nil {
2453 2445 t.Fatalf("repoint: %v", err)
2454 2446 }
@@ -2475,8 +2467,8 @@ func TestFirstPushCannotSeedForeignApprovals(t *testing.T) {
2475 2467 meta := f.newMetaRepo(t)
2476 2468 meta.key = writerKey
2477 2469 err := meta.apply(map[string]string{
2478 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur", f.accountID("wilbur")),
2479 "requests/" + reqID + "/approvals/" + f.accountID("keenan") + ".md": approvalFile("main", head),
2470 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur"),
2471 "requests/" + reqID + "/approvals/" + f.accountName("keenan") + ".md": approvalFile("main", head),
2480 2472 }, "seed")
2481 2473 if err == nil {
2482 2474 t.Fatal("the first push seeded an approval in another principal's name")
@@ -2511,13 +2503,13 @@ func TestModifiedApprovalCannotBeForged(t *testing.T) {
2511 2503 }
2512 2504 meta := f.newMetaRepo(t)
2513 2505 if err := meta.apply(map[string]string{
2514 "requests/" + reqID + "/request.md": requestMeta("main", approvedHead, "wilbur", f.accountID("wilbur")),
2506 "requests/" + reqID + "/request.md": requestMeta("main", approvedHead, "wilbur"),
2515 2507 }, "request"); err != nil {
2516 2508 t.Fatalf("request: %v", err)
2517 2509 }
2518 2510 approver := f.newMetaRepo(t)
2519 2511 if err := approver.apply(map[string]string{
2520 "requests/" + reqID + "/approvals/" + f.accountID("keenan") + ".md": approvalFile("main", approvedHead),
2512 "requests/" + reqID + "/approvals/" + f.accountName("keenan") + ".md": approvalFile("main", approvedHead),
2521 2513 }, "approve"); err != nil {
2522 2514 t.Fatalf("approve: %v", err)
2523 2515 }
@@ -2533,8 +2525,8 @@ func TestModifiedApprovalCannotBeForged(t *testing.T) {
2533 2525 forger := f.newMetaRepo(t)
2534 2526 forger.key = writerKey
2535 2527 err := forger.apply(map[string]string{
2536 "requests/" + reqID + "/request.md": requestMeta("main", sneaky, "wilbur", f.accountID("wilbur")),
2537 "requests/" + reqID + "/approvals/" + f.accountID("keenan") + ".md": approvalFile("main", sneaky),
2528 "requests/" + reqID + "/request.md": requestMeta("main", sneaky, "wilbur"),
2529 "requests/" + reqID + "/approvals/" + f.accountName("keenan") + ".md": approvalFile("main", sneaky),
2538 2530 }, "repoint approval")
2539 2531 if err == nil {
2540 2532 t.Fatal("a writer rewrote another principal's approval and the push was accepted")
@@ -2561,13 +2553,13 @@ func TestApprovalDeletionIsOwnerOrAdmin(t *testing.T) {
2561 2553 meta := f.newMetaRepo(t)
2562 2554 meta.key = writerKey
2563 2555 if err := meta.apply(map[string]string{
2564 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur", f.accountID("wilbur")),
2556 "requests/" + reqID + "/request.md": requestMeta("main", head, "wilbur"),
2565 2557 }, "request"); err != nil {
2566 2558 t.Fatalf("setup: %v", err)
2567 2559 }
2568 2560 approver := f.newMetaRepo(t)
2569 2561 if err := approver.apply(map[string]string{
2570 "requests/" + reqID + "/approvals/" + f.accountID("keenan") + ".md": approvalFile("main", head),
2562 "requests/" + reqID + "/approvals/" + f.accountName("keenan") + ".md": approvalFile("main", head),
2571 2563 }, "approve"); err != nil {
2572 2564 t.Fatalf("approve: %v", err)
2573 2565 }
@@ -2576,7 +2568,7 @@ func TestApprovalDeletionIsOwnerOrAdmin(t *testing.T) {
2576 2568 deleter := f.newMetaRepo(t)
2577 2569 deleter.key = writerKey
2578 2570 deleter.sync()
2579 if err := os.Remove(filepath.Join(deleter.dir, "requests", reqID, "approvals", f.accountID("keenan")+".md")); err != nil {
2571 if err := os.Remove(filepath.Join(deleter.dir, "requests", reqID, "approvals", f.accountName("keenan")+".md")); err != nil {
2580 2572 t.Fatal(err)
2581 2573 }
2582 2574 if _, errs, err := runGit(t, deleter.dir, "add", "-A"); err != nil {
@@ -2596,7 +2588,7 @@ func TestApprovalDeletionIsOwnerOrAdmin(t *testing.T) {
2596 2588 // keenan withdraws his own.
2597 2589 own := f.newMetaRepo(t)
2598 2590 own.sync()
2599 if err := os.Remove(filepath.Join(own.dir, "requests", reqID, "approvals", f.accountID("keenan")+".md")); err != nil {
2591 if err := os.Remove(filepath.Join(own.dir, "requests", reqID, "approvals", f.accountName("keenan")+".md")); err != nil {
2600 2592 t.Fatal(err)
2601 2593 }
2602 2594 if _, errs, cerr := runGit(t, own.dir, "add", "-A"); cerr != nil {
@@ -2610,11 +2602,9 @@ func TestApprovalDeletionIsOwnerOrAdmin(t *testing.T) {
2610 2602 }
2611 2603 }
2612 2604
2613 // TestDisplayNameChangeKeepsAccessAndApprovalOwnership: ACL entries and approval
2614 // files hold the account id, metadata authors hold the fixed account name, and a
2615 // display name is only a label — so relabelling a person must not change what
2616 // they may do, who owns their past approvals, or whose name their comments carry.
2617 func TestDisplayNameChangeKeepsAccessAndApprovalOwnership(t *testing.T) {
2605 // TestAccessAndApprovalOwnershipFollowTheName: ACL entries and approval files
2606 // are keyed by the same registered name metadata authors carry.
2607 func TestAccessAndApprovalOwnershipFollowTheName(t *testing.T) {
2618 2608 t.Parallel()
2619 2609 f := newFixture(t)
2620 2610 writerKey := f.addWriter(t)
@@ -2628,49 +2618,38 @@ func TestDisplayNameChangeKeepsAccessAndApprovalOwnership(t *testing.T) {
2628 2618 // keenan authors a request; wilbur (the writer) approves it.
2629 2619 meta := f.newMetaRepo(t)
2630 2620 if err := meta.apply(map[string]string{
2631 "requests/" + reqID + "/request.md": requestMeta("main", head, "keenan", f.ownerID),
2621 "requests/" + reqID + "/request.md": requestMeta("main", head, "keenan"),
2632 2622 }, "request"); err != nil {
2633 2623 t.Fatalf("request: %v", err)
2634 2624 }
2635 2625 approver := f.newMetaRepo(t)
2636 2626 approver.key = writerKey
2637 2627 if err := approver.apply(map[string]string{
2638 "requests/" + reqID + "/approvals/" + f.writerID + ".md": approvalFile("main", head),
2628 "requests/" + reqID + "/approvals/wilbur.md": approvalFile("main", head),
2639 2629 }, "approve"); err != nil {
2640 2630 t.Fatalf("approve: %v", err)
2641 2631 }
2642 2632
2643 if _, err := f.srv.Identity.SetDisplay("wilbur", "Wilbur Wright", "test"); err != nil {
2644 t.Fatal(err)
2645 }
2646 if got := f.srv.Identity.Label(f.writerID); got != "Wilbur Wright" {
2647 t.Fatalf("label = %q, want the display name", got)
2648 }
2649 if got := f.srv.Identity.Name(f.writerID); got != "wilbur" {
2650 t.Fatalf("name changed to %q; the name is not a display label", got)
2651 }
2652
2653 // Access follows the id: the same key still has write, under the same name.
2633 // The same key still has write, under the same name.
2654 2634 issue := f.newMetaRepo(t)
2655 2635 issue.key = writerKey
2656 2636 if err := issue.apply(map[string]string{
2657 "issues/01M5JR2JK29KKMAA1T9MDNTZ01/issue.md": issueFile("after display change", "wilbur", "open", "2026-10-22T22:00:00Z", nil, ""),
2658 }, "issue after display change"); err != nil {
2637 "issues/01M5JR2JK29KKMAA1T9MDNTZ01/issue.md": issueFile("after approval", "wilbur", "open", "2026-10-22T22:00:00Z", nil, ""),
2638 }, "issue after approval"); err != nil {
2659 2639 t.Fatalf("the account lost its access: %v", err)
2660 2640 }
2661 2641
2662 // Ownership follows the id too: wilbur may withdraw the approval they wrote,
2663 // because the file is named after the account, not the display name.
2642 // wilbur may withdraw the approval they wrote.
2664 2643 withdraw := f.newMetaRepo(t)
2665 2644 withdraw.key = writerKey
2666 2645 withdraw.sync()
2667 if err := os.Remove(filepath.Join(withdraw.dir, "requests", reqID, "approvals", f.writerID+".md")); err != nil {
2646 if err := os.Remove(filepath.Join(withdraw.dir, "requests", reqID, "approvals", "wilbur.md")); err != nil {
2668 2647 t.Fatal(err)
2669 2648 }
2670 2649 if _, errs, err := runGit(t, withdraw.dir, "add", "-A"); err != nil {
2671 2650 t.Fatalf("add: %v: %s", err, errs)
2672 2651 }
2673 if _, errs, err := runGit(t, withdraw.dir, "commit", "-qm", "withdraw after display change"); err != nil {
2652 if _, errs, err := runGit(t, withdraw.dir, "commit", "-qm", "withdraw approval"); err != nil {
2674 2653 t.Fatalf("commit: %v: %s", err, errs)
2675 2654 }
2676 2655 if _, errs, err := fgit(t, writerKey, withdraw.dir, "push", "origin", "HEAD:refs/heads/vole"); err != nil {
@@ -2694,7 +2673,7 @@ func TestRetiredNameCannotBeReissued(t *testing.T) {
2694 2673 t.Fatal(err)
2695 2674 }
2696 2675 reissue, _ := keypair(t, filepath.Join(f.cfg.DataDir, "id_reissued"))
2697 if _, err := f.srv.Identity.Create("wilbur", "", reissue, "test"); err == nil {
2676 if _, err := f.srv.Identity.Create("wilbur", reissue, "test"); err == nil {
2698 2677 t.Fatal("the retired name was reissued")
2699 2678 }
2700 2679 // And the retired key no longer authenticates.
@@ -3254,7 +3233,7 @@ func (f *fixture) openAndApprove(t *testing.T, head, author string) {
3254 3233 t.Helper()
3255 3234 meta := f.newMetaRepo(t)
3256 3235 if err := meta.apply(map[string]string{
3257 "requests/" + reqID + "/request.md": requestMeta("main", head, author, f.accountID(author)),
3236 "requests/" + reqID + "/request.md": requestMeta("main", head, author),
3258 3237 }, "request"); err != nil {
3259 3238 t.Fatalf("request: %v", err)
3260 3239 }
@@ -3307,7 +3286,7 @@ func TestOnlyAllowedRunnersGreenLightABranch(t *testing.T) {
3307 3286 t.Parallel()
3308 3287 f := newFixtureWith(t, func(c *config.Config) { c.LeaseSeconds = 2 })
3309 3288 writerKey := f.addWriter(t)
3310 wilbur := f.accountID("wilbur")
3289 wilbur := f.accountName("wilbur")
3311 3290 f.publish(f.repo)
3312 3291 if _, errs, err := f.git(workRepo(t, map[string]string{"a.md": "a\n"}),
3313 3292 "push", f.sshURL(f.repo), "main:refs/heads/main"); err != nil {
@@ -3401,7 +3380,7 @@ func TestACLRunnersEditsTheList(t *testing.T) {
3401 3380 } else if !strings.Contains(out, "wilbur") {
3402 3381 t.Fatalf("add did not report the account:\n%s", out)
3403 3382 }
3404 if got := runners(); len(got) != 1 || got[0] != f.accountID("wilbur") {
3383 if got := runners(); len(got) != 1 || got[0] != f.accountName("wilbur") {
3405 3384 t.Fatalf("runners after --add wilbur = %#v", got)
3406 3385 }
3407 3386