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.

forge/session/session_test.go +23−23

@@ -52,7 +52,7 @@ func (f *fixture) account(t *testing.T, name string) *identity.Account {
52 52 if err != nil {
53 53 t.Fatal(err)
54 54 }
55 a, err := f.ident.Create(name, "", strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))), "test")
55 a, err := f.ident.Create(name, strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))), "test")
56 56 if err != nil {
57 57 t.Fatal(err)
58 58 }
@@ -70,7 +70,7 @@ func (f *fixture) credential(t *testing.T, a *identity.Account) identity.Credent
70 70 t.Fatal(err)
71 71 }
72 72 cred := identity.Credential{ID: id, PublicKey: pub, Label: "laptop"}
73 if err := f.ident.AddCredential(a.ID, cred, "test"); err != nil {
73 if err := f.ident.AddCredential(a.Name, cred, "test"); err != nil {
74 74 t.Fatal(err)
75 75 }
76 76 return cred
@@ -80,7 +80,7 @@ func TestCreateLookupAndRevoke(t *testing.T) {
80 80 t.Parallel()
81 81 f := newFixture(t)
82 82 a := f.account(t, "alice")
83 sess, err := f.store.Create(a.ID, nil, "test-agent")
83 sess, err := f.store.Create(a.Name, nil, "test-agent")
84 84 if err != nil {
85 85 t.Fatal(err)
86 86 }
@@ -99,7 +99,7 @@ func TestCreateLookupAndRevoke(t *testing.T) {
99 99 if err != nil {
100 100 t.Fatal(err)
101 101 }
102 if got.AccountID != a.ID || got.UserAgent != "test-agent" || got.Token != "" {
102 if got.Name != a.Name || got.UserAgent != "test-agent" || got.Token != "" {
103 103 t.Fatalf("lookup = %+v", got)
104 104 }
105 105 if _, err := f.store.Lookup("not-a-token"); !errors.Is(err, ErrNoSession) {
@@ -122,7 +122,7 @@ func TestIdleExpiryAndSlidingUse(t *testing.T) {
122 122 f.store.Idle = time.Hour
123 123 f.store.Absolute = 24 * time.Hour
124 124 a := f.account(t, "alice")
125 sess, err := f.store.Create(a.ID, nil, "agent")
125 sess, err := f.store.Create(a.Name, nil, "agent")
126 126 if err != nil {
127 127 t.Fatal(err)
128 128 }
@@ -147,7 +147,7 @@ func TestAbsoluteExpiry(t *testing.T) {
147 147 f.store.Idle = 100 * time.Hour
148 148 f.store.Absolute = 2 * time.Hour
149 149 a := f.account(t, "alice")
150 sess, err := f.store.Create(a.ID, nil, "agent")
150 sess, err := f.store.Create(a.Name, nil, "agent")
151 151 if err != nil {
152 152 t.Fatal(err)
153 153 }
@@ -161,7 +161,7 @@ func TestLastSeenIsWrittenCoarsely(t *testing.T) {
161 161 t.Parallel()
162 162 f := newFixture(t)
163 163 a := f.account(t, "alice")
164 sess, err := f.store.Create(a.ID, nil, "agent")
164 sess, err := f.store.Create(a.Name, nil, "agent")
165 165 if err != nil {
166 166 t.Fatal(err)
167 167 }
@@ -171,7 +171,7 @@ func TestLastSeenIsWrittenCoarsely(t *testing.T) {
171 171 t.Fatal(err)
172 172 }
173 173 var seen int64
174 if err := f.store.db.QueryRow(`SELECT last_seen FROM sessions WHERE account_id=?`, a.ID).Scan(&seen); err != nil {
174 if err := f.store.db.QueryRow(`SELECT last_seen FROM sessions WHERE user_name=?`, a.Name).Scan(&seen); err != nil {
175 175 t.Fatal(err)
176 176 }
177 177 if seen != f.now.Unix() || seen == first {
@@ -183,7 +183,7 @@ func TestLastSeenIsWrittenCoarsely(t *testing.T) {
183 183 t.Fatal(err)
184 184 }
185 185 var again int64
186 if err := f.store.db.QueryRow(`SELECT last_seen FROM sessions WHERE account_id=?`, a.ID).Scan(&again); err != nil {
186 if err := f.store.db.QueryRow(`SELECT last_seen FROM sessions WHERE user_name=?`, a.Name).Scan(&again); err != nil {
187 187 t.Fatal(err)
188 188 }
189 189 if again != seen {
@@ -196,11 +196,11 @@ func TestRevokeAccountAndCredential(t *testing.T) {
196 196 f := newFixture(t)
197 197 a := f.account(t, "alice")
198 198 cred := f.credential(t, a)
199 byCredential, err := f.store.Create(a.ID, cred.ID, "laptop")
199 byCredential, err := f.store.Create(a.Name, cred.ID, "laptop")
200 200 if err != nil {
201 201 t.Fatal(err)
202 202 }
203 byCookie, err := f.store.Create(a.ID, nil, "other")
203 byCookie, err := f.store.Create(a.Name, nil, "other")
204 204 if err != nil {
205 205 t.Fatal(err)
206 206 }
@@ -217,7 +217,7 @@ func TestRevokeAccountAndCredential(t *testing.T) {
217 217 if _, err := f.store.Lookup(byCookie.Token); err != nil {
218 218 t.Fatalf("unrelated session was revoked: %v", err)
219 219 }
220 n, err = f.store.RevokeAccount(a.ID)
220 n, err = f.store.RevokeAccount(a.Name)
221 221 if err != nil {
222 222 t.Fatal(err)
223 223 }
@@ -234,27 +234,27 @@ func TestRetireAndCredentialRemovalEndSessions(t *testing.T) {
234 234 f := newFixture(t)
235 235 a := f.account(t, "alice")
236 236 cred := f.credential(t, a)
237 sess, err := f.store.Create(a.ID, cred.ID, "laptop")
237 sess, err := f.store.Create(a.Name, cred.ID, "laptop")
238 238 if err != nil {
239 239 t.Fatal(err)
240 240 }
241 if err := f.ident.RemoveCredential(a.ID, cred.ID, "test"); err != nil {
241 if err := f.ident.RemoveCredential(a.Name, cred.ID, "test"); err != nil {
242 242 t.Fatal(err)
243 243 }
244 244 if _, err := f.store.Lookup(sess.Token); !errors.Is(err, ErrNoSession) {
245 245 t.Fatal("removing the passkey left its session alive")
246 246 }
247 sess, err = f.store.Create(a.ID, nil, "cookie")
247 sess, err = f.store.Create(a.Name, nil, "cookie")
248 248 if err != nil {
249 249 t.Fatal(err)
250 250 }
251 if _, err := f.ident.Retire(a.ID, "test"); err != nil {
251 if _, err := f.ident.Retire(a.Name, "test"); err != nil {
252 252 t.Fatal(err)
253 253 }
254 254 if _, err := f.store.Lookup(sess.Token); !errors.Is(err, ErrNoSession) {
255 255 t.Fatal("retiring the account left its session alive")
256 256 }
257 if _, err := f.store.Create(a.ID, nil, "retired"); !errors.Is(err, ErrNoAccount) {
257 if _, err := f.store.Create(a.Name, nil, "retired"); !errors.Is(err, ErrNoAccount) {
258 258 t.Fatalf("created a session for a retired account: %v", err)
259 259 }
260 260 }
@@ -263,14 +263,14 @@ func TestListShowsLiveSessionsWithoutTokens(t *testing.T) {
263 263 t.Parallel()
264 264 f := newFixture(t)
265 265 a := f.account(t, "alice")
266 if _, err := f.store.Create(a.ID, nil, "one"); err != nil {
266 if _, err := f.store.Create(a.Name, nil, "one"); err != nil {
267 267 t.Fatal(err)
268 268 }
269 269 f.now = f.now.Add(time.Minute)
270 if _, err := f.store.Create(a.ID, nil, "two"); err != nil {
270 if _, err := f.store.Create(a.Name, nil, "two"); err != nil {
271 271 t.Fatal(err)
272 272 }
273 list, err := f.store.List(a.ID)
273 list, err := f.store.List(a.Name)
274 274 if err != nil {
275 275 t.Fatal(err)
276 276 }
@@ -290,11 +290,11 @@ func TestRevokeAll(t *testing.T) {
290 290 f := newFixture(t)
291 291 alice := f.account(t, "alice")
292 292 bob := f.account(t, "bob")
293 a, err := f.store.Create(alice.ID, nil, "one")
293 a, err := f.store.Create(alice.Name, nil, "one")
294 294 if err != nil {
295 295 t.Fatal(err)
296 296 }
297 b, err := f.store.Create(bob.ID, nil, "two")
297 b, err := f.store.Create(bob.Name, nil, "two")
298 298 if err != nil {
299 299 t.Fatal(err)
300 300 }
@@ -318,7 +318,7 @@ func TestCreateRejectsAnotherAccountsPasskey(t *testing.T) {
318 318 alice := f.account(t, "alice")
319 319 bob := f.account(t, "bob")
320 320 cred := f.credential(t, alice)
321 if _, err := f.store.Create(bob.ID, cred.ID, "wrong"); !errors.Is(err, ErrCredentialMismatch) {
321 if _, err := f.store.Create(bob.Name, cred.ID, "wrong"); !errors.Is(err, ErrCredentialMismatch) {
322 322 t.Fatalf("created a session for somebody else's passkey: %v", err)
323 323 }
324 324 }