summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-10 09:48:07 +0300
committerPaul Buetow <paul@buetow.org>2026-04-10 09:48:07 +0300
commit4ff456a6111d8553893308a84e9f0e992d4809bf (patch)
treeddde0aa190b8dcbf6eb6649a82db732f0cdfd6a7
parentc8e10b6c5ab26d8bd34c288a7ce91c320862b58e (diff)
processor: return error when markdown pre-scan cannot read .md
claimedByMarkdown now wraps os.ReadFile failures instead of skipping, so Run fails fast and avoids wrong image claim state. Add regression test using an unreadable markdown file (Unix). Made-with: Cursor
-rw-r--r--internal/processor/markdown_test.go35
-rw-r--r--internal/processor/processor.go11
2 files changed, 42 insertions, 4 deletions
diff --git a/internal/processor/markdown_test.go b/internal/processor/markdown_test.go
index a17b704..2445b53 100644
--- a/internal/processor/markdown_test.go
+++ b/internal/processor/markdown_test.go
@@ -3,7 +3,10 @@ package processor
import (
"os"
"path/filepath"
+ "runtime"
"testing"
+
+ "codeberg.org/snonux/snonux/internal/config"
)
func TestFindLocalImages(t *testing.T) {
@@ -88,3 +91,35 @@ func TestFindLocalImages(t *testing.T) {
})
}
}
+
+func TestRun_UnreadableMarkdownPreScanFails(t *testing.T) {
+ t.Parallel()
+ if runtime.GOOS == "windows" {
+ t.Skip("chmod does not reliably deny read for owned files on Windows")
+ }
+
+ base := t.TempDir()
+ inputDir := filepath.Join(base, "inbox")
+ outputDir := filepath.Join(base, "out")
+ if err := os.MkdirAll(inputDir, 0o755); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.MkdirAll(outputDir, 0o755); err != nil {
+ t.Fatal(err)
+ }
+
+ mdPath := filepath.Join(inputDir, "note.md")
+ if err := os.WriteFile(mdPath, []byte("# x\n"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.Chmod(mdPath, 0); err != nil {
+ t.Fatal(err)
+ }
+ t.Cleanup(func() { _ = os.Chmod(mdPath, 0o644) })
+
+ cfg := &config.Config{InputDir: inputDir, OutputDir: outputDir}
+ _, err := Run(cfg)
+ if err == nil {
+ t.Fatal("Run: expected error when markdown pre-scan cannot read a .md file")
+ }
+}
diff --git a/internal/processor/processor.go b/internal/processor/processor.go
index 2e2d626..b6fa40b 100644
--- a/internal/processor/processor.go
+++ b/internal/processor/processor.go
@@ -33,7 +33,10 @@ func Run(cfg *config.Config) (int, error) {
// Pre-scan markdown files to discover which image filenames they claim.
// Claimed images are excluded from independent processing.
- claimed := claimedByMarkdown(entries, cfg.InputDir)
+ claimed, err := claimedByMarkdown(entries, cfg.InputDir)
+ if err != nil {
+ return 0, err
+ }
count := 0
@@ -59,7 +62,7 @@ func Run(cfg *config.Config) (int, error) {
// claimedByMarkdown scans all .md entries in inputDir and returns a set of
// image filenames that are referenced within those markdown files.
// Those images should be embedded in the markdown post, not processed alone.
-func claimedByMarkdown(entries []os.DirEntry, inputDir string) map[string]bool {
+func claimedByMarkdown(entries []os.DirEntry, inputDir string) (map[string]bool, error) {
claimed := make(map[string]bool)
for _, entry := range entries {
@@ -70,7 +73,7 @@ func claimedByMarkdown(entries []os.DirEntry, inputDir string) map[string]bool {
mdPath := filepath.Join(inputDir, entry.Name())
data, err := os.ReadFile(mdPath)
if err != nil {
- continue
+ return nil, fmt.Errorf("read markdown for image claims %s: %w", entry.Name(), err)
}
for _, imgName := range findLocalImages(string(data), inputDir) {
@@ -78,7 +81,7 @@ func claimedByMarkdown(entries []os.DirEntry, inputDir string) map[string]bool {
}
}
- return claimed
+ return claimed, nil
}
// processFile processes a single input file into a new post directory.