Skip to content

feat(auth,docs): 403 без гранта — это auth и называет /design consent - #5

Merged
somework merged 2 commits into
mainfrom
docs/consent-prereq
Jul 25, 2026
Merged

feat(auth,docs): 403 без гранта — это auth и называет /design consent#5
somework merged 2 commits into
mainfrom
docs/consent-prereq

Conversation

@somework

@somework somework commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Всплыло при подготовке текста для знакомых: чтобы 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 автоматически; это покрыто отдельным тестом и не тронуто.

Тест написан красным и проверен обратной мутацией KindAuthKindProtocol — падает ровно на классификации.

Границы знания (важно)

Что consent — гейт именно аккаунта, стоит на свидетельстве владельца («без consent не пускало») плюс строке из бинаря claude v2.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.

Доки

  • README — предусловие /design consent и явно: Claude Design не нужно подключать MCP-сервером, dsx ходит на эндпоинт сам.
  • PROTOCOL.md/design consent|revoke как гейт аккаунта; отдельный /design-login, которого dsx не читает; enforced-scope необходим, но не достаточен.
  • CLAUDE.md — Known unknowns: форма отказа не измерена.

Test plan

  • go test -race ./... — 2502 passed
  • go vet ./..., gofmt -l . — чисто
  • staticcheck ./internal/mcp/... — чисто
  • TestForbiddenWithoutGrantIsAuthAndNamesConsent — red-first, проверен обратной мутацией
  • TestPublishedDocsNameOnlyRealCommandsAndFlags — зелёный (/design consent не dsx-команда, охраной не ловится)
  • Live-тест на consent-403 невозможен: воспроизвести аккаунт без consent нечем. Записано в Known unknowns.

Ревью

CodeRabbit по лимиту не жду (решение владельца). Если ответит без лимита — разберу.

Summary by CodeRabbit

  • Documentation

    • Clarified that Claude Design access requires account-level consent through Claude Code’s /design consent command.
    • Distinguished account consent from the separate per-project write grant.
    • Documented that dsx connects directly to Claude Design without MCP server configuration.
  • Bug Fixes

    • Improved handling of access-denied responses by identifying missing consent and providing actionable guidance to run /design consent.
    • Prevented unnecessary retries for consent-related access failures.

Предусловие, которого не было ни в коде, ни в доках: аккаунт должен один раз
выдать доступ к 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, но не замер на свежем аккаунте.
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@somework, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3089b63d-3acb-4b0c-998d-070c427e229c

📥 Commits

Reviewing files that changed from the base of the PR and between fd1d4b1 and f0c1bc5.

📒 Files selected for processing (2)
  • internal/mcp/mcp.go
  • internal/mcp/mcp_gen_test.go
📝 Walkthrough

Walkthrough

The MCP client now classifies non-project-grant HTTP 403 responses as authentication refusals, instructs users to run /design consent, and tests this behavior. Documentation describes account-level consent and distinguishes it from per-project write grants.

Changes

Claude Design consent handling

Layer / File(s) Summary
Map consent refusals to auth errors
internal/mcp/mcp.go, internal/mcp/mcp_gen_test.go
Non-needs_project_grant 403 responses return dsxerr.KindAuth errors naming /design consent; tests verify classification, messaging, no grant error, and no retry.
Document account consent requirements
PROTOCOL.md, README.md, CLAUDE.md
Documentation describes account-level consent commands, direct endpoint usage, refusal behavior, and the distinction from per-project write grants.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: 403 without a grant is now treated as auth and points users to /design consent, with docs updated too.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/consent-prereq

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between f6c6215 and fd1d4b1.

📒 Files selected for processing (5)
  • CLAUDE.md
  • PROTOCOL.md
  • README.md
  • internal/mcp/mcp.go
  • internal/mcp/mcp_gen_test.go

Comment thread internal/mcp/mcp_gen_test.go
Comment thread internal/mcp/mcp.go Outdated
Comment thread internal/mcp/mcp.go Outdated
…е ветки

Разбор ревью 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), поэтому безусловную форму из предложения ревью не
беру.
@somework
somework merged commit 6890a57 into main Jul 25, 2026
11 checks passed
@somework
somework deleted the docs/consent-prereq branch July 25, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant