返回 DeepSeek-Reasonix
embedded_reference_test.go
根目录 / internal / skill / embedded_reference_test.go
1 package skill_test
2
3 import (
4 "context"
5 "encoding/json"
6 "regexp"
7 "strings"
8 "testing"
9
10 "reasonix/internal/skill"
11 )
12
13 func TestEmbeddedGuideReferencesAreReadableOnDemand(t *testing.T) {
14 store := skill.New(skill.Options{HomeDir: t.TempDir()})
15 loader := skill.NewReadSkillTool(store)
16 root, err := loader.Execute(context.Background(), json.RawMessage(`{"name":"reasonix-guide"}`))
17 if err != nil {
18 t.Fatal(err)
19 }
20 links := regexp.MustCompile(`\]\((references/[^)]+\.md)\)`).FindAllStringSubmatch(root, -1)
21 if len(links) != 6 {
22 t.Fatalf("reference routes = %d, want 6", len(links))
23 }
24 for _, link := range links {
25 args, _ := json.Marshal(map[string]string{"name": "reasonix-guide", "reference": link[1]})
26 page, err := loader.Execute(context.Background(), args)
27 if err != nil || len(page) == 0 {
28 t.Fatalf("%s: %v", link[1], err)
29 }
30 if page == root || strings.Contains(root, strings.SplitN(page, "\n\n", 2)[1]) {
31 t.Fatalf("%s was not loaded separately", link[1])
32 }
33 again, _ := loader.Execute(context.Background(), args)
34 if again != page {
35 t.Fatalf("%s is not stable", link[1])
36 }
37 }
38 guide, _ := store.Read("reasonix-guide")
39 if !strings.Contains(skill.CatalogBlock(store.List()), guide.Description) {
40 t.Fatal("built-in guide trigger description was clipped")
41 }
42 }
43
44 func TestEmbeddedReferenceRejectsTraversalAndNonReferenceFiles(t *testing.T) {
45 loader := skill.NewReadSkillTool(skill.New(skill.Options{HomeDir: t.TempDir()}))
46 for _, ref := range []string{
47 "../SKILL.md", "references/../SKILL.md", "/etc/passwd",
48 "references/../../other/SKILL.md", "references\\skills.md",
49 "SKILL.md", "references/missing.md", "references/skills.md/extra",
50 } {
51 t.Run(ref, func(t *testing.T) {
52 args, _ := json.Marshal(map[string]string{"name": "reasonix-guide", "reference": ref})
53 if out, err := loader.Execute(context.Background(), args); err == nil || out != "" {
54 t.Fatalf("reference %q allowed: %q, %v", ref, out, err)
55 }
56 })
57 }
58 if _, err := loader.Execute(context.Background(), json.RawMessage(`{"name":"reasonix-guide","reference":"references/skills.md","arguments":"task"}`)); err == nil {
59 t.Fatal("ambiguous reference/task request accepted")
60 }
61 }
62
63 func TestEmbeddedReferenceHonorsOverrideAndDisabledSkill(t *testing.T) {
64 for _, disabled := range []bool{false, true} {
65 t.Run(map[bool]string{false: "override", true: "disabled"}[disabled], func(t *testing.T) {
66 opts := skill.Options{HomeDir: t.TempDir(), ProjectRoot: t.TempDir()}
67 if disabled {
68 opts.DisabledNames = []string{"reasonix-guide"}
69 }
70 store := skill.New(opts)
71 if !disabled {
72 _, err := store.CreateWithContent("reasonix-guide", skill.ScopeProject,
73 "---\nname: reasonix-guide\ndescription: Project guide\n---\nLocal guidance")
74 if err != nil {
75 t.Fatal(err)
76 }
77 }
78 loader := skill.NewReadSkillTool(skill.New(opts))
79 out, err := loader.Execute(context.Background(), json.RawMessage(`{"name":"reasonix-guide","reference":"references/skills.md"}`))
80 if err == nil || out != "" {
81 t.Fatal("embedded page bypassed the winning/disabled skill")
82 }
83 if !disabled {
84 out, err = loader.Execute(context.Background(), json.RawMessage(`{"name":"reasonix-guide"}`))
85 if err != nil || !strings.Contains(out, "Local guidance") {
86 t.Fatal("legacy body read no longer uses the project override")
87 }
88 }
89 })
90 }
91 }
92
92 lines GO