feat: add a-route uia send connector

This commit is contained in:
zhaoyilun
2026-07-11 11:16:53 +08:00
parent 456ef44e8e
commit 8aa952a491
15 changed files with 941 additions and 19 deletions

View File

@@ -385,6 +385,52 @@ func TestISphereSendMessageFakeConnectorFailureAudit(t *testing.T) {
}
}
func TestISphereSendMessageConnectorReceivesContentTextWithoutLeakingIt(t *testing.T) {
audit := &fakeSendMessageAuditSink{}
idempotency := newFakeSendMessageIdempotencyStore()
connector := &fakeSendMessageConnector{
result: SendMessageConnectorResult{
Accepted: true,
Status: "accepted",
AckRef: "fake-content-ack",
ConnectorMode: "fake",
},
}
session, cleanup := connectToolsTestSession(t, func(server *mcp.Server) {
RegisterISphereSendMessageToolWithStateAndConnector(server, audit, idempotency, connector)
})
defer cleanup()
content := "connector needs the raw text to send"
callResult, err := session.CallTool(context.Background(), &mcp.CallToolParams{
Name: ToolNameSendMessage,
Arguments: map[string]any{
"target_type": "direct",
"target_id": "alice@imopenfire1-lanzhou",
"content_text": content,
"content_sha256": sha256HexForSendMessageTest(content),
"idempotency_key": "idem-connector-content-1",
"execution_mode": "production",
},
})
if err != nil {
t.Fatalf("call %s: %v", ToolNameSendMessage, err)
}
payload, _ := json.Marshal(callResult.StructuredContent)
if connector.lastRequest.ContentText != content {
t.Fatalf("connector ContentText = %q, want raw content", connector.lastRequest.ContentText)
}
if strings.Contains(string(payload), content) {
t.Fatalf("structured response leaked raw content: %s", payload)
}
if len(audit.events) != 1 {
t.Fatalf("audit events = %+v, want one", audit.events)
}
if audit.events[0].ContentText != "" || strings.Contains(mustMarshalStringForSendMessageTest(audit.events[0]), content) {
t.Fatalf("audit leaked raw content: %+v", audit.events[0])
}
}
func TestISphereSendMessageRejectsContentHashMismatch(t *testing.T) {
session, cleanup := connectToolsTestSession(t, func(server *mcp.Server) {
RegisterISphereSendMessageToolWithState(server, &fakeSendMessageAuditSink{}, newFakeSendMessageIdempotencyStore())
@@ -650,13 +696,15 @@ func (f *fakeSendMessageIdempotencyStore) ReserveSendMessageIdempotency(_ contex
}
type fakeSendMessageConnector struct {
result SendMessageConnectorResult
err error
calls int
result SendMessageConnectorResult
err error
calls int
lastRequest SendMessageConnectorRequest
}
func (f *fakeSendMessageConnector) ExecuteSendMessage(_ context.Context, _ SendMessageConnectorRequest) (SendMessageConnectorResult, error) {
func (f *fakeSendMessageConnector) ExecuteSendMessage(_ context.Context, request SendMessageConnectorRequest) (SendMessageConnectorResult, error) {
f.calls++
f.lastRequest = request
return f.result, f.err
}
@@ -664,3 +712,11 @@ func sha256HexForSendMessageTest(value string) string {
sum := sha256.Sum256([]byte(value))
return hex.EncodeToString(sum[:])
}
func mustMarshalStringForSendMessageTest(value any) string {
payload, err := json.Marshal(value)
if err != nil {
panic(err)
}
return string(payload)
}