| 1 | package config |
| 2 | |
| 3 | import ( |
| 4 | "path/filepath" |
| 5 | "testing" |
| 6 | ) |
| 7 | |
| 8 | func TestExpandVars(t *testing.T) { |
| 9 | t.Setenv("REASONIX_TEST_TOKEN", "sk-123") |
| 10 | t.Setenv("REASONIX_TEST_EMPTY", "") |
| 11 | |
| 12 | cases := []struct{ in, want string }{ |
| 13 | {"Bearer ${REASONIX_TEST_TOKEN}", "Bearer sk-123"}, |
| 14 | {"${REASONIX_TEST_MISSING}", ""}, // unset, no default → empty |
| 15 | {"${REASONIX_TEST_MISSING:-fallback}", "fallback"}, // unset → default |
| 16 | {"${REASONIX_TEST_EMPTY:-fallback}", "fallback"}, // set-but-empty → default |
| 17 | {"${REASONIX_TEST_TOKEN:-fallback}", "sk-123"}, // set → value, default ignored |
| 18 | {"no vars here", "no vars here"}, // untouched |
| 19 | {"a${REASONIX_TEST_TOKEN}b${REASONIX_TEST_MISSING}c", "ask-123bc"}, // multiple refs |
| 20 | } |
| 21 | for _, c := range cases { |
| 22 | if got := ExpandVars(c.in); got != c.want { |
| 23 | t.Errorf("ExpandVars(%q) = %q, want %q", c.in, got, c.want) |
| 24 | } |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | func TestExpandedPlugin(t *testing.T) { |
| 29 | t.Setenv("REASONIX_TEST_KEY", "secret") |
| 30 | e := PluginEntry{ |
| 31 | Name: "x", |
| 32 | Type: "http", |
| 33 | URL: "https://api/${REASONIX_TEST_MISSING:-v1}", |
| 34 | Args: []string{"--token", "${REASONIX_TEST_KEY}"}, |
| 35 | Env: map[string]string{"K": "${REASONIX_TEST_KEY}"}, |
| 36 | Headers: map[string]string{"Authorization": "Bearer ${REASONIX_TEST_KEY}"}, |
| 37 | } |
| 38 | out := e.ExpandedPlugin() |
| 39 | if out.URL != "https://api/v1" { |
| 40 | t.Errorf("URL = %q", out.URL) |
| 41 | } |
| 42 | if out.Args[1] != "secret" { |
| 43 | t.Errorf("Args = %v", out.Args) |
| 44 | } |
| 45 | if out.Env["K"] != "secret" || out.Headers["Authorization"] != "Bearer secret" { |
| 46 | t.Errorf("env/headers not expanded: %v %v", out.Env, out.Headers) |
| 47 | } |
| 48 | // The original entry must be untouched (we returned a copy). |
| 49 | if e.Headers["Authorization"] != "Bearer ${REASONIX_TEST_KEY}" { |
| 50 | t.Error("ExpandedPlugin mutated the original entry") |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | func TestForbidReadRootsForRootResolvesRelativePathsAndScopedEnv(t *testing.T) { |
| 55 | root := t.TempDir() |
| 56 | cfg := Default() |
| 57 | cfg.setExpansionEnv(map[string]string{"REASONIX_TEST_SECRET_DIR": "from-dotenv"}) |
| 58 | cfg.Sandbox.ForbidRead = []string{ |
| 59 | "relative-secret", |
| 60 | "${REASONIX_TEST_SECRET_DIR}", |
| 61 | filepath.Join(root, "absolute-secret"), |
| 62 | } |
| 63 | |
| 64 | got := cfg.ForbidReadRootsForRoot(root) |
| 65 | want := []string{ |
| 66 | filepath.Join(root, "relative-secret"), |
| 67 | filepath.Join(root, "from-dotenv"), |
| 68 | filepath.Join(root, "absolute-secret"), |
| 69 | } |
| 70 | if len(got) != len(want) { |
| 71 | t.Fatalf("ForbidReadRootsForRoot returned %d roots, want %d: %v", len(got), len(want), got) |
| 72 | } |
| 73 | for i := range want { |
| 74 | if got[i] != want[i] { |
| 75 | t.Fatalf("root %d = %q, want %q (all roots: %v)", i, got[i], want[i], got) |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | func TestWriteRootsForRootExpandsMavenAllowWrite(t *testing.T) { |
| 81 | home := t.TempDir() |
| 82 | project := t.TempDir() |
| 83 | t.Setenv("HOME", home) |
| 84 | |
| 85 | cfg := Default() |
| 86 | cfg.Sandbox.AllowWrite = []string{ |
| 87 | "${HOME}/.m2", |
| 88 | "${HOME}/.m2/repository", |
| 89 | } |
| 90 | |
| 91 | got := cfg.WriteRootsForRoot(project) |
| 92 | // WriteRootsForRoot expands variables but leaves configured separators intact; |
| 93 | // the writer confiner normalizes roots later. |
| 94 | want := []string{ |
| 95 | project, |
| 96 | home + "/.m2", |
| 97 | home + "/.m2/repository", |
| 98 | } |
| 99 | if len(got) != len(want) { |
| 100 | t.Fatalf("WriteRootsForRoot() returned %d roots, want %d: %v", len(got), len(want), got) |
| 101 | } |
| 102 | for i := range want { |
| 103 | if got[i] != want[i] { |
| 104 | t.Fatalf("root %d = %q, want %q (all roots: %v)", i, got[i], want[i], got) |
| 105 | } |
| 106 | } |
| 107 | } |
| 108 |