package policy import ( "context" "fmt" "github.com/sipeed/picoclaw/pkg/agent" ) // Config defines the security policy for tool execution. type Config struct { // RequiresApproval maps a tool name to a boolean. // If true, the tool will always return Approved=false with a "requires human approval" reason. RequiresApproval map[string]bool `json:"requires_approval"` // DisallowedTools maps a tool name to a boolean. // If true, the tool will be rejected without any human-in-the-loop option. DisallowedTools map[string]bool `json:"disallowed_tools"` // AllowedTools maps a tool name to a boolean. // If set (non-empty), only tools in this map are allowed. AllowedTools map[string]bool `json:"allowed_tools"` } // Checker implements the agent.ToolApprover interface. type Checker struct { Config Config } // Ensure Checker implements ToolApprover. var _ agent.ToolApprover = (*Checker)(nil) // NewChecker creates a new policy checker. func NewChecker(cfg Config) *Checker { return &Checker{Config: cfg} } func (c *Checker) ApproveTool(ctx context.Context, req *agent.ToolApprovalRequest) (agent.ApprovalDecision, error) { if req == nil { return agent.ApprovalDecision{Approved: false, Reason: "request is nil"}, nil } // 1. Explicit Disallow if c.Config.DisallowedTools[req.Tool] { return agent.ApprovalDecision{ Approved: false, Reason: fmt.Sprintf("Tool %q is globally disallowed by security policy", req.Tool), }, nil } // 2. Whitelisting (if enabled) if len(c.Config.AllowedTools) > 0 { if !c.Config.AllowedTools[req.Tool] { return agent.ApprovalDecision{ Approved: false, Reason: fmt.Sprintf("Tool %q is not in the allowed tools whitelist", req.Tool), }, nil } } // 3. Human Approval Required if c.Config.RequiresApproval[req.Tool] { return agent.ApprovalDecision{ Approved: false, Reason: fmt.Sprintf("Tool %q requires explicit human approval", req.Tool), }, nil } return agent.ApprovalDecision{Approved: true}, nil }