Refactor installation and runner scripts for enhanced usability and security
- Updated the installation script to clarify that production wrappers do not include fixed test secrets, improving user guidance for local testing. - Modified the jiggablend-manager and jiggablend-runner scripts to remove fixed test configurations, emphasizing the use of local test credentials via `make init-test`. - Enhanced error handling in the runner script to ensure that an API key is provided, improving security and user feedback. - Added new flags and options for the runner, including sandboxing capabilities and GPU ray tracing control, enhancing flexibility for users. - Improved README documentation to reflect changes in usage and configuration, ensuring users have clear instructions for setup and execution.
This commit is contained in:
@@ -80,10 +80,54 @@ func (s *Storage) JobPath(jobID int64) string {
|
||||
return filepath.Join(s.basePath, "jobs", fmt.Sprintf("%d", jobID))
|
||||
}
|
||||
|
||||
// SanitizeFilename returns a safe basename for client-supplied names.
|
||||
// Rejects empty, ".", "..", and root-like basenames.
|
||||
func SanitizeFilename(name string) (string, error) {
|
||||
cleaned := filepath.Clean(strings.ReplaceAll(name, "\\", "/"))
|
||||
base := filepath.Base(cleaned)
|
||||
// filepath.Base("..") is ".." ; Clean("/../..") style inputs can yield "/" or "."
|
||||
if base == "" || base == "." || base == ".." || base == "/" || base == string(os.PathSeparator) {
|
||||
return "", fmt.Errorf("invalid filename: %q", name)
|
||||
}
|
||||
// Reject if the cleaned path still has parent references after basenaming was skipped
|
||||
if strings.Contains(cleaned, "..") && base == cleaned {
|
||||
return "", fmt.Errorf("invalid filename: %q", name)
|
||||
}
|
||||
return base, nil
|
||||
}
|
||||
|
||||
// SafePathUnderRoot joins root and a relative path and ensures the result stays under root.
|
||||
func SafePathUnderRoot(root, rel string) (string, error) {
|
||||
if rel == "" {
|
||||
return "", fmt.Errorf("empty path")
|
||||
}
|
||||
// Normalize to forward slashes then clean
|
||||
rel = filepath.ToSlash(rel)
|
||||
if filepath.IsAbs(rel) || strings.HasPrefix(rel, "/") {
|
||||
return "", fmt.Errorf("absolute path not allowed: %q", rel)
|
||||
}
|
||||
cleanRel := filepath.Clean(rel)
|
||||
if cleanRel == ".." || strings.HasPrefix(cleanRel, ".."+string(os.PathSeparator)) {
|
||||
return "", fmt.Errorf("path escapes root: %q", rel)
|
||||
}
|
||||
cleanRoot := filepath.Clean(root)
|
||||
full := filepath.Join(cleanRoot, cleanRel)
|
||||
cleanFull := filepath.Clean(full)
|
||||
sep := string(os.PathSeparator)
|
||||
if cleanFull != cleanRoot && !strings.HasPrefix(cleanFull, cleanRoot+sep) {
|
||||
return "", fmt.Errorf("path escapes root: %q", rel)
|
||||
}
|
||||
return cleanFull, nil
|
||||
}
|
||||
|
||||
// SaveUpload saves an uploaded file
|
||||
func (s *Storage) SaveUpload(jobID int64, filename string, reader io.Reader) (string, error) {
|
||||
// Sanitize filename to prevent path traversal
|
||||
filename = filepath.Base(filename)
|
||||
var err error
|
||||
filename, err = SanitizeFilename(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
jobPath := s.JobPath(jobID)
|
||||
if err := os.MkdirAll(jobPath, 0755); err != nil {
|
||||
@@ -106,12 +150,26 @@ func (s *Storage) SaveUpload(jobID int64, filename string, reader io.Reader) (st
|
||||
|
||||
// SaveOutput saves an output file
|
||||
func (s *Storage) SaveOutput(jobID int64, filename string, reader io.Reader) (string, error) {
|
||||
// Sanitize filename to prevent path traversal (parity with SaveUpload)
|
||||
var err error
|
||||
filename, err = SanitizeFilename(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(s.outputsPath(), fmt.Sprintf("%d", jobID))
|
||||
if err := os.MkdirAll(outputPath, 0755); err != nil {
|
||||
return "", fmt.Errorf("failed to create output directory: %w", err)
|
||||
}
|
||||
|
||||
filePath := filepath.Join(outputPath, filename)
|
||||
// Defense in depth: ensure resolved path stays under output dir
|
||||
if resolved, err := SafePathUnderRoot(outputPath, filename); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
filePath = resolved
|
||||
}
|
||||
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create file: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user