Skip to content

Log when authorization policies filter list responses#4690

Merged
jerm-dro merged 3 commits intomainfrom
jd/log-authz-denials
Apr 8, 2026
Merged

Log when authorization policies filter list responses#4690
jerm-dro merged 3 commits intomainfrom
jd/log-authz-denials

Conversation

@jerm-dro
Copy link
Copy Markdown
Contributor

@jerm-dro jerm-dro commented Apr 8, 2026

Summary

When Cedar policies deny tools, prompts, or resources during list filtering, items are silently removed from the response with zero log output. This makes it difficult for operators to diagnose authorization issues — the MCP client shows empty capabilities ("Capabilities: None") with no explanation of why. A community user hit this after upgrading to v0.15.0 when PR #4448 switched Cedar to evaluate upstream IDP access token claims, which had different claim keys than expected.

  • Add a generic AtMost utility (pkg/syncutil) that executes a function at most once per configurable interval, safe for concurrent use
  • Use it in the Cedar authorizer to emit a rate-limited (every 30s) DEBUG log of resolved JWT claim keys, so operators can see what claims are available for writing policies
  • Add DEBUG-level logs for denied items and filtering summaries during list operations
  • All authz diagnostic logs use DEBUG per the "silent success" convention — enable with TOOLHIVE_DEBUG=true in proxyConfig.env

Type of change

  • New feature

Test plan

  • Unit tests (task test)
  • Linting (task lint-fix)

Changes

File Change
pkg/syncutil/atmost.go New generic rate-limited invocation utility
pkg/syncutil/atmost_test.go Tests using injectable fake clock
pkg/authz/authorizers/cedar/core.go Rate-limited claim key logging in resolveClaims()
pkg/authz/tool_filter.go DEBUG logs for denied tools and filtering summary
pkg/authz/response_filter.go DEBUG logs for denied prompts/resources and filtering summaries

Does this introduce a user-facing change?

When TOOLHIVE_DEBUG=true is set in proxyConfig.env, operators will see:

  • Resolved JWT claim keys available for Cedar policy evaluation (rate-limited to every 30s)
  • Per-item denied tools/prompts/resources and filtering summaries

Special notes for reviewers

The AtMost utility is intentionally generic (not logging-specific) so it can be reused for any rate-limited side-effect. It uses atomic.Int64 CAS for lock-free concurrent safety, and accepts an injectable func() time.Time for deterministic testing without time.Sleep.

Generated with Claude Code

When Cedar policies deny access to tools, prompts, or resources during
list filtering, items are silently removed from the response. This makes
it difficult to diagnose authorization issues since the MCP client shows
empty capabilities with no explanation.

Add DEBUG-level logs for each denied item and an INFO-level summary
after filtering completes so operators can see that items were filtered
and enable DEBUG to see which ones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions bot added the size/XS Extra small PR: < 100 lines changed label Apr 8, 2026
Add a generic AtMost utility (pkg/syncutil) that executes a function at
most once per configurable interval, safe for concurrent use. Use it in
the Cedar authorizer to emit a rate-limited DEBUG log of resolved JWT
claim keys, helping operators see what claims are available for writing
Cedar policies without enabling verbose per-request logging.

Downgrade the authorization filtering summary logs from INFO to DEBUG to
follow the "silent success" convention — a policy correctly denying
access is working as intended, not something that warrants INFO output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/XS Extra small PR: < 100 lines changed size/S Small PR: 100-299 lines changed labels Apr 8, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.68%. Comparing base (495b86e) to head (fcaecce).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4690      +/-   ##
==========================================
- Coverage   68.78%   68.68%   -0.11%     
==========================================
  Files         506      508       +2     
  Lines       52599    52878     +279     
==========================================
+ Hits        36180    36318     +138     
- Misses      13617    13741     +124     
- Partials     2802     2819      +17     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jerm-dro jerm-dro requested a review from tgrunnagle April 8, 2026 22:15
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 8, 2026
Copy link
Copy Markdown
Contributor

@jhrozek jhrozek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fantastic

@jerm-dro jerm-dro merged commit c227629 into main Apr 8, 2026
40 checks passed
@jerm-dro jerm-dro deleted the jd/log-authz-denials branch April 8, 2026 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/S Small PR: 100-299 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants