Commit c63b9eb
Enforce Cedar policies on optimizer find_tool and call_tool (#4385)
* Enforce Cedar policies on optimizer find_tool and call_tool
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Enforce Cedar policies on optimizer call_tool via authz middleware
Move Cedar authorization enforcement for the optimizer meta-tools out of
the vmcp session layer and into the authz HTTP middleware, keeping the
changes isolated to pkg/authz and the composition root (commands.go).
The previous approach threaded an authorizers.Authorizer through five
layers (incoming.go → commands.go → server.go → sessionmanager →
factory → decorator), creating coupling between the optimizer decorator
and the authorization system.
New approach:
- authz middleware intercepts tools/call for pass-through meta-tools:
call_tool extracts the inner toolName from arguments and authorizes
that backend tool; find_tool is allowed through as a discovery op.
- commands.go builds passThroughTools (find_tool, call_tool) when the
optimizer is enabled and passes it to NewIncomingAuthMiddleware.
- incoming.go returns authzMw directly (as on main) instead of a raw
authorizer; accepts passThroughTools to configure the middleware.
- server.go, sessionmanager, and the optimizer decorator revert to their
main-branch signatures with no knowledge of the authorizer.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* Enforce Cedar policies on optimizer find_tool response
find_tool calls were allowed through the authz middleware with no
response filtering, letting callers discover tool names, descriptions,
and schemas for tools they are not authorized to call.
- Add filterFindToolResponse to ResponseFilteringWriter: intercepts the
find_tool CallToolResult, identifies the FindToolOutput payload by
attempting to unmarshal each TextContent item (stronger than checking
the type string), filters output.Tools through Cedar policy, and
populates the annotation cache from the unfiltered list so subsequent
call_tool Cedar when-clauses evaluate correctly
- Extend requiresResponseFiltering (renamed from isListOperation) and
filterListResponse to dispatch find_tool responses through the new
method, reusing all existing buffering, flush, and SSE logic
- Update handleToolsCall to wrap find_tool with NewResponseFilteringWriter
instead of passing through unfiltered
- Unexport FilterToolsByPolicy and AuthorizeToolCall; move tool_filter_test
to package authz to match
- Expand TestFindToolResponseFilter with sub-tests covering Cedar filtering,
isError pass-through, missing/non-FindToolOutput content pass-through,
and annotation cache population from the unfiltered tool list
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent 11cd266 commit c63b9eb
18 files changed
Lines changed: 2314 additions & 790 deletions
File tree
- cmd/vmcp/app
- docs/server
- pkg
- authz
- vmcp
- auth/factory
- session/optimizerdec
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
42 | 43 | | |
43 | 44 | | |
44 | 45 | | |
| |||
506 | 507 | | |
507 | 508 | | |
508 | 509 | | |
509 | | - | |
510 | | - | |
511 | | - | |
512 | | - | |
513 | | - | |
514 | | - | |
515 | | - | |
516 | 510 | | |
517 | 511 | | |
518 | 512 | | |
| |||
582 | 576 | | |
583 | 577 | | |
584 | 578 | | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
585 | 599 | | |
586 | 600 | | |
587 | 601 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments