package api import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/go-chi/chi/v5" ) func TestListModulesAPI(t *testing.T) { store := NewModuleStore(t.TempDir(), func() string { return "list-secret" }) h := NewModuleHandler(store) req := httptest.NewRequest(http.MethodGet, "/api/v1/fleet/modules", nil) rec := httptest.NewRecorder() h.ListModules(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status %d: %s", rec.Code, rec.Body.String()) } var mods []ModuleManifest if err := json.Unmarshal(rec.Body.Bytes(), &mods); err != nil { t.Fatal(err) } if len(mods) < 3 { t.Fatalf("expected at least 3 default packs, got %d", len(mods)) } names := map[string]ModuleManifest{} for _, m := range mods { names[m.Name] = m } for _, want := range []string{"crucible_ops", "spread", "gpu"} { m, ok := names[want] if !ok { t.Fatalf("missing pack %q", want) } if m.DisplayName == "" || m.Summary == "" || len(m.Capabilities) == 0 { t.Fatalf("pack %q missing UI metadata: %+v", want, m) } if len(m.Features) == 0 { t.Fatalf("pack %q missing features", want) } if m.Signature == "" { t.Fatalf("pack %q unsigned", want) } } } func TestGetAgentModuleAPI(t *testing.T) { store := NewModuleStore(t.TempDir(), func() string { return "agent-mod-secret" }) h := NewModuleHandler(store) req := httptest.NewRequest(http.MethodGet, "/api/v1/agent/module/gpu", nil) rctx := chi.NewRouteContext() rctx.URLParams.Add("name", "gpu") req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) rec := httptest.NewRecorder() h.GetAgentModule(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status %d: %s", rec.Code, rec.Body.String()) } var m ModuleManifest if err := json.Unmarshal(rec.Body.Bytes(), &m); err != nil { t.Fatal(err) } if m.Name != "gpu" || m.Features["gpu_enabled"] != true { t.Fatalf("unexpected gpu manifest: %+v", m) } if !VerifyModuleSignature(m, "agent-mod-secret") { t.Fatal("agent module signature invalid") } } func TestVerifyModuleSignatureRejectsTamper(t *testing.T) { store := NewModuleStore(t.TempDir(), func() string { return "tamper-secret" }) m, err := store.Get("crucible_ops") if err != nil { t.Fatal(err) } if !VerifyModuleSignature(m, "tamper-secret") { t.Fatal("expected valid signature") } m.Features["auto_spread"] = true if VerifyModuleSignature(m, "tamper-secret") { t.Fatal("expected tampered manifest to fail verification") } }