package membership_test import ( "encoding/json" "io" "net/http" "net/http/httptest" "path/filepath" "testing" "github.com/enmanuel/unibus/pkg/blobstore" "github.com/enmanuel/unibus/pkg/membership" ) // TestHealthExposesPosture: /healthz publishes the node's security posture so a // monitor (or a peer) can detect a cluster member that is not enforce+ACL+TLS // (audit 0008 N1). The probe stays unauthenticated. func TestHealthExposesPosture(t *testing.T) { dir := t.TempDir() store, err := membership.Open(filepath.Join(dir, "unibus.db")) if err != nil { t.Fatalf("store: %v", err) } t.Cleanup(func() { store.Close() }) blobs, _ := blobstore.New(filepath.Join(dir, "blobs")) srv := membership.NewServer(store, blobs, membership.AuthEnforce) srv.Posture = membership.Posture{Enforce: true, ACL: true, TLS: true, Cluster: true, Store: "kv"} ts := httptest.NewServer(srv) t.Cleanup(ts.Close) resp, err := http.Get(ts.URL + "/healthz") if err != nil { t.Fatalf("get healthz: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("healthz status %d, want 200", resp.StatusCode) } body, _ := io.ReadAll(resp.Body) var got struct { Status string `json:"status"` Posture membership.Posture `json:"posture"` } if err := json.Unmarshal(body, &got); err != nil { t.Fatalf("decode healthz %q: %v", string(body), err) } if got.Status != "ok" { t.Fatalf("status = %q, want ok", got.Status) } if !got.Posture.Enforce || !got.Posture.ACL || !got.Posture.TLS || !got.Posture.Cluster { t.Fatalf("posture not surfaced correctly: %+v", got.Posture) } if got.Posture.Store != "kv" { t.Fatalf("posture.store = %q, want kv", got.Posture.Store) } }