1package agent
2
3import (
4 "testing"
5
6 "github.com/bnema/zut/packages/agent/tools"
7)
8
9// TestSubagentActionAllowedMatrix pins the launch-time gating contract: a bare
10// "subagent" entry grants every action, "subagent:<action>" grants one action,
11// and every pre-existing disable path still disables all of them.
12func TestSubagentActionAllowedMatrix(t *testing.T) {
13 cases := []struct {
14 name string
15 args Args
16 spawn bool
17 status bool
18 stop bool
19 resume bool
20 }{
21 {name: "default grants every action", args: Args{}, spawn: true, status: true, stop: true, resume: true},
22 {name: "unrelated allowlist denies all", args: Args{ToolsSet: true, Tools: []string{"read"}}},
23 {name: "bare subagent grants every action", args: Args{ToolsSet: true, Tools: []string{"subagent"}}, spawn: true, status: true, stop: true, resume: true},
24 {name: "bare subagent wins beside a suffix", args: Args{ToolsSet: true, Tools: []string{"read", "subagent:resume", "subagent"}}, spawn: true, status: true, stop: true, resume: true},
25 {name: "one action suffix grants one action", args: Args{ToolsSet: true, Tools: []string{"subagent:resume"}}, resume: true},
26 {name: "two action suffixes grant two actions", args: Args{ToolsSet: true, Tools: []string{"subagent:spawn", "subagent:stop"}}, spawn: true, stop: true},
27 {name: "unknown action suffix denies all", args: Args{ToolsSet: true, Tools: []string{"subagent:bogus"}}},
28 {name: "empty allowlist denies all", args: Args{ToolsSet: true, Tools: []string{}}},
29 {name: "no tools denies all", args: Args{NoTools: true}},
30 {name: "packaged permission set denies all", args: Args{PermissionSet: &tools.PermissionSet{}}},
31 }
32 for _, tc := range cases {
33 t.Run(tc.name, func(t *testing.T) {
34 got := [4]bool{
35 autoSubagentsToolAllowed(tc.args),
36 autoSubagentsStatusToolAllowed(tc.args),
37 autoSubagentsStopToolAllowed(tc.args),
38 autoSubagentsResumeToolAllowed(tc.args),
39 }
40 want := [4]bool{tc.spawn, tc.status, tc.stop, tc.resume}
41 if got != want {
42 t.Fatalf("actions = %v, want %v (args %+v)", got, want, tc.args)
43 }
44 wantAny := tc.spawn || tc.status || tc.stop || tc.resume
45 if any := autoSubagentsAnyToolAllowed(tc.args); any != wantAny {
46 t.Fatalf("autoSubagentsAnyToolAllowed = %v, want %v (args %+v)", any, wantAny, tc.args)
47 }
48 })
49 }
50}