feature/recipe_implementation #5
@ -258,7 +258,7 @@ func createUnifiedPatch(changes []FileChange, patchPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeReadOnlyShell — now handles numbers in args (like tree -L 3)
|
// executeReadOnlyShell — safe, whitelisted, read-only shell execution with user confirmation
|
||||||
func (r *Runner) executeReadOnlyShell(step Step, previousResults []string) {
|
func (r *Runner) executeReadOnlyShell(step Step, previousResults []string) {
|
||||||
prompt := fmt.Sprintf(`You need additional context from the filesystem for this step.
|
prompt := fmt.Sprintf(`You need additional context from the filesystem for this step.
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ Return ONLY a JSON array of read-only commands. Example:
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
Only use safe read-only commands from the allowed list.`,
|
Only use safe read-only commands.`,
|
||||||
r.Recipe.Overview,
|
r.Recipe.Overview,
|
||||||
strings.Join(previousResults, "\n\n---\n\n"),
|
strings.Join(previousResults, "\n\n---\n\n"),
|
||||||
step.Objective,
|
step.Objective,
|
||||||
@ -312,7 +312,7 @@ Only use safe read-only commands from the allowed list.`,
|
|||||||
|
|
||||||
type ShellCommand struct {
|
type ShellCommand struct {
|
||||||
Command string `json:"command"`
|
Command string `json:"command"`
|
||||||
Args []interface{} `json:"args"` // allows strings and numbers
|
Args []interface{} `json:"args"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmds []ShellCommand
|
var cmds []ShellCommand
|
||||||
@ -321,6 +321,9 @@ Only use safe read-only commands from the allowed list.`,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use the GLOBAL safe list for the security check
|
||||||
|
safeMap := safeCommands()
|
||||||
|
|
||||||
for _, cmd := range cmds {
|
for _, cmd := range cmds {
|
||||||
// Build argument list, converting numbers to strings
|
// Build argument list, converting numbers to strings
|
||||||
args := make([]string, len(cmd.Args))
|
args := make([]string, len(cmd.Args))
|
||||||
@ -330,8 +333,6 @@ Only use safe read-only commands from the allowed list.`,
|
|||||||
args[i] = v
|
args[i] = v
|
||||||
case float64:
|
case float64:
|
||||||
args[i] = strconv.FormatFloat(v, 'f', -1, 64)
|
args[i] = strconv.FormatFloat(v, 'f', -1, 64)
|
||||||
case int, int64:
|
|
||||||
args[i] = fmt.Sprintf("%v", v)
|
|
||||||
default:
|
default:
|
||||||
args[i] = fmt.Sprintf("%v", v)
|
args[i] = fmt.Sprintf("%v", v)
|
||||||
}
|
}
|
||||||
@ -354,16 +355,18 @@ Only use safe read-only commands from the allowed list.`,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whitelist check
|
// FINAL SECURITY CHECK — use the global safe list
|
||||||
allowed := false
|
allowed := false
|
||||||
for _, allowedCmd := range r.Recipe.AllowedShellCommands {
|
trimmedCmd := strings.ToLower(strings.TrimSpace(cmd.Command))
|
||||||
if strings.HasPrefix(cmd.Command, allowedCmd) {
|
for safe := range safeMap {
|
||||||
|
if strings.HasPrefix(trimmedCmd, strings.ToLower(safe)) {
|
||||||
allowed = true
|
allowed = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !allowed {
|
if !allowed {
|
||||||
fmt.Printf(" ❌ Command not allowed: %s\n", cmd.Command)
|
fmt.Printf(" ❌ Command not allowed by global safety policy: %s\n", cmd.Command)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user