v0.7.0 3110ba7

web_search_policy_test.go RawHistoryFolder

1package subagents
2
3import "testing"
4
5func TestSupervisorResolvesWebSearchPolicy(t *testing.T) {
6	cases := []struct {
7		name   string
8		config Config
9		req    SpawnRequest
10		want   WebSearchPolicy
11	}{
12		{
13			name:   "generic child inherits allowed parent",
14			config: Config{WebSearchPolicy: WebSearchAllow},
15			want:   WebSearchAllow,
16		},
17		{
18			name:   "missing parent policy denies",
19			config: Config{},
20			want:   WebSearchDeny,
21		},
22		{
23			name:   "unknown parent policy denies",
24			config: Config{WebSearchPolicy: WebSearchPolicy(99)},
25			want:   WebSearchDeny,
26		},
27		{
28			name:   "parent denial wins",
29			config: Config{WebSearchPolicy: WebSearchDeny},
30			want:   WebSearchDeny,
31		},
32		{
33			name: "allowed tools ceiling denies generic child",
34			config: Config{
35				WebSearchPolicy: WebSearchAllow,
36				Policy:          SubagentPolicy{AllowedTools: []string{"read"}},
37			},
38			want: WebSearchDeny,
39		},
40		{
41			name:   "named profile without tools denies",
42			config: Config{WebSearchPolicy: WebSearchAllow},
43			req:    SpawnRequest{Subagent: "reviewer"},
44			want:   WebSearchDeny,
45		},
46		{
47			name:   "named profile explicit tool allows",
48			config: Config{WebSearchPolicy: WebSearchAllow},
49			req:    SpawnRequest{Subagent: "researcher", Tools: []string{"read", "web_search"}},
50			want:   WebSearchAllow,
51		},
52		{
53			name:   "named profile cannot exceed denied parent",
54			config: Config{WebSearchPolicy: WebSearchDeny},
55			req:    SpawnRequest{Subagent: "researcher", Tools: []string{"web_search"}},
56			want:   WebSearchDeny,
57		},
58		{
59			name:   "invalid request policy denies generic child",
60			config: Config{WebSearchPolicy: WebSearchAllow},
61			req:    SpawnRequest{WebSearchPolicy: WebSearchPolicy(99)},
62			want:   WebSearchDeny,
63		},
64		{
65			name:   "invalid request policy denies named child",
66			config: Config{WebSearchPolicy: WebSearchAllow},
67			req:    SpawnRequest{WebSearchPolicy: WebSearchPolicy(99), Subagent: "researcher", Tools: []string{"web_search"}},
68			want:   WebSearchDeny,
69		},
70	}
71	for _, tc := range cases {
72		t.Run(tc.name, func(t *testing.T) {
73			f := New(tc.config)
74			if got := f.resolveWebSearchPolicy(tc.req); got != tc.want {
75				t.Fatalf("policy = %v, want %v", got, tc.want)
76			}
77		})
78	}
79}
80
81func TestWorkerWebSearchPolicyIsExplicitAndFailClosed(t *testing.T) {
82	cases := []struct {
83		name     string
84		policy   WebSearchPolicy
85		subagent string
86		tools    []string
87		want     string
88	}{
89		{name: "missing generic policy", policy: WebSearchInherit, want: "deny"},
90		{name: "unknown generic policy", policy: WebSearchPolicy(99), want: "deny"},
91		{name: "named policy without opt in", policy: WebSearchAllow, subagent: "researcher", want: "deny"},
92		{name: "named policy with explicit opt in", policy: WebSearchAllow, subagent: "researcher", tools: []string{"read", "web_search"}, want: "allow"},
93		{name: "invalid named policy cannot use profile opt in", policy: WebSearchPolicy(99), subagent: "researcher", tools: []string{"web_search"}, want: "deny"},
94	}
95	for _, tc := range cases {
96		t.Run(tc.name, func(t *testing.T) {
97			args := subagentWorkerArgs(subagentWorkerArgsOpts{
98				Exe:             "/zut",
99				Dir:             "/work",
100				SessionPath:     "/state/session.json",
101				InboxPath:       "/state/inbox.sock",
102				Subagent:        tc.subagent,
103				Tools:           tc.tools,
104				WebSearchPolicy: tc.policy,
105			})
106			idx := indexOf(args, "--web-search-policy")
107			if idx < 0 || safeAt(args, idx+1) != tc.want {
108				t.Fatalf("argv = %v, want policy %q", args, tc.want)
109			}
110		})
111	}
112
113	if got := WebSearchPolicy(99).String(); got != "deny" {
114		t.Fatalf("unknown policy string = %q, want deny", got)
115	}
116}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 477

↑↓ moveenter openesc close