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.

Phase 6 is done: sites ride the instance's domain, TLS stays in front

9bea7f110ae780105f9c7c58024a3b67a86d7d7a · Keenan Nemetz · 17d ago · parent d3296cda

Phase 6 is done: sites ride the instance's domain, TLS stays in front

Custom domains and ACME are dropped as non-goals rather than deferred work. An
instance already owns one domain and terminates TLS in front of it, so every
repository's site is a subdomain of that domain and inherits the certificate
that already exists. `pages_domain` remains the only setting.

The operational requirement that falls out of it, documented in the README and
the sample config: the proxy must preserve the Host header, because Host is the
only thing that says which site a request is for.

docs/roadmap.md +25−11

@@ -41,6 +41,9 @@ Explicitly **not** built. Each is additive later; none is load-bearing for the c
41 41 - Federation, peer replication, cross-instance search, global entity IDs
42 42 - SSH transport (HTTP + PATs first; SSH keys are Phase 7 work if demanded)
43 43 - Container-isolated CI steps (shell steps only in v1)
44 - Per-repository custom domains and certificate issuance: an instance owns one domain
45 and terminates TLS in front of it, so sites are subdomains of that domain and
46 inheriting the certificate is the whole story
44 47 - Horizontal scaling, HA, multi-writer Postgres
45 48 - Kubernetes deployment story
46 49
@@ -338,7 +341,7 @@ the client's own pre-push check cannot stand in for the server's rule); GC never
338 341 collects an object reachable from a live ref (tested against an object reachable only
339 342 through history, and against an archived CI log).
340 343
341 ### Phase 6 — Site hosting
344 ### Phase 6 — Site hosting — ✅ complete
342 345
343 346 ✅ **Slice 1 — the tree is the site.** A repository's `pages` branch is served
344 347 directly out of git at `<repo>.<pages_domain>`: no export step, no build to drift.
@@ -359,18 +362,29 @@ file server and one that feels like a database. Resolving the repository and its
359 362 per request cost 3.8 ms, because it spawned three `git` subprocesses; that is why both
360 363 are resolved once per memo window.)
361 364
362 Remaining:
363
364 - Custom domains per repository, and automatic TLS (ACME) for them
365 - A per-repository pages ref; today `pages_ref` is one setting for the instance
366 - The `pages` branch has no review story of its own: it is a normal branch, so
367 protecting it is `vole acl protect`
365 Decisions:
366
367 - **Per-repository custom domains and ACME are dropped, not deferred.** An instance
368 already owns one domain and terminates TLS in front of it; sites inherit both from
369 the forge. Asking Vole to request certificates would add an ACME client, a
370 challenge listener and a DNS story to solve a problem the operator solved once
371 already. `pages_domain` is the single setting: point it at the forge's own domain
372 and every repository's site is a subdomain of it.
373 - The proxy must preserve the `Host` header (`proxy_set_header Host $host` in nginx,
374 the default in Caddy). `Host` is how a request names its site; nothing else routes.
375 - A per-repository pages ref is not planned. One ref name for the instance keeps the
376 mental model to one line, and a repository that wants a different branch can say so
377 by pushing to `pages`.
378 - The site branch is a normal branch with no review story of its own: protecting it
379 is `vole acl protect`, and a site change is reviewed exactly like code.
368 380
369 381 **Exit criteria:** a pushed doc tree is live in under 5 seconds ✅ (measured: pushed
370 over SSH, served on the site host, polled until the new bytes appeared); conditional
371 requests return `304` ✅; a custom domain gets a certificate with no manual steps ❌
372 (needs the ACME slice); serving a repo with a path-traversal-shaped filename is safe ✅
373 (and so is a traversal-shaped *request*).
382 over SSH, served on the site host, polled until the new bytes appeared, 1.4 s);
383 conditional requests return `304` ✅; serving a repo with a path-traversal-shaped
384 filename is safe ✅ (and so is a traversal-shaped *request*). The former criterion
385 "a custom domain gets a certificate with no manual steps" is withdrawn: certificates
386 are terminated in front of the instance, and a site is a subdomain of the domain that
387 certificate already covers.
374 388
375 389 ### Phase 7 — Signing and audit
376 390