package httpapi import ( "encoding/json" "io" "net/http" "net/http/httptest" "strings" "testing" ) func TestBearerDevWithoutInsecureDev(t *testing.T) { srv, err := New(Options{SeedDemo: true, BundleSeedHex: testBundleSeed}) if err != nil { t.Fatal(err) } defer srv.Close() ts := httptest.NewServer(srv.Handler()) defer ts.Close() req, _ := http.NewRequest(http.MethodGet, ts.URL+"/v1/modules?limit=1", nil) req.Header.Set("Authorization", "Bearer dev") resp, err := ts.Client().Do(req) if err != nil { t.Fatal(err) } defer func() { _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) t.Fatalf("status=%d body=%s", resp.StatusCode, b) } } func TestAPIKeysCRUDAndAuth(t *testing.T) { srv, err := New(Options{SeedDemo: true, BundleSeedHex: testBundleSeed}) if err != nil { t.Fatal(err) } defer srv.Close() tenant, _, _, _, _ := srv.Store().DemoIDs() mustSetTestAPIKeys(t, srv, "opkey|"+tenant+"|operator") ts := httptest.NewServer(srv.Handler()) defer ts.Close() client := ts.Client() base := ts.URL reqCreate, _ := http.NewRequest(http.MethodPost, base+"/v1/api-keys", strings.NewReader(`{"name":"ci","role":"editor"}`)) reqCreate.Header.Set("Authorization", "Bearer opkey") reqCreate.Header.Set("Content-Type", "application/json") respCreate, err := client.Do(reqCreate) if err != nil { t.Fatal(err) } defer func() { _ = respCreate.Body.Close() }() if respCreate.StatusCode != http.StatusCreated { b, _ := io.ReadAll(respCreate.Body) t.Fatalf("create status=%d body=%s", respCreate.StatusCode, b) } var created map[string]any if err := json.NewDecoder(respCreate.Body).Decode(&created); err != nil { t.Fatal(err) } token, _ := created["token"].(string) if token == "" { t.Fatal("missing token in create response") } id, _ := created["id"].(string) if id == "" { t.Fatal("missing id") } reqMod, _ := http.NewRequest(http.MethodGet, base+"/v1/modules?limit=1", nil) reqMod.Header.Set("Authorization", "Bearer "+token) respMod, err := client.Do(reqMod) if err != nil { t.Fatal(err) } defer func() { _ = respMod.Body.Close() }() if respMod.StatusCode != http.StatusOK { b, _ := io.ReadAll(respMod.Body) t.Fatalf("modules status=%d body=%s", respMod.StatusCode, b) } reqDel, _ := http.NewRequest(http.MethodDelete, base+"/v1/api-keys/"+id, nil) reqDel.Header.Set("Authorization", "Bearer opkey") respDel, err := client.Do(reqDel) if err != nil { t.Fatal(err) } defer func() { _ = respDel.Body.Close() }() if respDel.StatusCode != http.StatusNoContent { t.Fatalf("delete status=%d", respDel.StatusCode) } reqAfter, _ := http.NewRequest(http.MethodGet, base+"/v1/modules?limit=1", nil) reqAfter.Header.Set("Authorization", "Bearer "+token) respAfter, err := client.Do(reqAfter) if err != nil { t.Fatal(err) } defer func() { _ = respAfter.Body.Close() }() if respAfter.StatusCode != http.StatusUnauthorized { t.Fatalf("expected 401 after revoke, got %d", respAfter.StatusCode) } mustSetTestAPIKeys(t, srv, "nodekey|"+tenant+"|node,opkey|"+tenant+"|operator") reqNode2, _ := http.NewRequest(http.MethodGet, base+"/v1/api-keys", nil) reqNode2.Header.Set("Authorization", "Bearer nodekey") respNode, err := client.Do(reqNode2) if err != nil { t.Fatal(err) } defer func() { _ = respNode.Body.Close() }() if respNode.StatusCode != http.StatusForbidden { t.Fatalf("node list api-keys status=%d want 403", respNode.StatusCode) } }