Change module path from forge.lthn.ai/core/go-scm to dappco.re/go/core/scm. Update all Go source imports for migrated packages: - go-log -> dappco.re/go/core/log - go-io -> dappco.re/go/core/io - go-i18n -> dappco.re/go/core/i18n - go-ws -> dappco.re/go/core/ws - api -> dappco.re/go/core/api Non-migrated packages (cli, config) left on forge.lthn.ai paths. Replace directives use local paths (../go, ../go-io, etc.) until the dappco.re vanity URL server resolves these modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
50 lines
1.4 KiB
Go
50 lines
1.4 KiB
Go
package agentci
|
|
|
|
import (
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
|
|
coreerr "dappco.re/go/core/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.
|
|
func SecureSSHCommand(host string, remoteCmd string) *exec.Cmd {
|
|
return exec.Command("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:]
|
|
}
|