Consolidate path safety, temp downloads, and cleanup validation helpers
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/artifacts"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/config"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/pathsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -106,7 +107,7 @@ func BuildPlan(
|
||||
return result, nil
|
||||
}
|
||||
|
||||
runIDTemp, err := downloadObjectToTemp(ctx, store, currentRunIDKey, "narratio-previous-run-id-*.txt")
|
||||
runIDTemp, err := storage.DownloadObjectToTemp(ctx, store, currentRunIDKey, "narratio-previous-run-id-*.txt")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("download previous-session current run pointer %q: %w", currentRunIDKey, err)
|
||||
}
|
||||
@@ -134,7 +135,7 @@ func BuildPlan(
|
||||
return result, nil
|
||||
}
|
||||
|
||||
manifestTemp, err := downloadObjectToTemp(ctx, store, currentManifestKey, "narratio-previous-manifest-*.json")
|
||||
manifestTemp, err := storage.DownloadObjectToTemp(ctx, store, currentManifestKey, "narratio-previous-manifest-*.json")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("download previous-session current manifest %q: %w", currentManifestKey, err)
|
||||
}
|
||||
@@ -278,7 +279,7 @@ func artifactRelativePathCandidates(
|
||||
) []string {
|
||||
candidates := []string{}
|
||||
appendCandidate := func(v string) {
|
||||
normalized, err := normalizeArchiveRelativePath(v)
|
||||
normalized, err := pathsafe.NormalizeRelativeDestination(v)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -354,7 +355,7 @@ func deriveManifestRelativePath(previousManifest *manifest.Manifest, localPath s
|
||||
return "", false
|
||||
}
|
||||
if !filepath.IsAbs(trimmed) {
|
||||
normalized, err := normalizeArchiveRelativePath(filepath.ToSlash(trimmed))
|
||||
normalized, err := pathsafe.NormalizeRelativeDestination(filepath.ToSlash(trimmed))
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
@@ -369,7 +370,7 @@ func deriveManifestRelativePath(previousManifest *manifest.Manifest, localPath s
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
normalized, err := normalizeArchiveRelativePath(filepath.ToSlash(rel))
|
||||
normalized, err := pathsafe.NormalizeRelativeDestination(filepath.ToSlash(rel))
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
@@ -417,7 +418,7 @@ func manifestPublishedPaths(previousManifest *manifest.Manifest) []string {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
normalized, err := normalizeArchiveRelativePath(asString)
|
||||
normalized, err := pathsafe.NormalizeRelativeDestination(asString)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -426,21 +427,6 @@ func manifestPublishedPaths(previousManifest *manifest.Manifest) []string {
|
||||
return dedupeOrderedStrings(out)
|
||||
}
|
||||
|
||||
func normalizeArchiveRelativePath(rel string) (string, error) {
|
||||
trimmed := strings.TrimSpace(rel)
|
||||
if trimmed == "" {
|
||||
return "", fmt.Errorf("relative path is required")
|
||||
}
|
||||
cleaned := filepath.ToSlash(filepath.Clean(filepath.FromSlash(trimmed)))
|
||||
if cleaned == "." || cleaned == "" {
|
||||
return "", fmt.Errorf("relative path is required")
|
||||
}
|
||||
if filepath.IsAbs(trimmed) || strings.HasPrefix(cleaned, "/") || cleaned == ".." || strings.HasPrefix(cleaned, "../") {
|
||||
return "", fmt.Errorf("path must be a clean relative path")
|
||||
}
|
||||
return cleaned, nil
|
||||
}
|
||||
|
||||
func relativeToSession(paths artifacts.SessionPaths, localPath string) (string, error) {
|
||||
root := filepath.Clean(paths.Root)
|
||||
if strings.TrimSpace(root) == "" {
|
||||
@@ -450,7 +436,7 @@ func relativeToSession(paths artifacts.SessionPaths, localPath string) (string,
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("resolve previous-cache relative path: %w", err)
|
||||
}
|
||||
normalized, err := normalizeArchiveRelativePath(filepath.ToSlash(rel))
|
||||
normalized, err := pathsafe.NormalizeRelativeDestination(filepath.ToSlash(rel))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("resolve previous-cache relative path: %w", err)
|
||||
}
|
||||
@@ -476,20 +462,3 @@ func dedupeOrderedStrings(values []string) []string {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func downloadObjectToTemp(ctx context.Context, store storage.ObjectStore, key, pattern string) (string, error) {
|
||||
tmp, err := os.CreateTemp("", pattern)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create temp file: %w", err)
|
||||
}
|
||||
path := tmp.Name()
|
||||
if err := tmp.Close(); err != nil {
|
||||
_ = os.Remove(path)
|
||||
return "", fmt.Errorf("close temp file: %w", err)
|
||||
}
|
||||
if err := store.Download(ctx, key, path); err != nil {
|
||||
_ = os.Remove(path)
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user