neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
Plan: mirror by default, opt-in per org, the scanner shipped on its own, dogfood on our own findings
f98b9a7 · Gabriel Morell · 2026-10-22 19:52
Message
{commit_body(@commit)}
Files changed
modified
docs/plans/dependency-security.md
+69
−2
@@ -1,8 +1,8 @@
| 1 | 1 | # Plan: dependency security for repositories on the forge |
| 2 | 2 | |
| 3 | 3 | Status: **proposed** (2026-10-22). Nothing here is built yet except |
| 4 | −step 0. Decisions so far are under "Decisions"; open questions 3, 5, 6, | |
| 5 | −7 and 8 still have only recommended defaults. | |
| 4 | +step 0. Decisions are under "Decisions"; open questions 3 and 8 still | |
| 5 | +have only recommended defaults. | |
| 6 | 6 | |
| 7 | 7 | Three things, in the order they depend on each other: |
| 8 | 8 |
@@ -196,6 +196,57 @@ the EEF's for Hex, PyPA, Go, npm and more. Two ways to ask it:
| 196 | 196 | Config: `config :git_gud, GitGud.Advisories, source: :mirror | :api | |
| 197 | 197 | :off` (default `:mirror`), plus the ecosystems to fetch. |
| 198 | 198 | |
| 199 | +### Who it's on for | |
| 200 | + | |
| 201 | +Off until an **organization turns it on**: a "Dependency alerts" switch | |
| 202 | +in the org's settings, for its admins (`org.advisories_enabled` / | |
| 203 | +`.advisories_disabled` in the audit log). On, every repository the org | |
| 204 | +owns is scanned; a repository can't opt out of its org's choice. A | |
| 205 | +personal repository has the same switch in its own settings, for its | |
| 206 | +owner. The operator's `source: :off` turns it off for the instance | |
| 207 | +whatever anyone chose. The mirror only downloads anything once at least | |
| 208 | +one org or repository has it on. | |
| 209 | + | |
| 210 | +### Where the scanner comes from | |
| 211 | + | |
| 212 | +osv-scanner is a command, not a service, so the app runs it as a | |
| 213 | +subprocess wherever it's installed. It looks for it at | |
| 214 | +`GITGUD_OSV_SCANNER`, then `/usr/libexec/gitgud/osv-scanner`, then | |
| 215 | +`PATH`; absent, the feature says so on the admin page and in each org's | |
| 216 | +settings, and nothing else breaks. It is **not** baked into the app's | |
| 217 | +image or the `gitgud` .deb, so the two move on separately: | |
| 218 | + | |
| 219 | +- **.deb:** a separate package, `gitgud-osv-scanner`, built by CI from | |
| 220 | + the pinned upstream release (checked against its SHA-256), published | |
| 221 | + to the forge's own apt repository beside `gitgud`, installing | |
| 222 | + `/usr/libexec/gitgud/osv-scanner`. `gitgud` *Suggests* it. Bumping | |
| 223 | + the scanner is a new `gitgud-osv-scanner` version, not a forge | |
| 224 | + release. | |
| 225 | +- **Kubernetes (this instance):** an init container from upstream's own | |
| 226 | + image, pinned by digest, copies the binary into a shared `emptyDir` | |
| 227 | + the app container mounts: | |
| 228 | + | |
| 229 | + ```yaml | |
| 230 | + initContainers: | |
| 231 | + - name: osv-scanner | |
| 232 | + image: ghcr.io/google/osv-scanner:v2.6.0@sha256:<index digest> | |
| 233 | + command: ["cp", "/osv-scanner", "/tools/osv-scanner"] | |
| 234 | + volumeMounts: [{ name: tools, mountPath: /tools }] | |
| 235 | + containers: | |
| 236 | + - name: git-gud | |
| 237 | + env: [{ name: GITGUD_OSV_SCANNER, value: /tools/osv-scanner }] | |
| 238 | + volumeMounts: [{ name: tools, mountPath: /tools, readOnly: true }] | |
| 239 | + volumes: [{ name: tools, emptyDir: {} }] | |
| 240 | + ``` | |
| 241 | + | |
| 242 | + A long-running sidecar would need a small RPC wrapper around a CLI | |
| 243 | + for no gain; the init container is the sidecar pattern's simpler | |
| 244 | + cousin. The OSV dumps live on the existing data volume | |
| 245 | + (`GITGUD_DATA_DIR/osv`), so a restart doesn't re-download them. | |
| 246 | +- **Podman / Docker (`/run-your-own`):** the same: a named volume | |
| 247 | + filled once from the upstream image, mounted read-only, the env | |
| 248 | + variable pointing at it. | |
| 249 | + | |
| 199 | 250 | ### What the mirror costs (measured 2026-10-22, osv-scanner 2.6.0) |
| 200 | 251 | |
| 201 | 252 | OSV's per-ecosystem dumps, zipped, as osv-scanner keeps them: |
@@ -312,6 +363,22 @@ nothing pushed without asking (pushing deploys).
| 312 | 363 | |
| 313 | 364 | ## Decisions (2026-10-22) |
| 314 | 365 | |
| 366 | +- **OSV mirror by default** (open question 5); the API stays an opt-in | |
| 367 | + for an operator who'd rather not store the dumps. | |
| 368 | +- **Opt-in per organization** (and per personal repository), off until | |
| 369 | + turned on. | |
| 370 | +- **The scanner ships separately**: its own `gitgud-osv-scanner` .deb, | |
| 371 | + and on Kubernetes an init container from upstream's pinned image — | |
| 372 | + not inside the app's image or .deb (open question 6). | |
| 373 | +- **Notifications as proposed** (open question 7): immediately for high | |
| 374 | + and critical, a daily digest for the rest. | |
| 375 | +- **Dogfood the whole lifecycle on the forge's own findings** before | |
| 376 | + calling it done: `neiam` turns alerts on → the 21 findings of | |
| 377 | + 2026-10-22 appear as alerts → the update workflow (B) opens PRs as | |
| 378 | + `gg-security` → their CI, `audit.yml` included, goes green → merged → | |
| 379 | + the alerts close as `fixed` on the next scan. Until then those | |
| 380 | + dependencies stay as they are, by choice. | |
| 381 | + | |
| 315 | 382 | - **The CI account is `gg-security`**, one for the whole forge (open |
| 316 | 383 | question 1). |
| 317 | 384 | - **Job-token pull requests trigger `pull_request` workflows**, with the |
Parents: 29569b7