1a69fcfd04
- 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.
166 lines
4.4 KiB
Go
166 lines
4.4 KiB
Go
package workspace
|
|
|
|
import (
|
|
"archive/tar"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// ExtractTar extracts a tar archive from a reader to a directory.
|
|
func ExtractTar(reader io.Reader, destDir string) error {
|
|
if err := os.MkdirAll(destDir, 0755); err != nil {
|
|
return fmt.Errorf("failed to create destination directory: %w", err)
|
|
}
|
|
|
|
tarReader := tar.NewReader(reader)
|
|
|
|
for {
|
|
header, err := tarReader.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read tar header: %w", err)
|
|
}
|
|
|
|
// Sanitize path to prevent directory traversal
|
|
targetPath := filepath.Join(destDir, header.Name)
|
|
if !strings.HasPrefix(filepath.Clean(targetPath), filepath.Clean(destDir)+string(os.PathSeparator)) {
|
|
return fmt.Errorf("invalid file path in tar: %s", header.Name)
|
|
}
|
|
|
|
switch header.Typeflag {
|
|
case tar.TypeDir:
|
|
if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil {
|
|
return fmt.Errorf("failed to create directory: %w", err)
|
|
}
|
|
|
|
case tar.TypeReg:
|
|
if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
|
|
return fmt.Errorf("failed to create parent directory: %w", err)
|
|
}
|
|
|
|
outFile, err := os.Create(targetPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create file: %w", err)
|
|
}
|
|
|
|
if _, err := io.Copy(outFile, tarReader); err != nil {
|
|
outFile.Close()
|
|
return fmt.Errorf("failed to write file: %w", err)
|
|
}
|
|
outFile.Close()
|
|
|
|
if err := os.Chmod(targetPath, os.FileMode(header.Mode)); err != nil {
|
|
log.Printf("Warning: failed to set file permissions: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ExtractTarStripPrefix extracts a tar archive, stripping the top-level directory.
|
|
// Useful for Blender archives like "blender-4.2.3-linux-x64/".
|
|
func ExtractTarStripPrefix(reader io.Reader, destDir string) error {
|
|
if err := os.MkdirAll(destDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
tarReader := tar.NewReader(reader)
|
|
stripPrefix := ""
|
|
|
|
for {
|
|
header, err := tarReader.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Determine strip prefix from first entry (e.g., "blender-4.2.3-linux-x64/")
|
|
if stripPrefix == "" {
|
|
parts := strings.SplitN(header.Name, "/", 2)
|
|
if len(parts) > 0 {
|
|
stripPrefix = parts[0] + "/"
|
|
}
|
|
}
|
|
|
|
// Strip the top-level directory
|
|
name := strings.TrimPrefix(header.Name, stripPrefix)
|
|
if name == "" {
|
|
continue
|
|
}
|
|
|
|
targetPath := filepath.Join(destDir, name)
|
|
|
|
// Sanitize path to prevent directory traversal
|
|
if !strings.HasPrefix(filepath.Clean(targetPath), filepath.Clean(destDir)+string(os.PathSeparator)) {
|
|
return fmt.Errorf("invalid file path in tar: %s", header.Name)
|
|
}
|
|
|
|
switch header.Typeflag {
|
|
case tar.TypeDir:
|
|
if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil {
|
|
return err
|
|
}
|
|
|
|
case tar.TypeReg:
|
|
if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
|
|
return err
|
|
}
|
|
outFile, err := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(header.Mode))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := io.Copy(outFile, tarReader); err != nil {
|
|
outFile.Close()
|
|
return err
|
|
}
|
|
outFile.Close()
|
|
|
|
case tar.TypeSymlink:
|
|
if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
|
|
return err
|
|
}
|
|
// Reject absolute or escaping symlink targets so extraction cannot
|
|
// plant links that point outside destDir.
|
|
linkTarget := header.Linkname
|
|
if linkTarget == "" {
|
|
return fmt.Errorf("invalid empty symlink target in tar: %s", header.Name)
|
|
}
|
|
if filepath.IsAbs(linkTarget) {
|
|
return fmt.Errorf("absolute symlink target not allowed in tar: %s -> %s", header.Name, linkTarget)
|
|
}
|
|
resolvedLink := filepath.Clean(filepath.Join(filepath.Dir(targetPath), linkTarget))
|
|
cleanDest := filepath.Clean(destDir)
|
|
if resolvedLink != cleanDest && !strings.HasPrefix(resolvedLink, cleanDest+string(os.PathSeparator)) {
|
|
return fmt.Errorf("symlink target escapes extract root: %s -> %s", header.Name, linkTarget)
|
|
}
|
|
os.Remove(targetPath) // Remove existing symlink if present
|
|
if err := os.Symlink(header.Linkname, targetPath); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ExtractTarFile extracts a tar file to a directory.
|
|
func ExtractTarFile(tarPath, destDir string) error {
|
|
file, err := os.Open(tarPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open tar file: %w", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
return ExtractTar(file, destDir)
|
|
}
|
|
|