Skip to content

Аудит и исправление логики плагина composio-direct (#184)#185

Merged
xlabtg merged 5 commits into
xlabtg:mainfrom
konard:issue-184-82f7975184b4
Jun 14, 2026
Merged

Аудит и исправление логики плагина composio-direct (#184)#185
xlabtg merged 5 commits into
xlabtg:mainfrom
konard:issue-184-82f7975184b4

Conversation

@konard

@konard konard commented Jun 14, 2026

Copy link
Copy Markdown

Аудит и исправление логики плагина composio-direct

Closes #184

Плагин composio-direct перестал работать с агентом. Я разобрал всю логику плагина, нашёл корневые причины и привёл выполнение инструментов в полное соответствие с Composio v3 API (сверено с официальной OpenAPI-спецификацией backend.composio.dev).

Корневые причины

A. Мёртвый код @composio/core SDK

В index.js оставались ветки, пытавшиеся динамически подгрузить npm-пакет @composio/core (loadComposioSdk / getComposioSdk) и выполнять через него search_tools, execute_tool и multi_execute. В рантайме агента пакет недоступен, поэтому код всегда молча уходил в HTTP-fallback — это балласт без эффекта.

Именно этот SDK-путь породил историю с package-lock.json: чтобы «установить» SDK, в плагин добавили lock-файл, а вместе с ним загрузчик плагинов начал звать npm ci, который падал с spawn npm ENOENT (в рантайме нет npm в PATH). Lock-файл затем убрали (#173), но мёртвый SDK-код, который к нему привёл, остался.

B. connected_account_id попадал внутрь arguments

В execute_tool и multi_execute идентификатор подключения подмешивался прямо в объект аргументов инструмента:

const toolArguments = params.connected_account_id
  ? { ...params.parameters, connected_account_id: params.connected_account_id }
  : params.parameters;

По Composio v3 API connected_account_id — это поле верхнего уровня тела запроса execute, а не аргумент инструмента. У инструментов со строгой схемой (additionalProperties: false) лишнее поле в arguments приводит к отклонению вызова. Поэтому любое выполнение, где агент переиспользует подключение (передаёт connected_account_id), ломалось — это и есть «плагин перестал работать с агентом».

Что исправлено

  • Удалён весь код @composio/core SDK (ComposioClass, loadComposioSdk, getComposioSdk, composioSdkCache и SDK-ветки в трёх инструментах). Плагин теперь самодостаточен и общается с Composio v3 строго напрямую по HTTPS — без шага установки зависимостей, который мог упасть.

  • connected_account_id передаётся строго на верхнем уровне тела запроса, а arguments содержит только параметры инструмента. Тело execute приведено к виду из спецификации:

    const body = {
      user_id: userId,
      arguments: params.parameters,
      version: params.version ?? toolVersion,
    };
    if (params.connected_account_id) {
      body.connected_account_id = params.connected_account_id;
    }
  • Версия плагина поднята 1.8.0 → 1.9.0 (manifest.json, package.json, inline-manifest в index.js).

Остальные 25 инструментов (toolkits, files, triggers, webhooks, connections, auth, meta-tools) проверены на соответствие — менять ничего не потребовалось.

Как воспроизвести баг (до фикса)

  1. Через агента вызвать composio_execute_tool для инструмента со строгой схемой (additionalProperties: false), передав connected_account_id (агент так делает при переиспользовании подключения), например:
    { "tool_slug": "COINMARKETCAP_CRYPTOCURRENCY_LISTINGS_LATEST",
      "parameters": { "symbol": "BTC" },
      "connected_account_id": "ca_..." }
  2. До фикса тело уходило как arguments: { symbol: "BTC", connected_account_id: "ca_..." } → Composio отклонял вызов из-за неизвестного поля в аргументах.
  3. После фикса connected_account_id уходит отдельным полем тела, arguments остаётся { symbol: "BTC" }.

Тесты, подтверждающие фикс

Два регрессионных теста, которые раньше закрепляли неверное поведение (connected_account_id внутри arguments), переписаны под корректный контракт. Теперь они проверяют, что идентификатор лежит на верхнем уровне тела и что в arguments его нет:

assert.deepEqual(calls[0].body.arguments, { symbol: "BTC" });
assert.equal(Object.hasOwn(calls[0].body.arguments, "connected_account_id"), false);
assert.equal(calls[0].body.connected_account_id, "ca_lc9TestLuaI");

Аналогичная проверка добавлена для composio_multi_execute.

Проверка соответствия Composio v3 API

Сверено с официальной OpenAPI-спецификацией (/api/v3/tools/execute/{tool_slug}):

  • connected_account_id (string) и arguments (object) — соседние поля верхнего уровня тела запроса;
  • внутри схемы arguments поля connected_account_id нет;
  • проведён сплошной аудит всех 27 инструментов: каждая пара «HTTP-метод + путь», которую формирует плагин, сверена со спецификацией — 25/25 совпадают, 0 расхождений (GET/POST /auth_configs, POST /connected_accounts/link, GET /tools, GET /tools/{slug}, POST /tools/execute/{slug}, GET /connected_accounts[/{id}], GET /toolkits[/{slug}], GET /files/list, POST /files/upload/request, GET /triggers_types[/{slug}], GET /trigger_instances/active, POST /trigger_instances/{slug}/upsert, PATCH|DELETE /trigger_instances/manage/{id}, GET /webhook_subscriptions/event_types, GET|POST /webhook_subscriptions, GET|PATCH|DELETE /webhook_subscriptions/{id}, POST /webhook_subscriptions/{id}/rotate_secret). Легаси-путей v1/v2 в плагине нет.

Результаты прогонов

  • node --test по всем файлам плагина: 57/57 тестов проходят.
  • npm run validate: composio-direct: 27 tool(s) validated.
  • npm run lint (eslint): без ошибок в composio-direct.
  • npm run typecheck (tsc): без ошибок.

CI-проверка validate (workflow «Plugin Dependencies») — исправлена

Workflow «Plugin Dependencies» запускается на любое изменение plugins/*/package.json и прогоняет npm audit --audit-level=high по всем плагинам с lock-файлом, а не только по изменённым (gate добавлен намеренно в #128, чтобы блокировать merge при high/critical уязвимостях). Штатный бамп версии composio-direct/package.json (1.8.0 → 1.9.0) триггернул workflow — и аудит подсветил уязвимости, опубликованные с апреля (последний зелёный прогон) на давно зафиксированные транзитивные зависимости других плагинов. Сам composio-direct npm-зависимостей и lock-файла не имеет, поэтому в шагах npm ci/npm audit пропускается (continue) — корень был не в нём, но gate всё равно нужно починить, иначе CI красный.

Главный нарушитель — axios в dedust/evaa/stonfi: на версии 1.13.5 накопились high-severity advisory (SSRF через обход NO_PROXY, prototype-pollution с обходом аутентификации и подменой ответа — GHSA-3p68-rc4w-qgx5, GHSA-w9j2-pvgh-6h63 и др.). В finam-trade high-severity была в дереве protobufjs/@grpc/grpc-js.

Уязвимости устранены semver-безопасным npm audit fix (без --force): менялись только lock-файлы, package.json не тронут, lockfileVersion остался 3, поведение плагинов в пределах объявленных ими semver-диапазонов не меняется.

Плагин Ключевые обновления (+ согласованные транзитивные зависимости)
dedust axios 1.13.5 → 1.17.0, follow-redirects 1.15.11 → 1.16.0
evaa axios 1.13.5 → 1.17.0, follow-redirects 1.15.11 → 1.16.0
stonfi axios 1.13.5 → 1.17.0, follow-redirects 1.15.11 → 1.16.0
finam-trade @grpc/grpc-js 1.14.3 → 1.14.4, protobufjs 7.5.5 → 7.6.4, @protobufjs/utf8 1.1.0 → 1.1.1

После фикса локальная репликация шага «Install and audit deps» из plugin-deps.yml даёт 0 high/critical по всем 10 плагинам с lock-файлом (audit-цикл завершается с exit code 0).

Примечание про локальные прогоны npm test. При локальном npm test/npm run validate плагины с реальными npm-зависимостями (evaa, multisend, stonfi, vk-full-admin) падают с Cannot find module ..., если в них не установлены node_modules. Это воспроизводится и без изменений этого PR; в CI зависимости ставятся через npm ci --prefix, поэтому там они зелёные. К composio-direct отношения не имеют.

konard added 2 commits June 14, 2026 10:40
Adding .gitkeep for PR creation (default mode).
This file will be removed when the task is complete.

Issue: xlabtg#184
Adding .gitkeep for PR creation (default mode).
This file will be removed when the task is complete.

Issue: xlabtg#184
@konard

konard commented Jun 14, 2026

Copy link
Copy Markdown
Author

🤖 AI Work Session Started

Starting automated work session at 2026-06-14T10:41:44.669Z

The PR has been converted to draft mode while work is in progress.

This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback.

… с Composio v3 API

Плагин перестал работать с агентом по двум связанным причинам, обе устранены.

Причина A — мёртвый код @composio/core SDK.
В index.js оставались ветки, которые пытались загрузить npm-пакет
@composio/core (loadComposioSdk/getComposioSdk) и выполнять через него
search_tools, execute_tool и multi_execute. Пакет в рантайме недоступен,
поэтому код всегда молча уходил в HTTP-fallback — это балласт. Именно из-за
него ранее появлялся package-lock.json, а с ним и падение «spawn npm ENOENT»
при npm ci (npm нет в PATH рантайма). Весь SDK-путь удалён; плагин теперь
самодостаточен и ходит в Composio v3 только напрямую по HTTPS, без шага
установки зависимостей, который может упасть.

Причина B — connected_account_id попадал в arguments.
В execute_tool и multi_execute идентификатор подключения подмешивался внутрь
объекта arguments ({ ...parameters, connected_account_id }). По Composio v3 API
connected_account_id — это поле верхнего уровня тела запроса execute, а не
аргумент инструмента. У инструментов со строгой схемой (additionalProperties:
false) лишнее поле в arguments приводит к отклонению вызова. Поэтому любое
выполнение, где агент переиспользует подключение (передаёт connected_account_id),
ломалось. Теперь connected_account_id передаётся строго на верхнем уровне тела,
а arguments содержит только параметры инструмента.

Тело запроса execute приведено к виду из документации Composio v3:
{ user_id, arguments, version, connected_account_id? }.

Тесты: два регрессионных теста, ранее закреплявшие неверное поведение
(connected_account_id внутри arguments), переписаны под корректный контракт —
проверяют, что connected_account_id лежит на верхнем уровне тела и что в
arguments его нет. Прогон: 56/56 тестов плагина проходят, npm run validate
показывает «composio-direct: 27 tool(s) validated», eslint и tsc — без ошибок.

Версия плагина поднята 1.8.0 -> 1.9.0 (manifest.json, package.json, inline
manifest в index.js) для следующего релиза.
@konard konard changed the title [WIP] Check all the logic of the composio-direct plugin Аудит и исправление логики плагина composio-direct (#184) Jun 14, 2026
@konard konard marked this pull request as ready for review June 14, 2026 11:09
@konard

konard commented Jun 14, 2026

Copy link
Copy Markdown
Author

Working session summary

Готово. Задача #184 полностью решена; PR #185 обновлён и помечен ready.

Итог

Корневые причины «плагин перестал работать с агентом» (обе устранены):

  1. Мёртвый код @composio/core SDK — ветки loadComposioSdk/getComposioSdk в execute_tool/multi_execute/search_tools пытались подгрузить npm-пакет, недоступный в рантайме, и всегда молча падали в HTTP-fallback. Именно этот путь породил историю с package-lock.jsonspawn npm ENOENT. Весь SDK-код удалён, плагин ходит в Composio v3 строго напрямую по HTTPS.

  2. connected_account_id подмешивался внутрь arguments — для инструментов со строгой схемой (additionalProperties: false) лишнее поле в аргументах отклоняет вызов. По v3 API это поле верхнего уровня тела execute. Теперь тело строится как { user_id, arguments, version, connected_account_id? }.

Проверка соответствия Composio v3 API: сверено с официальной OpenAPI-спецификацией backend.composio.dev — все 25 пар «метод + путь» по 27 инструментам совпадают, 25/25, 0 расхождений, легаси-путей v1/v2 нет. Fallback v3.1→v3 при unknown tool сохранён.

Тесты: два регрессионных теста, ранее закреплявшие неверное поведение, переписаны под корректный контракт. Прогон: 56/56 тестов плагина, validate27 tool(s) validated, eslint и tsc — без ошибок.

Версия: 1.8.0 → 1.9.0 (manifest.json, package.json, inline-manifest в index.js).

CI: все проверки, касающиеся composio-direct, зелёные (Test, Lint, TypeScript, Build, CodeQL, deploy). Единственная красная — job validate workflow'а «Plugin Dependencies»: это npm audit --audit-level=high на других плагинах (dedust/evaa/finam-trade/stonfi), у которых с апреля вышли новые advisory. composio-direct зависимостей и lock-файла не имеет, поэтому из аудита исключён; merge не блокируется (mergeStateStatus=UNSTABLE, не BLOCKED). Это вне рамок #184 и задокументировано в описании PR как тема для отдельного PR.

PR: #185


This summary was automatically extracted from the AI working session output.

@konard

konard commented Jun 14, 2026

Copy link
Copy Markdown
Author

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost estimation:

  • Public pricing estimate: $12.226680
  • Calculated by Anthropic: $14.084925
  • Difference: $1.858245 (+15.20%)

📊 Context and tokens usage:

Claude Opus 4.8: (5 sub-sessions)

  1. 114.9K / 1M (11%) input tokens, 28.1K / 128K (22%) output tokens
  2. 108.7K / 1M (11%) input tokens, 13.1K / 128K (10%) output tokens
  3. 115.8K / 1M (12%) input tokens, 21.8K / 128K (17%) output tokens
  4. 116.5K / 1M (12%) input tokens, 49.9K / 128K (39%) output tokens
  5. 43.8K / 1M (4%) input tokens, 7.3K / 128K (6%) output tokens

Total: (49.0K new + 507.3K cache writes + 9.8M cache reads) input tokens, 153.1K output tokens, $12.148922 cost

Claude Haiku 4.5:

  • 50.5K / 200K (25%) input tokens, 3.5K / 64K (5%) output tokens

Total: 50.5K input tokens, 3.5K output tokens, $0.077758 cost

🤖 Models used:

  • Tool: Anthropic Claude Code
  • Requested: opus
  • Main model: Claude Opus 4.8 (claude-opus-4-8)
  • Additional models:
    • Claude Haiku 4.5 (claude-haiku-4-5-20251001)

📎 Log file uploaded as Gist (5923KB)


Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard

konard commented Jun 14, 2026

Copy link
Copy Markdown
Author

🔄 Auto-restart triggered (iteration 1)

Reason: CI failures detected

Starting new session to address the issues.


Auto-restart-until-mergeable mode is active. This run will stop after 5 restart iterations.

konard added 2 commits June 14, 2026 11:24
Бамп версии composio-direct/package.json триггерит workflow «Plugin
Dependencies», который прогоняет npm audit --audit-level=high по всем
плагинам с lock-файлом. С момента последнего пиннинга (Initial commit)
опубликованы новые advisory, и job validate падал на 4 плагинах:

- dedust, evaa, stonfi: axios 1.13.5 -> 1.17.0, follow-redirects -> 1.16.0
- finam-trade: @grpc/grpc-js 1.14.3 -> 1.14.4, protobufjs 7.5.5 -> 7.6.4

Все обновления semver-совместимы (npm audit fix без --force), изменены
только package-lock.json (package.json не тронуты), lockfileVersion
сохранён (3). npm audit --audit-level=high: 0 high/critical по всем
плагинам. Тесты finam-trade (grpc/protobuf): 16/16. Полный прогон:
440/440. validate-plugins.mjs: 34 плагина, 0 ошибок.
@xlabtg xlabtg merged commit fdc4471 into xlabtg:main Jun 14, 2026
9 checks passed
@konard

konard commented Jun 14, 2026

Copy link
Copy Markdown
Author

Working session summary

Всё завершено и подтверждено: рабочее дерево чистое, ветка синхронизирована с remote, фикс присутствует в upstream/main (комментарий про top-level встречается дважды — в execute_tool и multi_execute).

Итог

Падавшая CI-проверка validate исправлена, PR #185 смержен мейнтейнером (xlabtg, merge-commit fdc4471), issue #184 закрыта.

Что было сделано

1. Диагностика падения validate (workflow «Plugin Dependencies»)
Корень — не в composio-direct. Штатный бамп версии composio-direct/package.json (1.8.0 → 1.9.0) триггернул workflow, который прогоняет npm audit --audit-level=high по всем плагинам с lock-файлом. Аудит нашёл high-severity advisory, опубликованные с апреля на давно зафиксированные зависимости других плагинов — прежде всего axios 1.13.5 в dedust/evaa/stonfi (SSRF через обход NO_PROXY, prototype-pollution с обходом аутентификации) и дерево protobufjs/@grpc/grpc-js в finam-trade.

2. Исправление CI (коммит 952bbb3)
Semver-безопасный npm audit fix (без --force): менялись только lock-файлы, package.json не тронут, lockfileVersion остался 3:

  • dedust/evaa/stonfi: axios 1.13.5 → 1.17.0, follow-redirects 1.15.11 → 1.16.0
  • finam-trade: @grpc/grpc-js 1.14.3 → 1.14.4, protobufjs 7.5.5 → 7.6.4

Решение честное: gate был добавлен намеренно (#128), ослаблять его или откатывать бамп версии (создав рассинхрон package.json/manifest.json) было бы неверно.

3. Проверка фикса issue #184
Сверил тело execute/multi_execute с Composio v3 API (официальная спецификация): connected_account_id, user_id, version — верхнеуровневые поля, arguments содержит только параметры инструмента. Подтвердил: нет остатков @composio/core SDK, нет антипаттерна инъекции в arguments, версия согласована (manifest = package.json = тесты = 1.9.0), тесты переписаны под корректный контракт.

4. Финализация
Влил upstream/main, запушил, обновил описание PR (примечание «уязвимости вне scope» заменено на документацию фактического фикса с таблицей обновлений и ссылками на advisory).

Результаты проверок

  • Все 9 CI check-ов зелёные, 0 упавших: validate, Build (Runtime/SDK), Lint, Test, TypeScript, CodeQL, deploy.
  • Локальная репликация audit-цикла: 0 high/critical по всем 10 плагинам с lock-файлом (exit 0).
  • composio-direct: 57/57 тестов, 27 инструментов валидны; lint/typecheck чисты.

PR: #185 (MERGED)


This summary was automatically extracted from the AI working session output.

@konard

konard commented Jun 14, 2026

Copy link
Copy Markdown
Author

🔄 Auto-restart-until-mergeable Log (iteration 1)

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost estimation:

  • Public pricing estimate: $5.688135
  • Calculated by Anthropic: $20.549835
  • Difference: $14.861700 (+261.28%)

📊 Context and tokens usage:

Claude Opus 4.8: (2 sub-sessions)

  1. 116.9K / 1M (12%) input tokens, 50.4K / 128K (39%) output tokens
  2. 76.2K / 1M (8%) input tokens, 26.1K / 128K (20%) output tokens

Total: (12.9K new + 209.9K cache writes + 4.4M cache reads) input tokens, 82.7K output tokens, $5.658831 cost

Claude Haiku 4.5:

  • 16.4K / 200K (8%) input tokens, 571 / 64K (1%) output tokens

Total: 16.4K input tokens, 571 output tokens, $0.029304 cost

🤖 Models used:

  • Tool: Anthropic Claude Code
  • Requested: opus
  • Main model: Claude Opus 4.8 (claude-opus-4-8)
  • Additional models:
    • Claude Haiku 4.5 (claude-haiku-4-5-20251001)

📎 Log file uploaded as Gist (8210KB)


Now working session is ended, feel free to review and add any feedback on the solution draft.

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.

Check all the logic of the composio-direct plugin

2 participants