mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-06 10:21:05 +02:00
## Summary Adds `mcp_tool` PPL criterion, that matches MCP tool names like ```yaml - from: https://db.localhost.pomerium.io to: http://localhost:3000/mcp policy: allow: and: - email: in: ["user@pomerium.com"] - mcp_tool: in: ["list_tables", "read_table", "search_records"] mcp: {} ``` ## Related issues Fix https://linear.app/pomerium/issue/ENG-2393/mcp-authorize-each-incoming-request-to-an-mcp-route ## User Explanation <!-- How would you explain this change to the user? If this change doesn't create any user-facing changes, you can leave this blank. If filled out, add the `docs` label --> ## Checklist - [x] reference any related issues - [x] updated unit tests - [x] add appropriate label (`enhancement`, `bug`, `breaking`, `dependencies`, `ci`) - [x] ready for review
71 lines
2 KiB
Go
71 lines
2 KiB
Go
package criteria
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
|
)
|
|
|
|
func TestMCPTool(t *testing.T) {
|
|
t.Run("ok", func(t *testing.T) {
|
|
res, err := evaluate(t, `
|
|
allow:
|
|
and:
|
|
- mcp_tool:
|
|
is: list_tables
|
|
`, []*databroker.Record{}, Input{MCP: InputMCP{Tool: "list_tables", Method: "tools/call"}})
|
|
require.NoError(t, err)
|
|
require.Equal(t, A{true, A{ReasonMCPToolOK}, M{}}, res["allow"])
|
|
require.Equal(t, A{false, A{}}, res["deny"])
|
|
})
|
|
|
|
t.Run("unauthorized", func(t *testing.T) {
|
|
res, err := evaluate(t, `
|
|
allow:
|
|
and:
|
|
- mcp_tool:
|
|
is: list_tables
|
|
`, []*databroker.Record{}, Input{MCP: InputMCP{Tool: "read_table", Method: "tools/call"}})
|
|
require.NoError(t, err)
|
|
require.Equal(t, A{false, A{ReasonMCPToolUnauthorized}, M{}}, res["allow"])
|
|
require.Equal(t, A{false, A{}}, res["deny"])
|
|
})
|
|
|
|
t.Run("in list", func(t *testing.T) {
|
|
res, err := evaluate(t, `
|
|
allow:
|
|
and:
|
|
- mcp_tool:
|
|
in: ["list_tables", "read_table"]
|
|
`, []*databroker.Record{}, Input{MCP: InputMCP{Tool: "list_tables", Method: "tools/call"}})
|
|
require.NoError(t, err)
|
|
require.Equal(t, A{true, A{ReasonMCPToolOK}, M{}}, res["allow"])
|
|
require.Equal(t, A{false, A{}}, res["deny"])
|
|
})
|
|
|
|
t.Run("not in list", func(t *testing.T) {
|
|
res, err := evaluate(t, `
|
|
allow:
|
|
and:
|
|
- mcp_tool:
|
|
in: ["list_tables", "read_table"]
|
|
`, []*databroker.Record{}, Input{MCP: InputMCP{Tool: "delete_table", Method: "tools/call"}})
|
|
require.NoError(t, err)
|
|
require.Equal(t, A{false, A{ReasonMCPToolUnauthorized}, M{}}, res["allow"])
|
|
require.Equal(t, A{false, A{}}, res["deny"])
|
|
})
|
|
|
|
t.Run("non-tools/call method should pass", func(t *testing.T) {
|
|
res, err := evaluate(t, `
|
|
allow:
|
|
and:
|
|
- mcp_tool:
|
|
is: list_tables
|
|
`, []*databroker.Record{}, Input{MCP: InputMCP{Method: "some/other_method"}})
|
|
require.NoError(t, err)
|
|
require.Equal(t, A{true, A{ReasonMCPNotAToolCall}, M{}}, res["allow"])
|
|
require.Equal(t, A{false, A{}}, res["deny"])
|
|
})
|
|
}
|