package permission import ( "encoding/json" "testing" ) func input(t *testing.T, v any) json.RawMessage { t.Helper() b, err := json.Marshal(v) if err != nil { t.Fatal(err) } return b } func TestModeFor_UnknownToolDefaultsToAuto(t *testing.T) { p := &Policy{Modes: map[string]Mode{"edit": ModeAsk}} if got := p.ModeFor("github__create_issue"); got != ModeAuto { t.Errorf("ModeFor(unknown) = %q, want auto", got) } } func TestModeFor_NilPolicyDefaultsToAuto(t *testing.T) { var p *Policy if got := p.ModeFor("edit"); got != ModeAuto { t.Errorf("ModeFor on nil policy = %q, want auto", got) } } func TestModeFor_UsesConfiguredMode(t *testing.T) { p := &Policy{Modes: map[string]Mode{"edit": ModeAsk, "bash": ModeDeny}} if got := p.ModeFor("edit"); got != ModeAsk { t.Errorf("edit = %q, want ask", got) } if got := p.ModeFor("bash"); got != ModeDeny { t.Errorf("bash = %q, want deny", got) } } func TestCheck_DenyPathOverridesAutoMode(t *testing.T) { p := &Policy{ Modes: map[string]Mode{"edit": ModeAuto}, DenyPaths: []string{".git/**", "**/.env", "**/id_rsa*"}, } cases := []struct { path string want Mode }{ {".git/config", ModeDeny}, {".env", ModeDeny}, {"sub/.env", ModeDeny}, {"id_rsa", ModeDeny}, {"~/.ssh/id_rsa_backup", ModeDeny}, // "**/id_rsa*" matcht auch mit Verzeichnis-Präfix {"main.go", ModeAuto}, } for _, c := range cases { got := p.Check("edit", input(t, map[string]string{"path": c.path})) if got != c.want { t.Errorf("Check(edit, path=%q) = %q, want %q", c.path, got, c.want) } } } func TestCheck_DenyBashOverridesAutoMode(t *testing.T) { p := &Policy{ Modes: map[string]Mode{"bash": ModeAuto}, DenyBash: []string{"rm -rf /", "git push --force*"}, } cases := []struct { cmd string want Mode }{ {"rm -rf /", ModeDeny}, {"cd /tmp && rm -rf / --no-preserve-root", ModeDeny}, {"git push --force origin main", ModeDeny}, {"git status", ModeAuto}, } for _, c := range cases { got := p.Check("bash", input(t, map[string]string{"command": c.cmd})) if got != c.want { t.Errorf("Check(bash, command=%q) = %q, want %q", c.cmd, got, c.want) } } } func TestCheck_NonPathToolIgnoresDenyPaths(t *testing.T) { p := &Policy{DenyPaths: []string{"**/.env"}} // todo hat kein "path"-Feld -> DenyPaths darf nicht versehentlich greifen. got := p.Check("todo", input(t, map[string]any{"items": []any{}})) if got != ModeAuto { t.Errorf("Check(todo) = %q, want auto (no path field to match against)", got) } } func TestCheck_AskModePreservedWithoutDenyMatch(t *testing.T) { p := &Policy{Modes: map[string]Mode{"edit": ModeAsk}} got := p.Check("edit", input(t, map[string]string{"path": "main.go"})) if got != ModeAsk { t.Errorf("Check(edit) = %q, want ask", got) } }