v0.3.84 97ae0a2

permissions_test.go RawHistoryFolder

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

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