claude-code: refuse registering what a session runs, so no agent can plant it in the operator's sessions
The tool runner is not told who called, so a hook, a managed setting, a permission rule or a tool server registered through these tools could come from an agent confined on another node and run as the operator there (hq issue 340). They are set at the controller's terminal now; a skill, subagent or command that runs something by itself is refused too, kept hooks and settings are never rendered, and claude_code_registrations lists what is registered and by which node.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package main
|
||||
|
||||
// What a Claude Code session on the mesh runs or obeys, and where each came from (novox/hq issue 340): for the
|
||||
// operator to review what is registered today, read-only.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ByIs says what a registration's `by` is: the node whose tool runner served the call, never the caller, whom the
|
||||
// runner is not told.
|
||||
const ByIs = "the node whose tool runner served the registering call; who called it was never recorded, because the runner is not told"
|
||||
|
||||
// Registrations is every registration on the mesh that reaches a session, read from the state, and what the
|
||||
// operator set at the controller's terminal for this node: the tool servers (`servers`), the agent's
|
||||
// configuration (`config`) with whether each is still rendered and, when not, why; and the `managed_settings`
|
||||
// and `mcp_servers` this node's layers compose to.
|
||||
func Registrations(p Paths, servers ServerState, config ConfigState) (map[string]any, error) {
|
||||
serverKeys, err := servers.Keys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Strings(serverKeys)
|
||||
registered := map[string]any{}
|
||||
for _, key := range serverKeys {
|
||||
raw, found, err := servers.Get(key)
|
||||
if err != nil || !found {
|
||||
continue
|
||||
}
|
||||
var entry map[string]any
|
||||
if json.Unmarshal(raw, &entry) != nil {
|
||||
continue
|
||||
}
|
||||
row := map[string]any{"entry": entry, "by": "not recorded: a tool server's registration kept only its entry"}
|
||||
if _, name, ok := strings.Cut(key, "."); ok {
|
||||
if problem := EntryProblem(name, entry); problem != "" {
|
||||
row["rendered"] = "no: " + problem
|
||||
} else {
|
||||
row["rendered"] = "yes, on the nodes its key names"
|
||||
}
|
||||
}
|
||||
registered[key] = row
|
||||
}
|
||||
|
||||
configKeys, err := config.Keys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Strings(configKeys)
|
||||
items := map[string]any{}
|
||||
for _, key := range configKeys {
|
||||
raw, found, err := config.Get(key)
|
||||
if err != nil || !found {
|
||||
continue
|
||||
}
|
||||
var it Item
|
||||
if json.Unmarshal(raw, &it) != nil {
|
||||
continue
|
||||
}
|
||||
_, node, _, _, ok := ParseKey(key)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
row := map[string]any{"kind": it.Kind, "scope": it.Scope, "by": it.By, "at": it.At}
|
||||
files := make([]string, 0, len(it.Files))
|
||||
for f := range it.Files {
|
||||
files = append(files, f)
|
||||
}
|
||||
sort.Strings(files)
|
||||
if len(files) > 0 {
|
||||
row["files"] = files
|
||||
}
|
||||
switch it.Kind {
|
||||
case KindHook:
|
||||
row["event"], row["matcher"], row["command"] = it.Event, it.Matcher, it.Command
|
||||
case KindSettings:
|
||||
row["settings"] = it.Settings
|
||||
}
|
||||
switch problem := it.Problem(); {
|
||||
case it.Key(node) != key:
|
||||
row["rendered"] = "no: its key does not say what the item is"
|
||||
case problem != "":
|
||||
row["rendered"] = "no: " + problem
|
||||
default:
|
||||
row["rendered"] = "yes, as " + it.Scope + " " + it.Kind
|
||||
}
|
||||
items[key] = row
|
||||
}
|
||||
|
||||
var settings Settings
|
||||
_ = readJSON(p.Settings, &settings)
|
||||
return map[string]any{
|
||||
"set at the controller's terminal, as this node composes it": map[string]any{
|
||||
"managed_settings": settings.ManagedSettings, "mcp_servers": settings.MCPServers},
|
||||
"tool servers registered through this module": registered,
|
||||
"configuration registered through this module": items,
|
||||
"by": ByIs,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user