summaryrefslogtreecommitdiff
path: root/internal/image/download_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/image/download_test.go')
-rw-r--r--internal/image/download_test.go34
1 files changed, 34 insertions, 0 deletions
diff --git a/internal/image/download_test.go b/internal/image/download_test.go
index b9a6e31..84e8f5f 100644
--- a/internal/image/download_test.go
+++ b/internal/image/download_test.go
@@ -189,3 +189,37 @@ func TestDownloadImageRejectsNilResult(t *testing.T) {
t.Fatal("expected error for nil result")
}
}
+
+func TestDownloadImageRejectsSymlinkAncestor(t *testing.T) {
+ t.Parallel()
+
+ baseDir := t.TempDir()
+ outsideDir := t.TempDir()
+ linkDir := filepath.Join(baseDir, "link")
+ if err := os.Symlink(outsideDir, linkDir); err != nil {
+ t.Fatalf("Symlink() error = %v", err)
+ }
+
+ provider := &mockDownloaderProvider{payload: "image-bytes"}
+ d := NewDownloader(provider, &DownloadOptions{
+ OutputDir: baseDir,
+ CreateDir: true,
+ OverwriteExisting: true,
+ })
+
+ outputPath := filepath.Join(linkDir, "escape.png")
+ err := d.DownloadImage(context.Background(), &SearchResult{
+ URL: "https://example.com/image.png",
+ Source: Gemini,
+ Attribution: "safe attribution",
+ }, outputPath)
+ if err == nil {
+ t.Fatal("expected error for symlink ancestor")
+ }
+ if !strings.Contains(err.Error(), "symlink") {
+ t.Fatalf("DownloadImage() error = %v, want symlink rejection", err)
+ }
+ if _, statErr := os.Stat(filepath.Join(outsideDir, "escape.png")); !os.IsNotExist(statErr) {
+ t.Fatalf("unexpected file write outside output dir: %v", statErr)
+ }
+}