diff --git a/internal/tools/policy.go b/internal/tools/policy.go index 329525c9..a5629476 100644 --- a/internal/tools/policy.go +++ b/internal/tools/policy.go @@ -527,7 +527,11 @@ func StripToolPrefix(tmpl, name string) string { if strings.Contains(tmpl, placeholder) { parts := strings.SplitN(tmpl, placeholder, 2) prefix, suffix := parts[0], parts[1] - if strings.HasPrefix(name, prefix) && strings.HasSuffix(name, suffix) { + // Require the name to be at least as long as prefix+suffix so an + // overlapping match (e.g. tmpl "pre_{tool_name}_suf", name "pre_suf") + // doesn't slice with a negative length and panic. + if strings.HasPrefix(name, prefix) && strings.HasSuffix(name, suffix) && + len(prefix)+len(suffix) <= len(name) { result := name[len(prefix):] if suffix != "" { result = result[:len(result)-len(suffix)] diff --git a/internal/tools/policy_prefix_test.go b/internal/tools/policy_prefix_test.go index a07f7972..1698effc 100644 --- a/internal/tools/policy_prefix_test.go +++ b/internal/tools/policy_prefix_test.go @@ -16,6 +16,7 @@ func TestStripToolPrefix(t *testing.T) { {"template no match", "proxy_{tool_name}", "other_exec", "other_exec"}, {"template empty result", "proxy_{tool_name}", "proxy_", "proxy_"}, {"template exact placeholder", "{tool_name}", "exec", "exec"}, + {"template prefix+suffix overlap (regression)", "pre_{tool_name}_suf", "pre_suf", "pre_suf"}, // Literal prefix {"literal prefix with separator", "proxy_", "proxy_exec", "exec"},