CheckAndPrompt checks the policy for a tool call. If the policy is "ask", it acquires a mutex, pauses the spinner, and prompts the user interactively with full context about which agent is requesting the action and why.
(ctx context.Context, toolName, args string)
| 94 | // it acquires a mutex, pauses the spinner, and prompts the user interactively |
| 95 | // with full context about which agent is requesting the action and why. |
| 96 | func (a *workerPolicyAdapter) CheckAndPrompt(ctx context.Context, toolName, args string) (bool, string) { |
| 97 | action := a.pm.Check(toolName, args) |
| 98 | |
| 99 | switch action { |
| 100 | case coder.ActionAllow: |
| 101 | return true, "" |
| 102 | |
| 103 | case coder.ActionDeny: |
| 104 | a.logger.Info("Worker tool call blocked by policy (deny)", |
| 105 | zap.String("tool", toolName), |
| 106 | ) |
| 107 | return false, "AÇÃO BLOQUEADA (Regra de Segurança). NÃO TENTE NOVAMENTE." |
| 108 | |
| 109 | case coder.ActionAsk: |
| 110 | if a.unattended { |
| 111 | // Gateway: no human to answer; blocking on stdin would hang the |
| 112 | // worker silently. Auto-approve (see field doc). |
| 113 | a.logger.Info("Worker tool call auto-approved (unattended gateway)", |
| 114 | zap.String("tool", toolName)) |
| 115 | return true, "" |
| 116 | } |
| 117 | |
| 118 | // Serialize prompts: only one worker prompts the user at a time. |
| 119 | a.mu.Lock() |
| 120 | defer a.mu.Unlock() |
| 121 | |
| 122 | // Re-check after acquiring the lock — another worker's prompt may |
| 123 | // have created an "allow always" or "deny forever" rule for this |
| 124 | // same pattern while we were waiting. |
| 125 | newPM, pmErr := coder.NewPolicyManager(a.logger) // reload rules |
| 126 | if pmErr != nil { |
| 127 | a.logger.Error("failed to reload policy manager", zap.Error(pmErr)) |
| 128 | return false, "AÇÃO BLOQUEADA (erro ao recarregar políticas de segurança)." |
| 129 | } |
| 130 | a.pm = newPM |
| 131 | recheck := a.pm.Check(toolName, args) |
| 132 | if recheck == coder.ActionAllow { |
| 133 | return true, "" |
| 134 | } |
| 135 | if recheck == coder.ActionDeny { |
| 136 | return false, "AÇÃO BLOQUEADA (Regra de Segurança). NÃO TENTE NOVAMENTE." |
| 137 | } |
| 138 | |
| 139 | // Pause spinner so the prompt renders cleanly |
| 140 | a.pauseSpinner() |
| 141 | |
| 142 | // Build context for the enhanced prompt |
| 143 | secCtx := buildSecurityContext(ctx) |
| 144 | |
| 145 | // Prompt the user with full context |
| 146 | decision := coder.PromptSecurityCheckWithContextGuarded(ctx, toolName, args, secCtx, a.stdinCh) |
| 147 | pattern := coder.GetSuggestedPattern(toolName, args) |
| 148 | |
| 149 | // Clear the prompt area and resume spinner |
| 150 | fmt.Print(metrics.ClearLine()) |
| 151 | a.resumeSpinner() |
| 152 | |
| 153 | switch decision { |
nothing calls this directly
no test coverage detected