agent/pkg/orchestrator/security.go
Snider 5eb26f90fc refactor: replace fmt.Errorf/os.* with go-io/go-log conventions
Replace all fmt.Errorf and errors.New in production code with
coreerr.E("caller.Method", "message", err) from go-log. Replace
all os.ReadFile/os.WriteFile/os.MkdirAll/os.Remove with coreio.Local
equivalents from go-io. Test files are intentionally untouched.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-16 21:48:31 +00:00

58 lines
1.8 KiB
Go

package orchestrator
import (
"context"
"os/exec"
"path/filepath"
"regexp"
"strings"
coreerr "forge.lthn.ai/core/go-log"
)
var safeNameRegex = regexp.MustCompile(`^[a-zA-Z0-9\-\_\.]+$`)
// SanitizePath ensures a filename or directory name is safe and prevents path traversal.
// Returns filepath.Base of the input after validation.
func SanitizePath(input string) (string, error) {
base := filepath.Base(input)
if !safeNameRegex.MatchString(base) {
return "", coreerr.E("agentci.SanitizePath", "invalid characters in path element: "+input, nil)
}
if base == "." || base == ".." || base == "/" {
return "", coreerr.E("agentci.SanitizePath", "invalid path element: "+base, nil)
}
return base, nil
}
// EscapeShellArg wraps a string in single quotes for safe remote shell insertion.
// Prefer exec.Command arguments over constructing shell strings where possible.
func EscapeShellArg(arg string) string {
return "'" + strings.ReplaceAll(arg, "'", "'\\''") + "'"
}
// SecureSSHCommand creates an SSH exec.Cmd with strict host key checking and batch mode.
// Deprecated: Use SecureSSHCommandContext for context-aware cancellation.
func SecureSSHCommand(host string, remoteCmd string) *exec.Cmd {
return SecureSSHCommandContext(context.Background(), host, remoteCmd)
}
// SecureSSHCommandContext creates an SSH exec.Cmd with context support for cancellation,
// strict host key checking, and batch mode.
func SecureSSHCommandContext(ctx context.Context, host string, remoteCmd string) *exec.Cmd {
return exec.CommandContext(ctx, "ssh",
"-o", "StrictHostKeyChecking=yes",
"-o", "BatchMode=yes",
"-o", "ConnectTimeout=10",
host,
remoteCmd,
)
}
// MaskToken returns a masked version of a token for safe logging.
func MaskToken(token string) string {
if len(token) < 8 {
return "*****"
}
return token[:4] + "****" + token[len(token)-4:]
}