Skip to content

Claude/mcp codekeeper webapp ldnzsg - #3180

Merged
amirbiron merged 18 commits into
mainfrom
claude/mcp-codekeeper-webapp-ldnzsg
Jul 19, 2026
Merged

Claude/mcp codekeeper webapp ldnzsg#3180
amirbiron merged 18 commits into
mainfrom
claude/mcp-codekeeper-webapp-ldnzsg

Conversation

@amirbiron

@amirbiron amirbiron commented Jul 19, 2026

Copy link
Copy Markdown
Owner

תבנית Pull Request

✨ תיאור קצר

  • מה שיניתם ולמה? (2-3 משפטים)

📦 שינויים עיקריים

  • קוד (Backend)
  • בוט טלגרם
  • מסד נתונים/מיגרציות
  • תיעוד (docs/)
  • DevOps/CI/CD

פירוט נקודות (רשימת תבליטים):

🧪 בדיקות

  • איך בדקתם? מה עבר? מה נשאר?
  • Unit
  • Integration
  • Manual

🧪 בדיקות נדרשות ב‑PR

  • 🔍 Code Quality & Security
  • Unit Tests (3.11)
  • Unit Tests (3.12)

📝 סוג שינוי

  • feat: פיצ'ר חדש
  • fix: תיקון באג
  • docs: שינוי תיעוד בלבד
  • refactor: שינוי קוד ללא שינוי התנהגות
  • perf: שיפור ביצועים
  • chore/ci: תשתית/CI
  • breaking change: שינוי שובר תאימות

דוגמאות Conventional Commits

סוג דוגמה להודעה מתי להשתמש
feat feat: הוספת מסך הגדרות פיצ'ר חדש למשתמש
fix fix: תיקון קריסה בעת התחברות תיקון באג מול משתמשים/פרודקשן
chore chore: שדרוג Gradle ל-8.9 תחזוקה, כלי פיתוח, housekeeping
docs docs: עדכון README עם הוראות התקנה שינויי תיעוד בלבד
refactor refactor: חילוץ Repository ל-UseCases שינוי מבני ללא שינוי התנהגות
test test: הוספת בדיקות ל-LoginViewModel הוספת/עדכון בדיקות
build build: הוספת flavor staging ל-CI שינויים בבילד/תלויות/תצורה

✅ צ'קליסט

  • הקוד עוקב אחרי הסגנון (Black/isort/flake8/mypy)
  • בדיקות רצות ועוברות
  • תיעוד עודכן (README/Docs)
  • אם נוספו ג'ובים חדשים (Background Jobs) – וודא שהם רשומים ב-services/register_jobs.py (כולל Callback/Trigger להפעלה ידנית — למשל callback_name/trigger_func לפי המבנה) כדי שיופיעו בדשבורד
  • אם נוספו/שונו משתני סביבה – עודכן docs/environment-variables.rst וגם services/config_inspector_service.py
  • אם נוספו/השתנו טוקנים – עודכן גם docs/webapp/theming_and_css.rst + FEATURE_SUGGESTIONS/theme_matrix.md
  • אין סודות/מפתחות בקוד
  • אין מחיקות מסוכנות/פעולות על root (ראו .cursorrules)
  • הודעת הקומיט תואמת Conventional Commits (ע"פ הטבלה)
  • CHANGELOG עודכן אם נדרש
  • כל ה‑Required Checks לעיל ירוקים
  • צילום/וידאו UI מצורף אם רלוונטי

🧩 השפעות/סיכונים

  • השפעה אפשרית על פרודקשן, ביצועים, או אבטחה:

🔗 קישורים

🧯 סיכון / החזרה לאחור (Rollback)

  • תוכנית חזרה לאחור במקרה תקלה:

Summary by CodeRabbit

  • תכונות חדשות

    • נוספה תמיכה ב‑OAuth 2.1 לחיבור Claude.ai לשרת MCP.
    • ניתן להתחבר באמצעות PAT או OAuth, עם תהליך זיהוי ואישור מאובטח.
    • נוספה פקודת /connect_claude ותמיכה בחיבור Claude Code ו‑Claude Desktop.
    • כלי CodeKeeper מוצגים כקריאה בלבד ובשמות עקביים.
    • נוספה הגנה מפני הפניות לא מורשות ושיפור אבטחת חיבורי MCP.
  • תיעוד

    • עודכנו הוראות ההגדרה, משתני הסביבה, הנפקת PAT, חיבור Claude ופריסה.
  • בדיקות

    • נוספו בדיקות מקיפות לזרימות OAuth, הרשאות, תוקף אסימונים, PKCE ואבטחת זהות.

claude and others added 14 commits July 19, 2026 11:31
מסמך תכנון לחיבור Claude.ai לקבצי המשתמש ב-CodeKeeper דרך שרת MCP מרוחק.

- ממפה את הקיים: שכבת DB in-process (database/repository.py), אימות סשן
  (webapp/app.py:3204), וגשרי טוקנים קיימים (webapp_tokens/remember_tokens).
- מציע ארכיטקטורה: שירות MCP נפרד (ASGI) שניגש ישירות ל-database, מסונן user_id.
- אימות בשתי פאזות: PAT (MVP) → OAuth 2.1 מעל זהות טלגרם הקיימת.
- כלים: list_files/search_code/get_file/list_versions (+ save_file בהמשך).
- אבטחה: read-only כברירת מחדל, בידוד user_id מהטוקן, Smart Projection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
מימוש פאזה 0 מהתוכנית: שרת MCP מרוחק (Streamable HTTP) קריאה-בלבד שחושף
את קבצי הקוד והאוספים של המשתמש ל-Claude Code/Desktop.

- mcp_server/: חבילת FastMCP עם 7 כלים (list_files, search_code, get_file,
  list_versions, list_collections, get_collection, get_collection_items).
  ניגש ישירות ל-database.db + CollectionsManager, מסונן user_id, מכבד את
  חוק ה-Smart Projection (בלי code ברשימות/חיפוש).
- אימות PAT: token_store.py מנהל טוקנים (hash בלבד) בקולקשן mcp_tokens;
  auth.py מאמת Bearer ומזריק user_id ל-request.state; ה-user_id נגזר תמיד
  מהטוקן, לעולם לא מקלט הלקוח. get_file בודק בעלות גם לפי file_id.
- scripts/mcp_issue_token.py: הנפקת טוקן ל-CLI/בדיקות.
- tests/test_mcp_*.py: 27 טסטים (fakes ידניים, בלי MongoDB אמיתי) —
  token store, בעלות/סריאליזציה, clamping, middleware, ורישום כלים.
- requirements/base.txt: mcp==1.28.1 (תואם לפינים הקיימים).
- מסמך התכנון עודכן לסטטוס "פאזה 0 מומשה" + README ל-mcp_server.

פאזות הבאות (בתכנון): פקודת בוט /connect_claude, OAuth 2.1 ל-Claude.ai, כתיבה.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
… docs

תיקוני סקירה (כל ההערות היו תקפות):
- backend.get_collection_items: הגנת עומק — מסנן שדות כבדים (code/content)
  מפריטי אוסף לפני החזרה, כדי שלא ידלפו גם אם CollectionsManager ישתנה.
- mcp_server/wiring.py: חילוץ resolve_mongo המשותף; הוסרו ההעתקים
  מ-app.py ומ-scripts/mcp_issue_token.py.
- auth.py: לוג לחריגה שנבלעה ב-verify (בלי הטוקן) לצורך אבחון בפרודקשן.
- Markdown: שפת code fence (text) לדיאגרמות ולבלוק ההרצה, ושורות ריקות
  לפני טבלאות (MD040/MD058) ב-README ובמסמך התכנון.
- טסט חדש: מוודא שפריטי אוסף מסוננים משדות כבדים.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
מוסיף פקודת בוט /connect_claude שמנפיקה למשתמש טוקן MCP אישי מתוך טלגרם
(במקום להריץ סקריפט CLI), ומחזירה פקודת חיבור מוכנה ל-Claude Code.

- main.py: connect_claude_command (מודול-לבל), רישום ב-setup_handlers,
  וכניסה ב-HELP_SECTIONS. אבטחה: מונפק בצ'אט פרטי בלבד (שלא ידלוף בקבוצה);
  fallback לטקסט אם פרסום HTML נכשל (לא לאבד את הטוקן).
- files_facade.issue_mcp_token: עוטף את MCPTokenStore (import עצל) כדי
  לשמור את החיווט במקום אחד ולא לגעת ב-PyMongo גולמי מה-handler.
- README + מסמך התכנון עודכנו: /connect_claude זמין, + ENV MCP_SERVER_URL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
…ecrets

מבהיר בדיוק אילו ENV שירות ה-MCP צריך: MONGODB_URL+DATABASE_NAME זהים לבוט/וובאפ
(אותו DB, אחרת הטוקן מ-/connect_claude לא יימצא), BOT_TOKEN רק כדי שה-config
המשותף ייטען, ולא צריך את סודות הוובאפ. MCP_SERVER_URL מוגדר על שירות הבוט.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
לפי תבנית ה-PR: תיעוד משתני הסביבה החדשים ששירות ה-MCP/הבוט משתמשים בהם.

- docs/environment-variables.rst: שתי שורות בטבלת התפעול (URL ציבורי + שם תצוגה).
- services/config_inspector_service.py: ConfigDefinition לשניהם תחת category="mcp",
  כדי שיופיעו ב-Config Inspector.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
Render defaulted the new native Python MCP service to 3.14, where greenlet
(pulled in by gevent) fails to compile — its C++ uses CPython frame internals
that changed in 3.14. The project targets 3.11 (Dockerfile python:3.11-slim; CI
runs 3.11/3.12), so pin the native runtime to a supported version.

- .python-version = 3.11 -> Render uses the latest 3.11 patch.
- No effect on CI (explicit python-version in workflows) or Docker services;
  services that set PYTHON_VERSION explicitly still win over this file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
מתקן כפילות שנוצרה במיזוג/squash: שורת פתיחה ישנה + פסקת ENV כפולה בסעיף הפריסה.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
השרת הפרוס החזיר HTTP 421 "Invalid Host header" — הגנת ה-DNS-rebinding המובנית
של ה-SDK מאשרת כברירת מחדל רק localhost, וחסמה את הדומיין האמיתי
(codekeeper-mcp.onrender.com). הטסטים המקומיים עברו כי הם על 127.0.0.1.

- server.py: transport_security עם enable_dns_rebinding_protection=False
  כברירת מחדל (שרת ציבורי מוגן-טוקן — ההגנה הזו נועדה לשרתי localhost).
  ניתן לנעול עם MCP_ALLOWED_HOSTS (CSV, תומך wildcard) + MCP_ALLOWED_ORIGINS.
- טסטים: ברירת מחדל כבויה + נעילה דרך ENV.
- תיעוד: MCP_ALLOWED_HOSTS/ORIGINS ב-environment-variables.rst + config_inspector.

אומת מקומית: בקשה עם Host מזויף codekeeper-mcp.onrender.com מחזירה 200 (לא 421).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
מימוש פאזה 1: חיבור Claude.ai (Custom Connector) דרך OAuth 2.1 מלא, לצד
ה-PAT הקיים (Claude Code/Desktop) — מאוחדים תחת load_access_token.

- oauth_store.py: אחסון Mongo ל-clients/codes/tokens/txns (hash, TTL).
- oauth_provider.py: מימוש חוזה ה-SDK (DCR, authorize->txn, exchange code/
  refresh עם rotation, load_access_token שמקבל גם PAT וגם OAuth token).
- oauth_identity.py: חתימת/אימות זהות HMAC (SECRET_KEY משותף) — שיתוף עם הוובאפ.
- oauth_routes.py: מסך consent ב-MCP → מנפיק code → redirect ל-Claude.
- webapp /oauth/identify: גשר זהות — התחברות טלגרם (widget) וחתימת user_id,
  עם שער open-redirect ל-MCP_SERVER_URL. סינון שדות טלגרם (לא לחתום על txn/return).
- server.py/app.py: FastMCP עם auth_server_provider+AuthSettings כשמוגדרים
  MCP_SERVER_URL+WEBAPP_URL (אחרת נשאר PAT-only). current_user_id קורא
  get_access_token().subject (OAuth) עם fallback ל-request.state (PAT).

אימות: 27 טסטי OAuth (store/provider/identity/consent/HTTP-flow/webapp) +
e2e מקומי מלא (register->authorize->consent->token->tool) שמוכיח ש-PAT ו-OAuth
עובדים יחד ו-get_access_token זמין בתוך tool סינכרוני. תיעוד: README + env docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
…ations

לפי מדריך mcp-builder:
- שמות כלים מקודמים ב-codekeeper_ (get_file/list_files/search_code הם
  גנריים מדי ומתנגשים כשמחוברים כמה connectors) — codekeeper_list_files וכו'.
- annotations לכל כלי: readOnlyHint=True, destructiveHint=False,
  idempotentHint=True, openWorldHint=False (קריאה על נתוני המשתמש).
- עודכנו instructions, README, וטסט רישום הכלים.

הכלים מתגלים מחדש בכל סשן, אז זה לא שובר חיבורים קיימים — Claude פשוט
יראה את השמות החדשים בחיבור הבא.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 12 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 09d960d6-7813-44cb-a81c-3e65b3cf1402

📥 Commits

Reviewing files that changed from the base of the PR and between f0aaa55 and 785e7a9.

📒 Files selected for processing (12)
  • docs/environment-variables.rst
  • mcp_server/app.py
  • mcp_server/oauth_identity.py
  • services/config_inspector_service.py
  • tests/test_http_sync_new.py
  • tests/test_mcp_oauth_e2e.py
  • tests/test_mcp_oauth_identity.py
  • tests/test_mcp_oauth_provider.py
  • tests/test_mcp_oauth_routes.py
  • tests/test_mcp_oauth_store.py
  • tests/test_webapp_oauth_identify.py
  • webapp/routes/auth_routes.py
📝 Walkthrough

Walkthrough

ה-PR מוסיף לשרת MCP זרימת OAuth 2.1 לצד PAT, כולל אחסון MongoDB, גשר זהות דרך Telegram, מסך consent, שילוב ASGI/FastMCP, אבטחת transport ובדיקות יחידה ו-E2E.

Changes

OAuth ו-MCP

Layer / File(s) Summary
חתימת זהות ואחסון
mcp_server/oauth_identity.py, mcp_server/oauth_store.py, tests/_fake_mongo.py, tests/test_mcp_oauth_identity.py, tests/test_mcp_oauth_store.py
נוספו חתימות HMAC, אחסון clients/transactions/codes/tokens, TTL, hashing ו-revocation, לצד בדיקות מחזור חיים ו-expiry.
ספק OAuth ו-consent
mcp_server/oauth_provider.py, mcp_server/oauth_routes.py, tests/test_mcp_oauth_provider.py, tests/test_mcp_oauth_routes.py
נוספו authorize, החלפת קודים וטוקנים, PAT, refresh rotation, PKCE, מסלולי consent ואימות fail-closed.
שילוב שרת וגשר זהות
mcp_server/app.py, mcp_server/server.py, mcp_server/auth.py, webapp/routes/auth_routes.py, tests/test_webapp_oauth_identify.py, tests/test_mcp_server_build.py
שרת MCP תומך במצב OAuth וב-fallback ל-PAT; נוספו גשר /oauth/identify, שמות כלים, annotations read-only ו-transport security לפי ENV.
תיעוד ו-E2E
mcp_server/README.md, docs/environment-variables.rst, FEATURE_SUGGESTIONS/FEATURE_MCP_CLAUDE_INTEGRATION.md, tests/test_mcp_oauth_e2e.py
התיעוד עודכן לחיבור Claude ולתצורת OAuth, ונוספו בדיקות זרימה מלאה לרישום, consent, PKCE והנפקת טוקנים.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Poem

ארנב קטן קפץ אל ה-flow,
עם code ו-token בוהק עכשיו.
Telegram לחש: “זהות חתומה!”
Claude התחבר בהסכמה.
ו-PAT נשאר — קפץ לאחור.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning תיאור ה-PR הוא כמעט רק תבנית ריקה ואינו כולל את ה-What, Why, Tests, סיכונים או Rollback. מלא את כל סעיפי התבנית: מה שיניתם ולמה, שינויים עיקריים, בדיקות שבוצעו, השפעה/סיכון, וקישורי Checks/Docs/rollback.
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive הכותרת מזכירה את רכיבי הפרויקט, אך היא לא ברורה, לא משפטית, וחלקה גיבוב לא תיאורי. נסח כותרת קצרה וברורה שמסכמת את השינוי המרכזי, למשל: "הוספת תמיכת OAuth 2.1 ו-PAT ל-MCP של Claude".
✅ Passed checks (2 passed)
Check name Status Explanation
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 claude/mcp-codekeeper-webapp-ldnzsg

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.

פתרון קונפליקטים:
- mcp_server/server.py: נשמרה גרסת הענף (superset מלא — host-fix + OAuth +
  prefix לכלים); גרסת main היא תת-קבוצה ישנה יותר.
- docs/environment-variables.rst: אוחדו התוספות; הוסרה שורת WEBAPP_URL כפולה
  (המשתנה כבר תועד) והשימוש ב-MCP נוסף לשורה הקיימת.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
@github-actions

Copy link
Copy Markdown

🧯 Dangerous deletes guard report

Policy: see .cursorrules — dangerous deletions are blocked unless wrapped safely.

Summary:

  • Flagged findings (blocking): 0
    0
  • Excluded matches (not blocking): 15
  • Total matches (all files): 129

Flagged findings (file:line:snippet):
(none)

Excluded matches (by path pattern)
./webapp/static/js/md_preview.bundle.js.map:4:  "sourcesContent": ["// Markdown-it plugin to render GitHub-style task lists; see\n//\n// https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments\n// https://github.com/blog/1825-t … [truncated]
./README.md:842:find . -name "__pycache__" -exec rm -rf {} +
./Dockerfile:42:    rm -rf /var/lib/apt/lists/*
./Dockerfile:121:    rm -rf /var/lib/apt/lists/*
./node_modules/mermaid/dist/mermaid.min.js:1524:`,"getStyles"),c1e=RQe});var h1e={};dr(h1e,{diagram:()=>NQe});var NQe,f1e=N(()=>{"use strict";$ge();a1e();l1e();u1e();NQe={parser:Fge,db:n1e,renderer:o1e,styles:c1e}});var m1e,g1e=N(()=>{"use  … [truncated]
./node_modules/mermaid/dist/mermaid.min.js.map:4:  "sourcesContent": ["/**\n* Default values for dimensions\n*/\nconst defaultIconDimensions = Object.freeze({\n\tleft: 0,\n\ttop: 0,\n\twidth: 16,\n\theight: 16\n});\n/**\n* Default values fo … [truncated]
./node_modules/mermaid/dist/chunks/mermaid.core/chunk-KS23V3DP.mjs.map:4:  "sourcesContent": ["{\n  \"name\": \"mermaid\",\n  \"version\": \"11.12.0\",\n  \"description\": \"Markdown-ish syntax for generating flowcharts, mindmaps, sequence  … [truncated]
./node_modules/mermaid/dist/chunks/mermaid.esm/chunk-2M32CCKP.mjs.map:4:  "sourcesContent": ["{\n  \"name\": \"mermaid\",\n  \"version\": \"11.12.0\",\n  \"description\": \"Markdown-ish syntax for generating flowcharts, mindmaps, sequence d … [truncated]
./node_modules/mermaid/dist/chunks/mermaid.esm.min/chunk-4HFYJGYH.mjs.map:4:  "sourcesContent": ["{\n  \"name\": \"mermaid\",\n  \"version\": \"11.12.0\",\n  \"description\": \"Markdown-ish syntax for generating flowcharts, mindmaps, sequen … [truncated]
./node_modules/mermaid/dist/chunks/mermaid.esm.min/chunk-4HFYJGYH.mjs:1:var r={name:"mermaid",version:"11.12.0",description:"Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graph … [truncated]
./node_modules/mermaid/dist/mermaid.js.map:4:  "sourcesContent": ["/**\n* Default values for dimensions\n*/\nconst defaultIconDimensions = Object.freeze({\n\tleft: 0,\n\ttop: 0,\n\twidth: 16,\n\theight: 16\n});\n/**\n* Default values for tr … [truncated]
./node_modules/katex/src/fonts/Makefile:139:	rm -rf pfa ff otf ttf woff woff2
./node_modules/katex/package.json:153:    "build": "rimraf dist/ && mkdirp dist && cp README.md dist && rollup -c --failAfterWarnings && webpack && node update-sri.js package dist/README.md",
./docs/Makefile:24:	rm -rf $(BUILDDIR)
./docs/DOCUMENTATION_GUIDE.md:453:rm -rf _build

Comment thread tests/test_mcp_oauth_provider.py Fixed
Comment thread webapp/routes/auth_routes.py Fixed
Comment thread webapp/routes/auth_routes.py Dismissed
@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown

⏱️ Performance report

(No performance test durations collected. Mark tests with @pytest.mark.performance.)

@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown

📖 Documentation Preview

The documentation has been built successfully!

To view locally:

  1. Download the artifacts
  2. Extract the zip file
  3. Open index.html in your browser

@codecov

codecov Bot commented Jul 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.97068% with 40 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
mcp_server/app.py 0.00% 22 Missing ⚠️
mcp_server/oauth_routes.py 88.67% 3 Missing and 3 partials ⚠️
mcp_server/auth.py 16.66% 5 Missing ⚠️
mcp_server/oauth_provider.py 93.67% 3 Missing and 2 partials ⚠️
mcp_server/oauth_store.py 97.91% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@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: 7

🧹 Nitpick comments (6)
mcp_server/oauth_store.py (1)

61-69: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

מומלץ להוסיף TTL index אוטומטי לניקוי רשומות שפג תוקפן.

כרגע נבדק תוקף רק ברמת האפליקציה (_expired), אבל אין TTL index ב-Mongo. כתוצאה מכך, txns/codes/tokens שפג תוקפם (ולא נמחקו במפורש) יישארו לנצח באוסף ויגדילו אותו ללא הגבלה עם הזמן.

♻️ הצעת שיפור
     def _ensure_indexes(self) -> None:
         try:
             self._clients.create_index("client_id", unique=True)
             self._txns.create_index("txn_id", unique=True)
+            self._txns.create_index("expires_at", expireAfterSeconds=0)
             self._codes.create_index("code_hash", unique=True)
+            self._codes.create_index("expires_at", expireAfterSeconds=0)
             self._tokens.create_index("token_hash", unique=True)
             self._tokens.create_index("subject")
+            self._tokens.create_index("expires_at", expireAfterSeconds=0)
         except Exception:
             pass
🤖 Prompt for 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.

In `@mcp_server/oauth_store.py` around lines 61 - 69, Update _ensure_indexes to
create MongoDB TTL indexes for the expiration field used by txn, code, and token
records, configured to remove documents when they expire. Keep the existing
uniqueness and subject indexes intact, and use the same expiry-field semantics
already consumed by _expired.
tests/test_mcp_oauth_routes.py (1)

18-64: 📐 Maintainability & Code Quality | 🔵 Trivial

כפילות קוד: פייק Mongo זהה חוזר גם כאן (פעם שלישית).

ראו הערה מאוחדת.

🤖 Prompt for 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.

In `@tests/test_mcp_oauth_routes.py` around lines 18 - 64, הוציאו את המימושים
הכפולים של _Res ו-_Coll מתיק בדיקה משותף או fixture קיים, ועדכנו את
tests/test_mcp_oauth_routes.py לייבא ולהשתמש בהם במקום להגדיר אותם מחדש. שמרו על
אותה התנהגות של insert_one, find_one, update_one ו-delete_one בכל הבדיקות.
tests/test_mcp_oauth_store.py (1)

9-72: 📐 Maintainability & Code Quality | 🔵 Trivial

כפילות קוד: אותן מחלקות פייק ל-Mongo (_Res/_Coll/_DB) חוזרות בכמה קבצי טסט.

ראו הערה מאוחדת.

🤖 Prompt for 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.

In `@tests/test_mcp_oauth_store.py` around lines 9 - 72, Remove the duplicated
Mongo fake classes _Res, _Coll, and _DB from this test and reuse the shared test
fixture or helper that defines them. Update references as needed so the tests
retain the same in-memory collection behavior without maintaining another copy.
tests/test_mcp_oauth_provider.py (1)

23-79: 📐 Maintainability & Code Quality | 🔵 Trivial

כפילות קוד: פייק Mongo זהה חוזר גם כאן.

ראו הערה מאוחדת.

🤖 Prompt for 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.

In `@tests/test_mcp_oauth_provider.py` around lines 23 - 79, Remove the duplicated
fake Mongo implementations _Res and _Coll from this test module and reuse the
shared fake Mongo fixture/helper referenced by the consolidated review comment.
Update any tests here to use that shared implementation while preserving the
current collection behavior.
mcp_server/oauth_provider.py (1)

151-162: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

חסרה בדיקה ש-scopes המבוקשים הם תת-קבוצה של ההרשאות שהוענקו במקור.

use_scopes = list(scopes or refresh_token.scopes) (שורה 159) מאמץ כל scopes שמתקבל מהלקוח ללא אימות שהוא תת-קבוצה של refresh_token.scopes שהונפקו במקור. לפי RFC 6749 §6, scope מבוקש ב-refresh לא צריך לחרוג מזה שהוענק. כרגע המערכת מגדירה scope יחיד ("read") כך שהחשיפה מוגבלת בפועל, אך זו נקודת הגנה קלה להוספה שתמנע הרחבת הרשאות אם ייווספו scopes בעתיד.

🔒 הצעת תיקון
     async def exchange_refresh_token(
         self,
         client: OAuthClientInformationFull,
         refresh_token: RefreshToken,
         scopes: list[str],
     ) -> OAuthToken:
         # Rotate: invalidate the presented refresh token, issue a fresh pair.
         await anyio.to_thread.run_sync(self._store.revoke_token, refresh_token.token)
-        use_scopes = list(scopes or refresh_token.scopes)
+        requested = list(scopes or refresh_token.scopes)
+        if not set(requested).issubset(set(refresh_token.scopes)):
+            raise ValueError("requested scope exceeds originally granted scope")
+        use_scopes = requested
         return await anyio.to_thread.run_sync(
             self._issue, client.client_id, refresh_token.subject, use_scopes
         )
🤖 Prompt for 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.

In `@mcp_server/oauth_provider.py` around lines 151 - 162, Update
exchange_refresh_token to validate that every requested scope in scopes is
contained in refresh_token.scopes before issuing a new token. Reject requests
that expand the originally granted permissions, while preserving the existing
fallback to refresh_token.scopes when no scopes are requested.
FEATURE_SUGGESTIONS/FEATURE_MCP_CLAUDE_INTEGRATION.md (1)

3-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

אזהרת markdownlint: שורה ריקה בתוך blockquote (MD028)

לפי כלי הסטטיק אנליזה (markdownlint-cli2), השורה הריקה בין שני פסקאות ה-> שוברת את רצף ה-blockquote.

✏️ תיקון מוצע
 > **מתי להשתמש:** לפני מימוש חיבור MCP; מסמך זה הוא מקור האמת לתכנון.
 > **ראו גם:** `mcp_server/README.md` (שימוש), [CodeBot – Project Docs](https://amirbiron.github.io/CodeBot/), `CLAUDE.md` (מדיניות מחייבת).
+>
 > **מצב מימוש (פאזות 0–1):** חבילת `mcp_server/` (שרת FastMCP קריאה‑בלבד, 7 כלים ל‑
🤖 Prompt for 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.

In `@FEATURE_SUGGESTIONS/FEATURE_MCP_CLAUDE_INTEGRATION.md` around lines 3 - 7,
Remove the blank line separating the consecutive blockquote paragraphs in
FEATURE_SUGGESTIONS/FEATURE_MCP_CLAUDE_INTEGRATION.md so the quote remains
continuous and satisfies markdownlint rule MD028.

Source: Linters/SAST tools

🤖 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 `@mcp_server/oauth_identity.py`:
- Around line 25-48: Update sign_identity and verify_identity to reject a
missing or empty secret before performing any HMAC operation; raise a clear
configuration error rather than substituting an empty key. Ensure both signing
and verification use only a valid configured secret and never fall back to a
known default.

In `@mcp_server/oauth_provider.py`:
- Around line 123-132: Update exchange_authorization_code to verify the result
of _store.delete_code before calling _issue; only issue tokens when the
authorization code was successfully consumed, and otherwise reject the exchange
using the store’s established failure behavior. Preserve the existing client,
subject, and scope arguments for successful exchanges.
- Around line 151-162: Update exchange_refresh_token to check the result of
_store.revoke_token before calling _issue; only issue a new token pair when
revocation succeeds, matching the atomic single-use behavior of
exchange_authorization_code, and otherwise reject the reused refresh token
through the existing failure path.

In `@mcp_server/oauth_routes.py`:
- Around line 96-123: Update consent_post so authorization codes are issued only
when form["action"] is explicitly the expected approval value; treat missing,
empty, malformed, or any other action as denial or an appropriate error
response. Preserve the existing denial cleanup and access_denied redirect
behavior for non-approval decisions.

In `@mcp_server/oauth_store.py`:
- Around line 111-124: Update OAuthStore.delete_code to return whether
delete_one actually removed a record, using the deletion result’s deleted count,
while preserving the existing exception handling. Update
exchange_authorization_code to require a successful deletion before issuing
tokens, rejecting already-consumed or missing authorization codes.
- Around line 144-148: Update OAuthStore.revoke_token to return whether a token
was actually revoked, using the update result rather than assuming success;
preserve the existing exception-safe behavior by returning False on failure.
Update callers such as oauth_provider.exchange_refresh_token to check this
result and handle failed or already-consumed revocations consistently with
delete_code.

In `@mcp_server/server.py`:
- Around line 43-60: Update _transport_security so
enable_dns_rebinding_protection and TransportSecuritySettings are enabled only
when MCP_ALLOWED_HOSTS produces a non-empty hosts list, not when only origins
are configured. Preserve parsing of MCP_ALLOWED_ORIGINS and pass origins
alongside hosts when host protection is enabled; otherwise return the disabled
configuration.

---

Nitpick comments:
In `@FEATURE_SUGGESTIONS/FEATURE_MCP_CLAUDE_INTEGRATION.md`:
- Around line 3-7: Remove the blank line separating the consecutive blockquote
paragraphs in FEATURE_SUGGESTIONS/FEATURE_MCP_CLAUDE_INTEGRATION.md so the quote
remains continuous and satisfies markdownlint rule MD028.

In `@mcp_server/oauth_provider.py`:
- Around line 151-162: Update exchange_refresh_token to validate that every
requested scope in scopes is contained in refresh_token.scopes before issuing a
new token. Reject requests that expand the originally granted permissions, while
preserving the existing fallback to refresh_token.scopes when no scopes are
requested.

In `@mcp_server/oauth_store.py`:
- Around line 61-69: Update _ensure_indexes to create MongoDB TTL indexes for
the expiration field used by txn, code, and token records, configured to remove
documents when they expire. Keep the existing uniqueness and subject indexes
intact, and use the same expiry-field semantics already consumed by _expired.

In `@tests/test_mcp_oauth_provider.py`:
- Around line 23-79: Remove the duplicated fake Mongo implementations _Res and
_Coll from this test module and reuse the shared fake Mongo fixture/helper
referenced by the consolidated review comment. Update any tests here to use that
shared implementation while preserving the current collection behavior.

In `@tests/test_mcp_oauth_routes.py`:
- Around line 18-64: הוציאו את המימושים הכפולים של _Res ו-_Coll מתיק בדיקה משותף
או fixture קיים, ועדכנו את tests/test_mcp_oauth_routes.py לייבא ולהשתמש בהם
במקום להגדיר אותם מחדש. שמרו על אותה התנהגות של insert_one, find_one, update_one
ו-delete_one בכל הבדיקות.

In `@tests/test_mcp_oauth_store.py`:
- Around line 9-72: Remove the duplicated Mongo fake classes _Res, _Coll, and
_DB from this test and reuse the shared test fixture or helper that defines
them. Update references as needed so the tests retain the same in-memory
collection behavior without maintaining another copy.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6ad14f09-14c7-4c8d-8d3c-bcba4d92a070

📥 Commits

Reviewing files that changed from the base of the PR and between 0d84a9b and baa143d.

📒 Files selected for processing (19)
  • FEATURE_SUGGESTIONS/FEATURE_MCP_CLAUDE_INTEGRATION.md
  • docs/environment-variables.rst
  • mcp_server/README.md
  • mcp_server/app.py
  • mcp_server/auth.py
  • mcp_server/oauth_identity.py
  • mcp_server/oauth_provider.py
  • mcp_server/oauth_routes.py
  • mcp_server/oauth_store.py
  • mcp_server/server.py
  • services/config_inspector_service.py
  • tests/test_mcp_oauth_e2e.py
  • tests/test_mcp_oauth_identity.py
  • tests/test_mcp_oauth_provider.py
  • tests/test_mcp_oauth_routes.py
  • tests/test_mcp_oauth_store.py
  • tests/test_mcp_server_build.py
  • tests/test_webapp_oauth_identify.py
  • webapp/routes/auth_routes.py

Comment thread mcp_server/oauth_identity.py
Comment thread mcp_server/oauth_provider.py
Comment thread mcp_server/oauth_provider.py
Comment thread mcp_server/oauth_routes.py
Comment thread mcp_server/oauth_store.py Outdated
Comment thread mcp_server/oauth_store.py Outdated
Comment thread mcp_server/server.py
חיזוקי אבטחה ותקינות בזרימת ה-OAuth (מ-code review + CodeQL), שינויים מינימליים:

- קודי הרשאה ו-refresh tokens חד-פעמיים באמת: delete_code/revoke_token
  מחזירים bool, וה-provider מנפיק טוקנים רק אם ההסרה/הביטול הצליחו (מונע
  replay/כפילות); אחרת TokenError("invalid_grant").
- refresh לא מרחיב הרשאות: בדיקת subset מול ה-scope של הטוקן (invalid_scope).
- מסך consent נכשל-סגור: רק action=approve מנפיק code; כל ערך אחר = דחייה.
- זהות חתומה: דחיית SECRET_KEY ריק (sign זורק, verify מחזיר False).
- הגנת open-redirect ב-/oauth/identify לפי scheme+host מנותחים (במקום startswith).
- מניעת XSS ב-widget של ההתחברות: html.escape על ערכים שמוטמעים ב-HTML.
- DNS-rebinding: מפעילים host-check רק כשמוגדר MCP_ALLOWED_HOSTS (מונע 421).
- TTL indexes לניקוי אוטומטי של codes/txns/tokens שפגו.
- טסטים: איחוד fake Mongo משותף (tests/_fake_mongo.py) + כיסוי לתרחישי replay/scope/fail-closed/secret ריק.

עיינתי בתיעוד: https://amirbiron.github.io/CodeBot/

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K

@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.

🧹 Nitpick comments (1)
tests/test_mcp_oauth_provider.py (1)

147-147: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

שימוש בקבוע במקום ערך קשיח (Hardcoded value) עבור קידומת הקוד

בשני הקבצים נעשה שימוש בערך הקשיח "ckoc_" במקום להשתמש בקבוע המערכת (כגון CODE_PREFIX). מומלץ לייבא ולהשתמש בקבוע כדי למנוע שבירה של הטסטים במידה והקידומת תשתנה בעתיד, בדומה לאופן שבו נעשה שימוש ב-ACCESS_PREFIX בקבצים אחרים במערכת.

  • tests/test_mcp_oauth_provider.py#L147-L147: להחליף את המחרוזת "ckoc_" בקבוע המתאים בקריאה ל-new_secret.
  • tests/test_mcp_oauth_routes.py#L109-L109: להשתמש בקבוע במקום לכתוב "code=ckoc_" בבדיקת אי-הימצאות המחרוזת.
🤖 Prompt for 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.

In `@tests/test_mcp_oauth_provider.py` at line 147, Replace the hardcoded "ckoc_"
prefix with the appropriate CODE_PREFIX constant in the new_secret call in
tests/test_mcp_oauth_provider.py:147-147, and use the same constant instead of
"code=ckoc_" in tests/test_mcp_oauth_routes.py:109-109; import the constant as
needed.
🤖 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.

Nitpick comments:
In `@tests/test_mcp_oauth_provider.py`:
- Line 147: Replace the hardcoded "ckoc_" prefix with the appropriate
CODE_PREFIX constant in the new_secret call in
tests/test_mcp_oauth_provider.py:147-147, and use the same constant instead of
"code=ckoc_" in tests/test_mcp_oauth_routes.py:109-109; import the constant as
needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b4b7b78a-a471-4e07-a0f1-9933a87f11a2

📥 Commits

Reviewing files that changed from the base of the PR and between baa143d and f0aaa55.

📒 Files selected for processing (15)
  • FEATURE_SUGGESTIONS/FEATURE_MCP_CLAUDE_INTEGRATION.md
  • docs/environment-variables.rst
  • mcp_server/oauth_identity.py
  • mcp_server/oauth_provider.py
  • mcp_server/oauth_routes.py
  • mcp_server/oauth_store.py
  • mcp_server/server.py
  • tests/_fake_mongo.py
  • tests/test_mcp_oauth_e2e.py
  • tests/test_mcp_oauth_identity.py
  • tests/test_mcp_oauth_provider.py
  • tests/test_mcp_oauth_routes.py
  • tests/test_mcp_oauth_store.py
  • tests/test_webapp_oauth_identify.py
  • webapp/routes/auth_routes.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • tests/test_mcp_oauth_identity.py
  • FEATURE_SUGGESTIONS/FEATURE_MCP_CLAUDE_INTEGRATION.md
  • mcp_server/oauth_identity.py
  • webapp/routes/auth_routes.py
  • mcp_server/oauth_routes.py
  • mcp_server/server.py
  • mcp_server/oauth_provider.py
  • mcp_server/oauth_store.py

claude added 2 commits July 19, 2026 18:23
תיקון שתי בעיות שעלו ב-CI על ה-PR:

1) שגיאות איסוף טסטים (4 ERRORS):
   הייבוא `from tests._fake_mongo import FakeDB` נכשל ב-CI כי חבילת `tests`
   המקומית מוצללת ע"י חבילת `tests` אחרת ב-sys.path (בעיה מתועדת ב-tests/conftest.py).
   הפתרון: ייבוא הגנתי עם נפילה חזרה למודול-האח (`from _fake_mongo import FakeDB`),
   שעובד תמיד תחת מצב prepend של pytest. אומת מול סימולציית חבילה מצללת.

2) חיזוק SECRET_KEY (אבטחה): מצב OAuth השתמש בברירת מחדל ציבורית וידועה
   לחתימת זהות — מה שמאפשר זיוף user_id. נוסף `assert_strong_secret` שמסרב
   לעלות/לחתום עם מפתח ריק או ברירת המחדל — גם בשירות ה-MCP (app.py) וגם בוובאפ
   (`/oauth/identify` מחזיר 500 נקי במקום לחתום במפתח נחש).

עדכוני תיעוד/קונפיג (לפי תבנית ה-PR): docs/environment-variables.rst ו-
services/config_inspector_service.py — הובהר ש-SECRET_KEY חייב ערך אקראי חזק
וזהה בין הוובאפ לשירות ה-MCP במצב OAuth.

טסטים: הוספת assert_strong_secret + מסלול 500 למפתח שגוי + ייבוא הגנתי. 68 עוברים.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
…alls

הטסט `test_request_uses_merged_headers_and_respects_slow_logging` היה שביר:
הוא מדליף (patch) את `time.perf_counter` הגלובלי עם רשימה בת 2 ערכים ו-`pop(0)`,
ולכן כל קריאה שלישית ל-`perf_counter` (נתיב שגיאה, מטריקות או לוגים) מרוקנת את
הרשימה וזורקת `IndexError: pop from empty list`. הכשל תלוי-סדר: שינוי בסדר איסוף
הטסטים (למשל הוספת קבצי טסט אחרים) חשף אותו.

התיקון: שעון דמה שלא מתרוקן — קריאה ראשונה = t0, וכל קריאה נוספת מחזירה t0+200ms
(itertools.chain([...], repeat(...))). דטרמיניסטי, ולא קשור לפיצ'ר ה-OAuth —
פשוט נחשף על ידי שינוי סדר הריצה. אומת: עובר 5/5 עם/בלי HTTP_SLOW_MS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WNFuSyshwpRcxozVZEui5K
@amirbiron
amirbiron merged commit 42a5696 into main Jul 19, 2026
26 checks passed
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.

3 participants