Commit 9ff63ee5ef

9ff63ee5eff7f810bca1fcacf316f57ae4b4aab7

parent: a6378c178c

Verified · cmc ci/build: success ci/test: success

cmc <hello@cleberg.net> · 2026-09-29 15:30 UTC

wiki, changelog: ids not reused after a delete

Closes #306

Layout: unified · split

.gitbay/wiki/Architecture/09-Controls.org +1
@@ -40,6 +40,7 @@ chapter names of OWASP ASVS 4.0 where one fits.
40| Admin functions isolated | in place | =admin= noun gated in =Dispatch=; =audit= admin-only | 40| Admin functions isolated | in place | =admin= noun gated in =Dispatch=; =audit= admin-only |
41| CSRF protection | in place | SameSite=Lax plus =checkOrigin= (=accounts.go=) | 41| CSRF protection | in place | SameSite=Lax plus =checkOrigin= (=accounts.go=) |
42| Typed confirmation for destructive web actions | in place | =internal/httpd/confirm.go= | 42| Typed confirmation for destructive web actions | in place | =internal/httpd/confirm.go= |
43| Deleted rows' ids never handed out again | in place | AUTOINCREMENT on accounts, orgs, repositories, keys, tokens and the delivery queues; build ids from a high-water mark (=internal/store/builds.go=), so a grant, deploy key, parked about text, token or claim naming a deleted row names nothing; deletes take the grants, deploy keys and about texts that name the row by id |
43 44
44** Input handling and output encoding (V5) 45** Input handling and output encoding (V5)
45 46
.gitbay/wiki/Architecture/10-Known-Gaps.org +1
@@ -16,6 +16,7 @@ what the 2026-09-27 review found; remove a row when its issue closes.
16| Area | Gap | Severity | 16| Area | Gap | Severity |
17|-------+-------------------------------------------------------------------------------------------------------------+----------| 17|-------+-------------------------------------------------------------------------------------------------------------+----------|
18| Audit | The hash chain is unkeyed, so whoever can write the database can edit a row and recompute every later hash; removing the newest audit rows, or writing new rows under their freed ids, needs no recomputing at all. Neither is detectable from the database; only comparing =gitbayd admin audit verify='s last id and hash with the daemon's journal shows it. Rows written by =gitbayd shell= (=ssh.mode = "system"=) and host admin commands have no journal copy, and the refusal caps are per process, so under that mode each connection counts separately | low | 18| Audit | The hash chain is unkeyed, so whoever can write the database can edit a row and recompute every later hash; removing the newest audit rows, or writing new rows under their freed ids, needs no recomputing at all. Neither is detectable from the database; only comparing =gitbayd admin audit verify='s last id and hash with the daemon's journal shows it. Rows written by =gitbayd shell= (=ssh.mode = "system"=) and host admin commands have no journal copy, and the refusal caps are per process, so under that mode each connection counts separately | low |
19| Access | Grants and parked profile about texts (=profile_about_backfill=) of deleted accounts and organizations, and deploy keys of deleted repositories, left by deletes before #306, are removed on upgrade and the "schema migrated" log line gives the counts. One whose id a later row had already taken is no longer an orphan and stays with that row; on gitbay.org the orphans found (two grants, one deploy key) name ids no later row had taken | low |
19| Availability | Under =ssh.mode = "system"= each SSH session is a separate =gitbayd shell= process, so the pack-generation limit (=internal/packlimit=, #262) cannot count SSH clones across sessions; only HTTP and git:// share a budget there | low | 20| Availability | Under =ssh.mode = "system"= each SSH session is a separate =gitbayd shell= process, so the pack-generation limit (=internal/packlimit=, #262) cannot count SSH clones across sessions; only HTTP and git:// share a budget there | low |
20| Availability | Pushes have no concurrency limit; =max_pack_bytes= bounds each one, not how many run at once | medium | 21| Availability | Pushes have no concurrency limit; =max_pack_bytes= bounds each one, not how many run at once | medium |
21| Availability | =repo download= (SSH, API) runs =git archive= outside the pack limit; only its two-minute deadline and 512 MiB cap bound it | low | 22| Availability | =repo download= (SSH, API) runs =git archive= outside the pack limit; only its two-minute deadline and 512 MiB cap bound it | low |
CHANGELOG.org +13
@@ -23,6 +23,19 @@ anything beyond "replace the binary and restart" is needed.
23- A reply whose header has a field name outside RFC 5322 =ftext= 23- A reply whose header has a field name outside RFC 5322 =ftext=
24 (=From : x=), no single From, or a repeated To, Cc, Message-ID, 24 (=From : x=), no single From, or a repeated To, Cc, Message-ID,
25 Content-Type or Content-Transfer-Encoding is refused. (#307) 25 Content-Type or Content-Transfer-Encoding is refused. (#307)
26- Ids of accounts, organizations, repositories, SSH keys, API tokens,
27 webhook deliveries, queued pushes and builds are no longer handed out
28 again after a delete. Before, the next row took the id of the newest
29 deleted one, with anything that still named it: a deleted account's
30 repository grants, a deleted repository's deploy keys, signed LFS and
31 reply-by-mail tokens, a runner's claimed build. The migration rebuilds
32 those tables and starts each sequence above every id still named
33 (#306).
34- Deleting an account or organization removes its repository grants
35 and its parked profile about text, and deleting a repository removes
36 its deploy keys. On upgrade, rows of these kinds left by earlier
37 deletes are removed, and the "schema migrated" log line gives how many
38 (#306).
26 39
27* v1.39.0 — 2026-09-29 40* v1.39.0 — 2026-09-29
28 41