Skip to content

Conversation

@Codi33
Copy link

@Codi33 Codi33 commented Jan 13, 2026

Issue

On API key deletion, established websocket connections continue to have access

Steps to reproduce

  1. Create api key in websocket tab
  2. Connect using documentation
  3. Remove key

Changes

  • Terminate active websocket connections associated with the deleted API key

Summary by Sourcery

Исправления ошибок:

  • Закрывать активные WebSocket‑подключения Bot API, которые продолжают использовать ключ API после его удаления, связывая сокеты с этим ключом и принудительно разрывая такие соединения.
Original summary in English

Summary by Sourcery

Bug Fixes:

  • Close active bot API websocket connections that are still using an API key after it has been deleted by associating sockets with the key and force-disconnecting them.

Summary by CodeRabbit

Примечания к выпуску

  • Исправления ошибок
    • Улучшена очистка соединений при удалении API-ключей. Система теперь корректно разрывает активные соединения, связанные с удаляемым ключом, обеспечивая более надежное управление состоянием в реальном времени.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 13, 2026

📝 Walkthrough

Обзор

Изменения реализуют управление Socket.IO комнатами для операций с API ключами: сокеты теперь присоединяются к каналам, привязанным к идентификаторам ключей, а при удалении ключа все сокеты в этом канале отключаются перед удалением.

Изменения

Когорта / Файл(ы) Краткое описание
Управление сокетами при удалении API ключей
backend/src/api/routes/apiKeys.js
Импортирует socketHandler и IO экземпляр, отключает все сокеты в namespace "/bot-api" для комнаты key_ перед удалением ключа (+8/-0)
Присоединение сокетов к комнатам по ключам
backend/src/real-time/botApi/index.js
Каждое соединение теперь присоединяется как к комнате bot_, так и к комнате key_ (+1/-1)

Оценка трудозатрат на код-ревью

🎯 3 (Умеренная) | ⏱️ ~20 минут

Стихотворение

🐰 Когда ключик удаляют с утра,
Сокеты по комнатам разбежались, вот это да!
Теперь каждый ключик свою комнату охраняет,
И в тот час, когда его удаляют,
Все гости спешат на выход скорей —
Система танцует в ритме камней! 🎭✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: closing active connections when an API key is deleted, which aligns with the primary objective of the PR to fix a WebSocket security bug.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jan 13, 2026

Руководство для ревьюера (свернуто для небольших PR)

Руководство для ревьюера

Реализует отзыв активного доступа по WebSocket при удалении API-ключа за счёт привязки соединений к комнате, основанной на ключе, и принудительного отключения всех сокетов в этой комнате при удалении ключа.

Диаграмма последовательности для отзыва WebSocket при удалении API-ключа

sequenceDiagram
    actor Admin
    participant ApiKeysRoute
    participant Prisma
    participant SocketServer
    participant BotApiClient

    Admin->>ApiKeysRoute: DELETE /bots/:botId/api-keys/:keyId
    ApiKeysRoute->>ApiKeysRoute: parse botId and keyId
    ApiKeysRoute->>SocketServer: getIO()
    ApiKeysRoute->>SocketServer: namespace /bot-api
    ApiKeysRoute->>SocketServer: room key_keyId disconnectSockets(force=true)
    SocketServer-->>BotApiClient: disconnect WebSocket
    ApiKeysRoute->>Prisma: botApiKey.deleteMany(botId, keyId)
    Prisma-->>ApiKeysRoute: deletion result
    ApiKeysRoute-->>Admin: 200 OK (deletion result)
Loading

Изменения на уровне файлов

Изменение Подробности Файлы
Связать каждое WebSocket-соединение Bot API с комнатой, ключ которой основан на ID API-ключа, чтобы обеспечить выборочное отключение.
  • При подключении клиента добавить сокет в комнату key_<keyId> в дополнение к существующей комнате bot_<botId>.
  • Переиспользовать существующее поле socket.keyId для построения имени комнаты без изменения остальных метаданных соединения или его поведения.
backend/src/real-time/botApi/index.js
Принудительно отключать все WebSocket-соединения, связанные с удалённым API-ключом, при удалении ключа.
  • Импортировать аксессор socket.io (getIO) в маршрут удаления API-ключа для доступа к экземпляру сервера.
  • При удалении API-ключа выбрать пространство имён /bot-api и комнату key_<keyId> и вызвать disconnectSockets(true), чтобы принудительно закрыть все связанные сокеты.
  • Сохранить существующий вызов Prisma botApiKey.deleteMany без изменений, чтобы семантика удаления в базе данных осталась прежней.
backend/src/api/routes/apiKeys.js

Подсказки и команды

Взаимодействие с Sourcery

  • Запустить новое ревью: Оставьте комментарий @sourcery-ai review в pull request.
  • Продолжить обсуждение: Отвечайте напрямую на комментарии ревью от Sourcery.
  • Создать задачу GitHub из комментария ревью: Попросите Sourcery создать
    issue из комментария ревью, ответив на него. Также можно ответить на
    комментарий ревью командой @sourcery-ai issue, чтобы создать issue.
  • Сгенерировать заголовок pull request: Напишите @sourcery-ai где угодно
    в заголовке pull request, чтобы сгенерировать заголовок в любой момент. Также можно оставить комментарий
    @sourcery-ai title в pull request, чтобы (пере)сгенерировать заголовок в любое время.
  • Сгенерировать краткое описание pull request: Напишите @sourcery-ai summary где угодно
    в теле pull request, чтобы сгенерировать краткое описание PR в нужном месте. Также можно оставить комментарий
    @sourcery-ai summary в pull request, чтобы (пере)сгенерировать краткое описание в любое время.
  • Сгенерировать руководство для ревьюера: Оставьте комментарий @sourcery-ai guide в pull request,
    чтобы (пере)сгенерировать руководство для ревьюера в любое время.
  • Разрешить все комментарии Sourcery: Оставьте комментарий @sourcery-ai resolve в pull request,
    чтобы пометить все комментарии Sourcery как разрешённые. Полезно, если вы уже
    учли все комментарии и больше не хотите их видеть.
  • Скрыть все обзоры Sourcery: Оставьте комментарий @sourcery-ai dismiss в pull request,
    чтобы скрыть все существующие обзоры Sourcery. Особенно полезно, если вы
    хотите начать заново с новым ревью — не забудьте оставить комментарий
    @sourcery-ai review, чтобы запустить новое ревью!

Настройка работы

Перейдите в свою панель управления, чтобы:

  • Включать или отключать функции ревью, такие как сгенерированное Sourcery
    краткое описание pull request, руководство для ревьюера и другие.
  • Изменить язык ревью.
  • Добавлять, удалять или изменять пользовательские инструкции для ревью.
  • Настроить другие параметры ревью.

Получение помощи

Original review guide in English
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Implements revocation of active WebSocket access when an API key is deleted by tagging connections with a key-based room and force-disconnecting all sockets in that room on key deletion.

Sequence diagram for WebSocket revocation on API key deletion

sequenceDiagram
    actor Admin
    participant ApiKeysRoute
    participant Prisma
    participant SocketServer
    participant BotApiClient

    Admin->>ApiKeysRoute: DELETE /bots/:botId/api-keys/:keyId
    ApiKeysRoute->>ApiKeysRoute: parse botId and keyId
    ApiKeysRoute->>SocketServer: getIO()
    ApiKeysRoute->>SocketServer: namespace /bot-api
    ApiKeysRoute->>SocketServer: room key_keyId disconnectSockets(force=true)
    SocketServer-->>BotApiClient: disconnect WebSocket
    ApiKeysRoute->>Prisma: botApiKey.deleteMany(botId, keyId)
    Prisma-->>ApiKeysRoute: deletion result
    ApiKeysRoute-->>Admin: 200 OK (deletion result)
Loading

File-Level Changes

Change Details Files
Associate each Bot API WebSocket connection with a room keyed by the API key ID to enable targeted disconnects.
  • On client connection, add the socket to a key_<keyId> room in addition to the existing bot_<botId> room.
  • Reuse the existing socket.keyId field to build the room name without altering other connection metadata or behavior.
backend/src/real-time/botApi/index.js
Force-disconnect all WebSocket connections associated with a deleted API key when the key is removed.
  • Import the socket.io accessor (getIO) in the API key deletion route to access the server instance.
  • On API key deletion, select the /bot-api namespace and the key_<keyId> room and call disconnectSockets(true) to forcibly close all associated sockets.
  • Keep the existing Prisma botApiKey.deleteMany call intact so database deletion semantics remain unchanged.
backend/src/api/routes/apiKeys.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Привет — я оставил несколько комментариев на более высоком уровне:

  • Подумайте о том, чтобы перенести вызов require('../../real-time/socketHandler') на верхний уровень модуля вместо размещения внутри обработчика маршрута, чтобы избежать повторного разрешения модуля при каждом запросе и сохранить единообразный стиль файла.
  • Возможно, стоит обработать случай, когда getIO() ещё не инициализирован (или возвращает ложное значение), перед вызовом .of('/bot-api') и .disconnectSockets(true), чтобы избежать возможных ошибок времени выполнения при запуске или в тестовой среде.
Подсказка для AI-агентов
Пожалуйста, исправьте код с учётом комментариев из этого code review:

## Общие комментарии
- Подумайте о том, чтобы перенести вызов `require('../../real-time/socketHandler')` на верхний уровень модуля вместо размещения внутри обработчика маршрута, чтобы избежать повторного разрешения модуля при каждом запросе и сохранить единообразный стиль файла.
- Возможно, стоит обработать случай, когда `getIO()` ещё не инициализирован (или возвращает ложное значение), перед вызовом `.of('/bot-api')` и `.disconnectSockets(true)`, чтобы избежать возможных ошибок времени выполнения при запуске или в тестовой среде.

Sourcery бесплатен для open source — если вам нравятся наши обзоры, пожалуйста, расскажите о нас ✨
Помогите мне стать полезнее! Пожалуйста, нажмите 👍 или 👎 на каждом комментарии, и я использую этот фидбек, чтобы улучшить обзоры.
Original comment in English

Hey - I've left some high level feedback:

  • Consider moving the require('../../real-time/socketHandler') call to the module top-level instead of inside the route handler to avoid re-resolving the module on every request and to keep the file style consistent.
  • It may be worth handling the case where getIO() is not yet initialized (or returns a falsy value) before calling .of('/bot-api') and .disconnectSockets(true) to avoid potential runtime errors during startup or in test environments.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider moving the `require('../../real-time/socketHandler')` call to the module top-level instead of inside the route handler to avoid re-resolving the module on every request and to keep the file style consistent.
- It may be worth handling the case where `getIO()` is not yet initialized (or returns a falsy value) before calling `.of('/bot-api')` and `.disconnectSockets(true)` to avoid potential runtime errors during startup or in test environments.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @backend/src/api/routes/apiKeys.js:
- Around line 170-172: В блоке с вызовом
io.of("/bot-api").in(`key_${keyId}`).disconnectSockets(true) отсутствует
завершающая точка с запятой; добавьте точку с запятой после вызова
disconnectSockets(true) чтобы привести стиль к остальной части файла и избежать
несоответствий с конвенцией кода.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4baeb5 and 2f7db12.

📒 Files selected for processing (2)
  • backend/src/api/routes/apiKeys.js
  • backend/src/real-time/botApi/index.js
🧰 Additional context used
🧬 Code graph analysis (1)
backend/src/api/routes/apiKeys.js (1)
backend/src/real-time/socketHandler.js (1)
  • io (13-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (3)
backend/src/real-time/botApi/index.js (2)

15-31: Логика исправления выглядит корректно.

Добавление сокета в комнату key_${socket.keyId} — правильный подход для группировки соединений по API-ключу. Это позволяет эффективно отключать все соединения при удалении ключа через io.of("/bot-api").in(key_${keyId}).disconnectSockets(true).


18-19: Замечание отклонено: socket.keyId корректно устанавливается middleware.

Middleware authenticateApiClient проверяет подлинность ключа (линии 35-38) и только после успешной валидации устанавливает socket.keyId = matchedKey.id (линия 41). Вызов next() происходит только после установки всех свойств сокета, поэтому socket.keyId гарантированно содержит числовой идентификатор из базы данных и никогда не будет undefined. Код работает корректно.

backend/src/api/routes/apiKeys.js (1)

166-172: Логика отключения сокетов правильно использует комнату key_<keyId>.

В middleware authenticateApiClient на строке 41 файла backend/src/real-time/botApi/middleware.js установлено socket.keyId = matchedKey.id (идентификатор ключа из базы данных). В файле backend/src/real-time/botApi/index.js на строке 19 сокет присоединяется к комнате key_${socket.keyId} сразу после успешной аутентификации. Это обеспечивает корректное отключение всех сокетов, связанных с конкретным API ключом, при выполнении io.of("/bot-api").in(``key_${keyId}``).disconnectSockets(true).

Comment on lines +170 to +172
io.of("/bot-api")
.in(`key_${keyId}`)
.disconnectSockets(true)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Отсутствует точка с запятой.

В строке 172 отсутствует точка с запятой после .disconnectSockets(true). Хотя ASI (Automatic Semicolon Insertion) справится с этим, это несовместимо со стилем остального файла.

🔧 Предлагаемое исправление
         io.of("/bot-api")
             .in(`key_${keyId}`)
-            .disconnectSockets(true)
+            .disconnectSockets(true);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
io.of("/bot-api")
.in(`key_${keyId}`)
.disconnectSockets(true)
io.of("/bot-api")
.in(`key_${keyId}`)
.disconnectSockets(true);
🤖 Prompt for AI Agents
In @backend/src/api/routes/apiKeys.js around lines 170 - 172, В блоке с вызовом
io.of("/bot-api").in(`key_${keyId}`).disconnectSockets(true) отсутствует
завершающая точка с запятой; добавьте точку с запятой после вызова
disconnectSockets(true) чтобы привести стиль к остальной части файла и избежать
несоответствий с конвенцией кода.

@mmeerrkkaa mmeerrkkaa self-assigned this Jan 13, 2026
@mmeerrkkaa mmeerrkkaa added area: backend Бэкенд (Node.js/Express) area: api REST/WebSocket API labels Jan 13, 2026
@codecov
Copy link

codecov bot commented Jan 13, 2026

Codecov Report

❌ Patch coverage is 0% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
backend/src/api/routes/apiKeys.js 0.00% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@mmeerrkkaa mmeerrkkaa merged commit e58bd65 into blockmineJS:master Jan 13, 2026
3 of 4 checks passed
@mmeerrkkaa
Copy link
Member

thx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: api REST/WebSocket API area: backend Бэкенд (Node.js/Express)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants