fix(agentci): split path sanitising and validation
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
ec8149efbe
commit
f2c9cb39d0
2 changed files with 20 additions and 9 deletions
|
|
@ -16,28 +16,36 @@ import (
|
|||
var safeNameRegex = regexp.MustCompile(`^[a-zA-Z0-9\-\_\.]+$`)
|
||||
|
||||
// SanitizePath ensures a filename or directory name is safe and prevents path traversal.
|
||||
// Returns the validated input unchanged.
|
||||
// Returns the validated basename.
|
||||
// Usage: SanitizePath(...)
|
||||
func SanitizePath(input string) (string, error) {
|
||||
if input == "" {
|
||||
return "", coreerr.E("agentci.SanitizePath", "path element is required", nil)
|
||||
}
|
||||
if strings.ContainsAny(input, `/\`) {
|
||||
return "", coreerr.E("agentci.SanitizePath", "path separators are not allowed: "+input, nil)
|
||||
}
|
||||
if input == "." || input == ".." {
|
||||
safeName := filepath.Base(input)
|
||||
if safeName == "." || safeName == ".." {
|
||||
return "", coreerr.E("agentci.SanitizePath", "invalid path element: "+input, nil)
|
||||
}
|
||||
if !safeNameRegex.MatchString(input) {
|
||||
if strings.ContainsAny(safeName, `/\`) {
|
||||
return "", coreerr.E("agentci.SanitizePath", "path separators are not allowed: "+input, nil)
|
||||
}
|
||||
if !safeNameRegex.MatchString(safeName) {
|
||||
return "", coreerr.E("agentci.SanitizePath", "invalid characters in path element: "+input, nil)
|
||||
}
|
||||
return input, nil
|
||||
return safeName, nil
|
||||
}
|
||||
|
||||
// ValidatePathElement validates a single local path element and returns its safe form.
|
||||
// Usage: ValidatePathElement(...)
|
||||
func ValidatePathElement(input string) (string, error) {
|
||||
return SanitizePath(input)
|
||||
safeName, err := SanitizePath(input)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if safeName != input {
|
||||
return "", coreerr.E("agentci.ValidatePathElement", "path separators are not allowed: "+input, nil)
|
||||
}
|
||||
return safeName, nil
|
||||
}
|
||||
|
||||
// ResolvePathWithinRoot resolves a validated path element beneath a root directory.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ func TestSanitizePath_Good(t *testing.T) {
|
|||
{"with.dot", "with.dot"},
|
||||
{"CamelCase", "CamelCase"},
|
||||
{"123", "123"},
|
||||
{"../secret", "secret"},
|
||||
{"/var/tmp/report.txt", "report.txt"},
|
||||
{"nested/path/file", "file"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -44,8 +47,8 @@ func TestSanitizePath_Bad(t *testing.T) {
|
|||
{"pipe", "file|name"},
|
||||
{"ampersand", "file&name"},
|
||||
{"dollar", "file$name"},
|
||||
{"slash", "path/to/file.txt"},
|
||||
{"backslash", `path\to\file.txt`},
|
||||
{"current dir", "."},
|
||||
{"parent traversal base", ".."},
|
||||
{"root", "/"},
|
||||
{"empty", ""},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue