package main // The agent's configuration registered at three scopes (novox/hq ADR 0216): each test is one row of the // record's "How it is checked". import ( "encoding/json" "os" "path/filepath" "strings" "testing" ) // memConfig is the `config` state as a map, shared by the nodes of a test the way the bus shares it. type memConfig map[string]json.RawMessage func (m memConfig) Put(key string, value any) error { raw, err := json.Marshal(value) m[key] = raw return err } func (m memConfig) Delete(key string) error { delete(m, key); return nil } func (m memConfig) Keys() ([]string, error) { out := []string{} for k := range m { out = append(out, k) } return out, nil } func (m memConfig) Get(key string) (json.RawMessage, bool, error) { raw, ok := m[key] return raw, ok, nil } // deliver hands every key of the state to a node's view, as its watch would. func deliver(m memConfig, v *ConfigView) { for key, raw := range m { var it Item _ = json.Unmarshal(raw, &it) v.Take(key, "put", &it) } } // registeredBefore puts an item on the bus as a registration made before mesh- and node-scope text moved to the // controller's terminal (novox/hq issue 340), for each node given (none at the mesh scope), as every node's watch // would hand it over to this one, and renders. func registeredBefore(t *testing.T, p Paths, w map[string]string, state memConfig, view *ConfigView, it Item, nodes ...string) { t.Helper() if it.Scope == ScopeMesh { nodes = []string{""} } for _, n := range nodes { item := it if err := state.Put(it.Key(n), item); err != nil { t.Fatal(err) } view.Take(it.Key(n), "put", &item) } if _, err := RenderNow(p, writer(w)); err != nil { t.Fatal(err) } } func one(name, content string) map[string]string { return map[string]string{name + ".md": content} } func pluginOf(t *testing.T, w map[string]string) map[string]PluginFile { t.Helper() var files map[string]PluginFile if err := json.Unmarshal([]byte(w[MarketplaceDir+"/"]), &files); err != nil { t.Fatalf("no marketplace written: %v", err) } return files } func TestEachKindLandsInItsOnePlace(t *testing.T) { p, w := node(t, "laptop") state, view := memConfig{}, NewConfigView(p) register := func(it Item) { t.Helper() if problem := it.Problem(); problem != "" { t.Fatalf("%s %s: %s", it.Kind, it.Name, problem) } registeredBefore(t, p, w, state, view, it) } register(Item{Kind: KindSkill, Name: "review", Scope: ScopeMesh, Files: map[string]string{"SKILL.md": "---\nname: review\ndescription: d\n---\nbody", "scripts/run.sh": "#!/bin/sh\necho hi\n"}}) register(Item{Kind: KindAgent, Name: "reviewer", Scope: ScopeMesh, Files: one("reviewer", "---\nname: reviewer\n---\nx")}) register(Item{Kind: KindCommand, Name: "ship", Scope: ScopeMesh, Files: one("ship", "ship it")}) register(Item{Kind: KindOutputStyle, Name: "terse", Scope: ScopeMesh, Files: one("terse", "---\nname: terse\n---\nshort")}) register(Item{Kind: KindInstructions, Name: "conventions", Scope: ScopeMesh, Files: one("conventions", "Commit in the imperative.")}) plugin := pluginOf(t, w) root := "plugins/" + Plugin + "/" for _, want := range []string{".claude-plugin/marketplace.json", root + ".claude-plugin/plugin.json", root + "skills/review/SKILL.md", root + "skills/review/scripts/run.sh", root + "agents/reviewer.md", root + "commands/ship.md", root + "output-styles/terse.md"} { if _, ok := plugin[want]; !ok { t.Errorf("the plugin lacks %s", want) } } if !plugin[root+"skills/review/scripts/run.sh"].Executable { t.Error("a script is not executable") } if !strings.Contains(w["CLAUDE.md"], "### conventions\n\nCommit in the imperative.") { t.Errorf("the instruction section is not in the managed instruction file:\n%s", w["CLAUDE.md"]) } var managed map[string]any _ = json.Unmarshal([]byte(w["managed-settings.json"]), &managed) if managed["enabledPlugins"].(map[string]any)[Plugin+"@"+Plugin] != true { t.Errorf("managed settings: %v", managed) } if _, inPlugin := plugin[root+"settings.json"]; inPlugin { t.Error("settings were put in the plugin, which drops them") } } func TestAMeshItemReachesEveryNodeANodeItemOneAndAHomeItemOneHome(t *testing.T) { a, wa := confinedNode(t, "laptop") b, wb := node(t, "server") state := memConfig{} va, vb := NewConfigView(a), NewConfigView(b) for _, r := range []struct { it Item nodes []string }{ {Item{Kind: KindCommand, Name: "everywhere", Scope: ScopeMesh, Files: one("everywhere", "x")}, nil}, {Item{Kind: KindCommand, Name: "server-only", Scope: ScopeNode, Files: one("server-only", "x")}, []string{"server"}}, {Item{Kind: KindCommand, Name: "at-home", Scope: ScopeHome, Files: one("at-home", "x")}, []string{"laptop"}}, } { if r.it.Scope == ScopeHome { if _, err := Register(a, r.it, r.nodes, false, state, va, writer(wa)); err != nil { t.Fatal(err) } continue } registeredBefore(t, a, wa, state, va, r.it, r.nodes...) } deliver(state, vb) if _, err := RenderNow(b, writer(wb)); err != nil { t.Fatal(err) } root := "plugins/" + Plugin + "/commands/" pa, pb := pluginOf(t, wa), pluginOf(t, wb) if _, ok := pa[root+"everywhere.md"]; !ok { t.Error("the mesh item is missing on the laptop") } if _, ok := pb[root+"everywhere.md"]; !ok { t.Error("the mesh item is missing on the server") } if _, ok := pa[root+"server-only.md"]; ok { t.Error("the server's item reached the laptop") } if _, ok := pb[root+"server-only.md"]; !ok { t.Error("the server's item is missing on the server") } if _, err := os.Stat(filepath.Join(a.Home, ".claude", "commands", "at-home.md")); err != nil { t.Error("the home item was not placed in the laptop's home") } if _, err := os.Stat(filepath.Join(b.Home, ".claude", "commands", "at-home.md")); err == nil { t.Error("the laptop's home item reached the server's home") } if _, ok := pa[root+"at-home.md"]; ok { t.Error("a home item went into the plugin") } } func TestTheMeshsOwnKeysCannotBeSetOrReplaced(t *testing.T) { for _, key := range []string{"extraKnownMarketplaces", "enabledPlugins", "attribution", "apiKeyHelper"} { it := Item{Kind: KindSettings, Name: SettingsName, Scope: ScopeMesh, Settings: map[string]any{key: true}} if it.Problem() == "" { t.Errorf("a registration could set %s", key) } } out := Render(Facts{Console: "x"}, Settings{ManagedSettings: map[string]any{"enabledPlugins": map[string]any{Plugin + "@" + Plugin: false}}}, nil, "/h", nil, Config{}) var managed map[string]any _ = json.Unmarshal([]byte(out["managed-settings.json"]), &managed) if managed["enabledPlugins"].(map[string]any)[Plugin+"@"+Plugin] != true { t.Error("the operator's setting turned the mesh's plugin off") } } func TestTheHomeScopeOwnsOnlyWhatItPlaced(t *testing.T) { p, w := confinedNode(t, "laptop") state, view := memConfig{}, NewConfigView(p) mine := filepath.Join(p.Home, ".claude", "agents", "mine.md") _ = os.MkdirAll(filepath.Dir(mine), 0o755) writeFile(t, mine, "the person's own") answer, _ := Register(p, Item{Kind: KindAgent, Name: "mine", Scope: ScopeHome, Files: one("mine", "the mesh's")}, nil, false, state, view, writer(w)) if answer["registered"] != false { t.Fatalf("a name the person uses was taken: %v", answer) } if raw, _ := os.ReadFile(mine); string(raw) != "the person's own" { t.Fatal("the person's file was overwritten") } placed := filepath.Join(p.Home, ".claude", "agents", "placed.md") if _, err := Register(p, Item{Kind: KindAgent, Name: "placed", Scope: ScopeHome, Files: one("placed", "v1")}, nil, false, state, view, writer(w)); err != nil { t.Fatal(err) } if raw, _ := os.ReadFile(placed); string(raw) != "v1" { t.Fatal("the home item was not placed") } if _, err := Register(p, Item{Kind: KindAgent, Name: "placed", Scope: ScopeHome}, nil, true, state, view, writer(w)); err != nil { t.Fatal(err) } if _, err := os.Stat(placed); err == nil { t.Fatal("unregistering did not remove what the mesh placed") } if _, err := os.Stat(mine); err != nil { t.Fatal("unregistering removed the person's file") } // Changed by hand after it was placed: left alone when unregistered. if _, err := Register(p, Item{Kind: KindAgent, Name: "edited", Scope: ScopeHome, Files: one("edited", "v1")}, nil, false, state, view, writer(w)); err != nil { t.Fatal(err) } edited := filepath.Join(p.Home, ".claude", "agents", "edited.md") writeFile(t, edited, "changed by hand") if _, err := Register(p, Item{Kind: KindAgent, Name: "edited", Scope: ScopeHome}, nil, true, state, view, writer(w)); err != nil { t.Fatal(err) } if raw, _ := os.ReadFile(edited); string(raw) != "changed by hand" { t.Fatal("a placed file changed by hand was removed") } } func TestAnItemAboveTheLimitOrMisshapenIsRefused(t *testing.T) { big := Item{Kind: KindSkill, Name: "big", Scope: ScopeMesh, Files: map[string]string{"SKILL.md": strings.Repeat("x", MaxItemBytes+1)}} cases := map[string]Item{ "too big": big, "a bad name": {Kind: KindAgent, Name: "Bad Name", Scope: ScopeMesh, Files: one("Bad Name", "x")}, "a skill without one": {Kind: KindSkill, Name: "s", Scope: ScopeMesh, Files: map[string]string{"other.md": "x"}}, "a path outside": {Kind: KindSkill, Name: "s", Scope: ScopeMesh, Files: map[string]string{"SKILL.md": "x", "../escape": "x"}}, "a hook at home": {Kind: KindHook, Name: "h", Scope: ScopeHome, Event: "Stop", Command: "true"}, "settings at home": {Kind: KindSettings, Name: SettingsName, Scope: ScopeHome, Settings: map[string]any{"model": "x"}}, "a hook anywhere": {Kind: KindHook, Name: "h", Scope: ScopeMesh, Event: "Stop", Command: "true"}, } for label, it := range cases { if it.Problem() == "" { t.Errorf("%s was accepted", label) } } } func TestAHomeItemIsImportedAndTheStaleOnesAreNamed(t *testing.T) { p, _ := node(t, "laptop") dir := filepath.Join(p.Home, ".claude") _ = os.MkdirAll(filepath.Join(dir, "skills", "old", "scripts"), 0o755) writeFile(t, filepath.Join(dir, "skills", "old", "SKILL.md"), "---\nname: old\n---\nuse mcp__gone__do_it") writeFile(t, filepath.Join(dir, "skills", "old", "scripts", "a.sh"), "#!/bin/sh\n") it, err := ImportFromHome(p, KindSkill, "old") if err != nil || len(it.Files) != 2 || it.Files["scripts/a.sh"] == "" { t.Fatalf("%+v %v", it, err) } items := HomeItems(p, Config{Mesh: []Item{{Kind: KindSkill, Name: "old"}}}, Servers{}) if len(items) != 1 || len(items[0].Notes) != 2 { t.Fatalf("%+v", items) } } // The manifest lists exactly the tools the bundle serves: a tool missing from it is never announced. func TestTheManifestListsEveryToolServed(t *testing.T) { raw, err := os.ReadFile("../../module.json") if err != nil { t.Fatal(err) } var m struct { Tools []string `json:"tools"` } _ = json.Unmarshal(raw, &m) listed := map[string]bool{} for _, n := range m.Tools { listed[n] = true } p, _ := node(t, "laptop") served := tools(p, nil, NewServerView(p), memConfig{}, NewConfigView(p)) for _, tool := range served { if !listed[tool.Name] { t.Errorf("%s is served and not in the manifest", tool.Name) } delete(listed, tool.Name) } for n := range listed { t.Errorf("%s is in the manifest and not served", n) } } // The tree writer's comparison: a directory holding exactly the files given, executable bits included. func TestATreeIsTheSameOnlyWhenEveryFileAndModeIs(t *testing.T) { dir := t.TempDir() files := map[string]PluginFile{"a.md": {Content: "a"}, "s/run.sh": {Content: "#!/bin/sh\n", Executable: true}} _ = os.MkdirAll(filepath.Join(dir, "s"), 0o755) writeFile(t, filepath.Join(dir, "a.md"), "a") writeFile(t, filepath.Join(dir, "s", "run.sh"), "#!/bin/sh\n") if sameTree(dir, files) { t.Fatal("a script without its executable bit counted as the same") } _ = os.Chmod(filepath.Join(dir, "s", "run.sh"), 0o755) if !sameTree(dir, files) { t.Fatal("the same tree counted as different") } writeFile(t, filepath.Join(dir, "extra.md"), "x") if sameTree(dir, files) { t.Fatal("an extra file counted as the same") } } // A registration removed while a node was away is dropped when it is back: the watch hands over only what is // there, so the view is pruned to the keys the state still holds. func TestWhatWasRemovedWhileANodeWasAwayIsDropped(t *testing.T) { p, w := node(t, "laptop") state, view := memConfig{}, NewConfigView(p) for _, name := range []string{"kept", "gone"} { registeredBefore(t, p, w, state, view, Item{Kind: KindCommand, Name: name, Scope: ScopeMesh, Files: one(name, "x")}) } delete(state, "mesh.command.gone") // removed from another node while this one was off back := NewConfigView(p) // the node starts again from what it last wrote if len(back.Items()) != 2 { t.Fatalf("the view did not start from what was last written: %v", back.Items()) } keys, _ := state.Keys() if !back.Prune(keys) || len(back.Items()) != 1 { t.Fatalf("after pruning: %v", back.Items()) } } // The review's findings, each held by a test. func TestAPathOrAKeyThatIsNotWhatItSaysIsRefused(t *testing.T) { for label, files := range map[string]map[string]string{ "a dot": {"SKILL.md": "x", ".": "x"}, "an empty segment": {"SKILL.md": "x", "a//b": "x"}, "a parent segment": {"SKILL.md": "x", "a/../b": "x"}, "a file and directory": {"SKILL.md": "x", "a": "x", "a/b": "x"}, } { if (Item{Kind: KindSkill, Name: "s", Scope: ScopeMesh, Files: files}).Problem() == "" { t.Errorf("%s was accepted", label) } } p, _ := node(t, "laptop") v := NewConfigView(p) home := Item{Kind: KindCommand, Name: "x", Scope: ScopeHome, Files: one("x", "y")} if v.Take("mesh.command.x", "put", &home); len(v.Items()) != 0 { t.Fatal("a mesh key holding a home item was taken") } for _, key := range []string{"mesh.command.x", "mesh.agent.x"} { mesh := Item{Kind: KindCommand, Name: "x", Scope: ScopeMesh, Files: one("x", "y")} v.Take(key, "put", &mesh) } if len(v.Items()) != 1 { t.Fatalf("an item under a key of another kind was taken: %v", v.Items()) } } func TestAllIsEveryNodeAndANameThatCannotBeAKeyIsRefused(t *testing.T) { nodes, err := ExpandNodes([]string{"all"}, func() ([]string, error) { return []string{"ace", "g14"}, nil }) if err != nil || strings.Join(nodes, ",") != "ace,g14" { t.Fatalf("%v %v", nodes, err) } p, w := node(t, "laptop") answer, _ := Register(p, Item{Kind: KindCommand, Name: "c", Scope: ScopeHome, Files: one("c", "x")}, []string{"a.b"}, false, memConfig{}, NewConfigView(p), writer(w)) if answer["registered"] != false { t.Fatalf("a node name with a dot was used in a key: %v", answer) } if (Item{Kind: KindSettings, Name: SettingsName, Scope: ScopeMesh, Settings: map[string]any{"deniedMcpServers": []any{}}}).Problem() == "" { t.Fatal("a registration could deny the mesh's console") } } func TestTheOperatorsOwnPluginsAndMarketplacesAreKept(t *testing.T) { out := Render(Facts{Console: "x"}, Settings{ManagedSettings: map[string]any{ "enabledPlugins": map[string]any{"theirs@market": true}, "extraKnownMarketplaces": map[string]any{"market": map[string]any{"source": map[string]any{"source": "github", "repo": "o/r"}}}, }}, nil, "/h", nil, Config{}) var managed struct { Enabled map[string]any `json:"enabledPlugins"` Known map[string]any `json:"extraKnownMarketplaces"` } _ = json.Unmarshal([]byte(out["managed-settings.json"]), &managed) if managed.Enabled["theirs@market"] != true || managed.Enabled[Plugin+"@"+Plugin] != true || managed.Known["market"] == nil || managed.Known[Plugin] == nil { t.Fatalf("%+v", managed) } } func TestTheHomeLeavesThePersonsChoicesAlone(t *testing.T) { p, _ := node(t, "laptop") dir := filepath.Join(p.Home, ".claude") // An identical file the person made is not taken over, so unregistering never removes it. _ = os.MkdirAll(filepath.Join(dir, "agents"), 0o755) writeFile(t, filepath.Join(dir, "agents", "same.md"), "x") if _, left := PlaceHome(p, map[string]string{"agents/same.md": "x"}); len(left) != 1 { t.Fatalf("an identical file of the person's was taken over: %v", left) } PlaceHome(p, map[string]string{}) if _, err := os.Stat(filepath.Join(dir, "agents", "same.md")); err != nil { t.Fatal("the person's file was removed") } // A placed file the person deleted stays deleted while it is registered. PlaceHome(p, map[string]string{"commands/c.md": "x"}) _ = os.Remove(filepath.Join(dir, "commands", "c.md")) PlaceHome(p, map[string]string{"commands/c.md": "x"}) if _, err := os.Stat(filepath.Join(dir, "commands", "c.md")); err == nil { t.Fatal("a file the person deleted was placed again") } // The kind's own directory stays when the mesh's last item in it goes. PlaceHome(p, map[string]string{"skills/s/SKILL.md": "x"}) PlaceHome(p, map[string]string{}) if _, err := os.Stat(filepath.Join(dir, "skills", "s")); err == nil { t.Fatal("the item's own directory was left") } if _, err := os.Stat(filepath.Join(dir, "skills")); err != nil { t.Fatal("the kind's directory was removed") } // Never through a symbolic link. elsewhere := t.TempDir() if err := os.Symlink(elsewhere, filepath.Join(dir, "output-styles")); err != nil { t.Skip("no symbolic links here") } PlaceHome(p, map[string]string{"output-styles/o.md": "x"}) if _, err := os.Stat(filepath.Join(elsewhere, "o.md")); err == nil { t.Fatal("a file was written through a symbolic link") } } func TestOneFileThatCannotBeWrittenDoesNotStopTheOthers(t *testing.T) { p, _ := node(t, "laptop") w := map[string]string{} failing := func(name, content string) (string, error) { if name == MarketplaceDir+"/" { return "", os.ErrPermission } w[name] = content return name + ": written", nil } if _, err := RenderNow(p, failing); err == nil { t.Fatal("the failure was not reported") } if w["managed-settings.json"] == "" || w["managed-mcp.json"] == "" || w["CLAUDE.md"] == "" { t.Fatalf("the other files were not written: %v", w) } } // The answer says what this node wrote even when its own watch took the change first. func TestTheAnswerSaysWhatWasWrittenWhenTheWatchWasFirst(t *testing.T) { p, w := confinedNode(t, "laptop") state, view := memConfig{}, NewConfigView(p) it := Item{Kind: KindCommand, Name: "c", Scope: ScopeHome, Files: one("c", "x")} first := it view.Take(it.Key("laptop"), "put", &first) // the watch, first answer, err := Register(p, it, nil, false, state, view, writer(w)) if err != nil || answer["rendered here"] == nil || answer["here"] != nil { t.Fatalf("%v %v", answer, err) } }