Files
summercms/modules/pier/filter.go
Jakub Zych 211cec11b0 fix(pact): add MCPPrompt.Writes so a write-directing prompt sits under the read/write ceiling
- pact.MCPPrompt.Writes (additive; the zero value keeps today's listing)
- pier's allowsPrompt hides a prompt declared with Writes from an identity
  without write, as it hides a tool that is not read-only (C-IN-01
  framework part, P-28)
2026-10-23 16:08:27 +02:00

74 lines
2.3 KiB
Go

package pier
import (
"context"
"git.golem15.com/golem15/summercms/modules/pact"
)
// allowed computes the tools and prompts an identity may see and call: a
// tool needs a subject under its guard, the read/write ceiling hides
// non-read-only tools and prompts declared with Writes from an identity
// without write (D-20), and the
// guard provider's own check decides the rest (D-16, D-23). A provider
// error hides the item and is logged. The same function builds the
// per-identity server and re-checks every list and call for the current
// request's identity (D-08, D-25).
func (c *catalog) allowed(ctx context.Context, id Identity) ([]*tool, []*prompt) {
var tools []*tool
for _, t := range c.tools {
if c.allowsTool(ctx, id, t) {
tools = append(tools, t)
}
}
var prompts []*prompt
for _, p := range c.prompts {
if c.allowsPrompt(ctx, id, p) {
prompts = append(prompts, p)
}
}
return tools, prompts
}
func (c *catalog) allowsTool(ctx context.Context, id Identity, t *tool) bool {
subject := id.subjectFor(t.guardName)
if subject == nil {
return false
}
if !t.readOnly && !id.writes() {
return false
}
ok, err := allows(ctx, t.guard, *subject, t.req, t.decl.Permissions, t.method)
if err != nil {
logger().Warn("pier: guard check failed", "tool", t.name, "guard", t.guardName, "error", err)
return false
}
return ok
}
func (c *catalog) allowsPrompt(ctx context.Context, id Identity, p *prompt) bool {
// A prompt that directs write tools sits under the read/write ceiling
// like a tool that is not read-only (P-28).
if p.decl.Writes && !id.writes() {
return false
}
subject := id.subjectFor(p.guardName)
if subject == nil {
return false
}
ok, err := allows(ctx, p.guard, *subject, pact.MCPRequirements{}, p.decl.Permissions, "")
if err != nil {
logger().Warn("pier: guard check failed", "prompt", p.name, "guard", p.guardName, "error", err)
return false
}
return ok
}
// allows asks the provider, method-aware when it supports it.
func allows(ctx context.Context, g pact.MCPGuard, subject pact.MCPSubject, req pact.MCPRequirements, permissions []string, method string) (bool, error) {
if ma, ok := g.(methodAllower); ok && method != "" {
return ma.MCPAllowsMethod(ctx, subject, req, permissions, method)
}
return g.MCPAllows(ctx, subject, req, permissions)
}