package adminui import ( "context" "encoding/json" "errors" "net/http" "net/http/httptest" "strings" "testing" "cloud.campbellwireless.net/git/barkstack/treatvault/internal/manager" "cloud.campbellwireless.net/git/barkstack/treatvault/internal/provider" ) func TestManifestDescribesTreatVaultPlugin(t *testing.T) { response := httptest.NewRecorder() Handler(&fakeManager{}).ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/barkstack/ui/manifest.json", nil)) if response.Code != http.StatusOK { t.Fatalf("status = %d", response.Code) } var got manifest if err := json.Unmarshal(response.Body.Bytes(), &got); err != nil { t.Fatal(err) } if got.ID != "treatvault" || got.Element != "barkstack-treatvault" || got.Entry != entryPath { t.Fatalf("manifest = %#v", got) } } func TestListNeverReturnsSecretValues(t *testing.T) { manager := &fakeManager{status: manager.Status{State: "ready", Secrets: []manager.Secret{{Name: "database_password", InUse: true, Synced: true}}}} response := httptest.NewRecorder() Handler(manager).ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/barkstack/api/secrets", nil)) if response.Code != http.StatusOK { t.Fatalf("status = %d", response.Code) } if strings.Contains(response.Body.String(), "secret-value") || !strings.Contains(response.Body.String(), "database_password") { t.Fatalf("body = %s", response.Body.String()) } } func TestPutSetsSecretAndReturnsNoValue(t *testing.T) { manager := &fakeManager{} response := httptest.NewRecorder() request := httptest.NewRequest(http.MethodPut, "/barkstack/api/secrets/database_password", strings.NewReader(`{"value":"secret-value"}`)) Handler(manager).ServeHTTP(response, request) if response.Code != http.StatusNoContent { t.Fatalf("status = %d, body = %s", response.Code, response.Body.String()) } if manager.setName != "database_password" || string(manager.setValue) != "secret-value" { t.Fatalf("set = %q %q", manager.setName, manager.setValue) } if strings.Contains(response.Body.String(), "secret-value") { t.Fatal("response disclosed the secret value") } } func TestDeleteReturnsConflictForInUseSecret(t *testing.T) { manager := &fakeManager{deleteErr: fmtInUse("database_password")} response := httptest.NewRecorder() Handler(manager).ServeHTTP(response, httptest.NewRequest(http.MethodDelete, "/barkstack/api/secrets/database_password", nil)) if response.Code != http.StatusConflict { t.Fatalf("status = %d, body = %s", response.Code, response.Body.String()) } } func TestInvalidSecretNameIsRejected(t *testing.T) { response := httptest.NewRecorder() Handler(&fakeManager{}).ServeHTTP(response, httptest.NewRequest(http.MethodPut, "/barkstack/api/secrets/UPPERCASE", strings.NewReader(`{"value":"value"}`))) if response.Code != http.StatusBadRequest { t.Fatalf("status = %d", response.Code) } } type fakeManager struct { status manager.Status setName string setValue []byte setErr error deleteErr error } func (m *fakeManager) Status() manager.Status { return m.status } func (m *fakeManager) Set(_ context.Context, name string, value []byte) error { m.setName = name m.setValue = append([]byte(nil), value...) return m.setErr } func (m *fakeManager) Delete(context.Context, string) error { return m.deleteErr } func fmtInUse(name string) error { return errors.Join(provider.ErrSecretInUse, errors.New(name)) }