Files
Agent-System-Backend/internal/app/compiled.go
T
weichen d89e74880b Add the EXT-8 authorizer surface and a red sharing test
Why: EXT-8 is accepted (Documents #49); the surface (Registry.RegisterResourceAuthorizer, ResourceAuthorizer, SurfaceVersion 2.1.0-experimental) plus the Server injection seam must land before the read-path consultation, and the behavioral red run proves the gap.
Evidence: go test ./internal/server -run TestProjectResourceAuthorizerSharesReads FAIL (shared read 404 with adapter set); default-deny section passes; row recorded on the task card.
Impact: pkg/extension additive surface (surface.txt updated); projectAuthz slot in hostcaps; Server.ProjectAuthz + setter; app wiring after compiled load; declarative registry fails closed. Read behavior unchanged.
Refs: EXT-8 in Documents 2026-10-08-ext-c1-c7-rdm-shared-contracts; task card.
2026-10-08 15:32:04 +00:00

115 lines
3.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package app
import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"os"
"path/filepath"
agentcommand "agent-command"
"agent-system-backend/internal/cmdbus"
"agent-system-backend/pkg/extension"
core "agent-system-core"
)
type compiledRegistry struct {
skillsRoot string
bus *cmdbus.Bus
}
// pluginRegistry 携带插件身份与宿主能力,per-InProc 构造:
// AddCommandHandler 绑定的处理器在分发时按请求 Owner 构造 inprocHost(EXT-1)。
type pluginRegistry struct {
compiledRegistry
pluginID string
caps hostcaps
}
func (r pluginRegistry) AddCommandHandler(spec json.RawMessage, h extension.Handler) error {
if r.bus == nil {
return nil
}
if h == nil {
return fmt.Errorf("extension: %s: nil command handler", r.pluginID)
}
var s agentcommand.CommandSpec
if err := json.Unmarshal(spec, &s); err != nil {
return fmt.Errorf("extension: command spec: %w", err)
}
return r.bus.RegisterPluginCommand(s, func(ctx context.Context, req cmdbus.Request) (any, error) {
host := inprocHost{caps: r.caps, pluginID: r.pluginID, owner: req.Owner}
return h(ctx, host, extension.Request{
ID: req.ID, Params: req.Params, Entrance: req.Entrance,
Actor: req.Actor, Owner: req.Owner, ConversationID: req.ConversationID,
})
})
}
func (r compiledRegistry) AddSkill(name, markdown string) error {
if r.skillsRoot == "" || name == "" {
return nil
}
dest := filepath.Join(r.skillsRoot, "compiled", name)
if err := os.MkdirAll(dest, 0o755); err != nil {
return err
}
return os.WriteFile(filepath.Join(dest, "SKILL.md"), []byte(markdown), 0o644)
}
func (r compiledRegistry) AddCommand(spec json.RawMessage) error {
if r.bus == nil {
return nil
}
return r.bus.RegisterPluginCommands([]json.RawMessage{spec})
}
// RegisterResourceAuthorizer 声明式扩展无宿主进程内代码,不能提供回调(fail-closed)。
func (r compiledRegistry) RegisterResourceAuthorizer(extension.ResourceAuthorizer) error {
return errors.New("extension: declarative plugins cannot register resource authorizers")
}
func (r compiledRegistry) Note(kind, name string, payload json.RawMessage) error {
log.Printf("extension: note %s %s (%d bytes)", kind, name, len(payload))
return nil
}
func applyCompiled(skillsRoot string, bus *cmdbus.Bus, caps hostcaps) {
base := compiledRegistry{skillsRoot: skillsRoot, bus: bus}
for _, e := range extension.Compiled() {
if e.Register == nil {
continue
}
reg := pluginRegistry{compiledRegistry: base, pluginID: e.ID, caps: caps}
if err := e.Register(reg); err != nil {
log.Printf("extension: %s: %v", e.ID, err)
}
}
}
func mergeMCPServers(raw string, extra []core.PluginMCPServer) string {
var base []json.RawMessage
if raw != "" {
if err := json.Unmarshal([]byte(raw), &base); err != nil {
return raw
}
}
for _, s := range extra {
b, err := json.Marshal(s)
if err != nil {
continue
}
base = append(base, b)
}
if len(base) == 0 {
return ""
}
out, err := json.Marshal(base)
if err != nil {
return raw
}
return string(out)
}