ci / vet-and-test (pull_request) Successful in 41s
Why: N1 increment three host side - plugin agent assets must reject hooks/mcp/permissionMode declarations (WP1 acceptance), and squad members need the kernel ask port wired to the HITL card (WP4). Evidence: go vet clean; go test ./... 29 packages ok, including new agent-asset tests (banned keys located to the field, unknown keys, missing id) and the V2 asset suite. Nested pins at native c5b9dca (PR #18) and squad fc9620e (PR #17). Impact: plugins agents/ assets now parse via parseAgentAsset (strict JSON with banned-key rejection); PermissionAskOf exported and takes any host with the optional method; app.go wires cfg.PermissionAsk for the squad path. Legacy behavior unchanged when nothing registers the port. Refs: Documents proposal 2026-10-07-agent-stack-n1q1i1-plans.md WP1/WP4
73 lines
2.2 KiB
Go
73 lines
2.2 KiB
Go
package plugins
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
core "agent-system-core"
|
|
)
|
|
|
|
// writeAgentPlugin 写一个带 agents/ 资产的插件目录。
|
|
func writeAgentPlugin(t *testing.T, dir, id, agentJSON string) {
|
|
t.Helper()
|
|
root := filepath.Join(dir, id)
|
|
os.MkdirAll(filepath.Join(root, "agents"), 0o755)
|
|
write := func(rel, content string) {
|
|
if err := os.WriteFile(filepath.Join(root, rel), []byte(content), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
write("plugin.json", `{"id":"`+id+`","name":"代理插件","version":"0.1.0","apiVersion":"`+core.PluginAPIVersion+`",
|
|
"provides":{"agents":["reviewer"]}}`)
|
|
write("agents/reviewer.json", agentJSON)
|
|
}
|
|
|
|
func TestAgentAssetLoads(t *testing.T) {
|
|
h, _, dir := newHost(t)
|
|
writeAgentPlugin(t, dir, "agentplug", `{"id":"rdm-reviewer","title":"章节评审","instructions":"逐条核对来源","tools":["read_file","grep"]}`)
|
|
if err := h.LoadDir()["agentplug"]; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, ld := range h.List() {
|
|
if ld.Manifest.ID != "agentplug" {
|
|
continue
|
|
}
|
|
if len(ld.Agents) != 1 || ld.Agents[0].ID != "rdm-reviewer" || len(ld.Agents[0].Tools) != 2 {
|
|
t.Fatalf("agents = %+v", ld.Agents)
|
|
}
|
|
return
|
|
}
|
|
t.Fatal("plugin not loaded")
|
|
}
|
|
|
|
// TestAgentAssetBansHostOnlyKeys:插件代理声明 hooks/mcp/permissionMode 时
|
|
// 整批拒绝且错误定位到字段(N1 WP1 验收条款)。
|
|
func TestAgentAssetBansHostOnlyKeys(t *testing.T) {
|
|
for _, key := range []string{"hooks", "mcp", "permissionMode"} {
|
|
h, _, dir := newHost(t)
|
|
writeAgentPlugin(t, dir, "badplug", `{"id":"x","`+key+`":{}}`)
|
|
err := h.LoadDir()["badplug"]
|
|
if err == nil {
|
|
t.Fatalf("%s accepted", key)
|
|
}
|
|
if !strings.Contains(err.Error(), "不得声明 "+key) {
|
|
t.Fatalf("%s error 未定位到字段: %v", key, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAgentAssetRejectsUnknownKeysAndMissingID(t *testing.T) {
|
|
h, _, dir := newHost(t)
|
|
writeAgentPlugin(t, dir, "unknownkey", `{"id":"x","bogus":1}`)
|
|
if err := h.LoadDir()["unknownkey"]; err == nil {
|
|
t.Fatal("unknown key accepted")
|
|
}
|
|
h2, _, dir2 := newHost(t)
|
|
writeAgentPlugin(t, dir2, "noid", `{"title":"无 id"}`)
|
|
if err := h2.LoadDir()["noid"]; err == nil {
|
|
t.Fatal("missing id accepted")
|
|
}
|
|
}
|