refactor(recipe/loader): expand safe shell commands and refine validation logic

- Renamed safeReadOnlyCommands to safeCommands for clarity.
- Added support for additional safe commands including GNU utilities (find, grep, which),
  Git commands (diff, branch), and various test runners (go test, make test/lint, pytest, etc.).
- Updated safety check to allow commands prefixed with any safe command for flexibility.
- Improved error message for unsafe commands.
This commit is contained in:
Greg Gauthier 2026-03-07 17:59:59 +00:00
parent b2172b8546
commit 7e4bdbc21c

View File

@ -12,18 +12,35 @@ import (
) )
// Global safe read-only whitelist // Global safe read-only whitelist
var safeReadOnlyCommands = map[string]bool{ var safeCommands = map[string]bool{
"ls": true, //GNU Utilities
"pwd": true, "ls": true,
"cat": true, "pwd": true,
"tree": true, "cat": true,
"tree": true,
"find": true,
"grep": true,
"which": true,
//Git and Gitea
"git status": true, "git status": true,
"git log": true, "git log": true,
"find": true, "git diff": true,
"grep": true, "git branch": true,
"cndump -s": true,
"tea repos list -o csv -lm 100": true, "tea repos list -o csv -lm 100": true,
"tea repos search -o csv": true, "tea repos search -o csv": true,
//Miscellaneous Utilities
"cndump -s": true,
// Safe test runners
"go test": true,
"make test": true,
"make lint": true,
"pytest": true,
"poetry run pytest": true,
"ctest": true,
"python -m pytest": true,
"go vet": true,
"go fmt": true,
"go mod tidy": true,
} }
var ( var (
@ -47,11 +64,21 @@ func Load(path string, userParams map[string]any) (*Recipe, error) {
return nil, fmt.Errorf("yaml parse: %w", err) return nil, fmt.Errorf("yaml parse: %w", err)
} }
// === SAFETY CHECK: reject dangerous allowed_shell_commands === // === SAFETY CHECK: reject truly dangerous commands ===
for _, cmd := range r.AllowedShellCommands { for _, cmd := range r.AllowedShellCommands {
trimmed := strings.TrimSpace(strings.ToLower(cmd)) trimmed := strings.TrimSpace(strings.ToLower(cmd))
if !safeReadOnlyCommands[trimmed] && !strings.HasPrefix(trimmed, "git status") && !strings.HasPrefix(trimmed, "git log") {
return nil, fmt.Errorf("\u001B[31mRecipe contains unsafe shell command: %q. Remove or replace the dangerous command in your recipe.\u001B[0m", cmd) // Allow exact matches or common prefixed commands
allowed := false
for safe := range safeCommands {
if strings.HasPrefix(trimmed, safe) {
allowed = true
break
}
}
if !allowed {
return nil, fmt.Errorf("\u001B[31mRecipe contains unsafe shell command: %q. "+
"Remove or replace the dangerous command in your recipe.\u001B[0m", cmd)
} }
} }