v0.25.0 c3476a8

permissions_test.go RawHistoryFolder

1package tools
2
3import (
4	"path/filepath"
5	"strings"
6	"testing"
7)
8
9func TestPermissionSetEmptyScopesDenyAccess(t *testing.T) {
10	s := NewSandbox(t.TempDir())
11	s.SetPermissions(&PermissionSet{})
12	if err := s.CheckReadPath(filepath.Join(s.Root, "a")); err == nil {
13		t.Fatal("empty read scope allowed access")
14	}
15	if err := s.CheckWritePath(filepath.Join(s.Root, "a")); err == nil {
16		t.Fatal("empty write scope allowed access")
17	}
18}
19
20func TestPermissionSetScopedAccess(t *testing.T) {
21	root := t.TempDir()
22	var p PermissionSet
23	p.FS.Read = []string{"${workspace}/src"}
24	p.FS.Write = []string{"${agent_data}"}
25	expanded := p.Expand(root, filepath.Join(root, "data"))
26	s := NewSandbox(root)
27	s.SetPermissions(&expanded)
28	if err := s.CheckReadPath(filepath.Join(root, "src", "a.go")); err != nil {
29		t.Fatalf("read inside scope: %v", err)
30	}
31	if err := s.CheckReadPath(filepath.Join(root, "secret")); err == nil {
32		t.Fatal("read outside scope was allowed")
33	}
34	if err := s.CheckWritePath(filepath.Join(root, "data", "state.json")); err != nil {
35		t.Fatalf("write inside scope: %v", err)
36	}
37}
38
39func TestPermissionExpandDoesNotMutateManifest(t *testing.T) {
40	var p PermissionSet
41	p.FS.Read = []string{"${workspace}"}
42	_ = p.Expand("/first", "/data")
43	if got := p.FS.Read[0]; got != "${workspace}" {
44		t.Fatalf("manifest mutated to %q", got)
45	}
46}
47
48func TestBashAllowlistRejectsShellEscapes(t *testing.T) {
49	var p PermissionSet
50	p.Bash.Mode = "allowlist"
51	p.Bash.Allow = []string{"echo"}
52	s := NewSandbox(t.TempDir())
53	s.SetPermissions(&p)
54	for _, cmd := range []string{"echo $(uname)", "echo hi > /tmp/out", "echo `uname`", "echo ok\nrm -rf /"} {
55		if err := s.CheckBashPermission(cmd); err == nil || !strings.Contains(err.Error(), "does not permit") {
56			t.Errorf("command %q was not rejected: %v", cmd, err)
57		}
58	}
59	if err := s.CheckBashPermission("echo ok"); err != nil {
60		t.Fatalf("allowed command rejected: %v", err)
61	}
62	if err := s.CheckBashPermission("rm file"); err == nil {
63		t.Fatal("unlisted command was allowed")
64	}
65}
66
67func TestBashModeNoneDenies(t *testing.T) {
68	var p PermissionSet
69	p.Bash.Mode = "none"
70	s := NewSandbox(t.TempDir())
71	s.SetPermissions(&p)
72	if err := s.CheckBashPermission("echo ok"); err == nil {
73		t.Fatal("none mode allowed bash")
74	}
75}
76
77func TestBashModeAskAllows(t *testing.T) {
78	var p PermissionSet
79	p.Bash.Mode = "ask"
80	s := NewSandbox(t.TempDir())
81	s.SetPermissions(&p)
82	if err := s.CheckBashPermission("rm -rf /tmp/x"); err != nil {
83		t.Fatalf("ask mode rejected command: %v", err)
84	}
85}

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