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/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Create accounts with a key and find the instance config

c36d507302c0f7fb24af6eba390c4121d67318c3 · Keenan Nemetz · 16d ago · parent 3abbe749

Create accounts with a key and find the instance config

An account is now written with its first key in one transaction, so a name cannot be claimed without a credential. add-key remains for additional keys, and remote user create forwards the key on stdin.

Local commands now resolve the config from --config, VOLE_CONFIG, ./vole.toml, or ~/.vole/vole.toml before falling back to defaults. init prints --config in its next steps when the instance will not be discovered automatically.

forge/config/config_test.go +52

@@ -6,6 +6,58 @@ import (
6 6 "testing"
7 7 )
8 8
9 // TestDefaultPathFindsThePerUserInstance is the flow `vole admin init --dir
10 // ~/.vole` promises: later commands find that config without --config.
11 func TestDefaultPathFindsThePerUserInstance(t *testing.T) {
12 home := t.TempDir()
13 t.Setenv("HOME", home)
14 t.Setenv("USERPROFILE", home)
15 t.Setenv("VOLE_CONFIG", "")
16 t.Chdir(t.TempDir())
17
18 if got := DefaultPath(); got != "vole.toml" {
19 t.Fatalf("default path with no instance = %q, want vole.toml", got)
20 }
21
22 homeConfig := filepath.Join(home, ".vole", "vole.toml")
23 if err := os.MkdirAll(filepath.Dir(homeConfig), 0o755); err != nil {
24 t.Fatal(err)
25 }
26 if err := os.WriteFile(homeConfig, []byte("data_dir = \"/tmp/vole-data\"\n"), 0o644); err != nil {
27 t.Fatal(err)
28 }
29 if got := DefaultPath(); got != homeConfig {
30 t.Fatalf("default path = %q, want %q", got, homeConfig)
31 }
32
33 // A config in the working directory belongs to the checkout or instance the
34 // operator is standing in, so it wins over the home instance.
35 if err := os.WriteFile("vole.toml", []byte("data_dir = \"./data\"\n"), 0o644); err != nil {
36 t.Fatal(err)
37 }
38 if got := DefaultPath(); got != "vole.toml" {
39 t.Fatalf("local config did not win: %q", got)
40 }
41
42 // An explicit environment choice wins over both.
43 t.Setenv("VOLE_CONFIG", "/srv/vole/vole.toml")
44 if got := DefaultPath(); got != "/srv/vole/vole.toml" {
45 t.Fatalf("VOLE_CONFIG did not win: %q", got)
46 }
47 }
48
49 // TestResolvePathKeepsExplicitChoice: an empty path means discover, but a named
50 // path must never be silently replaced.
51 func TestResolvePathKeepsExplicitChoice(t *testing.T) {
52 t.Setenv("VOLE_CONFIG", "/from/env.toml")
53 if got := ResolvePath("/explicit/vole.toml"); got != "/explicit/vole.toml" {
54 t.Fatalf("ResolvePath explicit = %q", got)
55 }
56 if got := ResolvePath(""); got != "/from/env.toml" {
57 t.Fatalf("ResolvePath empty = %q", got)
58 }
59 }
60
9 61 // A mistyped TOML tag does not fail anything: the key is simply ignored and the
10 62 // default applies, which is invisible until somebody's cap does nothing. So the one
11 63 // setting whose absence is a *silent* policy change is pinned here.