wiki: Architecture fixes; review gaps filed as #273-#282 !476
11 files changed, +34 −41
Layout: unified · split
.gitbay/wiki/Architecture/00-Overview.org +6 −6
| @@ -38,13 +38,13 @@ the =ReadOnly= count from the =ReadOnly: true= literals in | |||
| 38 | 38 | ||
| 39 | | # | Document | Diagram | | 39 | | # | Document | Diagram | |
| 40 | |---+----------------------------------------------------+-------------------------------------------------| | 40 | |---+----------------------------------------------------+-------------------------------------------------| |
| 41 | | 1 | [[file:01-System-Context.org][System context]] | [[file:diagrams/01-context.svg][01-context.svg]] | | 41 | | 1 | [[file:01-System-Context.org][System context]] | =01-context.svg= | |
| 42 | | 2 | [[file:02-Components.org][Components]] | [[file:diagrams/02-components.svg][02-components.svg]] | | 42 | | 2 | [[file:02-Components.org][Components]] | =02-components.svg= | |
| 43 | | 3 | [[file:03-Deployment.org][Deployment and network]] | [[file:diagrams/03-deployment.svg][03-deployment.svg]] | | 43 | | 3 | [[file:03-Deployment.org][Deployment and network]] | =03-deployment.svg= | |
| 44 | | 4 | [[file:04-Trust-Boundaries.org][Trust boundaries and data flows]] | [[file:diagrams/04-trust-boundaries.svg][04-trust-boundaries.svg]], [[file:diagrams/06-push-flow.svg][06-push-flow.svg]] | | 44 | | 4 | [[file:04-Trust-Boundaries.org][Trust boundaries and data flows]] | =04-trust-boundaries.svg=, =06-push-flow.svg= | |
| 45 | | 5 | [[file:05-Identity-and-Access.org][Identity and access]] | [[file:diagrams/05-authorization.svg][05-authorization.svg]] | | 45 | | 5 | [[file:05-Identity-and-Access.org][Identity and access]] | =05-authorization.svg= | |
| 46 | | 6 | [[file:06-Data-and-Cryptography.org][Data and cryptography]] | | | 46 | | 6 | [[file:06-Data-and-Cryptography.org][Data and cryptography]] | | |
| 47 | | 7 | [[file:07-CI-and-Supply-Chain.org][CI and supply chain]] | [[file:diagrams/07-ci-flow.svg][07-ci-flow.svg]] | | 47 | | 7 | [[file:07-CI-and-Supply-Chain.org][CI and supply chain]] | =07-ci-flow.svg= | |
| 48 | | 8 | [[file:08-Operations.org][Operations]] | | | 48 | | 8 | [[file:08-Operations.org][Operations]] | | |
| 49 | | 9 | [[file:09-Controls.org][Controls matrix]] | | | 49 | | 9 | [[file:09-Controls.org][Controls matrix]] | | |
| 50 | | 10 | [[file:10-Known-Gaps.org][Known gaps]] | | | 50 | | 10 | [[file:10-Known-Gaps.org][Known gaps]] | | |
.gitbay/wiki/Architecture/01-System-Context.org +1 −1
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 1. System context | 1 | #+title: System context |
| 2 | 2 | ||
| 3 | [[file:diagrams/01-context.svg]] | 3 | [[file:diagrams/01-context.svg]] |
| 4 | 4 | ||
.gitbay/wiki/Architecture/02-Components.org +1 −1
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 2. Components | 1 | #+title: Components |
| 2 | 2 | ||
| 3 | [[file:diagrams/02-components.svg]] | 3 | [[file:diagrams/02-components.svg]] |
| 4 | 4 | ||
.gitbay/wiki/Architecture/03-Deployment.org +1 −1
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 3. Deployment and network | 1 | #+title: Deployment and network |
| 2 | 2 | ||
| 3 | [[file:diagrams/03-deployment.svg]] | 3 | [[file:diagrams/03-deployment.svg]] |
| 4 | 4 | ||
.gitbay/wiki/Architecture/04-Trust-Boundaries.org +1 −1
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 4. Trust boundaries and data flows | 1 | #+title: Trust boundaries and data flows |
| 2 | 2 | ||
| 3 | [[file:diagrams/04-trust-boundaries.svg]] | 3 | [[file:diagrams/04-trust-boundaries.svg]] |
| 4 | 4 | ||
.gitbay/wiki/Architecture/05-Identity-and-Access.org +1 −1
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 5. Identity and access | 1 | #+title: Identity and access |
| 2 | 2 | ||
| 3 | [[file:diagrams/05-authorization.svg]] | 3 | [[file:diagrams/05-authorization.svg]] |
| 4 | 4 | ||
.gitbay/wiki/Architecture/06-Data-and-Cryptography.org +1 −1
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 6. Data and cryptography | 1 | #+title: Data and cryptography |
| 2 | 2 | ||
| 3 | * Data inventory | 3 | * Data inventory |
| 4 | 4 | ||
.gitbay/wiki/Architecture/07-CI-and-Supply-Chain.org +1 −1
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 7. CI and supply chain | 1 | #+title: CI and supply chain |
| 2 | 2 | ||
| 3 | [[file:diagrams/07-ci-flow.svg]] | 3 | [[file:diagrams/07-ci-flow.svg]] |
| 4 | 4 | ||
.gitbay/wiki/Architecture/08-Operations.org +1 −1
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 8. Operations | 1 | #+title: Operations |
| 2 | 2 | ||
| 3 | * Logging | 3 | * Logging |
| 4 | 4 | ||
.gitbay/wiki/Architecture/09-Controls.org +9 −9
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 9. Controls matrix | 1 | #+title: Controls matrix |
| 2 | 2 | ||
| 3 | One row per control an auditor typically asks about. *Status*: =in | 3 | One row per control an auditor typically asks about. *Status*: =in |
| 4 | place= (implemented and cited), =partial= (implemented with a stated | 4 | place= (implemented and cited), =partial= (implemented with a stated |
| @@ -23,8 +23,8 @@ chapter names of OWASP ASVS 4.0 where one fits. | |||
| 23 | | Brute-force limit on SSH auth | in place | 10 failures a minute per IP (=internal/sshd/ratelimit.go=) | | 23 | | Brute-force limit on SSH auth | in place | 10 failures a minute per IP (=internal/sshd/ratelimit.go=) | |
| 24 | | Account enumeration resistance at login | in place | uniform response (=internal/control/loginlink.go=) | | 24 | | Account enumeration resistance at login | in place | uniform response (=internal/control/loginlink.go=) | |
| 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 | | 26 | | Session lifetime | partial | 7 days absolute, no idle timeout (#276) | |
| 27 | | Credential expiry | partial | API tokens optional; SSH and deploy keys none | | 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 | gap | removed SSH key keeps open connections (#256) | |
| 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 | ||
| @@ -56,9 +56,9 @@ chapter names of OWASP ASVS 4.0 where one fits. | |||
| 56 | | Control | Status | Evidence | | 56 | | Control | Status | Evidence | |
| 57 | |---------------------------------------------+----------+------------------------------------------------------------------| | 57 | |---------------------------------------------+----------+------------------------------------------------------------------| |
| 58 | | TLS for all authenticated HTTP | in place | ACME or certificate files; HSTS | | 58 | | TLS for all authenticated HTTP | in place | ACME or certificate files; HSTS | |
| 59 | | Secrets encrypted at rest | gap | CI secrets, webhook secrets, mirror tokens stored in clear ([[file:06-Data-and-Cryptography.org][6]]) | | 59 | | Secrets encrypted at rest | gap | CI secrets, webhook secrets, mirror tokens stored in clear (#273) | |
| 60 | | Secrets kept out of argv, logs and output | in place | =ReadsStdin=, pruned audit argv, write-only secret commands | | 60 | | Secrets kept out of argv, logs and output | in place | =ReadsStdin=, pruned audit argv, write-only secret commands | |
| 61 | | Local backups encrypted | gap | tar.gz in clear; offsite copy encrypted by restic | | 61 | | Local backups encrypted | gap | tar.gz in clear; offsite copy encrypted by restic (#274) | |
| 62 | | Data retention configurable | in place | =[retention]= (=internal/config/config.go=) | | 62 | | Data retention configurable | in place | =[retention]= (=internal/config/config.go=) | |
| 63 | | User data export | in place | =account export= | | 63 | | User data export | in place | =account export= | |
| 64 | 64 | ||
| @@ -68,16 +68,16 @@ chapter names of OWASP ASVS 4.0 where one fits. | |||
| 68 | |---------------------------------------------+----------+------------------------------------------------------------------| | 68 | |---------------------------------------------+----------+------------------------------------------------------------------| |
| 69 | | Security-relevant writes audited | in place | every successful mutating command (=control.go=) | | 69 | | Security-relevant writes audited | in place | every successful mutating command (=control.go=) | |
| 70 | | Authentication failures audited | in place | =auth.failed=, =auth.throttled= | | 70 | | Authentication failures audited | in place | =auth.failed=, =auth.throttled= | |
| 71 | | Denied attempts audited | gap | refused commands are not recorded | | 71 | | Denied attempts audited | gap | refused commands are not recorded (#275) | |
| 72 | | Audit log tamper resistance | gap | same database, writable by the daemon user | | 72 | | Audit log tamper resistance | gap | same database, writable by the daemon user (#275) | |
| 73 | 73 | ||
| 74 | ** Communications and integrations (V9, V10, V12) | 74 | ** Communications and integrations (V9, V10, V12) |
| 75 | 75 | ||
| 76 | | Control | Status | Evidence | | 76 | | Control | Status | Evidence | |
| 77 | |---------------------------------------------+----------+------------------------------------------------------------------| | 77 | |---------------------------------------------+----------+------------------------------------------------------------------| |
| 78 | | SSRF protection on user-supplied URLs | partial | webhooks at save and connect; mirrors at save only | | 78 | | SSRF protection on user-supplied URLs | partial | webhooks at save and connect; mirrors at save only (#279) | |
| 79 | | Webhook payload integrity | in place | HMAC-SHA256 header | | 79 | | Webhook payload integrity | in place | HMAC-SHA256 header | |
| 80 | | SMTP credentials protected in transit | partial | STARTTLS opportunistic; Go refuses PLAIN auth without TLS to a remote host | | 80 | | SMTP credentials protected in transit | partial | STARTTLS opportunistic (#280); Go refuses PLAIN auth without TLS to a remote host | |
| 81 | | Upload size limits | in place | per-owner storage quota at push (=internal/sshd/sshd.go=); API body 1 MiB | | 81 | | Upload size limits | in place | per-owner storage quota at push (=internal/sshd/sshd.go=); API body 1 MiB | |
| 82 | 82 | ||
| 83 | ** CI and build isolation | 83 | ** CI and build isolation |
.gitbay/wiki/Architecture/10-Known-Gaps.org +11 −18
| @@ -1,4 +1,4 @@ | |||
| 1 | #+title: 10. Known gaps | 1 | #+title: Known gaps |
| 2 | 2 | ||
| 3 | Open weaknesses. Issues on krz/gitbay are public; this page gives the | 3 | Open weaknesses. Issues on krz/gitbay are public; this page gives the |
| 4 | title and the consequence, not a reproduction. The current list is the | 4 | title and the consequence, not a reproduction. The current list is the |
| @@ -18,29 +18,22 @@ what the 2026-09-27 review found; remove a row when its issue closes. | |||
| 18 | | #260 | CI network | Builds share the runner's source address; no egress policy | medium | | 18 | | #260 | CI network | Builds share the runner's source address; no egress policy | medium | |
| 19 | | #261 | Various | Migration foreign-key check after commit; three web writes bypass dispatch; documentation drift | medium | | 19 | | #261 | Various | Migration foreign-key check after commit; three web writes bypass dispatch; documentation drift | medium | |
| 20 | | #262 | Availability | No limit on concurrent git pack generation | high | | 20 | | #262 | Availability | No limit on concurrent git pack generation | high | |
| 21 | | #273 | Data at rest | CI secrets, webhook secrets and mirror tokens are stored in clear in SQLite | high | | ||
| 22 | | #274 | Backups | The local backup archive is not encrypted | medium | | ||
| 23 | | #275 | Audit | Refused writes are not audited; the audit table is writable by the daemon user | medium | | ||
| 24 | | #276 | Sessions | Web sessions last 7 days with no idle timeout | low | | ||
| 25 | | #277 | Credentials | SSH and deploy keys never expire | low | | ||
| 26 | | #278 | Login links | =web login= over SSH skips the login-link rate limit | low | | ||
| 27 | | #279 | SSRF | Mirror URLs are checked when saved, not when git connects | medium | | ||
| 28 | | #280 | Mail | STARTTLS only when the relay offers it | medium | | ||
| 29 | | #281 | TLS | No explicit minimum TLS version | low | | ||
| 30 | | #282 | Hook socket | Anything that can open =hook.sock= can act as any user | medium | | ||
| 21 | 31 | ||
| 22 | Decisions already taken on these: #256 closes a removed key's | 32 | Decisions already taken on these: #256 closes a removed key's |
| 23 | connections, running commands included; #257 refuses credential | 33 | connections, running commands included; #257 refuses credential |
| 24 | creation from expiring tokens, records which token created each | 34 | creation from expiring tokens, records which token created each |
| 25 | credential, and makes =read= the default scope. | 35 | credential, and makes =read= the default scope. |
| 26 | 36 | ||
| 27 | * Not yet filed | ||
| 28 | |||
| 29 | Found during the 2026-09-27 review. | ||
| 30 | |||
| 31 | | Area | Gap | Where | | ||
| 32 | |------------------+---------------------------------------------------------------------------------------+---------------------------------------------| | ||
| 33 | | Data at rest | CI secrets, webhook secrets and mirror tokens are stored in clear in SQLite | =build_secrets=, =webhooks=, =mirrors= | | ||
| 34 | | Backups | The local backup archive is not encrypted | =cmd/gitbayd/backup.go= | | ||
| 35 | | Audit | Refused commands are not audited; the audit table is writable by the daemon user | =internal/control/control.go= | | ||
| 36 | | Sessions | Web sessions have a 7-day absolute lifetime and no idle timeout | =internal/httpd/accounts.go= | | ||
| 37 | | Credentials | SSH and deploy keys never expire | =ssh_keys= | | ||
| 38 | | Login links | =web login= over SSH is not counted against the 5-per-hour login-link limit | =internal/control/web.go= | | ||
| 39 | | SSRF | Mirror URLs are checked when saved but not when git connects, so a DNS change can redirect a mirror to a private address | =internal/control/mirrorcmd.go= | | ||
| 40 | | Mail | STARTTLS is used only when the relay offers it | =internal/mail/mail.go= | | ||
| 41 | | TLS | Go defaults; no explicit minimum version | =cmd/gitbayd/main.go= | | ||
| 42 | | Hook socket | Any process that can open =hook.sock= can claim any user id; it relies on the data directory's permissions | =internal/hookd/hookd.go= | | ||
| 43 | |||
| 44 | * Questions an auditor will ask that have no answer yet | 37 | * Questions an auditor will ask that have no answer yet |
| 45 | 38 | ||
| 46 | | Question | Status | | 39 | | Question | Status | |