Files
goclaw/cmd/gateway_lifecycle_shell_deny_groups.go
Duy /zuey/andGitHub 990fabf94b fix(config): persist shell deny group disables
Squash merge PR #112 after resolving the project changelog conflict with current dev. Local checks passed: config gateway tests, provider/http/tools deny-pattern tests, go build ./..., and go build -tags sqliteonly ./.... PR CI run 26704832350 passed release-versioning, go, and web.
2026-05-31 13:08:24 +07:00

91 lines
2.9 KiB
Go

package cmd
import (
"context"
"log/slog"
"github.com/nextlevelbuilder/goclaw/internal/bus"
"github.com/nextlevelbuilder/goclaw/internal/config"
"github.com/nextlevelbuilder/goclaw/internal/providers"
"github.com/nextlevelbuilder/goclaw/internal/store"
"github.com/nextlevelbuilder/goclaw/internal/tools"
)
// subscribeShellDenyGroupsReload wires pub/sub so global shell deny-group
// toggles applied via the /config page take effect without a process restart.
// Extracted from runLifecycle to make the dispatch path unit-testable
// (the regression coverage missing from the original PR #1005 attempt).
func subscribeShellDenyGroupsReload(msgBus *bus.MessageBus, toolsReg *tools.Registry) {
msgBus.Subscribe("shell-deny-groups-config-reload", func(evt bus.Event) {
if evt.Name != bus.TopicConfigChanged {
return
}
updatedCfg, ok := evt.Payload.(*config.Config)
if !ok {
return
}
snapshot := updatedCfg.Clone()
execTool, ok := toolsReg.Get("exec")
if !ok {
return
}
et, ok := execTool.(*tools.ExecTool)
if !ok {
return
}
et.SetGlobalShellDenyGroups(snapshot.Tools.ShellDenyGroups)
et.SetCommandKeywordAllowlist(snapshot.Tools.CommandKeywordAllowlist)
slog.Info("shell deny groups reloaded via pub/sub",
"groups", len(snapshot.Tools.ShellDenyGroups),
"command_keyword_allowlist_rules", len(snapshot.Tools.CommandKeywordAllowlist),
)
})
}
func subscribeProviderShellDenyGroupsReload(msgBus *bus.MessageBus, providerReg *providers.Registry, provStore store.ProviderStore, mcpStore store.MCPServerStore) {
if msgBus == nil || providerReg == nil {
return
}
msgBus.Subscribe("shell-deny-provider-policy-reload", func(evt bus.Event) {
if evt.Name != bus.TopicConfigChanged {
return
}
updatedCfg, ok := evt.Payload.(*config.Config)
if !ok {
return
}
reloadShellDenyProviderPolicies(providerReg, provStore, mcpStore, updatedCfg)
})
}
func reloadShellDenyProviderPolicies(providerReg *providers.Registry, provStore store.ProviderStore, mcpStore store.MCPServerStore, cfg *config.Config) {
if providerReg == nil || cfg == nil {
return
}
snapshot := cfg.Clone()
registerClaudeCLIFromConfig(providerReg, snapshot)
if snapshot.Providers.ACP.Binary != "" {
registerACPFromConfig(providerReg, snapshot.Providers.ACP, snapshot.ShellDenyGroupsSnapshot())
}
if provStore == nil {
return
}
dbProviders, err := provStore.ListAllProviders(context.Background())
if err != nil {
slog.Warn("shell deny provider policy reload: failed to load providers from DB", "error", err)
return
}
gatewayAddr := loopbackAddr(snapshot.Gateway.Host, snapshot.Gateway.Port)
for _, p := range dbProviders {
if !p.Enabled {
continue
}
switch p.ProviderType {
case store.ProviderClaudeCLI:
registerClaudeCLIFromDB(providerReg, p, gatewayAddr, snapshot.Gateway.Token, mcpStore, snapshot)
case store.ProviderACP:
registerACPFromDB(providerReg, p, snapshot.ShellDenyGroupsSnapshot())
}
}
}