package shared import ( "encoding/json" "net/http" "net/http/httptest" "strings" "testing" ) func TestHandleVaultKVToolReadsSecretData(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { t.Fatalf("unexpected method: %s", r.Method) } if got := r.Header.Get("X-Vault-Token"); got != "root-token" { t.Fatalf("unexpected token header: %s", got) } if got := r.Header.Get("X-Vault-Namespace"); got != "platform/team-a" { t.Fatalf("unexpected namespace header: %s", got) } if got := r.URL.Path; got != "/v1/secret/data/apps/demo" { t.Fatalf("unexpected request path: %s", got) } _ = json.NewEncoder(w).Encode(map[string]any{ "data": map[string]any{ "data": map[string]any{ "api_key": "demo-key", }, "metadata": map[string]any{ "version": 3, }, }, }) })) defer server.Close() t.Setenv("VAULT_SERVER_URL", server.URL) t.Setenv("VAULT_SERVER_ROOT_ACCESS_TOKEN", "root-token") t.Setenv("VAULT_NAMESPACE", "platform/team-a") output, err := HandleVaultKVTool(map[string]any{ "operation": "read", "path": "apps/demo", }) if err != nil { t.Fatalf("HandleVaultKVTool returned error: %v", err) } if !strings.Contains(output, `"api_key": "demo-key"`) { t.Fatalf("expected secret data in output, got %s", output) } } func TestHandleVaultKVToolWritesSecretData(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { t.Fatalf("unexpected method: %s", r.Method) } if got := r.URL.Path; got != "/v1/secret/data/apps/demo" { t.Fatalf("unexpected request path: %s", got) } var payload map[string]any if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { t.Fatalf("decode payload: %v", err) } data := mapArg(payload["data"]) if got := data["enabled"]; got != true { t.Fatalf("unexpected data payload: %v", payload) } options := mapArg(payload["options"]) if got := options["cas"]; got != float64(2) { t.Fatalf("unexpected cas payload: %v", payload) } _ = json.NewEncoder(w).Encode(map[string]any{ "data": map[string]any{ "metadata": map[string]any{ "version": 4, }, }, }) })) defer server.Close() t.Setenv("VAULT_SERVER_URL", server.URL) t.Setenv("VAULT_SERVER_ROOT_ACCESS_TOKEN", "root-token") output, err := HandleVaultKVTool(map[string]any{ "operation": "write", "path": "apps/demo", "data": map[string]any{ "enabled": true, }, "cas": 2, }) if err != nil { t.Fatalf("HandleVaultKVTool returned error: %v", err) } if !strings.Contains(output, `"version": 4`) { t.Fatalf("expected metadata in output, got %s", output) } } func TestHandleVaultKVToolListsSecretKeys(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != "LIST" { t.Fatalf("unexpected method: %s", r.Method) } if got := r.URL.Path; got != "/v1/secret/metadata/apps" { t.Fatalf("unexpected request path: %s", got) } _ = json.NewEncoder(w).Encode(map[string]any{ "data": map[string]any{ "keys": []string{"demo", "prod"}, }, }) })) defer server.Close() t.Setenv("VAULT_SERVER_URL", server.URL) t.Setenv("VAULT_SERVER_ROOT_ACCESS_TOKEN", "root-token") output, err := HandleVaultKVTool(map[string]any{ "operation": "list", "path": "apps", }) if err != nil { t.Fatalf("HandleVaultKVTool returned error: %v", err) } if !strings.Contains(output, `"demo"`) || !strings.Contains(output, `"prod"`) { t.Fatalf("expected listed keys in output, got %s", output) } } func TestHandleVaultKVToolRequiresEnvironment(t *testing.T) { // Explicitly clear relevant environment variables to ensure we test the validation logic t.Setenv("VAULT_SERVER_URL", "") t.Setenv("VAULT_SERVER_ROOT_ACCESS_TOKEN", "") _, err := HandleVaultKVTool(map[string]any{ "operation": "read", "path": "apps/demo", }) // We want to catch the specific validation error message if err == nil || !strings.Contains(err.Error(), "VAULT_SERVER_URL") { t.Fatalf("expected missing environment error, got %v", err) } }