package engineeringdashboard import ( "os" "path/filepath" "strings" "testing" "time" ) func TestDocs_IndexAndBacklinks(t *testing.T) { root := t.TempDir() writeDoc(t, root, ".doc/ops/CURRENT.md", "---\nstatus: in_progress\n---\n# Current\n\nSee [task](./short-term/task.md).\n") writeDoc(t, root, ".doc/ops/short-term/task.md", "---\ntitle: Demo Task\nstatus: planned\nowner: unassigned\nmutex: demo\n---\n# Demo Task\n\nLink to [current](../CURRENT.md).\n") writeDoc(t, root, ".doc/ops/short-term/orphan.md", "# Orphan\n\nNo links.\n") // assets must be skipped mustMkdir(t, filepath.Join(root, ".doc/test-reports/assets")) if err := os.WriteFile(filepath.Join(root, ".doc/test-reports/assets/secret.md"), []byte("# secret"), 0o600); err != nil { t.Fatal(err) } now := time.Now().UTC() res := CollectDocs(root, now) if res.Source.Status != SourceOK { t.Fatalf("docs source: %+v", res.Source) } var foundAssets bool var task *DocumentNode for i := range res.Documents { if strings.Contains(res.Documents[i].Path, "assets/") { foundAssets = true } if strings.HasSuffix(res.Documents[i].Path, "short-term/task.md") { task = &res.Documents[i] } } if foundAssets { t.Fatal("assets markdown must not be indexed as body") } if task == nil { t.Fatal("task doc missing") } if len(task.LinksIn) == 0 { t.Fatalf("expected backlink into task, got %+v", task) } var planned bool for _, tk := range res.Tasks { if strings.Contains(tk.Path, "task.md") { if tk.DocStatus != DocStatusPlanned || tk.Claim.Claimed { t.Fatalf("rdev-like task should stay planned/unclaimed: %+v", tk) } planned = true } } if !planned { t.Fatal("task not parsed into TaskState") } } func TestDocs_BrokenLinkDoesNotFailIndex(t *testing.T) { root := t.TempDir() writeDoc(t, root, ".doc/ops/note.md", "# Note\n\n[missing](./nope.md)\n") res := CollectDocs(root, time.Now().UTC()) if res.Source.Status != SourceOK { t.Fatalf("index should succeed: %+v", res.Source) } found := false for _, d := range res.Documents { if strings.HasSuffix(d.Path, "note.md") && len(d.BrokenLinks) > 0 { found = true } } if !found { t.Fatal("expected broken link recorded") } } func TestPathSafe_RejectsTraversalAndSymlink(t *testing.T) { root := t.TempDir() writeDoc(t, root, ".doc/ops/ok.md", "# ok\n") if _, err := SafeDocPath(root, ".doc/../.env"); err == nil { t.Fatal("expected traversal deny") } target := filepath.Join(root, ".doc/ops/ok.md") link := filepath.Join(root, ".doc/ops/link.md") if err := os.Symlink(target, link); err != nil { t.Fatal(err) } if _, err := SafeDocPath(root, ".doc/ops/link.md"); err == nil { t.Fatal("expected symlink deny") } if _, err := SafeDocPath(root, ".doc/ops/ok.md"); err != nil { t.Fatal(err) } } func writeDoc(t *testing.T, root, rel, body string) { t.Helper() abs := filepath.Join(root, filepath.FromSlash(rel)) mustMkdir(t, filepath.Dir(abs)) if err := os.WriteFile(abs, []byte(body), 0o600); err != nil { t.Fatal(err) } } func mustMkdir(t *testing.T, dir string) { t.Helper() if err := os.MkdirAll(dir, 0o755); err != nil { t.Fatal(err) } }