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/ssh/server.go +3−2
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | 13 | "crypto/x509" | |
| 14 | 14 | "encoding/pem" | |
| 15 | 15 | "fmt" | |
| 16 | "github.com/rodent-software/vole/internal/secure" | ||
| 16 | 17 | "io" | |
| 17 | 18 | "log/slog" | |
| 18 | 19 | "net" | |
| @@ -442,11 +443,11 @@ func loadOrCreateHostKey(path string) (xssh.Signer, error) { | |||
| 442 | 443 | if err != nil { | |
| 443 | 444 | return nil, err | |
| 444 | 445 | } | |
| 445 | if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil { | ||
| 446 | if err := secure.Mkdir(filepath.Dir(path)); err != nil { | ||
| 446 | 447 | return nil, err | |
| 447 | 448 | } | |
| 448 | 449 | blk := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: der}) | |
| 449 | if err := os.WriteFile(path, blk, 0o600); err != nil { | ||
| 450 | if err := secure.WriteFile(path, blk); err != nil { | ||
| 450 | 451 | return nil, err | |
| 451 | 452 | } | |
| 452 | 453 | return xssh.NewSignerFromKey(priv) | |