Why: Downstream products must extend the base through a public package and host API instead of editing internal code. Evidence: go test ./... passed, including plugin v2 assets, sidecar startup, migration v13, pending confirms, HITL timeout, hash embedder, command pairs, and the extension surface snapshot. Impact: apiVersion 2.0-experimental rejects empty network allowlists for declarative HTTP. Hash embeddings stay opt-in via models.embedding.provider=hash. Plugin secrets resolve per owner at execution time. Refs: docs/proposals/2026-10-01-plugin-contract-v2.md Co-authored-by: Cursor <cursoragent@cursor.com>
63 lines
1.8 KiB
Go
63 lines
1.8 KiB
Go
package hostapi
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"agent-system-backend/internal/store"
|
|
"agent-system-backend/pkg/extension"
|
|
)
|
|
|
|
func TestHostClientRoundTrip(t *testing.T) {
|
|
st, err := store.OpenSQLite(filepath.Join(t.TempDir(), "h.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { st.Close() })
|
|
srv := &Server{Token: "sek", Store: st, Dispatch: func(ctx context.Context, pluginID, owner, commandID string, params map[string]any) error {
|
|
return nil
|
|
}}
|
|
ts := httptest.NewServer(srv.Handler())
|
|
t.Cleanup(ts.Close)
|
|
c := extension.NewHostClient(ts.URL, "sek", "rdm", "acme")
|
|
if err := c.PutKV(context.Background(), "slice", "s1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := c.GetKV(context.Background(), "slice")
|
|
if err != nil || got != "s1" {
|
|
t.Fatalf("kv %q %v", got, err)
|
|
}
|
|
if err := c.Audit(context.Background(), "ingest", "doc", []byte(`{"ok":true}`)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
evs, err := st.ListAuditEvents("acme", 10)
|
|
if err != nil || len(evs) != 1 || evs[0].Action != "ingest" {
|
|
t.Fatalf("audit %+v %v", evs, err)
|
|
}
|
|
if err := c.Dispatch(context.Background(), "builtin.help", nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
bad := extension.NewHostClient(ts.URL, "nope", "rdm", "acme")
|
|
if err := bad.PutKV(context.Background(), "x", "y"); err == nil {
|
|
t.Fatal("bad token must fail")
|
|
}
|
|
}
|
|
|
|
func TestLLMUnconfigured(t *testing.T) {
|
|
st, err := store.OpenSQLite(filepath.Join(t.TempDir(), "h.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { st.Close() })
|
|
srv := &Server{Store: st}
|
|
req := httptest.NewRequest(http.MethodPost, "/host/v1/llm", nil)
|
|
rec := httptest.NewRecorder()
|
|
srv.Handler().ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusServiceUnavailable {
|
|
t.Fatalf("status %d", rec.Code)
|
|
}
|
|
}
|