tinyrelayfile
tinyrelay/internal/daemon/mcp_grant_request_test.go/

internal/daemon/mcp_grant_request_test.go raw
1package daemon
2
3import (
4 "context"
5 "strings"
6 "testing"
7 "time"
8
9 "github.com/FelineStateMachine/tinyrelay/internal/event"
10 "github.com/FelineStateMachine/tinyrelay/internal/mcp"
11)
12
13func TestMCPGrantRequestBuildsOperatorBoundRequest(t *testing.T) {
14 _, tenant := testTenant(t)
15 agent, _ := event.PublicKey(testAgentSecret)
16 now := time.Now().Unix()
17 if err := publishAs(t, tenant, agentGrantEvent(t, agent, now, now+3600, []string{"k", "1111"})); err != nil {
18 t.Fatal(err)
19 }
20 changes := map[string]any{"kinds": []any{9}, "rooms": []any{"work"}}
21 unsigned, err := tenant.mcpBuildGrantRequest(context.Background(), mcp.Call{Actor: agent, Arguments: map[string]any{"reason": "Need chat replies", "changes": changes}})
22 if err != nil {
23 t.Fatal(err)
24 }
25 if unsigned.Kind != 1111 || unsigned.Content != "Need chat replies" {
26 t.Fatalf("unsigned request: %+v", unsigned)
27 }
28 if event.Tag(event.Event{Tags: unsigned.Tags}, "p") != tenant.Policy().Owner || event.Tag(event.Event{Tags: unsigned.Tags}, "request") != "grant" {
29 t.Fatalf("request is not bound to operator: %v", unsigned.Tags)
30 }
31 grant := event.Tag(event.Event{Tags: unsigned.Tags}, "grant")
32 if !strings.Contains(grant, `"base"`) || !strings.Contains(grant, `"kinds":[9]`) {
33 t.Fatalf("grant change payload: %s", grant)
34 }
35}
36
37func TestMCPGrantRequestRejectsUnsupportedChanges(t *testing.T) {
38 for _, raw := range []any{map[string]any{"unknown": "x"}, map[string]any{}} {
39 if _, err := mcpGrantChanges(raw); err == nil {
40 t.Errorf("accepted invalid changes: %#v", raw)
41 }
42 }
43}
44
45func TestMCPGrantRequestRejectsMissingGrantAndLongReason(t *testing.T) {
46 _, tenant := testTenant(t)
47 agent, _ := event.PublicKey(testAgentSecret)
48 call := mcp.Call{Actor: agent, Arguments: map[string]any{"reason": "need access", "changes": map[string]any{"kinds": []any{float64(9)}}}}
49 if _, err := tenant.mcpBuildGrantRequest(context.Background(), call); err == nil {
50 t.Fatal("agent without a grant accepted")
51 }
52 now := time.Now().Unix()
53 if err := publishAs(t, tenant, agentGrantEvent(t, agent, now, now+3600, []string{"k", "1111"})); err != nil {
54 t.Fatal(err)
55 }
56 call.Arguments["reason"] = strings.Repeat("x", 501)
57 if _, err := tenant.mcpBuildGrantRequest(context.Background(), call); err == nil {
58 t.Fatal("501-character reason accepted")
59 }
60}
61
62func TestMCPGrantRequestSchema(t *testing.T) {
63 schema := mcpGrantRequestSchema()
64 if err := mcp.Validate(schema, map[string]any{"event": map[string]any{}}); err != nil {
65 t.Fatalf("signed follow-up should be schema-valid: %v", err)
66 }
67 valid := map[string]any{"reason": "Need room chat", "changes": map[string]any{"kinds": []any{float64(9)}}}
68 if err := mcp.Validate(schema, valid); err != nil {
69 t.Fatal(err)
70 }
71 if err := mcp.Validate(schema, map[string]any{"reason": "", "changes": map[string]any{"kinds": []any{float64(9)}}}); err == nil {
72 t.Fatal("empty reason accepted")
73 }
74}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs