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.
Validate the configuration and harden what a deployment creates
ed1812123cd9e9df0f34fdaf0d2511a340c2aaa6 · Keenan Nemetz · 13d ago · parent 13cff33f
Validate the configuration and harden what a deployment creates Two ways an instance used to run in a state it should have refused. The configuration was never checked. `dev_login` was guarded only by a loopback listener, so a proxy that rewrites Host to 127.0.0.1 inherited a credential-free session; open registration could be enabled on a plain-HTTP origin WebAuthn would never accept; a public_url could carry a path or credentials; a size could be negative. Config.Validate now runs before anything is opened and reports every problem at once, and dev_login requires an explicit dev_only opt-in next to a loopback listener with no public address. The per-request check no longer trusts Host at all: it must name the configured listener, and a request carrying a forwarding header gets no session. The files were never checked either. directories were created 0755 and the audit log 0644, and a file keeps the mode it was created with, so an upgraded instance stayed exposed. internal/secure creates secrets at 0600 in directories at 0700, tightens what an existing install left, keeps group access for a shared backup group, and refuses to start when a mode cannot be changed. Every audit writer and the account backup go through it. The service unit drops all capabilities, sets UMask=0027, disables core dumps, hides other processes and devices, and restricts address families; docs/operations.md now states the production baseline.
server/web/status.go +6
| @@ -270,6 +270,11 @@ func (w *Web) statusConfig() *statusConfigView { | |||
| 270 | 270 | instanceTaglineNote = "built-in tagline" | |
| 271 | 271 | } | |
| 272 | 272 | ||
| 273 | devOnly := statusSetting{Key: "dev_only", Value: yesNo(cfg.DevOnly)} | ||
| 274 | if cfg.DevOnly { | ||
| 275 | devOnly.Note = "development instance" | ||
| 276 | devOnly.Warn = true | ||
| 277 | } | ||
| 273 | 278 | devLogin := statusSetting{Key: "dev_login", Value: "off"} | |
| 274 | 279 | if strings.TrimSpace(cfg.DevLogin) != "" { | |
| 275 | 280 | devLogin.Value = cfg.DevLogin | |
| @@ -325,6 +330,7 @@ func (w *Web) statusConfig() *statusConfigView { | |||
| 325 | 330 | configSetting("public_url", cfg.PublicURL, publicNote), | |
| 326 | 331 | configSetting("open_registration", yesNo(cfg.OpenRegistration), registrationNote), | |
| 327 | 332 | configSetting("open_registration_role", cfg.OpenRegistrationRole, ""), | |
| 333 | devOnly, | ||
| 328 | 334 | devLogin, | |
| 329 | 335 | }}, | |
| 330 | 336 | {Name: "Listeners and TLS", Settings: []statusSetting{ | |