Commit 4bbf4f8114

4bbf4f8114d6f71fa70239a08a477147a4b0336c

parent: 2b840816c9

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

cmc <hello@cleberg.net> · 2026-09-28 06:44 UTC

wiki: revocation closes open connections

Closes #256

Layout: unified · split

.gitbay/wiki/Architecture/05-Identity-and-Access.org +2 −2
@@ -15,8 +15,8 @@
15 15
16| Credential | Format and generation | Stored as | Scope | Expiry | Revocation | 16| Credential | Format and generation | Stored as | Scope | Expiry | Revocation |
17|--------------------+-------------------------------------------------+----------------------------------+--------------------------------------------+-------------------------------+-------------------------------------| 17|--------------------+-------------------------------------------------+----------------------------------+--------------------------------------------+-------------------------------+-------------------------------------|
18| SSH user key | user's public key | fingerprint and public blob | =full=, =git=, or =runner= | none | =keys remove= (own keys) | 18| SSH user key | user's public key | fingerprint and public blob | =full=, =git=, or =runner= | none | =keys remove= (own keys); closes its connections |
19| Deploy key | public key | same table, scope =deploy:<repo>:ro/rw= | one repository, read or read-write | none | =repo deploy-key remove= (repo admin) | 19| Deploy key | public key | same table, scope =deploy:<repo>:ro/rw= | one repository, read or read-write | none | =repo deploy-key remove= (repo admin); closes its connections |
20| API token | =gb_= + 32 random bytes hex | SHA-256 hash | =full= or =read= | optional =--ttl= | =token revoke= | 20| API token | =gb_= + 32 random bytes hex | SHA-256 hash | =full= or =read= | optional =--ttl= | =token revoke= |
21| Web session | 32 random bytes hex, cookie =gitbay_session= | SHA-256 hash | full account | 7 days, no sliding renewal | logout, =web sessions revoke= | 21| Web session | 32 random bytes hex, cookie =gitbay_session= | SHA-256 hash | full account | 7 days, no sliding renewal | logout, =web sessions revoke= |
22| Login link | 32 random bytes hex in a URL | SHA-256 hash, single use | creates a web session | 15 min (mail), 5 min (SSH) | consumed on use | 22| Login link | 32 random bytes hex in a URL | SHA-256 hash, single use | creates a web session | 15 min (mail), 5 min (SSH) | consumed on use |
.gitbay/wiki/Architecture/08-Operations.org −3
@@ -84,6 +84,3 @@ is preserved.
84| Hide a repository | =admin repo visibility <repo> private= | 84| Hide a repository | =admin repo visibility <repo> private= |
85| Close registration | =registration.mode = "closed"= and restart | 85| Close registration | =registration.mode = "closed"= and restart |
86| See what happened | =audit= (filter by actor, action, time) | 86| See what happened | =audit= (filter by actor, action, time) |
87
88Open connections of a removed key keep working until they close; see
89#256.
.gitbay/wiki/Architecture/09-Controls.org +1 −1
@@ -25,7 +25,7 @@ chapter names of OWASP ASVS 4.0 where one fits.
25| Session cookie flags | in place | HttpOnly, SameSite=Lax, Secure with TLS (=internal/httpd/accounts.go=) | 25| Session cookie flags | in place | HttpOnly, SameSite=Lax, Secure with TLS (=internal/httpd/accounts.go=) |
26| Session lifetime | partial | 7 days absolute, no idle timeout (#276) | 26| Session lifetime | partial | 7 days absolute, no idle timeout (#276) |
27| Credential expiry | partial | API tokens optional; SSH and deploy keys none (#277) | 27| Credential expiry | partial | API tokens optional; SSH and deploy keys none (#277) |
28| Revocation takes effect immediately | gap | removed SSH key keeps open connections (#256) | 28| Revocation takes effect immediately | in place | removing a key or disabling an account closes its connections; every exec re-reads its key (=internal/sshd/sshd.go=) |
29| Delegation bounded by the delegating credential | gap | expiring tokens can mint lasting credentials (#257) | 29| Delegation bounded by the delegating credential | gap | expiring tokens can mint lasting credentials (#257) |
30 30
31** Access control (V4) 31** Access control (V4)
.gitbay/wiki/Architecture/10-Known-Gaps.org +1 −3
@@ -11,7 +11,6 @@ what the 2026-09-27 review found; remove a row when its issue closes.
11| Issue | Area | Gap | Severity | 11| Issue | Area | Gap | Severity |
12|-------+------------------+-----------------------------------------------------------------------+----------| 12|-------+------------------+-----------------------------------------------------------------------+----------|
13| #255 | CI isolation | Untrusted and trusted builds of a repository share a writable build home | high | 13| #255 | CI isolation | Untrusted and trusted builds of a repository share a writable build home | high |
14| #256 | Authentication | A removed SSH key keeps working on connections already open | high |
15| #257 | Credentials | An expiring token can create credentials that outlive it; tokens default to full scope | high | 14| #257 | Credentials | An expiring token can create credentials that outlive it; tokens default to full scope | high |
16| #258 | CI integrity | Any writer can post a =ci/*= status; tree reuse ignores trust and image | high | 15| #258 | CI integrity | Any writer can post a =ci/*= status; tree reuse ignores trust and image | high |
17| #259 | Recovery | No restore has been exercised; verification does not check git connectivity | high | 16| #259 | Recovery | No restore has been exercised; verification does not check git connectivity | high |
@@ -29,8 +28,7 @@ what the 2026-09-27 review found; remove a row when its issue closes.
29| #281 | TLS | No explicit minimum TLS version | low | 28| #281 | TLS | No explicit minimum TLS version | low |
30| #282 | Hook socket | Anything that can open =hook.sock= can act as any user | medium | 29| #282 | Hook socket | Anything that can open =hook.sock= can act as any user | medium |
31 30
32Decisions already taken on these: #256 closes a removed key's 31Decisions already taken on these: #257 refuses credential
33connections, running commands included; #257 refuses credential
34creation from expiring tokens, records which token created each 32creation from expiring tokens, records which token created each
35credential, and makes =read= the default scope. 33credential, and makes =read= the default scope.
36 34
.gitbay/wiki/Threat-Model.org +9
@@ -36,6 +36,15 @@ matrix and the open gaps are in the [[file:Architecture/00-Overview.org][Archite
36 36
37- *SSH public key = identity.* The SSH username is ignored; the presented 37- *SSH public key = identity.* The SSH username is ignored; the presented
38 key's fingerprint resolves to an account. Key uniqueness is global. 38 key's fingerprint resolves to an account. Key uniqueness is global.
39- *Revocation is immediate.* Every exec and every git transport session
40 re-reads its key. Removing a key, removing a deploy key, disabling or
41 deleting an account closes the connections the affected keys opened:
42 a git transport is killed with its children, and a push killed before
43 its pre-receive hook answers moves no ref. A control command already
44 inside its database write finishes it; its output is lost. A
45 revocation made by =gitbayd admin= on the host, another process, is
46 found within 15 seconds. In =ssh.mode = "system"= each exec is its
47 own process: the next exec is refused, one already running is not cut.
39- *Per-instance trust.* Email verification and key registration are local 48- *Per-instance trust.* Email verification and key registration are local
40 to an instance and never transfer. Account migration re-registers keys 49 to an instance and never transfer. Account migration re-registers keys
41 and re-verifies emails on the target by design. 50 and re-verifies emails on the target by design.
.gitbay/wiki/Users.org +4
@@ -69,6 +69,10 @@ A key's label is the comment on its =authorized_keys= line unless
69=--label= gives one; =keys label= renames a key, and with no text 69=--label= gives one; =keys label= renames a key, and with no text
70clears the name. Labels are one line of up to 64 bytes. 70clears the name. Labels are one line of up to 64 bytes.
71 71
72Removing a key closes every connection it opened, including the CLI's
73shared one; removing the key the current command runs on ends that
74command's connection too.
75
72Scopes: =full= (default; git plus every control command), =git= (git 76Scopes: =full= (default; git plus every control command), =git= (git
73transport only — right for automation keys, which then cannot touch 77transport only — right for automation keys, which then cannot touch
74issues, settings, or your account), or =runner= (the CI runner's 78issues, settings, or your account), or =runner= (the CI runner's
CHANGELOG.org +6
@@ -4,6 +4,12 @@ Versioning follows semver from v0.1.0. Database migrations run
4automatically on daemon start; upgrade notes appear per release when 4automatically on daemon start; upgrade notes appear per release when
5anything beyond "replace the binary and restart" is needed. 5anything beyond "replace the binary and restart" is needed.
6 6
7* unreleased
8
9- Removing an SSH key, removing a deploy key, or disabling or deleting an
10 account closes every open connection using an affected key, git
11 transports included; every command re-reads its key (#256).
12
7* v1.36.0 — 2026-09-23 13* v1.36.0 — 2026-09-23
8 14
9Terminal output for the CLI (#254). 15Terminal output for the CLI (#254).