feat(auth,docs): 403 без гранта — это auth и называет /design consent - #5
Conversation
Предусловие, которого не было ни в коде, ни в доках: аккаунт должен один раз выдать доступ к Claude Design через /design consent в Claude Code. Это состояние аккаунта, не свойство токена — скоуп user:mcp_servers сервер и так принимает. Код. 403 без needs_project_grant проваливался в общую ветку non-200 и классифицировался как KindProtocol (exit 1) с голым "http 403: <body>". Но 403 — отказ авторизации, симметричный 401: теперь KindAuth (exit 5), называет /design consent как внесистемный шаг, которого dsx за пользователя сделать не может, и эхом отдаёт тело сервера. Матч по статусу, не по телу: тело consent-отказа не измерено. needs_project_grant отщепляется веткой выше и по-прежнему чинится finalize_plan сам. Тест написан красным и проверен обратной мутацией KindAuth->KindProtocol. Доки. README — предусловие и что Design НЕ надо подключать MCP-сервером. PROTOCOL.md — /design consent/revoke как гейт аккаунта, отдельный design-login которого dsx не читает, и что enforced-scope это не sufficient. CLAUDE.md, Known unknowns — форма отказа на аккаунте без consent не измерена: свидетельство владельца плюс строка из бинаря claude, но не замер на свежем аккаунте.
|
Warning Review limit reached
Next review available in: 52 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe MCP client now classifies non-project-grant HTTP 403 responses as authentication refusals, instructs users to run ChangesClaude Design consent handling
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/mcp/mcp_gen_test.go`:
- Around line 251-260: Extend the 403 authorization test assertions around
dsxerr.Classify(err) to verify that de.Msg also contains the server response
payload, in addition to the existing “/design consent” guidance. Use the payload
text established by the test fixture or response setup, ensuring removal of the
production payload echo causes the test to fail.
In `@internal/mcp/mcp.go`:
- Around line 257-259: Update the 403 refusal message in the Msg construction to
describe the consent gate as account-level Claude Design access: replace the
“has not used Claude Design” wording with “has not granted Claude Design
access,” while preserving the existing /design consent guidance and server
payload.
- Around line 256-259: Update the 403 error construction in the authentication
handling path to sanitize the server response with fmtutil.Printable before
passing it to fmtutil.Truncate and appending it to Msg. Preserve the existing
truncation limit and error wording while ensuring payload control bytes cannot
reach user-facing output.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 45791dc3-c870-4b8b-9126-bfcf1782b86c
📒 Files selected for processing (5)
CLAUDE.mdPROTOCOL.mdREADME.mdinternal/mcp/mcp.gointernal/mcp/mcp_gen_test.go
…е ветки Разбор ревью CodeRabbit на #5. Три находки, все приняты; одна оказалась шире, чем указана. Major (безопасность). 403-ветка echo-ила тело сервера через Truncate, который только режет длину и сохраняет управляющие байты. dsxerr.Render на человеческом пути печатает Msg сырым в stderr, так что \r или ANSI из враждебного 403 переписали бы терминал — ровно инвариант 7. Находка указывала на мою строку, но соседние 429/500/non-200 делали то же и предшествуют PR: обёрнуты fmtutil.Printable все четыре. Тест усилен управляющими байтами в теле фикстуры и проверкой, что \r\n\x1b не доходят до Msg; проверено ручной мутацией (снял Printable — падает на санитайз-проверке). Minor (тест). Тест не пинил эхо тела — добавлена проверка, что "forbidden" из тела попадает в сообщение. Minor (формулировка). "has not used Claude Design" неточно: consent это грант, а не факт использования. Стало "has not been granted Claude Design access". Условность оставлена намеренно — что consent есть причина именно этого 403, не измерено (Known unknowns), поэтому безусловную форму из предложения ревью не беру.
Что и зачем
Всплыло при подготовке текста для знакомых: чтобы dsx заработал, аккаунт должен один раз выдать доступ к Claude Design —
/design consentв Claude Code. Это состояние аккаунта, а не свойство токена: скоупuser:mcp_serversсервер и так принимает. Ни в коде, ни в доках этого предусловия не было.Код
403 без
needs_project_grantпроваливался в общую ветку non-200 и классифицировался какKindProtocol(exit 1) с голымhttp 403: <body>. Но 403 — отказ авторизации, симметричный 401. Теперь:KindAuth(exit 5), как у 401;/design consent— внесистемный шаг, которого dsx за пользователя сделать не может;Матч по статусу 403, не по телу — тело consent-отказа я не видел (все доступные аккаунты consent уже прошли).
needs_project_grantотщепляется веткой выше и по-прежнему чинитсяfinalize_planавтоматически; это покрыто отдельным тестом и не тронуто.Тест написан красным и проверен обратной мутацией
KindAuth→KindProtocol— падает ровно на классификации.Границы знания (важно)
Что consent — гейт именно аккаунта, стоит на свидетельстве владельца («без consent не пускало») плюс строке из бинаря
claudev2.1.219:/design-consent → "Grant Claude agent access to your Design projects", в паре с/design-revoke. Оба — сильное свидетельство, ни одно не замер на свежем аккаунте: форма отказа для аккаунта без consent не видена. Это честно записано в CLAUDE.md → Known unknowns, а классификация по статусу выбрана именно поэтому.Отдельно проверено на живой машине: dsx не читает никакого «design-креденшла» от
/design-login— его нет ни в keychain (mcpOAuthсодержит только atlassian/figma), ни файлом. dsx работает на обычномclaudeAiOauth.Доки
/design consentи явно: Claude Design не нужно подключать MCP-сервером, dsx ходит на эндпоинт сам./design consent|revokeкак гейт аккаунта; отдельный/design-login, которого dsx не читает; enforced-scope необходим, но не достаточен.Test plan
go test -race ./...— 2502 passedgo vet ./...,gofmt -l .— чистоstaticcheck ./internal/mcp/...— чистоTestForbiddenWithoutGrantIsAuthAndNamesConsent— red-first, проверен обратной мутациейTestPublishedDocsNameOnlyRealCommandsAndFlags— зелёный (/design consentне dsx-команда, охраной не ловится)Ревью
CodeRabbit по лимиту не жду (решение владельца). Если ответит без лимита — разберу.
Summary by CodeRabbit
Documentation
/design consentcommand.Bug Fixes
/design consent.