feat: wire permission checker into engine tool execution
Tools now go through permission.Checker before executing: - plan mode: denies all writes (fs.write, bash), allows reads - bypass mode: allows all (deny rules still enforced) - default mode: prompts user (pipe: stdin prompt, TUI: auto-approve for now) - accept_edits: auto-allows file ops, prompts for bash - deny mode: denies all without allow rules CLI flags: --permission <mode>, --incognito Pipe mode: console Y/N prompt on stderr TUI mode: auto-approve (proper overlay TODO) Verified: plan mode correctly blocks fs.write, model sees error.
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"somegit.dev/Owlibou/gnoma/internal/message"
|
||||
"somegit.dev/Owlibou/gnoma/internal/permission"
|
||||
"somegit.dev/Owlibou/gnoma/internal/provider"
|
||||
"somegit.dev/Owlibou/gnoma/internal/router"
|
||||
"somegit.dev/Owlibou/gnoma/internal/stream"
|
||||
@@ -199,6 +200,24 @@ func (e *Engine) executeTools(ctx context.Context, calls []message.ToolCall, cb
|
||||
continue
|
||||
}
|
||||
|
||||
// Permission check
|
||||
if e.cfg.Permissions != nil {
|
||||
info := permission.ToolInfo{
|
||||
Name: call.Name,
|
||||
IsReadOnly: t.IsReadOnly(),
|
||||
IsDestructive: t.IsDestructive(),
|
||||
}
|
||||
if err := e.cfg.Permissions.Check(ctx, info, call.Arguments); err != nil {
|
||||
e.logger.Info("tool permission denied", "name", call.Name, "error", err)
|
||||
results = append(results, message.ToolResult{
|
||||
ToolCallID: call.ID,
|
||||
Content: fmt.Sprintf("permission denied: %v", err),
|
||||
IsError: true,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
e.logger.Debug("executing tool", "name", call.Name, "id", call.ID)
|
||||
|
||||
result, err := t.Execute(ctx, call.Arguments)
|
||||
|
||||
Reference in New Issue
Block a user