Co-authored-by: Mathias <mthbqv@gmail.com>
This commit was merged in pull request #152.
This commit is contained in:
+15
-5
@@ -20,6 +20,7 @@ const defaultBrainURL = "http://koala:30330"
|
||||
// shell-friendly client; MCP framing is unnecessary.
|
||||
type brainClient struct {
|
||||
baseURL string
|
||||
token string // BRAIN_MCP_TOKEN; the REST API requires it since hyperguild#149
|
||||
http *http.Client
|
||||
}
|
||||
|
||||
@@ -30,6 +31,7 @@ func newBrainClient() *brainClient {
|
||||
}
|
||||
return &brainClient{
|
||||
baseURL: u,
|
||||
token: os.Getenv("BRAIN_MCP_TOKEN"),
|
||||
http: &http.Client{Timeout: 5 * time.Second},
|
||||
}
|
||||
}
|
||||
@@ -62,8 +64,7 @@ func (c *brainClient) Query(ctx context.Context, topic string, limit int) (*Quer
|
||||
return nil, fmt.Errorf("build request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
resp, err := c.do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("brain POST /query: %w", err)
|
||||
}
|
||||
@@ -105,8 +106,7 @@ func (c *brainClient) Write(ctx context.Context, wing, hall, filename string, co
|
||||
return nil, fmt.Errorf("build request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
resp, err := c.do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("brain POST /write: %w", err)
|
||||
}
|
||||
@@ -143,7 +143,7 @@ func (c *brainClient) PassRate(ctx context.Context, skill, window string) (*Pass
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("build request: %w", err)
|
||||
}
|
||||
resp, err := c.http.Do(req)
|
||||
resp, err := c.do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("brain GET /pass-rate: %w", err)
|
||||
}
|
||||
@@ -158,3 +158,13 @@ func (c *brainClient) PassRate(ctx context.Context, skill, window string) (*Pass
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
// do sends every brain request, adding the bearer token when one is
|
||||
// configured. All methods go through here so none can forget it (PassRate
|
||||
// did, PR #152 review).
|
||||
func (c *brainClient) do(req *http.Request) (*http.Response, error) {
|
||||
if c.token != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+c.token)
|
||||
}
|
||||
return c.http.Do(req)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// hyperguild#149: the ingestion REST API now requires a bearer token; the CLI
|
||||
// sends BRAIN_MCP_TOKEN, or it gets 401 on every brain call.
|
||||
func TestBrainClientSendsBrainMCPTokenOnQueryWriteAndPassRate(t *testing.T) {
|
||||
var got []string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
got = append(got, r.URL.Path+" "+r.Header.Get("Authorization"))
|
||||
switch r.URL.Path {
|
||||
case "/write":
|
||||
_, _ = w.Write([]byte(`{"path":"wiki/x/facts/y.md"}`))
|
||||
return
|
||||
case "/pass-rate":
|
||||
_, _ = w.Write([]byte(`{}`))
|
||||
return
|
||||
}
|
||||
_, _ = w.Write([]byte(`{"results":[]}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
t.Setenv("BRAIN_URL", srv.URL)
|
||||
t.Setenv("BRAIN_MCP_TOKEN", "cli-test-token")
|
||||
|
||||
c := newBrainClient()
|
||||
_, err := c.Query(context.Background(), "x", 1)
|
||||
require.NoError(t, err)
|
||||
_, err = c.Write(context.Background(), "x", "facts", "y", strings.NewReader("# y"))
|
||||
require.NoError(t, err)
|
||||
// PR #152 review: PassRate sent no token and would 401 in production.
|
||||
_, _ = c.PassRate(context.Background(), "tdd", "7d")
|
||||
assert.Equal(t, []string{"/query Bearer cli-test-token", "/write Bearer cli-test-token",
|
||||
"/pass-rate Bearer cli-test-token"}, got)
|
||||
}
|
||||
|
||||
func TestBrainClientSendsNoAuthorizationWhenTokenUnset(t *testing.T) {
|
||||
var auth string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
auth = r.Header.Get("Authorization")
|
||||
_, _ = w.Write([]byte(`{"results":[]}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
t.Setenv("BRAIN_URL", srv.URL)
|
||||
t.Setenv("BRAIN_MCP_TOKEN", "")
|
||||
_, err := newBrainClient().Query(context.Background(), "x", 1)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, auth)
|
||||
}
|
||||
Reference in New Issue
Block a user